Uprev to branch-heads/74 To commit 'Merge to M74: Revert "Remove rtc::TimeMillis() call from ALR detector."' https://webrtc.googlesource.com/src/+/303fc7963064a46a27e8287e531ded8cec21ff77 Existing aec.ini config files should be modified base on the parameters change as below: Added: AEC_DELAY_DELAY_HEADROOM_SAMPLES "delay:delay_headroom_samples" AEC_DELAY_HYSTERESIS_LIMIT_BLOCKS "delay:hysteresis_limit_blocks" AEC_EP_STRENGTH_DEFAULT_GAIN "ep_strength:default_gain" Removed: AEC_BUFFERING_USE_NEW_RENDER_BUFFERING "buffering:use_new_render_buffering" AEC_DELAY_API_CALL_JITTER_BLOCKS "delay:api_call_jitter_blocks" AEC_DELAY_MIN_ECHO_PATH_DELAY_BLOCKS "delay:min_echo_path_delay_blocks" AEC_DELAY_DELAY_HEADROOM_BLOCKS "delay:delay_headroom_blocks" AEC_DELAY_HYSTERESIS_LIMIT_1_BLOCKS "delay:hysteresis_limit_1_blocks" AEC_DELAY_HYSTERESIS_LIMIT_2_BLOCKS "delay:hysteresis_limit_2_blocks" AEC_DELAY_SKEW_HYSTERESIS_BLOCKS "delay:skew_hysteresis_blocks" AEC_EP_STRENGTH_LF "ep_strength:lf" AEC_EP_STRENGTH_MF "ep_strength:mf" AEC_EP_STRENGTH_HF "ep_strength:hf" AEC_ECHO_REMOVAL_CTL_INITIAL_GAIN "echo_removal_control:initial_gain" AEC_ECHO_REMOVAL_CTL_FIRST_NON_ZERO_GAIN "echo_removal_control:first_non_zero_gain" AEC_ECHO_REMOVAL_CTL_NON_ZERO_GAIN_BLOCKS "echo_removal_control:non_zero_gain_blocks" AEC_ECHO_REMOVAL_CTL_FULL_GAIN_BLOCKS "echo_removal_control:full_gain_blocks" BUG=chromium:947914 TEST=emerge-atlas webrtc-apm CQ-DEPEND=CL:1545342 Change-Id: Ifb701bfc14844c32b8d7561c4b48fd61be3f7157 Reviewed-on: https://chromium-review.googlesource.com/1545814 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Tested-by: Hsinyu Chao <hychao@chromium.org> Reviewed-by: Hsinyu Chao <hychao@chromium.org> Reviewed-by: Per Ã…hgren <peah@chromium.org>
diff --git a/absl/BUILD.bazel b/absl/BUILD.bazel index edd0274..8e3c177 100644 --- a/absl/BUILD.bazel +++ b/absl/BUILD.bazel
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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,
diff --git a/absl/CMakeLists.txt b/absl/CMakeLists.txt index 1d09b19..bba0f3e 100644 --- a/absl/CMakeLists.txt +++ b/absl/CMakeLists.txt
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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,
diff --git a/absl/algorithm/BUILD.bazel b/absl/algorithm/BUILD.bazel index d04dc71..8d266db 100644 --- a/absl/algorithm/BUILD.bazel +++ b/absl/algorithm/BUILD.bazel
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -15,7 +15,7 @@ # load( - "//absl:copts.bzl", + "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_TEST_COPTS", )
diff --git a/absl/algorithm/CMakeLists.txt b/absl/algorithm/CMakeLists.txt index fdf45c5..c51eb10 100644 --- a/absl/algorithm/CMakeLists.txt +++ b/absl/algorithm/CMakeLists.txt
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -14,50 +14,50 @@ # limitations under the License. # -list(APPEND ALGORITHM_PUBLIC_HEADERS - "algorithm.h" - "container.h" -) - - -# -## TESTS -# - -# test algorithm_test -list(APPEND ALGORITHM_TEST_SRC - "algorithm_test.cc" - ${ALGORITHM_PUBLIC_HEADERS} - ${ALGORITHM_INTERNAL_HEADERS} -) - -absl_header_library( - TARGET - absl_algorithm - EXPORT_NAME +absl_cc_library( + NAME algorithm + HDRS + "algorithm.h" + COPTS + ${ABSL_DEFAULT_COPTS} + PUBLIC ) -absl_test( - TARGET +absl_cc_test( + NAME algorithm_test - SOURCES - ${ALGORITHM_TEST_SRC} - PUBLIC_LIBRARIES + SRCS + "algorithm_test.cc" + DEPS absl::algorithm + gmock_main ) - - - -# test container_test -set(CONTAINER_TEST_SRC "container_test.cc") - -absl_test( - TARGET - container_test - SOURCES - ${CONTAINER_TEST_SRC} - PUBLIC_LIBRARIES +absl_cc_library( + NAME + algorithm_container + HDRS + "container.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS absl::algorithm + absl::core_headers + absl::meta + PUBLIC +) + +absl_cc_test( + NAME + container_test + SRCS + "container_test.cc" + DEPS + absl::algorithm_container + absl::base + absl::core_headers + absl::memory + absl::span + gmock_main )
diff --git a/absl/algorithm/algorithm.h b/absl/algorithm/algorithm.h index 3d65864..bb90215 100644 --- a/absl/algorithm/algorithm.h +++ b/absl/algorithm/algorithm.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -94,7 +94,7 @@ // then the predicate is never invoked and the function returns false. // // This is a C++11-compatible implementation of C++14 `std::equal`. See -// http://en.cppreference.com/w/cpp/algorithm/equal for more information. +// https://en.cppreference.com/w/cpp/algorithm/equal for more information. template <typename InputIter1, typename InputIter2, typename Pred> bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2, InputIter2 last2, Pred&& pred) {
diff --git a/absl/algorithm/algorithm_test.cc b/absl/algorithm/algorithm_test.cc index e4322bc..81fccb6 100644 --- a/absl/algorithm/algorithm_test.cc +++ b/absl/algorithm/algorithm_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h index 53ab156..752e47b 100644 --- a/absl/algorithm/container.h +++ b/absl/algorithm/container.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -36,7 +36,6 @@ // For template parameter and variable naming, `C` indicates the container type // to which the function is applied, `Pred` indicates the predicate object type // to be used by the function and `T` indicates the applicable element type. -// #ifndef ABSL_ALGORITHM_CONTAINER_H_ #define ABSL_ALGORITHM_CONTAINER_H_ @@ -46,6 +45,8 @@ #include <iterator> #include <numeric> #include <type_traits> +#include <unordered_map> +#include <unordered_set> #include <utility> #include <vector> @@ -54,7 +55,6 @@ #include "absl/meta/type_traits.h" namespace absl { - namespace container_algorithm_internal { // NOTE: it is important to defer to ADL lookup for building with C++ modules, @@ -101,6 +101,17 @@ template <typename C> ContainerIter<C> c_end(C& c) { return end(c); } +template <typename T> +struct IsUnorderedContainer : std::false_type {}; + +template <class Key, class T, class Hash, class KeyEqual, class Allocator> +struct IsUnorderedContainer< + std::unordered_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type {}; + +template <class Key, class Hash, class KeyEqual, class Allocator> +struct IsUnorderedContainer<std::unordered_set<Key, Hash, KeyEqual, Allocator>> + : std::true_type {}; + } // namespace container_algorithm_internal // PUBLIC API @@ -636,7 +647,6 @@ // and `unique()` are omitted, because it's not clear whether or not such // functions should call erase on their supplied sequences afterwards. Either // behavior would be surprising for a different set of users. -// // c_remove_copy() // @@ -1154,7 +1164,13 @@ // Container-based version of the <algorithm> `std::set_union()` function // to return an iterator containing the union of two containers; duplicate // values are not copied into the output. -template <typename C1, typename C2, typename OutputIterator> +template <typename C1, typename C2, typename OutputIterator, + typename = typename std::enable_if< + !container_algorithm_internal::IsUnorderedContainer<C1>::value, + void>::type, + typename = typename std::enable_if< + !container_algorithm_internal::IsUnorderedContainer<C2>::value, + void>::type> OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output) { return std::set_union(container_algorithm_internal::c_begin(c1), container_algorithm_internal::c_end(c1), @@ -1164,7 +1180,13 @@ // Overload of c_set_union() for performing a merge using a `comp` other than // `operator<`. -template <typename C1, typename C2, typename OutputIterator, typename Compare> +template <typename C1, typename C2, typename OutputIterator, typename Compare, + typename = typename std::enable_if< + !container_algorithm_internal::IsUnorderedContainer<C1>::value, + void>::type, + typename = typename std::enable_if< + !container_algorithm_internal::IsUnorderedContainer<C2>::value, + void>::type> OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output, Compare&& comp) { return std::set_union(container_algorithm_internal::c_begin(c1), @@ -1178,7 +1200,13 @@ // // Container-based version of the <algorithm> `std::set_intersection()` function // to return an iterator containing the intersection of two containers. -template <typename C1, typename C2, typename OutputIterator> +template <typename C1, typename C2, typename OutputIterator, + typename = typename std::enable_if< + !container_algorithm_internal::IsUnorderedContainer<C1>::value, + void>::type, + typename = typename std::enable_if< + !container_algorithm_internal::IsUnorderedContainer<C2>::value, + void>::type> OutputIterator c_set_intersection(const C1& c1, const C2& c2, OutputIterator output) { return std::set_intersection(container_algorithm_internal::c_begin(c1), @@ -1189,7 +1217,13 @@ // Overload of c_set_intersection() for performing a merge using a `comp` other // than `operator<`. -template <typename C1, typename C2, typename OutputIterator, typename Compare> +template <typename C1, typename C2, typename OutputIterator, typename Compare, + typename = typename std::enable_if< + !container_algorithm_internal::IsUnorderedContainer<C1>::value, + void>::type, + typename = typename std::enable_if< + !container_algorithm_internal::IsUnorderedContainer<C2>::value, + void>::type> OutputIterator c_set_intersection(const C1& c1, const C2& c2, OutputIterator output, Compare&& comp) { return std::set_intersection(container_algorithm_internal::c_begin(c1), @@ -1204,7 +1238,13 @@ // Container-based version of the <algorithm> `std::set_difference()` function // to return an iterator containing elements present in the first container but // not in the second. -template <typename C1, typename C2, typename OutputIterator> +template <typename C1, typename C2, typename OutputIterator, + typename = typename std::enable_if< + !container_algorithm_internal::IsUnorderedContainer<C1>::value, + void>::type, + typename = typename std::enable_if< + !container_algorithm_internal::IsUnorderedContainer<C2>::value, + void>::type> OutputIterator c_set_difference(const C1& c1, const C2& c2, OutputIterator output) { return std::set_difference(container_algorithm_internal::c_begin(c1), @@ -1215,7 +1255,13 @@ // Overload of c_set_difference() for performing a merge using a `comp` other // than `operator<`. -template <typename C1, typename C2, typename OutputIterator, typename Compare> +template <typename C1, typename C2, typename OutputIterator, typename Compare, + typename = typename std::enable_if< + !container_algorithm_internal::IsUnorderedContainer<C1>::value, + void>::type, + typename = typename std::enable_if< + !container_algorithm_internal::IsUnorderedContainer<C2>::value, + void>::type> OutputIterator c_set_difference(const C1& c1, const C2& c2, OutputIterator output, Compare&& comp) { return std::set_difference(container_algorithm_internal::c_begin(c1), @@ -1230,7 +1276,13 @@ // Container-based version of the <algorithm> `std::set_symmetric_difference()` // function to return an iterator containing elements present in either one // container or the other, but not both. -template <typename C1, typename C2, typename OutputIterator> +template <typename C1, typename C2, typename OutputIterator, + typename = typename std::enable_if< + !container_algorithm_internal::IsUnorderedContainer<C1>::value, + void>::type, + typename = typename std::enable_if< + !container_algorithm_internal::IsUnorderedContainer<C2>::value, + void>::type> OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2, OutputIterator output) { return std::set_symmetric_difference( @@ -1242,7 +1294,13 @@ // Overload of c_set_symmetric_difference() for performing a merge using a // `comp` other than `operator<`. -template <typename C1, typename C2, typename OutputIterator, typename Compare> +template <typename C1, typename C2, typename OutputIterator, typename Compare, + typename = typename std::enable_if< + !container_algorithm_internal::IsUnorderedContainer<C1>::value, + void>::type, + typename = typename std::enable_if< + !container_algorithm_internal::IsUnorderedContainer<C2>::value, + void>::type> OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2, OutputIterator output, Compare&& comp) {
diff --git a/absl/algorithm/container_test.cc b/absl/algorithm/container_test.cc index 1502b17..04282b8 100644 --- a/absl/algorithm/container_test.cc +++ b/absl/algorithm/container_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/algorithm/equal_benchmark.cc b/absl/algorithm/equal_benchmark.cc index 19c0780..7bf62c9 100644 --- a/absl/algorithm/equal_benchmark.cc +++ b/absl/algorithm/equal_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index f7d8101..804f62a 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -15,7 +15,7 @@ # load( - "//absl:copts.bzl", + "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_TEST_COPTS", "ABSL_EXCEPTIONS_FLAG", @@ -67,6 +67,7 @@ name = "core_headers", hdrs = [ "attributes.h", + "const_init.h", "macros.h", "optimization.h", "port.h", @@ -75,7 +76,6 @@ copts = ABSL_DEFAULT_COPTS, deps = [ ":config", - ":dynamic_annotations", ], ) @@ -89,6 +89,10 @@ "internal/low_level_alloc.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = select({ + "//absl:windows": [], + "//conditions:default": ["-pthread"], + }), visibility = [ "//absl:__subpackages__", ], @@ -108,6 +112,7 @@ "internal/identity.h", "internal/inline_variable.h", "internal/invoke.h", + "internal/scheduling_mode.h", ], copts = ABSL_DEFAULT_COPTS, visibility = [ @@ -141,6 +146,10 @@ "log_severity.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = select({ + "//absl:windows": [], + "//conditions:default": ["-pthread"], + }), deps = [ ":base_internal", ":config", @@ -188,7 +197,6 @@ deps = [ ":base", ":config", - ":core_headers", ], ) @@ -231,13 +239,12 @@ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, deps = [ - ":base", ":config", ":pretty_function", "//absl/memory", "//absl/meta:type_traits", "//absl/strings", - "//absl/types:optional", + "//absl/utility", "@com_google_googletest//:gtest", ], ) @@ -316,6 +323,33 @@ ) cc_library( + name = "spinlock_benchmark_common", + testonly = 1, + srcs = ["internal/spinlock_benchmark.cc"], + copts = ABSL_TEST_COPTS, + visibility = [ + "//absl/base:__pkg__", + ], + deps = [ + ":base", + ":base_internal", + "//absl/synchronization", + "@com_github_google_benchmark//:benchmark_main", + ], + alwayslink = 1, +) + +cc_binary( + name = "spinlock_benchmark", + testonly = 1, + copts = ABSL_DEFAULT_COPTS, + visibility = ["//visibility:private"], + deps = [ + ":spinlock_benchmark_common", + ], +) + +cc_library( name = "endian", hdrs = [ "internal/endian.h", @@ -397,10 +431,6 @@ size = "small", srcs = ["internal/low_level_alloc_test.cc"], copts = ABSL_TEST_COPTS, - linkopts = select({ - "//absl:windows": [], - "//conditions:default": ["-pthread"], - }), tags = ["no_test_ios_x86_64"], deps = [":malloc_internal"], ) @@ -410,10 +440,6 @@ size = "small", srcs = ["internal/thread_identity_test.cc"], copts = ABSL_TEST_COPTS, - linkopts = select({ - "//absl:windows": [], - "//conditions:default": ["-pthread"], - }), tags = [ "no_test_wasm", ], @@ -457,3 +483,25 @@ "@com_google_googletest//:gtest_main", ], ) + +cc_library( + name = "scoped_set_env", + testonly = 1, + srcs = ["internal/scoped_set_env.cc"], + hdrs = ["internal/scoped_set_env.h"], + visibility = [ + "//absl:__subpackages__", + ], + deps = [":base"], +) + +cc_test( + name = "scoped_set_env_test", + size = "small", + srcs = ["internal/scoped_set_env_test.cc"], + copts = ABSL_TEST_COPTS, + deps = [ + ":scoped_set_env", + "@com_google_googletest//:gtest_main", + ], +)
diff --git a/absl/base/BUILD.gn b/absl/base/BUILD.gn index 6c540f3..c7fa3f3 100644 --- a/absl/base/BUILD.gn +++ b/absl/base/BUILD.gn
@@ -88,6 +88,7 @@ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] public = [ "attributes.h", + "const_init.h", "macros.h", "optimization.h", "port.h", @@ -95,7 +96,6 @@ ] deps = [ ":config", - ":dynamic_annotations", ] } @@ -136,6 +136,7 @@ "internal/identity.h", "internal/inline_variable.h", "internal/invoke.h", + "internal/scheduling_mode.h", ] visibility = [] visibility += [ "../*" ] @@ -196,7 +197,6 @@ deps = [ ":base", ":config", - ":core_headers", ] visibility = [] visibility += [ "../*" ] @@ -251,13 +251,12 @@ # "internal/exception_safety_testing.h", # ] # deps = [ -# ":base", # ":config", # ":pretty_function", # "../memory", # "../meta:type_traits", # "../strings", -# "../types:optional", +# "../utility", # "//testing/gtest", # ] # } @@ -314,3 +313,23 @@ visibility = [] visibility += [ "../*" ] } + +source_set("scoped_set_env") { + testonly = true + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ + "//build/config/compiler:no_chromium_code", + "//third_party/abseil-cpp:absl_default_cflags_cc", + ] + public = [ + "internal/scoped_set_env.h", + ] + sources = [ + "internal/scoped_set_env.cc", + ] + deps = [ + ":base", + ] + visibility = [] + visibility += [ "../*" ] +}
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt index 04a6eb3..d8a311c 100644 --- a/absl/base/CMakeLists.txt +++ b/absl/base/CMakeLists.txt
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -14,374 +14,427 @@ # limitations under the License. # -list(APPEND BASE_PUBLIC_HEADERS - "attributes.h" - "call_once.h" - "casts.h" - "config.h" - "dynamic_annotations.h" - "log_severity.h" - "macros.h" - "optimization.h" - "policy_checks.h" - "port.h" - "thread_annotations.h" +absl_cc_library( + NAME + spinlock_wait + HDRS + "internal/scheduling_mode.h" + "internal/spinlock_wait.h" + SRCS + "internal/spinlock_akaros.inc" + "internal/spinlock_linux.inc" + "internal/spinlock_posix.inc" + "internal/spinlock_wait.cc" + "internal/spinlock_win32.inc" + DEPS + absl::core_headers ) - -list(APPEND BASE_INTERNAL_HEADERS - "internal/atomic_hook.h" - "internal/bits.h" - "internal/cycleclock.h" - "internal/direct_mmap.h" - "internal/endian.h" - "internal/exception_testing.h" - "internal/exception_safety_testing.h" - "internal/hide_ptr.h" - "internal/identity.h" - "internal/invoke.h" - "internal/inline_variable.h" - "internal/low_level_alloc.h" - "internal/low_level_scheduling.h" - "internal/per_thread_tls.h" - "internal/pretty_function.h" - "internal/raw_logging.h" - "internal/scheduling_mode.h" - "internal/spinlock.h" - "internal/spinlock_wait.h" - "internal/sysinfo.h" - "internal/thread_identity.h" - "internal/throw_delegate.h" - "internal/tsan_mutex_interface.h" - "internal/unaligned_access.h" - "internal/unscaledcycleclock.h" +absl_cc_library( + NAME + config + HDRS + "config.h" + "policy_checks.h" + COPTS + ${ABSL_DEFAULT_COPTS} + PUBLIC ) - -# absl_base main library -list(APPEND BASE_SRC - "internal/cycleclock.cc" - "internal/raw_logging.cc" - "internal/spinlock.cc" - "internal/sysinfo.cc" - "internal/thread_identity.cc" - "internal/unscaledcycleclock.cc" - "internal/low_level_alloc.cc" - ${BASE_PUBLIC_HEADERS} - ${BASE_INTERNAL_HEADERS} +absl_cc_library( + NAME + dynamic_annotations + HDRS + "dynamic_annotations.h" + SRCS + "dynamic_annotations.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEFINES + "__CLANG_SUPPORT_DYN_ANNOTATION__" + PUBLIC ) -absl_library( - TARGET - absl_base - SOURCES - ${BASE_SRC} - PUBLIC_LIBRARIES - absl_dynamic_annotations - absl_spinlock_wait - EXPORT_NAME - base +absl_cc_library( + NAME + core_headers + HDRS + "attributes.h" + "const_init.h" + "macros.h" + "optimization.h" + "port.h" + "thread_annotations.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::config + PUBLIC ) -# throw delegate library -set(THROW_DELEGATE_SRC "internal/throw_delegate.cc") - -absl_library( - TARGET - absl_throw_delegate - SOURCES - ${THROW_DELEGATE_SRC} - PUBLIC_LIBRARIES - ${THROW_DELEGATE_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS - ${ABSL_EXCEPTIONS_FLAG} - EXPORT_NAME - throw_delegate -) - -if(BUILD_TESTING) - # exception-safety testing library - set(EXCEPTION_SAFETY_TESTING_SRC - "internal/exception_safety_testing.h" - "internal/exception_safety_testing.cc" - ) - set(EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES - ${ABSL_TEST_COMMON_LIBRARIES} +absl_cc_library( + NAME + malloc_internal + HDRS + "internal/direct_mmap.h" + "internal/low_level_alloc.h" + SRCS + "internal/low_level_alloc.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS absl::base + absl::config + absl::core_headers + absl::dynamic_annotations + absl::spinlock_wait +) + +absl_cc_library( + NAME + base_internal + HDRS + "internal/hide_ptr.h" + "internal/identity.h" + "internal/inline_variable.h" + "internal/invoke.h" + COPTS + ${ABSL_DEFAULT_COPTS} +) + +absl_cc_library( + NAME + base + HDRS + "call_once.h" + "casts.h" + "internal/atomic_hook.h" + "internal/cycleclock.h" + "internal/low_level_scheduling.h" + "internal/per_thread_tls.h" + "internal/raw_logging.h" + "internal/spinlock.h" + "internal/sysinfo.h" + "internal/thread_identity.h" + "internal/tsan_mutex_interface.h" + "internal/unscaledcycleclock.h" + "log_severity.h" + SRCS + "internal/cycleclock.cc" + "internal/raw_logging.cc" + "internal/spinlock.cc" + "internal/sysinfo.cc" + "internal/thread_identity.cc" + "internal/unscaledcycleclock.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::base_internal + absl::config + absl::core_headers + absl::dynamic_annotations + absl::spinlock_wait + PUBLIC +) + +absl_cc_library( + NAME + throw_delegate + HDRS + "internal/throw_delegate.h" + SRCS + "internal/throw_delegate.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + ${ABSL_EXCEPTIONS_FLAG} + DEPS + absl::base +) + +absl_cc_library( + NAME + exception_testing + HDRS + "internal/exception_testing.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::config + gtest + TESTONLY +) + +absl_cc_library( + NAME + pretty_function + HDRS + "internal/pretty_function.h" + COPTS + ${ABSL_DEFAULT_COPTS} +) + +absl_cc_library( + NAME + exception_safety_testing + HDRS + "internal/exception_safety_testing.h" + SRCS + "internal/exception_safety_testing.cc" + COPTS + ${ABSL_TEST_COPTS} + ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::config + absl::pretty_function absl::memory absl::meta absl::strings - absl::optional + absl::utility gtest - ) - -absl_library( - TARGET - absl_base_internal_exception_safety_testing - SOURCES - ${EXCEPTION_SAFETY_TESTING_SRC} - PUBLIC_LIBRARIES - ${EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS - ${ABSL_EXCEPTIONS_FLAG} -) -endif() - - -# dynamic_annotations library -set(DYNAMIC_ANNOTATIONS_SRC "dynamic_annotations.cc") - -absl_library( - TARGET - absl_dynamic_annotations - SOURCES - ${DYNAMIC_ANNOTATIONS_SRC} + TESTONLY ) - -# spinlock_wait library -set(SPINLOCK_WAIT_SRC "internal/spinlock_wait.cc") - -absl_library( - TARGET - absl_spinlock_wait - SOURCES - ${SPINLOCK_WAIT_SRC} -) - - -# malloc_internal library -list(APPEND MALLOC_INTERNAL_SRC - "internal/low_level_alloc.cc" -) - -absl_library( - TARGET - absl_malloc_internal - SOURCES - ${MALLOC_INTERNAL_SRC} - PUBLIC_LIBRARIES - absl_dynamic_annotations -) - - - -# -## TESTS -# - -# call once test -set(ATOMIC_HOOK_TEST_SRC "internal/atomic_hook_test.cc") -set(ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES absl::base) - -absl_test( - TARGET - atomic_hook_test - SOURCES - ${ATOMIC_HOOK_TEST_SRC} - PUBLIC_LIBRARIES - ${ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES} -) - - -# call once test -set(CALL_ONCE_TEST_SRC "call_once_test.cc") -set(CALL_ONCE_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) - -absl_test( - TARGET - call_once_test - SOURCES - ${CALL_ONCE_TEST_SRC} - PUBLIC_LIBRARIES - ${CALL_ONCE_TEST_PUBLIC_LIBRARIES} -) - - -# test bit_cast_test -set(BIT_CAST_TEST_SRC "bit_cast_test.cc") - -absl_test( - TARGET - bit_cast_test - SOURCES - ${BIT_CAST_TEST_SRC} -) - - -# test absl_throw_delegate_test -set(THROW_DELEGATE_TEST_SRC "throw_delegate_test.cc") -set(THROW_DELEGATE_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate) - -absl_test( - TARGET - throw_delegate_test - SOURCES - ${THROW_DELEGATE_TEST_SRC} - PUBLIC_LIBRARIES - ${THROW_DELEGATE_TEST_PUBLIC_LIBRARIES} -) - - -# test invoke_test -set(INVOKE_TEST_SRC "invoke_test.cc") -set(INVOKE_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET - invoke_test - SOURCES - ${INVOKE_TEST_SRC} - PUBLIC_LIBRARIES - ${INVOKE_TEST_PUBLIC_LIBRARIES} -) - - -# test inline_variable_test -list(APPEND INLINE_VARIABLE_TEST_SRC - "internal/inline_variable_testing.h" - "inline_variable_test.cc" - "inline_variable_test_a.cc" - "inline_variable_test_b.cc" -) - -set(INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES absl::base) - -absl_test( - TARGET - inline_variable_test - SOURCES - ${INLINE_VARIABLE_TEST_SRC} - PUBLIC_LIBRARIES - ${INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES} -) - - -# test spinlock_test_common -set(SPINLOCK_TEST_COMMON_SRC "spinlock_test_common.cc") -set(SPINLOCK_TEST_COMMON_PUBLIC_LIBRARIES absl::base absl::synchronization) - -absl_test( - TARGET - spinlock_test_common - SOURCES - ${SPINLOCK_TEST_COMMON_SRC} - PUBLIC_LIBRARIES - ${SPINLOCK_TEST_COMMON_PUBLIC_LIBRARIES} -) - - -# test spinlock_test -set(SPINLOCK_TEST_SRC "spinlock_test_common.cc") -set(SPINLOCK_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) - -absl_test( - TARGET - spinlock_test - SOURCES - ${SPINLOCK_TEST_SRC} - PUBLIC_LIBRARIES - ${SPINLOCK_TEST_PUBLIC_LIBRARIES} -) - - -# test endian_test -set(ENDIAN_TEST_SRC "internal/endian_test.cc") - -absl_test( - TARGET - endian_test - SOURCES - ${ENDIAN_TEST_SRC} -) - - -# test config_test -set(CONFIG_TEST_SRC "config_test.cc") -set(CONFIG_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) -absl_test( - TARGET - config_test - SOURCES - ${CONFIG_TEST_SRC} - PUBLIC_LIBRARIES - ${CONFIG_TEST_PUBLIC_LIBRARIES} -) - - -# test raw_logging_test -set(RAW_LOGGING_TEST_SRC "raw_logging_test.cc") -set(RAW_LOGGING_TEST_PUBLIC_LIBRARIES absl::base absl::strings) - -absl_test( - TARGET - raw_logging_test - SOURCES - ${RAW_LOGGING_TEST_SRC} - PUBLIC_LIBRARIES - ${RAW_LOGGING_TEST_PUBLIC_LIBRARIES} -) - - -# test sysinfo_test -set(SYSINFO_TEST_SRC "internal/sysinfo_test.cc") -set(SYSINFO_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) - -absl_test( - TARGET - sysinfo_test - SOURCES - ${SYSINFO_TEST_SRC} - PUBLIC_LIBRARIES - ${SYSINFO_TEST_PUBLIC_LIBRARIES} -) - - -# test low_level_alloc_test -set(LOW_LEVEL_ALLOC_TEST_SRC "internal/low_level_alloc_test.cc") -set(LOW_LEVEL_ALLOC_TEST_PUBLIC_LIBRARIES absl::base) - -absl_test( - TARGET - low_level_alloc_test - SOURCES - ${LOW_LEVEL_ALLOC_TEST_SRC} - PUBLIC_LIBRARIES - ${LOW_LEVEL_ALLOC_TEST_PUBLIC_LIBRARIES} -) - - -# test thread_identity_test -set(THREAD_IDENTITY_TEST_SRC "internal/thread_identity_test.cc") -set(THREAD_IDENTITY_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) - -absl_test( - TARGET - thread_identity_test - SOURCES - ${THREAD_IDENTITY_TEST_SRC} - PUBLIC_LIBRARIES - ${THREAD_IDENTITY_TEST_PUBLIC_LIBRARIES} -) - -#test exceptions_safety_testing_test -set(EXCEPTION_SAFETY_TESTING_TEST_SRC "exception_safety_testing_test.cc") -set(EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES - absl::base - absl_base_internal_exception_safety_testing - absl::memory - absl::meta - absl::strings - absl::optional -) - -absl_test( - TARGET +absl_cc_test( + NAME absl_exception_safety_testing_test - SOURCES - ${EXCEPTION_SAFETY_TESTING_TEST_SRC} - PUBLIC_LIBRARIES - ${EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS + SRCS + "exception_safety_testing_test.cc" + COPTS + ${ABSL_TEST_COPTS} ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::exception_safety_testing + absl::memory + gtest_main +) + +absl_cc_test( + NAME + atomic_hook_test + SRCS + "internal/atomic_hook_test.cc" + DEPS + absl::base + absl::core_headers + gtest_main +) + +absl_cc_test( + NAME + bit_cast_test + SRCS + "bit_cast_test.cc" + DEPS + absl::base + absl::core_headers + gtest_main +) + +absl_cc_test( + NAME + throw_delegate_test + SRCS + "throw_delegate_test.cc" + DEPS + absl::base + absl::throw_delegate + gtest_main +) + +absl_cc_test( + NAME + inline_variable_test + SRCS + "internal/inline_variable_testing.h" + "inline_variable_test.cc" + "inline_variable_test_a.cc" + "inline_variable_test_b.cc" + DEPS + absl::base_internal + gtest_main +) + +absl_cc_test( + NAME + invoke_test + SRCS + "invoke_test.cc" + DEPS + absl::base_internal + absl::memory + absl::strings + gmock + gtest_main +) + +absl_cc_library( + NAME + spinlock_test_common + SRCS + "spinlock_test_common.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::base + absl::core_headers + absl::spinlock_wait + absl::synchronization + gtest + TESTONLY +) + +# On bazel BUILD this target use "alwayslink = 1" which is not implemented here +absl_cc_test( + NAME + spinlock_test + SRCS + "spinlock_test_common.cc" + DEPS + absl::base + absl::core_headers + absl::spinlock_wait + absl::synchronization + gtest_main +) + +absl_cc_library( + NAME + endian + HDRS + "internal/endian.h" + "internal/unaligned_access.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::config + absl::core_headers + PUBLIC +) + +absl_cc_test( + NAME + endian_test + SRCS + "internal/endian_test.cc" + DEPS + absl::base + absl::config + absl::endian + gtest_main +) + +absl_cc_test( + NAME + config_test + SRCS + "config_test.cc" + DEPS + absl::config + absl::synchronization + gtest_main +) + +absl_cc_test( + NAME + call_once_test + SRCS + "call_once_test.cc" + DEPS + absl::base + absl::core_headers + absl::synchronization + gtest_main +) + +absl_cc_test( + NAME + raw_logging_test + SRCS + "raw_logging_test.cc" + DEPS + absl::base + absl::strings + gtest_main +) + +absl_cc_test( + NAME + sysinfo_test + SRCS + "internal/sysinfo_test.cc" + DEPS + absl::base + absl::synchronization + gtest_main +) + +absl_cc_test( + NAME + low_level_alloc_test + SRCS + "internal/low_level_alloc_test.cc" + DEPS + absl::malloc_internal + Threads::Threads +) + +absl_cc_test( + NAME + thread_identity_test + SRCS + "internal/thread_identity_test.cc" + DEPS + absl::base + absl::core_headers + absl::synchronization + Threads::Threads + gtest_main +) + +absl_cc_library( + NAME + bits + HDRS + "internal/bits.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::core_headers +) + +absl_cc_test( + NAME + bits_test + SRCS + "internal/bits_test.cc" + DEPS + absl::bits + gtest_main +) + +absl_cc_library( + NAME + scoped_set_env + SRCS + "internal/scoped_set_env.cc" + HDRS + "internal/scoped_set_env.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::base +) + +absl_cc_test( + NAME + scoped_set_env_test + SRCS + "internal/scoped_set_env_test.cc" + DEPS + absl::scoped_set_env + gtest_main )
diff --git a/absl/base/attributes.h b/absl/base/attributes.h index e850022..48195d6 100644 --- a/absl/base/attributes.h +++ b/absl/base/attributes.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -80,7 +80,7 @@ // // A function-like feature checking macro that accepts C++11 style attributes. // It's a wrapper around `__has_cpp_attribute`, defined by ISO C++ SD-6 -// (http://en.cppreference.com/w/cpp/experimental/feature_test). If we don't +// (https://en.cppreference.com/w/cpp/experimental/feature_test). If we don't // find `__has_cpp_attribute`, will evaluate to 0. #if defined(__cplusplus) && defined(__has_cpp_attribute) // NOTE: requiring __cplusplus above should not be necessary, but @@ -102,7 +102,7 @@ // // Tells the compiler to perform `printf` format string checking if the // compiler supports it; see the 'format' attribute in -// <http://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>. +// <https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>. // // Note: As the GCC manual states, "[s]ince non-static C++ methods // have an implicit 'this' argument, the arguments of such methods @@ -155,7 +155,12 @@ // ABSL_ATTRIBUTE_WEAK // // Tags a function as weak for the purposes of compilation and linking. -#if ABSL_HAVE_ATTRIBUTE(weak) || (defined(__GNUC__) && !defined(__clang__)) +// 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) || \ + (defined(__GNUC__) && !defined(__clang__))) && \ + !(defined(__llvm__) && defined(_WIN32)) #undef ABSL_ATTRIBUTE_WEAK #define ABSL_ATTRIBUTE_WEAK __attribute__((weak)) #define ABSL_HAVE_ATTRIBUTE_WEAK 1 @@ -282,6 +287,17 @@ #define ABSL_ATTRIBUTE_NO_SANITIZE_CFI #endif +// ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK +// +// 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) +#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \ + __attribute__((no_sanitize("safe-stack"))) +#else +#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK +#endif + // ABSL_ATTRIBUTE_RETURNS_NONNULL // // Tells the compiler that a particular function never returns a null pointer. @@ -296,13 +312,13 @@ // ABSL_HAVE_ATTRIBUTE_SECTION // -// Indicates whether labeled sections are supported. Labeled sections are not -// supported on Darwin/iOS. +// Indicates whether labeled sections are supported. Weak symbol support is +// a prerequisite. Labeled sections are not supported on Darwin/iOS. #ifdef ABSL_HAVE_ATTRIBUTE_SECTION #error ABSL_HAVE_ATTRIBUTE_SECTION cannot be directly set #elif (ABSL_HAVE_ATTRIBUTE(section) || \ (defined(__GNUC__) && !defined(__clang__))) && \ - !defined(__APPLE__) + !defined(__APPLE__) && ABSL_HAVE_ATTRIBUTE_WEAK #define ABSL_HAVE_ATTRIBUTE_SECTION 1 // ABSL_ATTRIBUTE_SECTION @@ -397,17 +413,28 @@ // ABSL_MUST_USE_RESULT // -// Tells the compiler to warn about unused return values for functions declared -// with this macro. The macro must appear as the very first part of a function -// declaration or definition: +// Tells the compiler to warn about unused results. // -// Example: +// When annotating a function, it must appear as the first part of the +// declaration or definition. The compiler will warn if the return value from +// such a function is unused: // // ABSL_MUST_USE_RESULT Sprocket* AllocateSprocket(); +// AllocateSprocket(); // Triggers a warning. // -// This placement has the broadest compatibility with GCC, Clang, and MSVC, with -// both defs and decls, and with GCC-style attributes, MSVC declspec, C++11 -// and C++17 attributes. +// When annotating a class, it is equivalent to annotating every function which +// returns an instance. +// +// class ABSL_MUST_USE_RESULT Sprocket {}; +// Sprocket(); // Triggers a warning. +// +// Sprocket MakeSprocket(); +// MakeSprocket(); // Triggers a warning. +// +// Note that references and pointers are not instances: +// +// Sprocket* SprocketPointer(); +// SprocketPointer(); // Does *not* trigger a warning. // // ABSL_MUST_USE_RESULT allows using cast-to-void to suppress the unused result // warning. For that, warn_unused_result is used only for clang but not for gcc.
diff --git a/absl/base/bit_cast_test.cc b/absl/base/bit_cast_test.cc index 8cd878d..4846add 100644 --- a/absl/base/bit_cast_test.cc +++ b/absl/base/bit_cast_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/call_once.h b/absl/base/call_once.h index 532ee2e..8c4f297 100644 --- a/absl/base/call_once.h +++ b/absl/base/call_once.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -150,12 +150,8 @@ old_control != kOnceRunning && old_control != kOnceWaiter && old_control != kOnceDone) { - ABSL_RAW_LOG( - FATAL, - "Unexpected value for control word: %lx. Either the control word " - "has non-static storage duration (where GoogleOnceDynamic might " - "be appropriate), or there's been a memory corruption.", - static_cast<unsigned long>(old_control)); // NOLINT + ABSL_RAW_LOG(FATAL, "Unexpected value for control word: 0x%lx", + static_cast<unsigned long>(old_control)); // NOLINT } } #endif // NDEBUG
diff --git a/absl/base/call_once_test.cc b/absl/base/call_once_test.cc index cd58ee1..9c2a0c4 100644 --- a/absl/base/call_once_test.cc +++ b/absl/base/call_once_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -18,6 +18,8 @@ #include <vector> #include "gtest/gtest.h" +#include "absl/base/attributes.h" +#include "absl/base/const_init.h" #include "absl/base/thread_annotations.h" #include "absl/synchronization/mutex.h" @@ -25,7 +27,8 @@ namespace { absl::once_flag once; -Mutex counters_mu; + +ABSL_CONST_INIT Mutex counters_mu(absl::kConstInit); int running_thread_count GUARDED_BY(counters_mu) = 0; int call_once_invoke_count GUARDED_BY(counters_mu) = 0;
diff --git a/absl/base/casts.h b/absl/base/casts.h index 20fd34d..00196d2 100644 --- a/absl/base/casts.h +++ b/absl/base/casts.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -105,7 +105,7 @@ // // Such implicit cast chaining may be useful within template logic. template <typename To> -inline To implicit_cast(typename absl::internal::identity_t<To> to) { +constexpr To implicit_cast(typename absl::internal::identity_t<To> to) { return to; }
diff --git a/absl/base/config.h b/absl/base/config.h index d4eb7d0..3b81e26 100644 --- a/absl/base/config.h +++ b/absl/base/config.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -118,7 +118,7 @@ // Checks whether `std::is_trivially_copy_assignable<T>` is supported. // Notes: Clang with libc++ supports these features, as does gcc >= 5.1 with -// either libc++ or libstdc++, and Visual Studio. +// either libc++ or libstdc++, and Visual Studio (but not NVCC). #if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE) #error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set #elif defined(ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE) @@ -127,7 +127,7 @@ (!defined(__clang__) && defined(__GNUC__) && \ (__GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)) && \ (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || \ - defined(_MSC_VER) + (defined(_MSC_VER) && !defined(__NVCC__)) #define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1 #define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1 #endif @@ -139,12 +139,18 @@ #ifdef ABSL_HAVE_THREAD_LOCAL #error ABSL_HAVE_THREAD_LOCAL cannot be directly set #elif defined(__APPLE__) -// Notes: Xcode's clang did not support `thread_local` until version -// 8, and even then not for all iOS < 9.0. Also, Xcode 9.3 started disallowing -// `thread_local` for 32-bit iOS simulator targeting iOS 9.x. -// `__has_feature` is only supported by Clang so it has be inside +// Notes: +// * Xcode's clang did not support `thread_local` until version 8, and +// even then not for all iOS < 9.0. +// * 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. +// +// Otherwise, `__has_feature` is only supported by Clang so it has be inside // `defined(__APPLE__)` check. -#if __has_feature(cxx_thread_local) +#if __has_feature(cxx_thread_local) && \ + !(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0) #define ABSL_HAVE_THREAD_LOCAL 1 #endif #else // !defined(__APPLE__) @@ -268,7 +274,8 @@ #error ABSL_HAVE_MMAP cannot be directly set #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \ - defined(__wasm__) || defined(__Fuchsia__) || defined(__sun) + defined(__wasm__) || defined(__Fuchsia__) || defined(__sun) || \ + defined(__ASYLO__) #define ABSL_HAVE_MMAP 1 #endif @@ -322,6 +329,8 @@ #define ABSL_HAVE_ALARM 1 #elif defined(_MSC_VER) // feature tests for Microsoft's library +#elif defined(__EMSCRIPTEN__) +// emscripten doesn't support signals #elif defined(__native_client__) #else // other standard libraries @@ -356,6 +365,18 @@ #error "absl endian detection needs to be set up for your compiler" #endif +// MacOS 10.13 doesn't let you use <any>, <optional>, or <variant> even though +// the headers exist and are publicly noted to work. See +// https://github.com/abseil/abseil-cpp/issues/207 and +// https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes +#if defined(__APPLE__) && defined(_LIBCPP_VERSION) && \ + defined(__MAC_OS_X_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101400 +#define ABSL_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE 1 +#else +#define ABSL_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE 0 +#endif + // ABSL_HAVE_STD_ANY // // Checks whether C++17 std::any is available by checking whether <any> exists. @@ -364,7 +385,8 @@ #endif #ifdef __has_include -#if __has_include(<any>) && __cplusplus >= 201703L +#if __has_include(<any>) && __cplusplus >= 201703L && \ + !ABSL_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE #define ABSL_HAVE_STD_ANY 1 #endif #endif @@ -377,7 +399,8 @@ #endif #ifdef __has_include -#if __has_include(<optional>) && __cplusplus >= 201703L +#if __has_include(<optional>) && __cplusplus >= 201703L && \ + !ABSL_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE #define ABSL_HAVE_STD_OPTIONAL 1 #endif #endif @@ -390,7 +413,8 @@ #endif #ifdef __has_include -#if __has_include(<variant>) && __cplusplus >= 201703L +#if __has_include(<variant>) && __cplusplus >= 201703L && \ + !ABSL_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE #define ABSL_HAVE_STD_VARIANT 1 #endif #endif @@ -423,4 +447,12 @@ #define ABSL_HAVE_STD_STRING_VIEW 1 #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 +// variant_exception_safety_test. +#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_DEBUG) +#define ABSL_INTERNAL_MSVC_2017_DBG_MODE +#endif + #endif // ABSL_BASE_CONFIG_H_
diff --git a/absl/base/config_test.cc b/absl/base/config_test.cc index c839712..7e0c033 100644 --- a/absl/base/config_test.cc +++ b/absl/base/config_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/const_init.h b/absl/base/const_init.h new file mode 100644 index 0000000..17858a7 --- /dev/null +++ b/absl/base/const_init.h
@@ -0,0 +1,72 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// 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. +// +// ----------------------------------------------------------------------------- +// kConstInit +// ----------------------------------------------------------------------------- +// +// A constructor tag used to mark an object as safe for use as a global +// variable, avoiding the usual lifetime issues that can affect globals. + +#ifndef ABSL_BASE_CONST_INIT_H_ +#define ABSL_BASE_CONST_INIT_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 +// undefined behavior, unless their constructors and destructors are designed +// with this issue in mind. +// +// The normal way to deal with this issue in C++11 is to use constant +// initialization and trivial destructors. +// +// Constant initialization is guaranteed to occur before any other code +// executes. Constructors that are declared 'constexpr' are eligible for +// constant initialization. You can annotate a variable declaration with the +// ABSL_CONST_INIT macro to express this intent. For compilers that support +// it, this annotation will cause a compilation error for declarations that +// aren't subject to constant initialization (perhaps because a runtime value +// was passed as a constructor argument). +// +// On program shutdown, lifetime issues can be avoided on global objects by +// ensuring that they contain trivial destructors. A class has a trivial +// destructor unless it has a user-defined destructor, a virtual method or base +// class, or a data member or base class with a non-trivial destructor of its +// own. Objects with static storage duration and a trivial destructor are not +// cleaned up on program shutdown, and are thus safe to access from other code +// running during shutdown. +// +// For a few core Abseil classes, we make a best effort to allow for safe global +// instances, even though these classes have non-trivial destructors. These +// objects can be created with the absl::kConstInit tag. For example: +// ABSL_CONST_INIT absl::Mutex global_mutex(absl::kConstInit); +// +// The line above declares a global variable of type absl::Mutex which can be +// accessed at any point during startup or shutdown. global_mutex's destructor +// will still run, but will not invalidate the object. Note that C++ specifies +// that accessing an object after its destructor has run results in undefined +// behavior, but this pattern works on the toolchains we support. +// +// The absl::kConstInit tag should only be used to define objects with static +// or thread_local storage duration. + +namespace absl { + +enum ConstInitType { + kConstInit, +}; + +} // namespace absl + +#endif // ABSL_BASE_CONST_INIT_H_
diff --git a/absl/base/dynamic_annotations.cc b/absl/base/dynamic_annotations.cc index b97fa3a..1411093 100644 --- a/absl/base/dynamic_annotations.cc +++ b/absl/base/dynamic_annotations.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/dynamic_annotations.h b/absl/base/dynamic_annotations.h index 88048b0..8ac7498 100644 --- a/absl/base/dynamic_annotations.h +++ b/absl/base/dynamic_annotations.h
@@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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, @@ -139,6 +139,7 @@ #define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */ #define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) /* empty */ #endif /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED || MEMORY_SANITIZER */ + /* TODO(delesley) -- Replace __CLANG_SUPPORT_DYN_ANNOTATION__ with the appropriate feature ID. */ #if defined(__clang__) && (!defined(SWIG)) \
diff --git a/absl/base/exception_safety_testing_test.cc b/absl/base/exception_safety_testing_test.cc index 106bc34..2ed3860 100644 --- a/absl/base/exception_safety_testing_test.cc +++ b/absl/base/exception_safety_testing_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -770,6 +770,18 @@ .Test(invoker)); } +TEST(ExceptionSafetyTesterTest, ResetsCountdown) { + auto test = + testing::MakeExceptionSafetyTester() + .WithInitialValue(ThrowingValue<>()) + .WithContracts([](ThrowingValue<>*) { return AssertionSuccess(); }) + .WithOperation([](ThrowingValue<>*) {}); + ASSERT_TRUE(test.Test()); + // If the countdown isn't reset because there were no exceptions thrown, then + // this will fail with a termination from an unhandled exception + EXPECT_TRUE(test.Test()); +} + struct NonCopyable : public NonNegative { NonCopyable(const NonCopyable&) = delete; NonCopyable() : NonNegative{0} {}
diff --git a/absl/base/inline_variable_test.cc b/absl/base/inline_variable_test.cc index 5499189..471f706 100644 --- a/absl/base/inline_variable_test.cc +++ b/absl/base/inline_variable_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/inline_variable_test_a.cc b/absl/base/inline_variable_test_a.cc index a3bf3b6..d0b8e7d 100644 --- a/absl/base/inline_variable_test_a.cc +++ b/absl/base/inline_variable_test_a.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/inline_variable_test_b.cc b/absl/base/inline_variable_test_b.cc index b4b9393..931d56d 100644 --- a/absl/base/inline_variable_test_b.cc +++ b/absl/base/inline_variable_test_b.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/atomic_hook.h b/absl/base/internal/atomic_hook.h index b458511..803e905 100644 --- a/absl/base/internal/atomic_hook.h +++ b/absl/base/internal/atomic_hook.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/atomic_hook_test.cc b/absl/base/internal/atomic_hook_test.cc index cf74075..ecc8040 100644 --- a/absl/base/internal/atomic_hook_test.cc +++ b/absl/base/internal/atomic_hook_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/bits.h b/absl/base/internal/bits.h index bc7faae..b0780f2 100644 --- a/absl/base/internal/bits.h +++ b/absl/base/internal/bits.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/bits_test.cc b/absl/base/internal/bits_test.cc index e5d991d..7855fa6 100644 --- a/absl/base/internal/bits_test.cc +++ b/absl/base/internal/bits_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/cycleclock.cc b/absl/base/internal/cycleclock.cc index a742df0..4b553c2 100644 --- a/absl/base/internal/cycleclock.cc +++ b/absl/base/internal/cycleclock.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -22,6 +22,7 @@ #include "absl/base/internal/cycleclock.h" +#include <atomic> #include <chrono> // NOLINT(build/c++11) #include "absl/base/internal/unscaledcycleclock.h" @@ -52,17 +53,26 @@ #endif static constexpr double kFrequencyScale = 1.0 / (1 << kShift); +static std::atomic<CycleClockSourceFunc> cycle_clock_source; } // namespace int64_t CycleClock::Now() { - return base_internal::UnscaledCycleClock::Now() >> kShift; + auto fn = cycle_clock_source.load(std::memory_order_relaxed); + if (fn == nullptr) { + return base_internal::UnscaledCycleClock::Now() >> kShift; + } + return fn() >> kShift; } double CycleClock::Frequency() { return kFrequencyScale * base_internal::UnscaledCycleClock::Frequency(); } +void CycleClockSource::Register(CycleClockSourceFunc source) { + cycle_clock_source.store(source, std::memory_order_relaxed); +} + #else int64_t CycleClock::Now() {
diff --git a/absl/base/internal/cycleclock.h b/absl/base/internal/cycleclock.h index 60e9715..794564e 100644 --- a/absl/base/internal/cycleclock.h +++ b/absl/base/internal/cycleclock.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -28,7 +28,6 @@ // not necessarily "CPU cycles" and code should not rely on that behavior, even // if experimentally observed. // -// // An arbitrary offset may have been added to the counter at power on. // // On some platforms, the rate and offset of the counter may differ @@ -71,6 +70,20 @@ CycleClock& operator=(const CycleClock&) = delete; }; +using CycleClockSourceFunc = int64_t (*)(); + +class CycleClockSource { + private: + // CycleClockSource::Register() + // + // Register a function that provides an alternate source for the unscaled CPU + // cycle count value. The source function must be async signal safe, must not + // call CycleClock::Now(), and must have a frequency that matches that of the + // unscaled clock used by CycleClock. A nullptr value resets CycleClock to use + // the default source. + static void Register(CycleClockSourceFunc source); +}; + } // namespace base_internal } // namespace absl
diff --git a/absl/base/internal/direct_mmap.h b/absl/base/internal/direct_mmap.h index 0426e11..0401ddf 100644 --- a/absl/base/internal/direct_mmap.h +++ b/absl/base/internal/direct_mmap.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -75,7 +75,11 @@ // On these architectures, implement mmap with mmap2. static int pagesize = 0; if (pagesize == 0) { +#if defined(__wasm__) || defined(__asmjs__) pagesize = getpagesize(); +#else + pagesize = sysconf(_SC_PAGESIZE); +#endif } if (offset < 0 || offset % pagesize != 0) { errno = EINVAL;
diff --git a/absl/base/internal/endian.h b/absl/base/internal/endian.h index edc10f1..6b828b6 100644 --- a/absl/base/internal/endian.h +++ b/absl/base/internal/endian.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -75,21 +75,21 @@ if (__builtin_constant_p(host_int)) { return __bswap_constant_64(host_int); } else { - register uint64_t result; + uint64_t result; __asm__("bswap %0" : "=r"(result) : "0"(host_int)); return result; } #elif defined(__GLIBC__) return bswap_64(host_int); #else - return (((x & uint64_t{(0xFF}) << 56) | - ((x & uint64_t{(0xFF00}) << 40) | - ((x & uint64_t{(0xFF0000}) << 24) | - ((x & uint64_t{(0xFF000000}) << 8) | - ((x & uint64_t{(0xFF00000000}) >> 8) | - ((x & uint64_t{(0xFF0000000000}) >> 24) | - ((x & uint64_t{(0xFF000000000000}) >> 40) | - ((x & uint64_t{(0xFF00000000000000}) >> 56)); + return (((host_int & uint64_t{0xFF}) << 56) | + ((host_int & uint64_t{0xFF00}) << 40) | + ((host_int & uint64_t{0xFF0000}) << 24) | + ((host_int & uint64_t{0xFF000000}) << 8) | + ((host_int & uint64_t{0xFF00000000}) >> 8) | + ((host_int & uint64_t{0xFF0000000000}) >> 24) | + ((host_int & uint64_t{0xFF000000000000}) >> 40) | + ((host_int & uint64_t{0xFF00000000000000}) >> 56)); #endif // bswap_64 } @@ -97,8 +97,10 @@ #if defined(__GLIBC__) return bswap_32(host_int); #else - return (((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | - ((x & 0xFF000000) >> 24)); + return (((host_int & uint32_t{0xFF}) << 24) | + ((host_int & uint32_t{0xFF00}) << 8) | + ((host_int & uint32_t{0xFF0000}) >> 8) | + ((host_int & uint32_t{0xFF000000}) >> 24)); #endif } @@ -106,7 +108,8 @@ #if defined(__GLIBC__) return bswap_16(host_int); #else - return uint16_t{((x & 0xFF) << 8) | ((x & 0xFF00) >> 8)}; + return (((host_int & uint16_t{0xFF}) << 8) | + ((host_int & uint16_t{0xFF00}) >> 8)); #endif }
diff --git a/absl/base/internal/endian_test.cc b/absl/base/internal/endian_test.cc index e276915..98a099e 100644 --- a/absl/base/internal/endian_test.cc +++ b/absl/base/internal/endian_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/exception_safety_testing.cc b/absl/base/internal/exception_safety_testing.cc index f1d081f..6ef4325 100644 --- a/absl/base/internal/exception_safety_testing.cc +++ b/absl/base/internal/exception_safety_testing.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -23,6 +23,10 @@ exceptions_internal::StrongGuaranteeTagType strong_guarantee; +exceptions_internal::ExceptionSafetyTestBuilder<> MakeExceptionSafetyTester() { + return {}; +} + namespace exceptions_internal { int countdown = -1;
diff --git a/absl/base/internal/exception_safety_testing.h b/absl/base/internal/exception_safety_testing.h index 5665a1b..be38ba5 100644 --- a/absl/base/internal/exception_safety_testing.h +++ b/absl/base/internal/exception_safety_testing.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -33,7 +33,7 @@ #include "absl/meta/type_traits.h" #include "absl/strings/string_view.h" #include "absl/strings/substitute.h" -#include "absl/types/optional.h" +#include "absl/utility/utility.h" namespace testing { @@ -127,10 +127,8 @@ void* address = it.first; TrackedAddress& tracked_address = it.second; if (tracked_address.is_alive) { - ADD_FAILURE() << "Object at address " << address - << " with countdown of " << countdown_ - << " was not destroyed [" << tracked_address.description - << "]"; + ADD_FAILURE() << ErrorMessage(address, tracked_address.description, + countdown_, "Object was not destroyed."); } } } @@ -141,11 +139,11 @@ TrackedAddress& tracked_address = current_tracker_instance_->address_map_[address]; if (tracked_address.is_alive) { - ADD_FAILURE() << "Object at address " << address << " with countdown of " - << current_tracker_instance_->countdown_ - << " was re-constructed. Previously: [" - << tracked_address.description << "] Now: [" << description - << "]"; + ADD_FAILURE() << ErrorMessage( + address, tracked_address.description, + current_tracker_instance_->countdown_, + "Object was re-constructed. Current object was constructed by " + + description); } tracked_address = {true, std::move(description)}; } @@ -159,10 +157,9 @@ TrackedAddress& tracked_address = it->second; if (!tracked_address.is_alive) { - ADD_FAILURE() << "Object at address " << address << " with countdown of " - << current_tracker_instance_->countdown_ - << " was re-destroyed or created prior to construction " - << "tracking [" << tracked_address.description << "]"; + ADD_FAILURE() << ErrorMessage(address, tracked_address.description, + current_tracker_instance_->countdown_, + "Object was re-destroyed."); } tracked_address.is_alive = false; } @@ -172,6 +169,18 @@ return current_tracker_instance_ != nullptr; } + static std::string ErrorMessage(void* address, + const std::string& address_description, + int countdown, + const std::string& error_description) { + return absl::Substitute( + "With coundtown at $0:\n" + " $1\n" + " Object originally constructed by $2\n" + " Object address: $3\n", + countdown, error_description, address_description, address); + } + std::unordered_map<void*, TrackedAddress> address_map_; int countdown_; @@ -190,70 +199,6 @@ ~TrackedObject() noexcept { ConstructorTracker::ObjectDestructed(this); } }; - -template <typename Factory, typename Operation, typename Contract> -absl::optional<testing::AssertionResult> TestSingleContractAtCountdownImpl( - const Factory& factory, const Operation& operation, int count, - const Contract& contract) { - auto t_ptr = factory(); - absl::optional<testing::AssertionResult> current_res; - SetCountdown(count); - try { - operation(t_ptr.get()); - } catch (const exceptions_internal::TestException& e) { - current_res.emplace(contract(t_ptr.get())); - if (!current_res.value()) { - *current_res << e.what() << " failed contract check"; - } - } - UnsetCountdown(); - return current_res; -} - -template <typename Factory, typename Operation> -absl::optional<testing::AssertionResult> TestSingleContractAtCountdownImpl( - const Factory& factory, const Operation& operation, int count, - StrongGuaranteeTagType) { - using TPtr = typename decltype(factory())::pointer; - auto t_is_strong = [&](TPtr t) { return *t == *factory(); }; - return TestSingleContractAtCountdownImpl(factory, operation, count, - t_is_strong); -} - -template <typename Factory, typename Operation, typename Contract> -int TestSingleContractAtCountdown( - const Factory& factory, const Operation& operation, int count, - const Contract& contract, - absl::optional<testing::AssertionResult>* reduced_res) { - // If reduced_res is empty, it means the current call to - // TestSingleContractAtCountdown(...) is the first test being run so we do - // want to run it. Alternatively, if it's not empty (meaning a previous test - // has run) we want to check if it passed. If the previous test did pass, we - // want to contine running tests so we do want to run the current one. If it - // failed, we want to short circuit so as not to overwrite the AssertionResult - // output. If that's the case, we do not run the current test and instead we - // simply return. - if (!reduced_res->has_value() || reduced_res->value()) { - *reduced_res = - TestSingleContractAtCountdownImpl(factory, operation, count, contract); - } - return 0; -} - -template <typename Factory, typename Operation, typename... Contracts> -inline absl::optional<testing::AssertionResult> TestAllContractsAtCountdown( - const Factory& factory, const Operation& operation, int count, - const Contracts&... contracts) { - absl::optional<testing::AssertionResult> reduced_res; - - // Run each checker, short circuiting after the first failure - int dummy[] = { - 0, (TestSingleContractAtCountdown(factory, operation, count, contracts, - &reduced_res))...}; - static_cast<void>(dummy); - return reduced_res; -} - } // namespace exceptions_internal extern exceptions_internal::NoThrowTag nothrow_ctor; @@ -613,8 +558,8 @@ // We provide both regular and templated operator delete because if only the // templated version is provided as we did with operator new, the compiler has // no way of knowing which overload of operator delete to call. See - // http://en.cppreference.com/w/cpp/memory/new/operator_delete and - // http://en.cppreference.com/w/cpp/language/delete for the gory details. + // https://en.cppreference.com/w/cpp/memory/new/operator_delete and + // https://en.cppreference.com/w/cpp/language/delete for the gory details. void operator delete(void* p) noexcept { ::operator delete(p); } template <typename... Args> @@ -773,7 +718,7 @@ } size_type max_size() const noexcept { - return std::numeric_limits<difference_type>::max() / sizeof(value_type); + return (std::numeric_limits<difference_type>::max)() / sizeof(value_type); } ThrowingAllocator select_on_container_copy_construction() noexcept( @@ -871,7 +816,7 @@ namespace exceptions_internal { -// Dummy struct for ExceptionSafetyTester<> partial state. +// Dummy struct for ExceptionSafetyTestBuilder<> partial state. struct UninitializedT {}; template <typename T> @@ -893,20 +838,97 @@ template <typename Factory = UninitializedT, typename Operation = UninitializedT, typename... Contracts> -class ExceptionSafetyTester; +class ExceptionSafetyTestBuilder; } // namespace exceptions_internal -exceptions_internal::ExceptionSafetyTester<> MakeExceptionSafetyTester(); +/* + * Constructs an empty ExceptionSafetyTestBuilder. All + * ExceptionSafetyTestBuilder objects are immutable and all With[thing] mutation + * methods return new instances of ExceptionSafetyTestBuilder. + * + * In order to test a T for exception safety, a factory for that T, a testable + * operation, and at least one contract callback returning an assertion + * result must be applied using the respective methods. + */ +exceptions_internal::ExceptionSafetyTestBuilder<> MakeExceptionSafetyTester(); namespace exceptions_internal { +template <typename T> +struct IsUniquePtr : std::false_type {}; + +template <typename T, typename D> +struct IsUniquePtr<std::unique_ptr<T, D>> : std::true_type {}; + +template <typename Factory> +struct FactoryPtrTypeHelper { + using type = decltype(std::declval<const Factory&>()()); + + static_assert(IsUniquePtr<type>::value, "Factories must return a unique_ptr"); +}; + +template <typename Factory> +using FactoryPtrType = typename FactoryPtrTypeHelper<Factory>::type; + +template <typename Factory> +using FactoryElementType = typename FactoryPtrType<Factory>::element_type; + +template <typename T> +class ExceptionSafetyTest { + using Factory = std::function<std::unique_ptr<T>()>; + using Operation = std::function<void(T*)>; + using Contract = std::function<AssertionResult(T*)>; + + public: + template <typename... Contracts> + explicit ExceptionSafetyTest(const Factory& f, const Operation& op, + const Contracts&... contracts) + : factory_(f), operation_(op), contracts_{WrapContract(contracts)...} {} + + AssertionResult Test() const { + for (int count = 0;; ++count) { + exceptions_internal::ConstructorTracker ct(count); + + for (const auto& contract : contracts_) { + auto t_ptr = factory_(); + try { + SetCountdown(count); + operation_(t_ptr.get()); + // Unset for the case that the operation throws no exceptions, which + // would leave the countdown set and break the *next* exception safety + // test after this one. + UnsetCountdown(); + return AssertionSuccess(); + } catch (const exceptions_internal::TestException& e) { + if (!contract(t_ptr.get())) { + return AssertionFailure() << e.what() << " failed contract check"; + } + } + } + } + } + + private: + template <typename ContractFn> + Contract WrapContract(const ContractFn& contract) { + return [contract](T* t_ptr) { return AssertionResult(contract(t_ptr)); }; + } + + Contract WrapContract(StrongGuaranteeTagType) { + return [this](T* t_ptr) { return AssertionResult(*factory_() == *t_ptr); }; + } + + Factory factory_; + Operation operation_; + std::vector<Contract> contracts_; +}; /* * Builds a tester object that tests if performing a operation on a T follows * exception safety guarantees. Verification is done via contract assertion * callbacks applied to T instances post-throw. * - * Template parameters for ExceptionSafetyTester: + * Template parameters for ExceptionSafetyTestBuilder: * * - Factory: The factory object (passed in via tester.WithFactory(...) or * tester.WithInitialValue(...)) must be invocable with the signature @@ -933,13 +955,13 @@ * please. */ template <typename Factory, typename Operation, typename... Contracts> -class ExceptionSafetyTester { +class ExceptionSafetyTestBuilder { public: /* - * Returns a new ExceptionSafetyTester with an included T factory based on the - * provided T instance. The existing factory will not be included in the newly - * created tester instance. The created factory returns a new T instance by - * copy-constructing the provided const T& t. + * Returns a new ExceptionSafetyTestBuilder with an included T factory based + * on the provided T instance. The existing factory will not be included in + * the newly created tester instance. The created factory returns a new T + * instance by copy-constructing the provided const T& t. * * Preconditions for tester.WithInitialValue(const T& t): * @@ -948,41 +970,41 @@ * tester.WithFactory(...). */ template <typename T> - ExceptionSafetyTester<DefaultFactory<T>, Operation, Contracts...> + ExceptionSafetyTestBuilder<DefaultFactory<T>, Operation, Contracts...> WithInitialValue(const T& t) const { return WithFactory(DefaultFactory<T>(t)); } /* - * Returns a new ExceptionSafetyTester with the provided T factory included. - * The existing factory will not be included in the newly-created tester - * instance. This method is intended for use with types lacking a copy + * Returns a new ExceptionSafetyTestBuilder with the provided T factory + * included. The existing factory will not be included in the newly-created + * tester instance. This method is intended for use with types lacking a copy * constructor. Types that can be copy-constructed should instead use the * method tester.WithInitialValue(...). */ template <typename NewFactory> - ExceptionSafetyTester<absl::decay_t<NewFactory>, Operation, Contracts...> + ExceptionSafetyTestBuilder<absl::decay_t<NewFactory>, Operation, Contracts...> WithFactory(const NewFactory& new_factory) const { return {new_factory, operation_, contracts_}; } /* - * Returns a new ExceptionSafetyTester with the provided testable operation - * included. The existing operation will not be included in the newly created - * tester. + * Returns a new ExceptionSafetyTestBuilder with the provided testable + * operation included. The existing operation will not be included in the + * newly created tester. */ template <typename NewOperation> - ExceptionSafetyTester<Factory, absl::decay_t<NewOperation>, Contracts...> + ExceptionSafetyTestBuilder<Factory, absl::decay_t<NewOperation>, Contracts...> WithOperation(const NewOperation& new_operation) const { return {factory_, new_operation, contracts_}; } /* - * Returns a new ExceptionSafetyTester with the provided MoreContracts... + * Returns a new ExceptionSafetyTestBuilder with the provided MoreContracts... * combined with the Contracts... that were already included in the instance * on which the method was called. Contracts... cannot be removed or replaced - * once added to an ExceptionSafetyTester instance. A fresh object must be - * created in order to get an empty Contracts... list. + * once added to an ExceptionSafetyTestBuilder instance. A fresh object must + * be created in order to get an empty Contracts... list. * * In addition to passing in custom contract assertion callbacks, this method * accepts `testing::strong_guarantee` as an argument which checks T instances @@ -991,8 +1013,8 @@ * properly rolled back. */ template <typename... MoreContracts> - ExceptionSafetyTester<Factory, Operation, Contracts..., - absl::decay_t<MoreContracts>...> + ExceptionSafetyTestBuilder<Factory, Operation, Contracts..., + absl::decay_t<MoreContracts>...> WithContracts(const MoreContracts&... more_contracts) const { return { factory_, operation_, @@ -1039,48 +1061,27 @@ typename LazyOperation = Operation, typename = EnableIfTestable<sizeof...(Contracts), Factory, LazyOperation>> testing::AssertionResult Test() const { - return TestImpl(operation_, absl::index_sequence_for<Contracts...>()); + return Test(operation_); } private: template <typename, typename, typename...> - friend class ExceptionSafetyTester; + friend class ExceptionSafetyTestBuilder; - friend ExceptionSafetyTester<> testing::MakeExceptionSafetyTester(); + friend ExceptionSafetyTestBuilder<> testing::MakeExceptionSafetyTester(); - ExceptionSafetyTester() {} + ExceptionSafetyTestBuilder() {} - ExceptionSafetyTester(const Factory& f, const Operation& o, - const std::tuple<Contracts...>& i) + ExceptionSafetyTestBuilder(const Factory& f, const Operation& o, + const std::tuple<Contracts...>& i) : factory_(f), operation_(o), contracts_(i) {} template <typename SelectedOperation, size_t... Indices> - testing::AssertionResult TestImpl(const SelectedOperation& selected_operation, + testing::AssertionResult TestImpl(SelectedOperation selected_operation, absl::index_sequence<Indices...>) const { - // Starting from 0 and counting upwards until one of the exit conditions is - // hit... - for (int count = 0;; ++count) { - exceptions_internal::ConstructorTracker ct(count); - - // Run the full exception safety test algorithm for the current countdown - auto reduced_res = - TestAllContractsAtCountdown(factory_, selected_operation, count, - std::get<Indices>(contracts_)...); - // If there is no value in the optional, no contracts were run because no - // exception was thrown. This means that the test is complete and the loop - // can exit successfully. - if (!reduced_res.has_value()) { - return testing::AssertionSuccess(); - } - // If the optional is not empty and the value is falsy, an contract check - // failed so the test must exit to propegate the failure. - if (!reduced_res.value()) { - return reduced_res.value(); - } - // If the optional is not empty and the value is not falsy, it means - // exceptions were thrown but the contracts passed so the test must - // continue to run. - } + return ExceptionSafetyTest<FactoryElementType<Factory>>( + factory_, selected_operation, std::get<Indices>(contracts_)...) + .Test(); } Factory factory_; @@ -1090,20 +1091,6 @@ } // namespace exceptions_internal -/* - * Constructs an empty ExceptionSafetyTester. All ExceptionSafetyTester - * objects are immutable and all With[thing] mutation methods return new - * instances of ExceptionSafetyTester. - * - * In order to test a T for exception safety, a factory for that T, a testable - * operation, and at least one contract callback returning an assertion - * result must be applied using the respective methods. - */ -inline exceptions_internal::ExceptionSafetyTester<> -MakeExceptionSafetyTester() { - return {}; -} - } // namespace testing #endif // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
diff --git a/absl/base/internal/exception_testing.h b/absl/base/internal/exception_testing.h index 0cf7918..01b5465 100644 --- a/absl/base/internal/exception_testing.h +++ b/absl/base/internal/exception_testing.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/hide_ptr.h b/absl/base/internal/hide_ptr.h index 45cf438..cf8f408 100644 --- a/absl/base/internal/hide_ptr.h +++ b/absl/base/internal/hide_ptr.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/identity.h b/absl/base/internal/identity.h index a1a5d70..086447c 100644 --- a/absl/base/internal/identity.h +++ b/absl/base/internal/identity.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/inline_variable.h b/absl/base/internal/inline_variable.h index f7bb8c5..130d8c2 100644 --- a/absl/base/internal/inline_variable.h +++ b/absl/base/internal/inline_variable.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/inline_variable_testing.h b/absl/base/internal/inline_variable_testing.h index a0dd2bb..15dc481 100644 --- a/absl/base/internal/inline_variable_testing.h +++ b/absl/base/internal/inline_variable_testing.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/invoke.h b/absl/base/internal/invoke.h index 8c3f4f6..8da2869 100644 --- a/absl/base/internal/invoke.h +++ b/absl/base/internal/invoke.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/low_level_alloc.cc b/absl/base/internal/low_level_alloc.cc index 159f945..e4030ed 100644 --- a/absl/base/internal/low_level_alloc.cc +++ b/absl/base/internal/low_level_alloc.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -208,7 +208,7 @@ int32_t allocation_count GUARDED_BY(mu); // flags passed to NewArena const uint32_t flags; - // Result of getpagesize() + // Result of sysconf(_SC_PAGESIZE) const size_t pagesize; // Lowest power of two >= max(16, sizeof(AllocList)) const size_t roundup; @@ -324,8 +324,10 @@ SYSTEM_INFO system_info; GetSystemInfo(&system_info); return std::max(system_info.dwPageSize, system_info.dwAllocationGranularity); -#else +#elif defined(__wasm__) || defined(__asmjs__) return getpagesize(); +#else + return sysconf(_SC_PAGESIZE); #endif }
diff --git a/absl/base/internal/low_level_alloc.h b/absl/base/internal/low_level_alloc.h index fba9466..b35673d 100644 --- a/absl/base/internal/low_level_alloc.h +++ b/absl/base/internal/low_level_alloc.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -119,4 +119,5 @@ } // namespace base_internal } // namespace absl + #endif // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
diff --git a/absl/base/internal/low_level_alloc_test.cc b/absl/base/internal/low_level_alloc_test.cc index cf2b363..34a080c 100644 --- a/absl/base/internal/low_level_alloc_test.cc +++ b/absl/base/internal/low_level_alloc_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -137,6 +137,7 @@ TEST_ASSERT(LowLevelAlloc::DeleteArena(arena)); } } + // LowLevelAlloc is designed to be safe to call before main(). static struct BeforeMain { BeforeMain() {
diff --git a/absl/base/internal/low_level_scheduling.h b/absl/base/internal/low_level_scheduling.h index e716f2b..0fcc8d3 100644 --- a/absl/base/internal/low_level_scheduling.h +++ b/absl/base/internal/low_level_scheduling.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -86,6 +86,7 @@ //------------------------------------------------------------------------------ // End of public interfaces. //------------------------------------------------------------------------------ + inline bool SchedulingGuard::ReschedulingIsAllowed() { return false; } @@ -98,7 +99,7 @@ return; } - } // namespace base_internal } // namespace absl + #endif // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
diff --git a/absl/base/internal/per_thread_tls.h b/absl/base/internal/per_thread_tls.h index 2428bdc..cf5e97a 100644 --- a/absl/base/internal/per_thread_tls.h +++ b/absl/base/internal/per_thread_tls.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -16,13 +16,17 @@ #define ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_ // This header defines two macros: +// // If the platform supports thread-local storage: -// ABSL_PER_THREAD_TLS_KEYWORD is the C keyword needed to declare a -// thread-local variable ABSL_PER_THREAD_TLS is 1 +// +// * ABSL_PER_THREAD_TLS_KEYWORD is the C keyword needed to declare a +// thread-local variable +// * ABSL_PER_THREAD_TLS is 1 // // Otherwise: -// ABSL_PER_THREAD_TLS_KEYWORD is empty -// ABSL_PER_THREAD_TLS is 0 +// +// * ABSL_PER_THREAD_TLS_KEYWORD is empty +// * ABSL_PER_THREAD_TLS is 0 // // Microsoft C supports thread-local storage. // GCC supports it if the appropriate version of glibc is available,
diff --git a/absl/base/internal/pretty_function.h b/absl/base/internal/pretty_function.h index 01b0547..35d5167 100644 --- a/absl/base/internal/pretty_function.h +++ b/absl/base/internal/pretty_function.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc index d9485a6..b5a05e8 100644 --- a/absl/base/internal/raw_logging.cc +++ b/absl/base/internal/raw_logging.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/raw_logging.h b/absl/base/internal/raw_logging.h index 79a7bb9..6a4c093 100644 --- a/absl/base/internal/raw_logging.h +++ b/absl/base/internal/raw_logging.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -38,6 +38,7 @@ // ABSL_RAW_LOG(ERROR, "Failed foo with %i: %s", status, error); // This will print an almost standard log line like this to stderr only: // E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file + #define ABSL_RAW_LOG(severity, ...) \ do { \ constexpr const char* absl_raw_logging_internal_basename = \ @@ -79,13 +80,13 @@ absl_raw_logging_internal_basename, __LINE__, message); \ } while (0) -#define ABSL_INTERNAL_CHECK(condition, message) \ - do { \ - if (ABSL_PREDICT_FALSE(!(condition))) { \ +#define ABSL_INTERNAL_CHECK(condition, message) \ + do { \ + if (ABSL_PREDICT_FALSE(!(condition))) { \ std::string death_message = "Check " #condition " failed: "; \ death_message += std::string(message); \ - ABSL_INTERNAL_LOG(FATAL, death_message); \ - } \ + ABSL_INTERNAL_LOG(FATAL, death_message); \ + } \ } while (0) #define ABSL_RAW_LOGGING_INTERNAL_INFO ::absl::LogSeverity::kInfo
diff --git a/absl/base/internal/scheduling_mode.h b/absl/base/internal/scheduling_mode.h index 1b6497a..d5b4b7f 100644 --- a/absl/base/internal/scheduling_mode.h +++ b/absl/base/internal/scheduling_mode.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/scoped_set_env.cc b/absl/base/internal/scoped_set_env.cc new file mode 100644 index 0000000..3ac3f68 --- /dev/null +++ b/absl/base/internal/scoped_set_env.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 "absl/base/internal/scoped_set_env.h" + +#ifdef _WIN32 +#include <windows.h> +#endif + +#include <cstdlib> + +#include "absl/base/internal/raw_logging.h" + +namespace absl { +namespace base_internal { + +namespace { + +#ifdef _WIN32 +const int kMaxEnvVarValueSize = 1024; +#endif + +void SetEnvVar(const char* name, const char* value) { +#ifdef _WIN32 + SetEnvironmentVariableA(name, value); +#else + if (value == nullptr) { + ::unsetenv(name); + } else { + ::setenv(name, value, 1); + } +#endif +} + +} // namespace + +ScopedSetEnv::ScopedSetEnv(const char* var_name, const char* new_value) + : var_name_(var_name), was_unset_(false) { +#ifdef _WIN32 + char buf[kMaxEnvVarValueSize]; + auto get_res = GetEnvironmentVariableA(var_name_.c_str(), buf, sizeof(buf)); + ABSL_INTERNAL_CHECK(get_res < sizeof(buf), "value exceeds buffer size"); + + if (get_res == 0) { + was_unset_ = (GetLastError() == ERROR_ENVVAR_NOT_FOUND); + } else { + old_value_.assign(buf, get_res); + } + + SetEnvironmentVariableA(var_name_.c_str(), new_value); +#else + const char* val = ::getenv(var_name_.c_str()); + if (val == nullptr) { + was_unset_ = true; + } else { + old_value_ = val; + } +#endif + + SetEnvVar(var_name_.c_str(), new_value); +} + +ScopedSetEnv::~ScopedSetEnv() { + SetEnvVar(var_name_.c_str(), was_unset_ ? nullptr : old_value_.c_str()); +} + +} // namespace base_internal +} // namespace absl
diff --git a/absl/base/internal/scoped_set_env.h b/absl/base/internal/scoped_set_env.h new file mode 100644 index 0000000..855b22f --- /dev/null +++ b/absl/base/internal/scoped_set_env.h
@@ -0,0 +1,41 @@ +// +// 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_SCOPED_SET_ENV_H_ +#define ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_ + +#include <string> + +namespace absl { +namespace base_internal { + +class ScopedSetEnv { + public: + ScopedSetEnv(const char* var_name, const char* new_value); + ~ScopedSetEnv(); + + private: + std::string var_name_; + std::string old_value_; + + // True if the environment variable was initially not set. + bool was_unset_; +}; + +} // namespace base_internal +} // namespace absl + +#endif // ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
diff --git a/absl/base/internal/scoped_set_env_test.cc b/absl/base/internal/scoped_set_env_test.cc new file mode 100644 index 0000000..5cbad24 --- /dev/null +++ b/absl/base/internal/scoped_set_env_test.cc
@@ -0,0 +1,99 @@ +// 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. + +#ifdef _WIN32 +#include <windows.h> +#endif + +#include "gtest/gtest.h" +#include "absl/base/internal/scoped_set_env.h" + +namespace { + +using absl::base_internal::ScopedSetEnv; + +std::string GetEnvVar(const char* name) { +#ifdef _WIN32 + char buf[1024]; + auto get_res = GetEnvironmentVariableA(name, buf, sizeof(buf)); + if (get_res >= sizeof(buf)) { + return "TOO_BIG"; + } + + if (get_res == 0) { + return "UNSET"; + } + + return std::string(buf, get_res); +#else + const char* val = ::getenv(name); + if (val == nullptr) { + return "UNSET"; + } + + return val; +#endif +} + +TEST(ScopedSetEnvTest, SetNonExistingVarToString) { + EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET"); + + { + ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", "value"); + + EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "value"); + } + + EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET"); +} + +TEST(ScopedSetEnvTest, SetNonExistingVarToNull) { + EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET"); + + { + ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", nullptr); + + EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET"); + } + + EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET"); +} + +TEST(ScopedSetEnvTest, SetExistingVarToString) { + ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", "value"); + EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "value"); + + { + ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", "new_value"); + + EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "new_value"); + } + + EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "value"); +} + +TEST(ScopedSetEnvTest, SetExistingVarToNull) { + ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", "value"); + EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "value"); + + { + ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", nullptr); + + EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET"); + } + + EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "value"); +} + +} // namespace
diff --git a/absl/base/internal/spinlock.cc b/absl/base/internal/spinlock.cc index 1b97efb..7354438 100644 --- a/absl/base/internal/spinlock.cc +++ b/absl/base/internal/spinlock.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -95,13 +95,9 @@ } // Monitor the lock to see if its value changes within some time period -// (adaptive_spin_count loop iterations). A timestamp indicating -// when the thread initially started waiting for the lock is passed in via -// the initial_wait_timestamp value. The total wait time in cycles for the -// lock is returned in the wait_cycles parameter. The last value read -// from the lock is returned from the method. -uint32_t SpinLock::SpinLoop(int64_t initial_wait_timestamp, - uint32_t *wait_cycles) { +// (adaptive_spin_count loop iterations). The last value read from the lock +// is returned from the method. +uint32_t SpinLock::SpinLoop() { // We are already in the slow path of SpinLock, initialize the // adaptive_spin_count here. ABSL_CONST_INIT static absl::once_flag init_adaptive_spin_count; @@ -115,22 +111,21 @@ do { lock_value = lockword_.load(std::memory_order_relaxed); } while ((lock_value & kSpinLockHeld) != 0 && --c > 0); - uint32_t spin_loop_wait_cycles = - EncodeWaitCycles(initial_wait_timestamp, CycleClock::Now()); - *wait_cycles = spin_loop_wait_cycles; - - return TryLockInternal(lock_value, spin_loop_wait_cycles); + return lock_value; } void SpinLock::SlowLock() { + uint32_t lock_value = SpinLoop(); + lock_value = TryLockInternal(lock_value, 0); + if ((lock_value & kSpinLockHeld) == 0) { + return; + } // The lock was not obtained initially, so this thread needs to wait for // it. Record the current timestamp in the local variable wait_start_time // so the total wait time can be stored in the lockword once this thread // obtains the lock. int64_t wait_start_time = CycleClock::Now(); - uint32_t wait_cycles; - uint32_t lock_value = SpinLoop(wait_start_time, &wait_cycles); - + uint32_t wait_cycles = 0; int lock_wait_call_count = 0; while ((lock_value & kSpinLockHeld) != 0) { // If the lock is currently held, but not marked as having a sleeper, mark @@ -141,7 +136,7 @@ // owner to think it experienced contention. if (lockword_.compare_exchange_strong( lock_value, lock_value | kSpinLockSleeper, - std::memory_order_acquire, std::memory_order_relaxed)) { + std::memory_order_relaxed, std::memory_order_relaxed)) { // Successfully transitioned to kSpinLockSleeper. Pass // kSpinLockSleeper to the SpinLockWait routine to properly indicate // the last lock_value observed. @@ -170,7 +165,9 @@ ABSL_TSAN_MUTEX_POST_DIVERT(this, 0); // Spin again after returning from the wait routine to give this thread // some chance of obtaining the lock. - lock_value = SpinLoop(wait_start_time, &wait_cycles); + lock_value = SpinLoop(); + wait_cycles = EncodeWaitCycles(wait_start_time, CycleClock::Now()); + lock_value = TryLockInternal(lock_value, wait_cycles); } } @@ -206,14 +203,20 @@ (wait_end_time - wait_start_time) >> PROFILE_TIMESTAMP_SHIFT; // Return a representation of the time spent waiting that can be stored in - // the lock word's upper bits. bit_cast is required as Atomic32 is signed. - const uint32_t clamped = static_cast<uint32_t>( + // the lock word's upper bits. + uint32_t clamped = static_cast<uint32_t>( std::min(scaled_wait_time, kMaxWaitTime) << LOCKWORD_RESERVED_SHIFT); - // bump up value if necessary to avoid returning kSpinLockSleeper. - const uint32_t after_spinlock_sleeper = - kSpinLockSleeper + (1 << LOCKWORD_RESERVED_SHIFT); - return clamped == kSpinLockSleeper ? after_spinlock_sleeper : clamped; + 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); + if (clamped == kSpinLockSleeper) { + return kMinWaitTime; + } + return clamped; } uint64_t SpinLock::DecodeWaitCycles(uint32_t lock_value) {
diff --git a/absl/base/internal/spinlock.h b/absl/base/internal/spinlock.h index 212abc6..4a31639 100644 --- a/absl/base/internal/spinlock.h +++ b/absl/base/internal/spinlock.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -101,8 +101,8 @@ inline void Unlock() UNLOCK_FUNCTION() { ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0); uint32_t lock_value = lockword_.load(std::memory_order_relaxed); - lockword_.store(lock_value & kSpinLockCooperative, - std::memory_order_release); + lock_value = lockword_.exchange(lock_value & kSpinLockCooperative, + std::memory_order_release); if ((lock_value & kSpinLockDisabledScheduling) != 0) { base_internal::SchedulingGuard::EnableRescheduling(true); @@ -161,7 +161,7 @@ void InitLinkerInitializedAndCooperative(); void SlowLock() ABSL_ATTRIBUTE_COLD; void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD; - uint32_t SpinLoop(int64_t initial_wait_timestamp, uint32_t* wait_cycles); + uint32_t SpinLoop(); inline bool TryLockImpl() { uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
diff --git a/absl/base/internal/spinlock_akaros.inc b/absl/base/internal/spinlock_akaros.inc index 051c8cf..bc46894 100644 --- a/absl/base/internal/spinlock_akaros.inc +++ b/absl/base/internal/spinlock_akaros.inc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/spinlock_benchmark.cc b/absl/base/internal/spinlock_benchmark.cc new file mode 100644 index 0000000..0451c65 --- /dev/null +++ b/absl/base/internal/spinlock_benchmark.cc
@@ -0,0 +1,52 @@ +// 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. + +// See also //absl/synchronization:mutex_benchmark for a comparison of SpinLock +// and Mutex performance under varying levels of contention. + +#include "absl/base/internal/raw_logging.h" +#include "absl/base/internal/scheduling_mode.h" +#include "absl/base/internal/spinlock.h" +#include "absl/synchronization/internal/create_thread_identity.h" +#include "benchmark/benchmark.h" + +namespace { + +template <absl::base_internal::SchedulingMode scheduling_mode> +static void BM_SpinLock(benchmark::State& state) { + // Ensure a ThreadIdentity is installed. + ABSL_INTERNAL_CHECK( + absl::synchronization_internal::GetOrCreateCurrentThreadIdentity() != + nullptr, + "GetOrCreateCurrentThreadIdentity() failed"); + + static auto* spinlock = new absl::base_internal::SpinLock(scheduling_mode); + for (auto _ : state) { + absl::base_internal::SpinLockHolder holder(spinlock); + } +} + +BENCHMARK_TEMPLATE(BM_SpinLock, + absl::base_internal::SCHEDULE_KERNEL_ONLY) + ->UseRealTime() + ->Threads(1) + ->ThreadPerCpu(); + +BENCHMARK_TEMPLATE(BM_SpinLock, + absl::base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL) + ->UseRealTime() + ->Threads(1) + ->ThreadPerCpu(); + +} // namespace
diff --git a/absl/base/internal/spinlock_linux.inc b/absl/base/internal/spinlock_linux.inc index 94c861d..28e29d1 100644 --- a/absl/base/internal/spinlock_linux.inc +++ b/absl/base/internal/spinlock_linux.inc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -51,17 +51,12 @@ ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay( std::atomic<uint32_t> *w, uint32_t value, int loop, absl::base_internal::SchedulingMode) { - if (loop != 0) { - int save_errno = errno; - struct timespec tm; - tm.tv_sec = 0; - // Increase the delay; we expect (but do not rely on) explicit wakeups. - // We don't rely on explicit wakeups because we intentionally allow for - // a race on the kSpinLockSleeper bit. - tm.tv_nsec = 16 * absl::base_internal::SpinLockSuggestedDelayNS(loop); - syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm); - errno = save_errno; - } + int save_errno = errno; + 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/absl/base/internal/spinlock_posix.inc b/absl/base/internal/spinlock_posix.inc index 0098c1c..f025b5f 100644 --- a/absl/base/internal/spinlock_posix.inc +++ b/absl/base/internal/spinlock_posix.inc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/spinlock_wait.cc b/absl/base/internal/spinlock_wait.cc index 0fde9c0..fac8a21 100644 --- a/absl/base/internal/spinlock_wait.cc +++ b/absl/base/internal/spinlock_wait.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -38,14 +38,15 @@ uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n, const SpinLockWaitTransition trans[], base_internal::SchedulingMode scheduling_mode) { - for (int loop = 0; ; loop++) { + int loop = 0; + for (;;) { uint32_t v = w->load(std::memory_order_acquire); int i; for (i = 0; i != n && v != trans[i].from; i++) { } if (i == n) { - SpinLockDelay(w, v, loop, scheduling_mode); // no matching transition - } else if (trans[i].to == v || // null transition + SpinLockDelay(w, v, ++loop, scheduling_mode); // no matching transition + } else if (trans[i].to == v || // null transition w->compare_exchange_strong(v, trans[i].to, std::memory_order_acquire, std::memory_order_relaxed)) { @@ -64,17 +65,14 @@ r = 0x5deece66dLL * r + 0xb; // numbers from nrand48() delay_rand.store(r, std::memory_order_relaxed); - r <<= 16; // 48-bit random number now in top 48-bits. if (loop < 0 || loop > 32) { // limit loop to 0..32 loop = 32; } - // loop>>3 cannot exceed 4 because loop cannot exceed 32. - // Select top 20..24 bits of lower 48 bits, - // giving approximately 0ms to 16ms. - // Mean is exponential in loop for first 32 iterations, then 8ms. - // The futex path multiplies this by 16, since we expect explicit wakeups - // almost always on that path. - return static_cast<int>(r >> (44 - (loop >> 3))); + const int kMinDelay = 128 << 10; // 128us + // Double delay every 8 iterations, up to 16x (2ms). + int delay = kMinDelay << (loop / 8); + // Randomize in delay..2*delay range, for resulting 128us..4ms range. + return delay | ((delay - 1) & static_cast<int>(r)); } } // namespace base_internal
diff --git a/absl/base/internal/spinlock_wait.h b/absl/base/internal/spinlock_wait.h index 5c6cc7f..6642ce1 100644 --- a/absl/base/internal/spinlock_wait.h +++ b/absl/base/internal/spinlock_wait.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/spinlock_win32.inc b/absl/base/internal/spinlock_win32.inc index 32c8fc0..78654b5 100644 --- a/absl/base/internal/spinlock_win32.inc +++ b/absl/base/internal/spinlock_win32.inc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc index db41bac..4dd3add 100644 --- a/absl/base/internal/sysinfo.cc +++ b/absl/base/internal/sysinfo.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/sysinfo.h b/absl/base/internal/sysinfo.h index 5bd1c50..b864a59 100644 --- a/absl/base/internal/sysinfo.h +++ b/absl/base/internal/sysinfo.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/sysinfo_test.cc b/absl/base/internal/sysinfo_test.cc index e0d9aab..247f3d8 100644 --- a/absl/base/internal/sysinfo_test.cc +++ b/absl/base/internal/sysinfo_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/thread_identity.cc b/absl/base/internal/thread_identity.cc index cff9c1b..91273a6 100644 --- a/absl/base/internal/thread_identity.cc +++ b/absl/base/internal/thread_identity.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/thread_identity.h b/absl/base/internal/thread_identity.h index a51722f..b34674a 100644 --- a/absl/base/internal/thread_identity.h +++ b/absl/base/internal/thread_identity.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -42,9 +42,9 @@ class SpinLock; struct ThreadIdentity; -// Used by the implementation of base::Mutex and base::CondVar. +// Used by the implementation of absl::Mutex and absl::CondVar. struct PerThreadSynch { - // The internal representation of base::Mutex and base::CondVar rely + // The internal representation of absl::Mutex and absl::CondVar rely // on the alignment of PerThreadSynch. Both store the address of the // PerThreadSynch in the high-order bits of their internal state, // which means the low kLowZeroBits of the address of PerThreadSynch @@ -237,4 +237,5 @@ } // namespace base_internal } // namespace absl + #endif // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
diff --git a/absl/base/internal/thread_identity_benchmark.cc b/absl/base/internal/thread_identity_benchmark.cc index 242522b..0ae10f2 100644 --- a/absl/base/internal/thread_identity_benchmark.cc +++ b/absl/base/internal/thread_identity_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/thread_identity_test.cc b/absl/base/internal/thread_identity_test.cc index ecb8af6..13bfbe3 100644 --- a/absl/base/internal/thread_identity_test.cc +++ b/absl/base/internal/thread_identity_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/throw_delegate.cc b/absl/base/internal/throw_delegate.cc index 46dc573..8e928b8 100644 --- a/absl/base/internal/throw_delegate.cc +++ b/absl/base/internal/throw_delegate.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -30,8 +30,8 @@ #ifdef ABSL_HAVE_EXCEPTIONS throw error; #else - ABSL_RAW_LOG(ERROR, "%s", error.what()); - abort(); + ABSL_RAW_LOG(FATAL, "%s", error.what()); + std::abort(); #endif } } // namespace
diff --git a/absl/base/internal/throw_delegate.h b/absl/base/internal/throw_delegate.h index 70e2d77..03c700b 100644 --- a/absl/base/internal/throw_delegate.h +++ b/absl/base/internal/throw_delegate.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/tsan_mutex_interface.h b/absl/base/internal/tsan_mutex_interface.h index 6bb4fae..2a51060 100644 --- a/absl/base/internal/tsan_mutex_interface.h +++ b/absl/base/internal/tsan_mutex_interface.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/unaligned_access.h b/absl/base/internal/unaligned_access.h index f9df3b7..2d66737 100644 --- a/absl/base/internal/unaligned_access.h +++ b/absl/base/internal/unaligned_access.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/unscaledcycleclock.cc b/absl/base/internal/unscaledcycleclock.cc index a12d68b..593762b 100644 --- a/absl/base/internal/unscaledcycleclock.cc +++ b/absl/base/internal/unscaledcycleclock.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/internal/unscaledcycleclock.h b/absl/base/internal/unscaledcycleclock.h index 049f1ca..58950cc 100644 --- a/absl/base/internal/unscaledcycleclock.h +++ b/absl/base/internal/unscaledcycleclock.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -83,6 +83,7 @@ defined(_M_IX86) || defined(_M_X64)) #define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY #endif + namespace absl { namespace time_internal { class UnscaledCycleClockWrapperForGetCurrentTime; @@ -114,6 +115,7 @@ } // namespace base_internal } // namespace absl + #endif // ABSL_USE_UNSCALED_CYCLECLOCK #endif // ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
diff --git a/absl/base/invoke_test.cc b/absl/base/invoke_test.cc index 466bf11..691f553 100644 --- a/absl/base/invoke_test.cc +++ b/absl/base/invoke_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/log_severity.h b/absl/base/log_severity.h index 5770d36..b19a7ff 100644 --- a/absl/base/log_severity.h +++ b/absl/base/log_severity.h
@@ -4,14 +4,13 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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_LOG_SEVERITY_H_ #define ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
diff --git a/absl/base/macros.h b/absl/base/macros.h index ca3d5ed..5b43d7c 100644 --- a/absl/base/macros.h +++ b/absl/base/macros.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -24,7 +24,6 @@ // This code is compiled directly on many platforms, including client // platforms like Windows, Mac, and embedded systems. Before making // any changes here, make sure that you're not breaking any platforms. -// #ifndef ABSL_BASE_MACROS_H_ #define ABSL_BASE_MACROS_H_ @@ -199,4 +198,14 @@ : [] { assert(false && #expr); }()) // NOLINT #endif +#ifdef ABSL_HAVE_EXCEPTIONS +#define ABSL_INTERNAL_TRY try +#define ABSL_INTERNAL_CATCH_ANY catch (...) +#define ABSL_INTERNAL_RETHROW do { throw; } while (false) +#else // ABSL_HAVE_EXCEPTIONS +#define ABSL_INTERNAL_TRY if (true) +#define ABSL_INTERNAL_CATCH_ANY else if (false) +#define ABSL_INTERNAL_RETHROW do {} while (false) +#endif // ABSL_HAVE_EXCEPTIONS + #endif // ABSL_BASE_MACROS_H_
diff --git a/absl/base/optimization.h b/absl/base/optimization.h index 2fddfc8..6974f1f 100644 --- a/absl/base/optimization.h +++ b/absl/base/optimization.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -111,9 +111,9 @@ // See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html // for more information. // -// On some compilers, `ABSL_CACHELINE_ALIGNED` expands to -// `__attribute__((aligned(ABSL_CACHELINE_SIZE)))`. For compilers where this is -// not known to work, the macro expands to nothing. +// On some compilers, `ABSL_CACHELINE_ALIGNED` expands to an `__attribute__` +// or `__declspec` attribute. For compilers where this is not known to work, +// the macro expands to nothing. // // No further guarantees are made here. The result of applying the macro // to variables and types is always implementation-defined. @@ -122,6 +122,14 @@ // of causing bugs that are difficult to diagnose, crash, etc. It does not // of itself guarantee that objects are aligned to a cache line. // +// NOTE: Some compilers are picky about the locations of annotations such as +// this attribute, so prefer to put it at the beginning of your declaration. +// For example, +// +// ABSL_CACHELINE_ALIGNED static Foo* foo = ... +// +// class ABSL_CACHELINE_ALIGNED Bar { ... +// // Recommendations: // // 1) Consult compiler documentation; this comment is not kept in sync as @@ -131,8 +139,10 @@ // 3) Prefer applying this attribute to individual variables. Avoid // applying it to types. This tends to localize the effect. #define ABSL_CACHELINE_ALIGNED __attribute__((aligned(ABSL_CACHELINE_SIZE))) - -#else // not GCC +#elif defined(_MSC_VER) +#define ABSL_CACHELINE_SIZE 64 +#define ABSL_CACHELINE_ALIGNED __declspec(align(ABSL_CACHELINE_SIZE)) +#else #define ABSL_CACHELINE_SIZE 64 #define ABSL_CACHELINE_ALIGNED #endif
diff --git a/absl/base/policy_checks.h b/absl/base/policy_checks.h index 0a07fc0..699fb1a 100644 --- a/absl/base/policy_checks.h +++ b/absl/base/policy_checks.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/port.h b/absl/base/port.h index 1c67257..6c28068 100644 --- a/absl/base/port.h +++ b/absl/base/port.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/raw_logging_test.cc b/absl/base/raw_logging_test.cc index b21cf65..3d30bd3 100644 --- a/absl/base/raw_logging_test.cc +++ b/absl/base/raw_logging_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/base/spinlock_test_common.cc b/absl/base/spinlock_test_common.cc index 1b50884..e62b2ea 100644 --- a/absl/base/spinlock_test_common.cc +++ b/absl/base/spinlock_test_common.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -54,6 +54,7 @@ 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, @@ -155,7 +156,8 @@ // Test corner cases int64_t start_time = time_distribution(generator); - EXPECT_EQ(0, SpinLockTest::EncodeWaitCycles(start_time, start_time)); + EXPECT_EQ(kSpinLockSleeper, + SpinLockTest::EncodeWaitCycles(start_time, start_time)); EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(0)); EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(kLockwordReservedMask)); EXPECT_EQ(kMaxCycles & ~kProfileTimestampMask, @@ -188,6 +190,7 @@ SpinLockTest::DecodeWaitCycles(before_max_value); EXPECT_GT(expected_max_value_decoded, before_max_value_decoded); } + TEST(SpinLockWithThreads, StaticSpinLock) { ThreadedTest(&static_spinlock); }
diff --git a/absl/base/thread_annotations.h b/absl/base/thread_annotations.h index fbb2797..0b2c306 100644 --- a/absl/base/thread_annotations.h +++ b/absl/base/thread_annotations.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -21,7 +21,6 @@ // code. The annotations can also help program analysis tools to identify // potential thread safety issues. // -// // These annotations are implemented using compiler attributes. Using the macros // defined here instead of raw attributes allow for portability and future // compatibility. @@ -34,6 +33,7 @@ #ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_ #define ABSL_BASE_THREAD_ANNOTATIONS_H_ + #if defined(__clang__) #define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) #else @@ -108,13 +108,23 @@ // The mutex is expected to be held both on entry to, and exit from, the // function. // +// An exclusive lock allows read-write access to the guarded data member(s), and +// only one thread can acquire a lock exclusively at any one time. A shared lock +// allows read-only access, and any number of threads can acquire a shared lock +// concurrently. +// +// Generally, non-const methods should be annotated with +// EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with +// SHARED_LOCKS_REQUIRED. +// // Example: // // Mutex mu1, mu2; // int a GUARDED_BY(mu1); // int b GUARDED_BY(mu2); // -// void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }; +// void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... } +// void bar() const SHARED_LOCKS_REQUIRED(mu1, mu2) { ... } #define EXCLUSIVE_LOCKS_REQUIRED(...) \ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
diff --git a/absl/base/throw_delegate_test.cc b/absl/base/throw_delegate_test.cc index 0f15df0..a74dd3c 100644 --- a/absl/base/throw_delegate_test.cc +++ b/absl/base/throw_delegate_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/compiler_config_setting.bzl b/absl/compiler_config_setting.bzl index b77c4f5..6696229 100644 --- a/absl/compiler_config_setting.bzl +++ b/absl/compiler_config_setting.bzl
@@ -5,35 +5,34 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, - ) + # 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/absl/container/BUILD.bazel b/absl/container/BUILD.bazel index f2210e3..cd914ba 100644 --- a/absl/container/BUILD.bazel +++ b/absl/container/BUILD.bazel
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -15,11 +15,11 @@ # load( - "//absl:copts.bzl", + "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", - "ABSL_TEST_COPTS", "ABSL_EXCEPTIONS_FLAG", "ABSL_EXCEPTIONS_FLAG_LINKOPTS", + "ABSL_TEST_COPTS", ) package(default_visibility = ["//visibility:public"]) @@ -41,6 +41,8 @@ copts = ABSL_TEST_COPTS, deps = [ ":compressed_tuple", + "//absl/memory", + "//absl/utility", "@com_google_googletest//:gtest_main", ], ) @@ -110,10 +112,20 @@ ) cc_library( + name = "inlined_vector_internal", + hdrs = ["internal/inlined_vector.h"], + copts = ABSL_DEFAULT_COPTS, + deps = [ + "//absl/meta:type_traits", + ], +) + +cc_library( name = "inlined_vector", hdrs = ["inlined_vector.h"], copts = ABSL_DEFAULT_COPTS, deps = [ + ":inlined_vector_internal", "//absl/algorithm", "//absl/base:core_headers", "//absl/base:throw_delegate", @@ -121,12 +133,21 @@ ], ) +cc_library( + name = "counting_allocator", + testonly = 1, + hdrs = ["internal/counting_allocator.h"], + copts = ABSL_DEFAULT_COPTS, + visibility = ["//visibility:private"], +) + cc_test( name = "inlined_vector_test", srcs = ["inlined_vector_test.cc"], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, deps = [ + ":counting_allocator", ":inlined_vector", ":test_instance_tracker", "//absl/base", @@ -144,6 +165,7 @@ srcs = ["inlined_vector_test.cc"], copts = ABSL_TEST_COPTS, deps = [ + ":counting_allocator", ":inlined_vector", ":test_instance_tracker", "//absl/base", @@ -212,6 +234,7 @@ ":container_memory", ":hash_function_defaults", ":raw_hash_map", + "//absl/algorithm:container", "//absl/memory", ], ) @@ -219,13 +242,14 @@ cc_test( name = "flat_hash_map_test", srcs = ["flat_hash_map_test.cc"], - copts = ABSL_TEST_COPTS + ["-DUNORDERED_MAP_CXX17"], + copts = ABSL_TEST_COPTS, tags = NOTEST_TAGS_NONMOBILE, deps = [ ":flat_hash_map", ":hash_generator_testing", ":unordered_map_constructor_test", ":unordered_map_lookup_test", + ":unordered_map_members_test", ":unordered_map_modifiers_test", "//absl/types:any", "@com_google_googletest//:gtest_main", @@ -240,6 +264,7 @@ ":container_memory", ":hash_function_defaults", ":raw_hash_set", + "//absl/algorithm:container", "//absl/base:core_headers", "//absl/memory", ], @@ -255,6 +280,7 @@ ":hash_generator_testing", ":unordered_set_constructor_test", ":unordered_set_lookup_test", + ":unordered_set_members_test", ":unordered_set_modifiers_test", "//absl/memory", "//absl/strings", @@ -271,6 +297,7 @@ ":hash_function_defaults", ":node_hash_policy", ":raw_hash_map", + "//absl/algorithm:container", "//absl/memory", ], ) @@ -278,7 +305,7 @@ cc_test( name = "node_hash_map_test", srcs = ["node_hash_map_test.cc"], - copts = ABSL_TEST_COPTS + ["-DUNORDERED_MAP_CXX17"], + copts = ABSL_TEST_COPTS, tags = NOTEST_TAGS_NONMOBILE, deps = [ ":hash_generator_testing", @@ -286,6 +313,7 @@ ":tracked", ":unordered_map_constructor_test", ":unordered_map_lookup_test", + ":unordered_map_members_test", ":unordered_map_modifiers_test", "@com_google_googletest//:gtest_main", ], @@ -296,10 +324,10 @@ hdrs = ["node_hash_set.h"], copts = ABSL_DEFAULT_COPTS, deps = [ - ":container_memory", ":hash_function_defaults", ":node_hash_policy", ":raw_hash_set", + "//absl/algorithm:container", "//absl/memory", ], ) @@ -310,10 +338,10 @@ copts = ABSL_TEST_COPTS + ["-DUNORDERED_SET_CXX17"], tags = NOTEST_TAGS_NONMOBILE, deps = [ - ":hash_generator_testing", ":node_hash_set", ":unordered_set_constructor_test", ":unordered_set_lookup_test", + ":unordered_set_members_test", ":unordered_set_modifiers_test", "@com_google_googletest//:gtest_main", ], @@ -432,6 +460,39 @@ ) cc_library( + name = "hashtablez_sampler", + srcs = [ + "internal/hashtablez_sampler.cc", + "internal/hashtablez_sampler_force_weak_definition.cc", + ], + hdrs = ["internal/hashtablez_sampler.h"], + copts = ABSL_DEFAULT_COPTS, + deps = [ + ":have_sse", + "//absl/base", + "//absl/base:core_headers", + "//absl/debugging:stacktrace", + "//absl/memory", + "//absl/synchronization", + "//absl/utility", + ], +) + +cc_test( + name = "hashtablez_sampler_test", + srcs = ["internal/hashtablez_sampler_test.cc"], + deps = [ + ":hashtablez_sampler", + ":have_sse", + "//absl/base:core_headers", + "//absl/synchronization", + "//absl/synchronization:thread_pool", + "//absl/time", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( name = "node_hash_policy", hdrs = ["internal/node_hash_policy.h"], copts = ABSL_DEFAULT_COPTS, @@ -459,15 +520,35 @@ ) cc_library( + name = "have_sse", + hdrs = ["internal/have_sse.h"], + copts = ABSL_DEFAULT_COPTS, + visibility = ["//visibility:private"], +) + +cc_library( + name = "common", + hdrs = ["internal/common.h"], + copts = ABSL_DEFAULT_COPTS, + deps = [ + "//absl/meta:type_traits", + "//absl/types:optional", + ], +) + +cc_library( name = "raw_hash_set", srcs = ["internal/raw_hash_set.cc"], hdrs = ["internal/raw_hash_set.h"], copts = ABSL_DEFAULT_COPTS, deps = [ + ":common", ":compressed_tuple", ":container_memory", ":hash_policy_traits", ":hashtable_debug_hooks", + ":hashtablez_sampler", + ":have_sse", ":layout", "//absl/base:bits", "//absl/base:config", @@ -475,7 +556,6 @@ "//absl/base:endian", "//absl/memory", "//absl/meta:type_traits", - "//absl/types:optional", "//absl/utility", ], ) @@ -592,6 +672,29 @@ deps = [ ":hash_generator_testing", ":hash_policy_testing", + "//absl/meta:type_traits", + "@com_google_googletest//:gtest", + ], +) + +cc_library( + name = "unordered_set_members_test", + testonly = 1, + hdrs = ["internal/unordered_set_members_test.h"], + copts = ABSL_TEST_COPTS, + deps = [ + "//absl/meta:type_traits", + "@com_google_googletest//:gtest", + ], +) + +cc_library( + name = "unordered_map_members_test", + testonly = 1, + hdrs = ["internal/unordered_map_members_test.h"], + copts = ABSL_TEST_COPTS, + deps = [ + "//absl/meta:type_traits", "@com_google_googletest//:gtest", ], ) @@ -628,6 +731,7 @@ deps = [ ":unordered_set_constructor_test", ":unordered_set_lookup_test", + ":unordered_set_members_test", ":unordered_set_modifiers_test", "@com_google_googletest//:gtest_main", ], @@ -641,6 +745,7 @@ deps = [ ":unordered_map_constructor_test", ":unordered_map_lookup_test", + ":unordered_map_members_test", ":unordered_map_modifiers_test", "@com_google_googletest//:gtest_main", ],
diff --git a/absl/container/BUILD.gn b/absl/container/BUILD.gn index a2fbd54..3b8ece7 100644 --- a/absl/container/BUILD.gn +++ b/absl/container/BUILD.gn
@@ -49,6 +49,21 @@ ] } +source_set("inlined_vector_internal") { + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ + "//build/config/compiler:no_chromium_code", + "//third_party/abseil-cpp:absl_default_cflags_cc", + ] + public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] + public = [ + "internal/inlined_vector.h", + ] + deps = [ + "../meta:type_traits", + ] +} + source_set("inlined_vector") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ @@ -60,6 +75,7 @@ "inlined_vector.h", ] deps = [ + ":inlined_vector_internal", "../algorithm", "../base:core_headers", "../base:throw_delegate", @@ -67,6 +83,21 @@ ] } +source_set("counting_allocator") { + testonly = true + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ + "//build/config/compiler:no_chromium_code", + "//third_party/abseil-cpp:absl_default_cflags_cc", + ] + public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] + public = [ + "internal/counting_allocator.h", + ] + visibility = [] + visibility += [ ":*" ] +} + source_set("test_instance_tracker") { testonly = true configs -= [ "//build/config/compiler:chromium_code" ] @@ -99,6 +130,7 @@ ":container_memory", ":hash_function_defaults", ":raw_hash_map", + "../algorithm:container", "../memory", ] } @@ -117,6 +149,7 @@ ":container_memory", ":hash_function_defaults", ":raw_hash_set", + "../algorithm:container", "../base:core_headers", "../memory", ] @@ -137,6 +170,7 @@ ":hash_function_defaults", ":node_hash_policy", ":raw_hash_map", + "../algorithm:container", "../memory", ] } @@ -156,6 +190,7 @@ ":hash_function_defaults", ":node_hash_policy", ":raw_hash_set", + "../algorithm:container", "../memory", ] } @@ -273,6 +308,31 @@ ] } +source_set("hashtablez_sampler") { + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ + "//build/config/compiler:no_chromium_code", + "//third_party/abseil-cpp:absl_default_cflags_cc", + ] + public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] + public = [ + "internal/hashtablez_sampler.h", + ] + sources = [ + "internal/hashtablez_sampler.cc", + "internal/hashtablez_sampler_force_weak_definition.cc", + ] + deps = [ + ":have_sse", + "../base", + "../base:core_headers", + "../debugging:stacktrace", + "../memory", + "../synchronization", + "../utility", + ] +} + source_set("node_hash_policy") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ @@ -301,6 +361,36 @@ ] } +source_set("have_sse") { + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ + "//build/config/compiler:no_chromium_code", + "//third_party/abseil-cpp:absl_default_cflags_cc", + ] + public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] + public = [ + "internal/have_sse.h", + ] + visibility = [] + visibility += [ ":*" ] +} + +source_set("common") { + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ + "//build/config/compiler:no_chromium_code", + "//third_party/abseil-cpp:absl_default_cflags_cc", + ] + public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] + public = [ + "internal/common.h", + ] + deps = [ + "../meta:type_traits", + "../types:optional", + ] +} + source_set("raw_hash_set") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ @@ -315,10 +405,13 @@ "internal/raw_hash_set.h", ] deps = [ + ":common", ":compressed_tuple", ":container_memory", ":hash_policy_traits", ":hashtable_debug_hooks", + ":hashtablez_sampler", + ":have_sse", ":layout", "../base:bits", "../base:config", @@ -326,7 +419,6 @@ "../base:endian", "../memory", "../meta:type_traits", - "../types:optional", "../utility", ] } @@ -431,6 +523,41 @@ deps = [ ":hash_generator_testing", ":hash_policy_testing", + "../meta:type_traits", + "//testing/gtest", + ] +} + +source_set("unordered_set_members_test") { + testonly = true + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ + "//build/config/compiler:no_chromium_code", + "//third_party/abseil-cpp:absl_default_cflags_cc", + ] + public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] + public = [ + "internal/unordered_set_members_test.h", + ] + deps = [ + "../meta:type_traits", + "//testing/gtest", + ] +} + +source_set("unordered_map_members_test") { + testonly = true + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ + "//build/config/compiler:no_chromium_code", + "//third_party/abseil-cpp:absl_default_cflags_cc", + ] + public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] + public = [ + "internal/unordered_map_members_test.h", + ] + deps = [ + "../meta:type_traits", "//testing/gtest", ] }
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt index 9e40690..292fea2 100644 --- a/absl/container/CMakeLists.txt +++ b/absl/container/CMakeLists.txt
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -14,163 +14,772 @@ # limitations under the License. # - -list(APPEND CONTAINER_PUBLIC_HEADERS - "fixed_array.h" - "flat_hash_map.h" - "flat_hash_set.h" - "inlined_vector.h" - "node_hash_map.h" - "node_hash_set.h" -) - - -list(APPEND CONTAINER_INTERNAL_HEADERS - "internal/compressed_tuple.h" - "internal/container_memory.h" - "internal/hash_function_defaults.h" - "internal/hash_generator_testing.h" - "internal/hash_policy_testing.h" - "internal/hash_policy_traits.h" - "internal/hashtable_debug.h" - "internal/layout.h" - "internal/node_hash_policy.h" - "internal/raw_hash_map.h" - "internal/raw_hash_set.h" - "internal/test_instance_tracker.h" - "internal/tracked.h" - "internal/unordered_map_constructor_test.h" - "internal/unordered_map_lookup_test.h" - "internal/unordered_map_modifiers_test.h" - "internal/unordered_set_constructor_test.h" - "internal/unordered_set_lookup_test.h" - "internal/unordered_set_modifiers_test.h" -) - - -absl_library( - TARGET - absl_container - SOURCES - "internal/raw_hash_set.cc" - EXPORT_NAME +# This is deprecated and will be removed in the future. It also doesn't do +# anything anyways. Prefer to use the library associated with the API you are +# using. +absl_cc_library( + NAME container + PUBLIC ) - -# -## TESTS -# - -list(APPEND TEST_INSTANCE_TRACKER_LIB_SRC - "internal/test_instance_tracker.cc" - ${CONTAINER_PUBLIC_HEADERS} - ${CONTAINER_INTERNAL_HEADERS} +absl_cc_library( + NAME + compressed_tuple + HDRS + "internal/compressed_tuple.h" + DEPS + absl::utility + PUBLIC ) - -absl_library( - TARGET - test_instance_tracker_lib - SOURCES - ${TEST_INSTANCE_TRACKER_LIB_SRC} - PUBLIC_LIBRARIES - absl::container +absl_cc_test( + NAME + compressed_tuple_test + SRCS + "internal/compressed_tuple_test.cc" + DEPS + absl::compressed_tuple + absl::memory + absl::utility + gmock_main ) +absl_cc_library( + NAME + fixed_array + HDRS + "fixed_array.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::compressed_tuple + absl::algorithm + absl::core_headers + absl::dynamic_annotations + absl::throw_delegate + absl::memory + PUBLIC +) - -# test fixed_array_test -set(FIXED_ARRAY_TEST_SRC "fixed_array_test.cc") -set(FIXED_ARRAY_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate test_instance_tracker_lib) - -absl_test( - TARGET +absl_cc_test( + NAME fixed_array_test - SOURCES - ${FIXED_ARRAY_TEST_SRC} - PUBLIC_LIBRARIES - ${FIXED_ARRAY_TEST_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS + SRCS + "fixed_array_test.cc" + COPTS ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::fixed_array + absl::exception_testing + absl::hash_testing + absl::memory + gmock_main ) - - -absl_test( - TARGET +absl_cc_test( + NAME fixed_array_test_noexceptions - SOURCES - ${FIXED_ARRAY_TEST_SRC} - PUBLIC_LIBRARIES - ${FIXED_ARRAY_TEST_PUBLIC_LIBRARIES} + SRCS + "fixed_array_test.cc" + DEPS + absl::fixed_array + absl::exception_testing + absl::hash_testing + absl::memory + gmock_main ) - -# test fixed_array_exception_safety_test -set(FIXED_ARRAY_EXCEPTION_SAFETY_TEST_SRC "fixed_array_exception_safety_test.cc") -set(FIXED_ARRAY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES - absl::container - absl_base_internal_exception_safety_testing -) - -absl_test( - TARGET +absl_cc_test( + NAME fixed_array_exception_safety_test - SOURCES - ${FIXED_ARRAY_EXCEPTION_SAFETY_TEST_SRC} - PUBLIC_LIBRARIES - ${FIXED_ARRAY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS + SRCS + "fixed_array_exception_safety_test.cc" + COPTS ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::fixed_array + absl::exception_safety_testing + gmock_main ) +absl_cc_library( + NAME + inlined_vector_internal + HDRS + "internal/inlined_vector.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::type_traits + PUBLIC +) -# test inlined_vector_test -set(INLINED_VECTOR_TEST_SRC "inlined_vector_test.cc") -set(INLINED_VECTOR_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate test_instance_tracker_lib) +absl_cc_library( + NAME + inlined_vector + HDRS + "inlined_vector.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::algorithm + absl::core_headers + absl::throw_delegate + absl::memory + PUBLIC +) -absl_test( - TARGET +absl_cc_library( + NAME + counting_allocator + HDRS + "internal/counting_allocator.h" + COPTS + ${ABSL_DEFAULT_COPTS} +) + +absl_cc_test( + NAME inlined_vector_test - SOURCES - ${INLINED_VECTOR_TEST_SRC} - PUBLIC_LIBRARIES - ${INLINED_VECTOR_TEST_PUBLIC_LIBRARIES} + SRCS + "inlined_vector_test.cc" + COPTS + ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::counting_allocator + absl::inlined_vector + absl::test_instance_tracker + absl::base + absl::core_headers + absl::exception_testing + absl::hash_testing + absl::memory + absl::strings + gmock_main ) -absl_test( - TARGET +absl_cc_test( + NAME inlined_vector_test_noexceptions - SOURCES - ${INLINED_VECTOR_TEST_SRC} - PUBLIC_LIBRARIES - ${INLINED_VECTOR_TEST_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS - ${ABSL_NOEXCEPTION_CXXFLAGS} + SRCS + "inlined_vector_test.cc" + DEPS + absl::inlined_vector + absl::test_instance_tracker + absl::base + absl::core_headers + absl::exception_testing + absl::hash_testing + absl::memory + absl::strings + gmock_main ) +absl_cc_library( + NAME + test_instance_tracker + HDRS + "internal/test_instance_tracker.h" + SRCS + "internal/test_instance_tracker.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + TESTONLY +) -# test test_instance_tracker_test -set(TEST_INSTANCE_TRACKER_TEST_SRC "internal/test_instance_tracker_test.cc") -set(TEST_INSTANCE_TRACKER_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate test_instance_tracker_lib) - - -absl_test( - TARGET +absl_cc_test( + NAME test_instance_tracker_test - SOURCES - ${TEST_INSTANCE_TRACKER_TEST_SRC} - PUBLIC_LIBRARIES - ${TEST_INSTANCE_TRACKER_TEST_PUBLIC_LIBRARIES} + SRCS + "internal/test_instance_tracker_test.cc" + DEPS + absl::test_instance_tracker + gmock_main ) +absl_cc_library( + NAME + flat_hash_map + HDRS + "flat_hash_map.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::container_memory + absl::hash_function_defaults + absl::raw_hash_map + absl::algorithm_container + absl::memory + PUBLIC +) -absl_test( - TARGET +absl_cc_test( + NAME + flat_hash_map_test + SRCS + "flat_hash_map_test.cc" + DEPS + absl::flat_hash_map + absl::hash_generator_testing + absl::unordered_map_constructor_test + absl::unordered_map_lookup_test + absl::unordered_map_members_test + absl::unordered_map_modifiers_test + absl::any + gmock_main +) + +absl_cc_library( + NAME + flat_hash_set + HDRS + "flat_hash_set.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::container_memory + absl::hash_function_defaults + absl::raw_hash_set + absl::algorithm_container + absl::core_headers + absl::memory + PUBLIC +) + +absl_cc_test( + NAME + flat_hash_set_test + SRCS + "flat_hash_set_test.cc" + COPTS + "-DUNORDERED_SET_CXX17" + DEPS + absl::flat_hash_set + absl::hash_generator_testing + absl::unordered_set_constructor_test + absl::unordered_set_lookup_test + absl::unordered_set_members_test + absl::unordered_set_modifiers_test + absl::memory + absl::strings + gmock_main +) + +absl_cc_library( + NAME + node_hash_map + HDRS + "node_hash_map.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::container_memory + absl::hash_function_defaults + absl::node_hash_policy + absl::raw_hash_map + absl::algorithm_container + absl::memory + PUBLIC +) + +absl_cc_test( + NAME + node_hash_map_test + SRCS + "node_hash_map_test.cc" + DEPS + absl::hash_generator_testing + absl::node_hash_map + absl::tracked + absl::unordered_map_constructor_test + absl::unordered_map_lookup_test + absl::unordered_map_members_test + absl::unordered_map_modifiers_test + gmock_main +) + +absl_cc_library( + NAME + node_hash_set + HDRS + "node_hash_set.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::hash_function_defaults + absl::node_hash_policy + absl::raw_hash_set + absl::algorithm_container + absl::memory + PUBLIC +) + +absl_cc_test( + NAME + node_hash_set_test + SRCS + "node_hash_set_test.cc" + COPTS + "-DUNORDERED_SET_CXX17" + DEPS + absl::hash_generator_testing + absl::node_hash_set + absl::unordered_set_constructor_test + absl::unordered_set_lookup_test + absl::unordered_set_members_test + absl::unordered_set_modifiers_test + gmock_main +) + +absl_cc_library( + NAME + container_memory + HDRS + "internal/container_memory.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::memory + absl::utility + PUBLIC +) + +absl_cc_test( + NAME + container_memory_test + SRCS + "internal/container_memory_test.cc" + DEPS + absl::container_memory + absl::strings + gmock_main +) + +absl_cc_library( + NAME + hash_function_defaults + HDRS + "internal/hash_function_defaults.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::config + absl::hash + absl::strings + PUBLIC +) + +absl_cc_test( + NAME + hash_function_defaults_test + SRCS + "internal/hash_function_defaults_test.cc" + DEPS + absl::hash_function_defaults + absl::hash + absl::strings + gmock_main +) + +absl_cc_library( + NAME + hash_generator_testing + HDRS + "internal/hash_generator_testing.h" + SRCS + "internal/hash_generator_testing.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::hash_policy_testing + absl::meta + absl::strings + TESTONLY +) + +absl_cc_library( + NAME + hash_policy_testing + HDRS + "internal/hash_policy_testing.h" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::hash + absl::strings + TESTONLY +) + +absl_cc_test( + NAME + hash_policy_testing_test + SRCS + "internal/hash_policy_testing_test.cc" + DEPS + absl::hash_policy_testing + gmock_main +) + +absl_cc_library( + NAME + hash_policy_traits + HDRS + "internal/hash_policy_traits.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::meta + PUBLIC +) + +absl_cc_test( + NAME + hash_policy_traits_test + SRCS + "internal/hash_policy_traits_test.cc" + DEPS + absl::hash_policy_traits + gmock_main +) + +absl_cc_library( + NAME + hashtablez_sampler + HDRS + "internal/hashtablez_sampler.h" + SRCS + "internal/hashtablez_sampler.cc" + "internal/hashtablez_sampler_force_weak_definition.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::base + absl::have_sse + absl::synchronization +) + +absl_cc_test( + NAME + hashtablez_sampler_test + SRCS + "internal/hashtablez_sampler_test.cc" + DEPS + absl::hashtablez_sampler + absl::have_sse + gmock_main +) + +absl_cc_library( + NAME + hashtable_debug + HDRS + "internal/hashtable_debug.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::hashtable_debug_hooks +) + +absl_cc_library( + NAME + hashtable_debug_hooks + HDRS + "internal/hashtable_debug_hooks.h" + COPTS + ${ABSL_DEFAULT_COPTS} + PUBLIC +) + +absl_cc_library( + NAME + have_sse + HDRS + "internal/have_sse.h" + COPTS + ${ABSL_DEFAULT_COPTS} +) + +absl_cc_library( + NAME + node_hash_policy + HDRS + "internal/node_hash_policy.h" + COPTS + ${ABSL_DEFAULT_COPTS} + PUBLIC +) + +absl_cc_test( + NAME + node_hash_policy_test + SRCS + "internal/node_hash_policy_test.cc" + DEPS + absl::hash_policy_traits + absl::node_hash_policy + gmock_main +) + +absl_cc_library( + NAME + raw_hash_map + HDRS + "internal/raw_hash_map.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::container_memory + absl::raw_hash_set + PUBLIC +) + +absl_cc_library( + NAME + container_common + HDRS + "internal/commom.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::type_traits +) + +absl_cc_library( + NAME + raw_hash_set + HDRS + "internal/raw_hash_set.h" + SRCS + "internal/raw_hash_set.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::bits + absl::compressed_tuple + absl::config + absl::container_common + absl::container_memory + absl::core_headers + absl::endian + absl::hash_policy_traits + absl::hashtable_debug_hooks + absl::have_sse + absl::layout + absl::memory + absl::meta + absl::optional + absl::utility + absl::hashtablez_sampler + PUBLIC +) + +absl_cc_test( + NAME raw_hash_set_test - SOURCES + SRCS "internal/raw_hash_set_test.cc" - PUBLIC_LIBRARIES - absl::base absl::hash absl_throw_delegate test_instance_tracker_lib + DEPS + absl::container_memory + absl::hash_function_defaults + absl::hash_policy_testing + absl::hashtable_debug + absl::raw_hash_set + absl::base + absl::core_headers + absl::strings + gmock_main +) + +absl_cc_test( + NAME + raw_hash_set_allocator_test + SRCS + "internal/raw_hash_set_allocator_test.cc" + DEPS + absl::raw_hash_set + absl::tracked + absl::core_headers + gmock_main +) + +absl_cc_library( + NAME + layout + HDRS + "internal/layout.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::core_headers + absl::meta + absl::strings + absl::span + absl::utility + PUBLIC +) + +absl_cc_test( + NAME + layout_test + SRCS + "internal/layout_test.cc" + DEPS + absl::layout + absl::base + absl::core_headers + absl::span + gmock_main +) + +absl_cc_library( + NAME + tracked + HDRS + "internal/tracked.h" + COPTS + ${ABSL_TEST_COPTS} + TESTONLY +) + +absl_cc_library( + NAME + unordered_map_constructor_test + HDRS + "internal/unordered_map_constructor_test.h" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::hash_generator_testing + absl::hash_policy_testing + gmock + TESTONLY +) + +absl_cc_library( + NAME + unordered_map_lookup_test + HDRS + "internal/unordered_map_lookup_test.h" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::hash_generator_testing + absl::hash_policy_testing + gmock + TESTONLY +) + +absl_cc_library( + NAME + unordered_map_members_test + HDRS + "internal/unordered_map_members_test.h" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::type_traits + gmock + TESTONLY +) + +absl_cc_library( + NAME + unordered_map_modifiers_test + HDRS + "internal/unordered_map_modifiers_test.h" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::hash_generator_testing + absl::hash_policy_testing + gmock + TESTONLY +) + +absl_cc_library( + NAME + unordered_set_constructor_test + HDRS + "internal/unordered_set_constructor_test.h" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::hash_generator_testing + absl::hash_policy_testing + gmock + TESTONLY +) + +absl_cc_library( + NAME + unordered_set_lookup_test + HDRS + "internal/unordered_set_lookup_test.h" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::hash_generator_testing + absl::hash_policy_testing + gmock + TESTONLY +) + +absl_cc_library( + NAME + unordered_set_members_test + HDRS + "internal/unordered_set_members_test.h" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::type_traits + gmock + TESTONLY +) + +absl_cc_library( + NAME + unordered_set_modifiers_test + HDRS + "internal/unordered_set_modifiers_test.h" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::hash_generator_testing + absl::hash_policy_testing + gmock + TESTONLY +) + +absl_cc_test( + NAME + unordered_set_test + SRCS + "internal/unordered_set_test.cc" + DEPS + absl::unordered_set_constructor_test + absl::unordered_set_lookup_test + absl::unordered_set_members_test + absl::unordered_set_modifiers_test + gmock_main +) + +absl_cc_test( + NAME + unordered_map_test + SRCS + "internal/unordered_map_test.cc" + DEPS + absl::unordered_map_constructor_test + absl::unordered_map_lookup_test + absl::unordered_map_members_test + absl::unordered_map_modifiers_test + gmock_main )
diff --git a/absl/container/fixed_array.h b/absl/container/fixed_array.h index 6d9fa5f..60da048 100644 --- a/absl/container/fixed_array.h +++ b/absl/container/fixed_array.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -188,7 +188,7 @@ // `FixedArray<T>`. This is equivalent to the most possible addressable bytes // over the number of bytes taken by T. constexpr size_type max_size() const { - return std::numeric_limits<difference_type>::max() / sizeof(value_type); + return (std::numeric_limits<difference_type>::max)() / sizeof(value_type); } // FixedArray::empty() @@ -515,4 +515,5 @@ static_cast<void>(n); // Mark used when not in asan mode } } // namespace absl + #endif // ABSL_CONTAINER_FIXED_ARRAY_H_
diff --git a/absl/container/fixed_array_benchmark.cc b/absl/container/fixed_array_benchmark.cc index b4f0cf2..ff56f46 100644 --- a/absl/container/fixed_array_benchmark.cc +++ b/absl/container/fixed_array_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/container/fixed_array_exception_safety_test.cc b/absl/container/fixed_array_exception_safety_test.cc index da63dbf..826eca6 100644 --- a/absl/container/fixed_array_exception_safety_test.cc +++ b/absl/container/fixed_array_exception_safety_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/container/fixed_array_test.cc b/absl/container/fixed_array_test.cc index 205ff41..a4f2498 100644 --- a/absl/container/fixed_array_test.cc +++ b/absl/container/fixed_array_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -150,7 +150,7 @@ } { - // Arrays of > default size should be on the stack + // Arrays of > default size should be on the heap absl::FixedArray<int, 100> array(101); EXPECT_FALSE(IsOnStack(array)); } @@ -365,7 +365,8 @@ TEST(IteratorConstructorTest, NonPod) { char const* kInput[] = { "red", "orange", "yellow", "green", "blue", "indigo", "violet" }; - absl::FixedArray<std::string> const fixed(kInput, kInput + ABSL_ARRAYSIZE(kInput)); + absl::FixedArray<std::string> const fixed(kInput, + kInput + ABSL_ARRAYSIZE(kInput)); ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size()); for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) { ASSERT_EQ(kInput[i], fixed[i]); @@ -869,4 +870,21 @@ } #endif // ADDRESS_SANITIZER +TEST(FixedArrayTest, AbslHashValueWorks) { + using V = absl::FixedArray<int>; + std::vector<V> cases; + + // Generate a variety of vectors some of these are small enough for the inline + // space but are stored out of line. + for (int i = 0; i < 10; ++i) { + V v(i); + for (int j = 0; j < i; ++j) { + v[j] = j; + } + cases.push_back(v); + } + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases)); +} + } // namespace
diff --git a/absl/container/flat_hash_map.h b/absl/container/flat_hash_map.h index e5570d1..00cc4dc 100644 --- a/absl/container/flat_hash_map.h +++ b/absl/container/flat_hash_map.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -35,6 +35,7 @@ #include <type_traits> #include <utility> +#include "absl/algorithm/container.h" #include "absl/container/internal/container_memory.h" #include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export #include "absl/container/internal/raw_hash_map.h" // IWYU pragma: export @@ -69,7 +70,7 @@ // By default, `flat_hash_map` uses the `absl::Hash` hashing framework. // All fundamental and Abseil types that support the `absl::Hash` framework have // a compatible equality operator for comparing insertions into `flat_hash_map`. -// If your type is not yet supported by the `asbl::Hash` framework, see +// If your type is not yet supported by the `absl::Hash` framework, see // absl/hash/hash.h for information on extending Abseil hashing to user-defined // types. // @@ -109,6 +110,46 @@ using Base = typename flat_hash_map::raw_hash_map; public: + // Constructors and Assignment Operators + // + // A flat_hash_map supports the same overload set as `std::unordered_map` + // for construction and assignment: + // + // * Default constructor + // + // // No allocation for the table's elements is made. + // absl::flat_hash_map<int, std::string> map1; + // + // * Initializer List constructor + // + // absl::flat_hash_map<int, std::string> map2 = + // {{1, "huey"}, {2, "dewey"}, {3, "louie"},}; + // + // * Copy constructor + // + // absl::flat_hash_map<int, std::string> map3(map2); + // + // * Copy assignment operator + // + // // Hash functor and Comparator are copied as well + // absl::flat_hash_map<int, std::string> map4; + // map4 = map3; + // + // * Move constructor + // + // // Move is guaranteed efficient + // absl::flat_hash_map<int, std::string> map5(std::move(map4)); + // + // * Move assignment operator + // + // // May be efficient if allocators are compatible + // absl::flat_hash_map<int, std::string> map6; + // map6 = std::move(map5); + // + // * Range constructor + // + // std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}}; + // absl::flat_hash_map<int, std::string> map7(v.begin(), v.end()); flat_hash_map() {} using Base::Base; @@ -178,8 +219,12 @@ // Erases the element at `position` of the `flat_hash_map`, returning // `void`. // - // NOTE: this return behavior is different than that of STL containers in - // general and `std::unordered_map` in particular. + // NOTE: returning `void` in this case is different than that of STL + // containers in general and `std::unordered_map` in particular (which + // return an iterator to the element following the erased element). If that + // iterator is needed, simply post increment the iterator: + // + // map.erase(it++); // // iterator erase(const_iterator first, const_iterator last): // @@ -486,25 +531,26 @@ template <class K, class V> struct FlatHashMapPolicy { - using slot_type = container_internal::slot_type<K, V>; + using slot_policy = container_internal::map_slot_policy<K, V>; + using slot_type = typename slot_policy::slot_type; using key_type = K; using mapped_type = V; using init_type = std::pair</*non const*/ key_type, mapped_type>; template <class Allocator, class... Args> static void construct(Allocator* alloc, slot_type* slot, Args&&... args) { - slot_type::construct(alloc, slot, std::forward<Args>(args)...); + slot_policy::construct(alloc, slot, std::forward<Args>(args)...); } template <class Allocator> static void destroy(Allocator* alloc, slot_type* slot) { - slot_type::destroy(alloc, slot); + slot_policy::destroy(alloc, slot); } template <class Allocator> static void transfer(Allocator* alloc, slot_type* new_slot, slot_type* old_slot) { - slot_type::transfer(alloc, new_slot, old_slot); + slot_policy::transfer(alloc, new_slot, old_slot); } template <class F, class... Args> @@ -524,5 +570,16 @@ }; } // namespace container_internal + +namespace container_algorithm_internal { + +// Specialization of trait in absl/algorithm/container.h +template <class Key, class T, class Hash, class KeyEqual, class Allocator> +struct IsUnorderedContainer< + absl::flat_hash_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type {}; + +} // namespace container_algorithm_internal + } // namespace absl + #endif // ABSL_CONTAINER_FLAT_HASH_MAP_H_
diff --git a/absl/container/flat_hash_map_test.cc b/absl/container/flat_hash_map_test.cc index 10a781f..ebcb560 100644 --- a/absl/container/flat_hash_map_test.cc +++ b/absl/container/flat_hash_map_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -17,6 +17,7 @@ #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" +#include "absl/container/internal/unordered_map_members_test.h" #include "absl/container/internal/unordered_map_modifiers_test.h" #include "absl/types/any.h" @@ -30,19 +31,20 @@ using ::testing::UnorderedElementsAre; template <class K, class V> -using Map = - flat_hash_map<K, V, StatefulTestingHash, StatefulTestingEqual, Alloc<>>; +using Map = flat_hash_map<K, V, StatefulTestingHash, StatefulTestingEqual, + Alloc<std::pair<const K, V>>>; static_assert(!std::is_standard_layout<NonStandardLayout>(), ""); using MapTypes = - ::testing::Types<Map<int, int>, Map<std::string, int>, Map<Enum, std::string>, - Map<EnumClass, int>, Map<int, NonStandardLayout>, - Map<NonStandardLayout, int>>; + ::testing::Types<Map<int, int>, Map<std::string, int>, + Map<Enum, std::string>, Map<EnumClass, int>, + Map<int, NonStandardLayout>, Map<NonStandardLayout, int>>; -INSTANTIATE_TYPED_TEST_CASE_P(FlatHashMap, ConstructorTest, MapTypes); -INSTANTIATE_TYPED_TEST_CASE_P(FlatHashMap, LookupTest, MapTypes); -INSTANTIATE_TYPED_TEST_CASE_P(FlatHashMap, ModifiersTest, MapTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashMap, ConstructorTest, MapTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashMap, LookupTest, MapTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashMap, MembersTest, MapTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashMap, ModifiersTest, MapTypes); TEST(FlatHashMap, StandardLayout) { struct Int { @@ -94,7 +96,7 @@ } } -// Demonstration of the "Lazy Key" pattern. This uses heterogenous insert to +// Demonstration of the "Lazy Key" pattern. This uses heterogeneous insert to // avoid creating expensive key elements when the item is already present in the // map. struct LazyInt { @@ -139,6 +141,7 @@ int conversions = 0; int hashes = 0; flat_hash_map<size_t, size_t, Hash, Eq> m(0, Hash{&hashes}); + m.reserve(3); m[LazyInt(1, &conversions)] = 1; EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 1))); @@ -203,7 +206,9 @@ m.insert(std::move(node)); EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 17), Pair(2, 9))); } -#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__) + +#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); @@ -234,7 +239,8 @@ ASSERT_NE(it2, m2.end()); EXPECT_EQ(7, it2->second); } -#endif // __ANDROID__ +#endif // (defined(ABSL_HAVE_STD_ANY) || !defined(_LIBCPP_VERSION)) && + // !defined(__EMSCRIPTEN__) } // namespace } // namespace container_internal
diff --git a/absl/container/flat_hash_set.h b/absl/container/flat_hash_set.h index 98aead1..6bf5183 100644 --- a/absl/container/flat_hash_set.h +++ b/absl/container/flat_hash_set.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -32,6 +32,7 @@ #include <type_traits> #include <utility> +#include "absl/algorithm/container.h" #include "absl/base/macros.h" #include "absl/container/internal/container_memory.h" #include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export @@ -66,7 +67,7 @@ // By default, `flat_hash_set` uses the `absl::Hash` hashing framework. All // fundamental and Abseil types that support the `absl::Hash` framework have a // compatible equality operator for comparing insertions into `flat_hash_map`. -// If your type is not yet supported by the `asbl::Hash` framework, see +// If your type is not yet supported by the `absl::Hash` framework, see // absl/hash/hash.h for information on extending Abseil hashing to user-defined // types. // @@ -84,7 +85,7 @@ // {"huey", "dewey", "louie"}; // // // Insert a new element into the flat hash set -// ducks.insert("donald"}; +// ducks.insert("donald"); // // // Force a rehash of the flat hash set // ducks.rehash(0); @@ -102,6 +103,46 @@ using Base = typename flat_hash_set::raw_hash_set; public: + // Constructors and Assignment Operators + // + // A flat_hash_set supports the same overload set as `std::unordered_map` + // for construction and assignment: + // + // * Default constructor + // + // // No allocation for the table's elements is made. + // absl::flat_hash_set<std::string> set1; + // + // * Initializer List constructor + // + // absl::flat_hash_set<std::string> set2 = + // {{"huey"}, {"dewey"}, {"louie"},}; + // + // * Copy constructor + // + // absl::flat_hash_set<std::string> set3(set2); + // + // * Copy assignment operator + // + // // Hash functor and Comparator are copied as well + // absl::flat_hash_set<std::string> set4; + // set4 = set3; + // + // * Move constructor + // + // // Move is guaranteed efficient + // absl::flat_hash_set<std::string> set5(std::move(set4)); + // + // * Move assignment operator + // + // // May be efficient if allocators are compatible + // absl::flat_hash_set<std::string> set6; + // set6 = std::move(set5); + // + // * Range constructor + // + // std::vector<std::string> v = {"a", "b"}; + // absl::flat_hash_set<std::string> set7(v.begin(), v.end()); flat_hash_set() {} using Base::Base; @@ -171,8 +212,12 @@ // Erases the element at `position` of the `flat_hash_set`, returning // `void`. // - // NOTE: this return behavior is different than that of STL containers in - // general and `std::unordered_map` in particular. + // NOTE: returning `void` in this case is different than that of STL + // containers in general and `std::unordered_set` in particular (which + // return an iterator to the element following the erased element). If that + // iterator is needed, simply post increment the iterator: + // + // set.erase(it++); // // iterator erase(const_iterator first, const_iterator last): // @@ -238,8 +283,7 @@ // // The element may be constructed even if there already is an element with the // key in the container, in which case the newly constructed element will be - // destroyed immediately. Prefer `try_emplace()` unless your key is not - // copyable or moveable. + // destroyed immediately. // // If rehashing occurs due to the insertion, all iterators are invalidated. using Base::emplace; @@ -253,8 +297,7 @@ // // The element may be constructed even if there already is an element with the // key in the container, in which case the newly constructed element will be - // destroyed immediately. Prefer `try_emplace()` unless your key is not - // copyable or moveable. + // destroyed immediately. // // If rehashing occurs due to the insertion, all iterators are invalidated. using Base::emplace_hint; @@ -435,5 +478,16 @@ static size_t space_used(const T*) { return 0; } }; } // namespace container_internal + +namespace container_algorithm_internal { + +// Specialization of trait in absl/algorithm/container.h +template <class Key, class Hash, class KeyEqual, class Allocator> +struct IsUnorderedContainer<absl::flat_hash_set<Key, Hash, KeyEqual, Allocator>> + : std::true_type {}; + +} // namespace container_algorithm_internal + } // namespace absl + #endif // ABSL_CONTAINER_FLAT_HASH_SET_H_
diff --git a/absl/container/flat_hash_set_test.cc b/absl/container/flat_hash_set_test.cc index e52fd53..b55be59 100644 --- a/absl/container/flat_hash_set_test.cc +++ b/absl/container/flat_hash_set_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -19,6 +19,7 @@ #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" +#include "absl/container/internal/unordered_set_members_test.h" #include "absl/container/internal/unordered_set_modifiers_test.h" #include "absl/memory/memory.h" #include "absl/strings/string_view.h" @@ -40,9 +41,10 @@ using SetTypes = ::testing::Types<Set<int>, Set<std::string>, Set<Enum>, Set<EnumClass>>; -INSTANTIATE_TYPED_TEST_CASE_P(FlatHashSet, ConstructorTest, SetTypes); -INSTANTIATE_TYPED_TEST_CASE_P(FlatHashSet, LookupTest, SetTypes); -INSTANTIATE_TYPED_TEST_CASE_P(FlatHashSet, ModifiersTest, SetTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashSet, ConstructorTest, SetTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashSet, LookupTest, SetTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashSet, MembersTest, SetTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashSet, ModifiersTest, SetTypes); TEST(FlatHashSet, EmplaceString) { std::vector<std::string> v = {"a", "b"};
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h index 12756bb..7798805 100644 --- a/absl/container/inlined_vector.h +++ b/absl/container/inlined_vector.h
@@ -1,10 +1,10 @@ -// Copyright 2017 The Abseil Authors. +// 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 // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -20,17 +20,17 @@ // vector" which behaves in an equivalent fashion to a `std::vector`, except // that storage for small sequences of the vector are provided inline without // requiring any heap allocation. - -// An `absl::InlinedVector<T,N>` specifies the size N at which to inline as one -// of its template parameters. Vectors of length <= N are provided inline. -// Typically N is very small (e.g., 4) so that sequences that are expected to be -// short do not require allocations. - -// An `absl::InlinedVector` does not usually require a specific allocator; if +// +// An `absl::InlinedVector<T, N>` specifies the default capacity `N` as one of +// its template parameters. Instances where `size() <= N` hold contained +// elements in inline space. Typically `N` is very small so that sequences that +// are expected to be short do not require allocations. +// +// An `absl::InlinedVector` does not usually require a specific allocator. If // the inlined vector grows beyond its initial constraints, it will need to -// allocate (as any normal `std::vector` would) and it will generally use the -// default allocator in that case; optionally, a custom allocator may be -// specified using an `absl::InlinedVector<T,N,A>` construction. +// allocate (as any normal `std::vector` would). This is usually performed with +// the default allocator (defined as `std::allocator<T>`). Optionally, a custom +// allocator type may be specified as `A` in `absl::InlinedVector<T, N, A>`. #ifndef ABSL_CONTAINER_INLINED_VECTOR_H_ #define ABSL_CONTAINER_INLINED_VECTOR_H_ @@ -50,10 +50,10 @@ #include "absl/base/internal/throw_delegate.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 { - // ----------------------------------------------------------------------------- // InlinedVector // ----------------------------------------------------------------------------- @@ -61,323 +61,633 @@ // An `absl::InlinedVector` is designed to be a drop-in replacement for // `std::vector` for use cases where the vector's size is sufficiently small // that it can be inlined. If the inlined vector does grow beyond its estimated -// size, it will trigger an initial allocation on the heap, and will behave as a -// `std:vector`. The API of the `absl::InlinedVector` within this file is +// 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 // designed to cover the same API footprint as covered by `std::vector`. -template <typename T, size_t N, typename A = std::allocator<T> > +template <typename T, size_t N, typename A = std::allocator<T>> class InlinedVector { - using AllocatorTraits = std::allocator_traits<A>; + static_assert( + N > 0, "InlinedVector cannot be instantiated with `0` inlined elements."); + + using Storage = inlined_vector_internal::Storage<InlinedVector>; + using Tag = typename Storage::Tag; + using AllocatorAndTag = typename Storage::AllocatorAndTag; + using Allocation = typename Storage::Allocation; + + template <typename Iterator> + using IsAtLeastForwardIterator = std::is_convertible< + typename std::iterator_traits<Iterator>::iterator_category, + std::forward_iterator_tag>; + + template <typename Iterator> + using EnableIfAtLeastForwardIterator = + absl::enable_if_t<IsAtLeastForwardIterator<Iterator>::value>; + + template <typename Iterator> + using DisableIfAtLeastForwardIterator = + absl::enable_if_t<!IsAtLeastForwardIterator<Iterator>::value>; + + using rvalue_reference = typename Storage::rvalue_reference; public: - using allocator_type = A; - using value_type = typename allocator_type::value_type; - using pointer = typename allocator_type::pointer; - using const_pointer = typename allocator_type::const_pointer; - using reference = typename allocator_type::reference; - using const_reference = typename allocator_type::const_reference; - using size_type = typename allocator_type::size_type; - using difference_type = typename allocator_type::difference_type; - using iterator = pointer; - using const_iterator = const_pointer; - using reverse_iterator = std::reverse_iterator<iterator>; - using const_reverse_iterator = std::reverse_iterator<const_iterator>; + using allocator_type = typename Storage::allocator_type; + 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 iterator = typename Storage::iterator; + using const_iterator = typename Storage::const_iterator; + using reverse_iterator = typename Storage::reverse_iterator; + using const_reverse_iterator = typename Storage::const_reverse_iterator; + // --------------------------------------------------------------------------- + // InlinedVector Constructors and Destructor + // --------------------------------------------------------------------------- + + // Creates an empty inlined vector with a default initialized allocator. InlinedVector() noexcept(noexcept(allocator_type())) - : allocator_and_tag_(allocator_type()) {} + : storage_(allocator_type()) {} + // Creates an empty inlined vector with a specified allocator. explicit InlinedVector(const allocator_type& alloc) noexcept - : allocator_and_tag_(alloc) {} + : storage_(alloc) {} - // Create a vector with n copies of value_type(). + // Creates an inlined vector with `n` copies of `value_type()`. explicit InlinedVector(size_type n, const allocator_type& alloc = allocator_type()) - : allocator_and_tag_(alloc) { + : storage_(alloc) { InitAssign(n); } - // Create a vector with n copies of elem - InlinedVector(size_type n, const value_type& elem, + // Creates an inlined vector with `n` copies of `v`. + InlinedVector(size_type n, const_reference v, const allocator_type& alloc = allocator_type()) - : allocator_and_tag_(alloc) { - InitAssign(n, elem); + : storage_(alloc) { + InitAssign(n, v); } - // Create and initialize with the elements [first .. last). - // The unused enable_if argument restricts this constructor so that it is - // elided when value_type is an integral type. This prevents ambiguous - // interpretation between a call to this constructor with two integral - // arguments and a call to the preceding (n, elem) constructor. - template <typename InputIterator> - InlinedVector( - InputIterator first, InputIterator last, - const allocator_type& alloc = allocator_type(), - typename std::enable_if<!std::is_integral<InputIterator>::value>::type* = - nullptr) - : allocator_and_tag_(alloc) { - AppendRange(first, last); - } - - InlinedVector(std::initializer_list<value_type> init, + // Creates an inlined vector of copies of the values in `list`. + InlinedVector(std::initializer_list<value_type> list, const allocator_type& alloc = allocator_type()) - : allocator_and_tag_(alloc) { - AppendRange(init.begin(), init.end()); + : storage_(alloc) { + AppendForwardRange(list.begin(), list.end()); } - InlinedVector(const InlinedVector& v); - InlinedVector(const InlinedVector& v, const allocator_type& alloc); + // Creates an inlined vector with elements constructed from the provided + // forward iterator range [`first`, `last`). + // + // NOTE: The `enable_if` prevents ambiguous interpretation between a call to + // this constructor with two integral arguments and a call to the above + // `InlinedVector(size_type, const_reference)` constructor. + template <typename ForwardIterator, + EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr> + InlinedVector(ForwardIterator first, ForwardIterator last, + const allocator_type& alloc = allocator_type()) + : storage_(alloc) { + AppendForwardRange(first, last); + } - // This move constructor does not allocate and only moves the underlying - // objects, so its `noexcept` specification depends on whether moving the - // underlying objects can throw or not. We assume - // a) move constructors should only throw due to allocation failure and - // b) if `value_type`'s move constructor allocates, it uses the same - // allocation function as the `InlinedVector`'s allocator, so the move + // Creates an inlined vector with elements constructed from the provided input + // iterator range [`first`, `last`). + template <typename InputIterator, + DisableIfAtLeastForwardIterator<InputIterator>* = nullptr> + InlinedVector(InputIterator first, InputIterator last, + const allocator_type& alloc = allocator_type()) + : storage_(alloc) { + std::copy(first, last, std::back_inserter(*this)); + } + + // Creates a copy of an `other` inlined vector using `other`'s allocator. + InlinedVector(const InlinedVector& other) + : InlinedVector(other, other.allocator()) {} + + // Creates a copy of an `other` inlined vector using a specified allocator. + InlinedVector(const InlinedVector& other, const allocator_type& alloc) + : storage_(alloc) { + reserve(other.size()); + if (allocated()) { + UninitializedCopy(other.begin(), other.end(), allocated_space()); + tag().set_allocated_size(other.size()); + } else { + UninitializedCopy(other.begin(), other.end(), inlined_space()); + tag().set_inline_size(other.size()); + } + } + + // Creates an inlined vector by moving in the contents of an `other` inlined + // vector without performing any allocations. If `other` contains allocated + // memory, the newly-created instance will take ownership of that memory + // (leaving `other` itself empty). However, if `other` does not contain any + // allocated memory, the new inlined vector will will perform element-wise + // move construction of `other`s elements. + // + // NOTE: since no allocation is performed for the inlined vector in either + // case, the `noexcept(...)` specification depends on whether moving the + // underlying objects can throw. We assume: + // a) Move constructors should only throw due to allocation failure. + // b) If `value_type`'s move constructor allocates, it uses the same + // allocation function as the `InlinedVector`'s allocator. Thus, the move // constructor is non-throwing if the allocator is non-throwing or // `value_type`'s move constructor is specified as `noexcept`. - InlinedVector(InlinedVector&& v) noexcept( + InlinedVector(InlinedVector&& other) noexcept( absl::allocator_is_nothrow<allocator_type>::value || - std::is_nothrow_move_constructible<value_type>::value); + std::is_nothrow_move_constructible<value_type>::value) + : storage_(other.allocator()) { + if (other.allocated()) { + // We can just steal the underlying buffer from the source. + // That leaves the source empty, so we clear its size. + init_allocation(other.allocation()); + tag().set_allocated_size(other.size()); + other.tag() = Tag(); + } else { + UninitializedCopy( + std::make_move_iterator(other.inlined_space()), + std::make_move_iterator(other.inlined_space() + other.size()), + inlined_space()); + tag().set_inline_size(other.size()); + } + } - // This move constructor allocates and also moves the underlying objects, so - // its `noexcept` specification depends on whether the allocation can throw - // and whether moving the underlying objects can throw. Based on the same - // assumptions above, the `noexcept` specification is dominated by whether the - // allocation can throw regardless of whether `value_type`'s move constructor - // is specified as `noexcept`. - InlinedVector(InlinedVector&& v, const allocator_type& alloc) noexcept( - absl::allocator_is_nothrow<allocator_type>::value); + // Creates an inlined vector by moving in the contents of an `other` inlined + // vector, performing allocations with the specified `alloc` allocator. If + // `other`'s allocator is not equal to `alloc` and `other` contains allocated + // memory, this move constructor will create a new allocation. + // + // NOTE: since allocation is performed in this case, this constructor can + // only be `noexcept` if the specified allocator is also `noexcept`. If this + // is the case, or if `other` contains allocated memory, this constructor + // performs element-wise move construction of its contents. + // + // Only in the case where `other`'s allocator is equal to `alloc` and `other` + // contains allocated memory will the newly created inlined vector take + // ownership of `other`'s allocated memory. + InlinedVector(InlinedVector&& other, const allocator_type& alloc) noexcept( + absl::allocator_is_nothrow<allocator_type>::value) + : storage_(alloc) { + if (other.allocated()) { + if (alloc == other.allocator()) { + // We can just steal the allocation from the source. + tag() = other.tag(); + init_allocation(other.allocation()); + other.tag() = Tag(); + } else { + // We need to use our own allocator + reserve(other.size()); + UninitializedCopy(std::make_move_iterator(other.begin()), + std::make_move_iterator(other.end()), + allocated_space()); + tag().set_allocated_size(other.size()); + } + } else { + UninitializedCopy( + std::make_move_iterator(other.inlined_space()), + std::make_move_iterator(other.inlined_space() + other.size()), + inlined_space()); + tag().set_inline_size(other.size()); + } + } ~InlinedVector() { clear(); } - InlinedVector& operator=(const InlinedVector& v) { - if (this == &v) { - return *this; + // --------------------------------------------------------------------------- + // InlinedVector Member Accessors + // --------------------------------------------------------------------------- + + // `InlinedVector::empty()` + // + // Checks if the inlined vector has no elements. + bool empty() const noexcept { return !size(); } + + // `InlinedVector::size()` + // + // Returns the number of elements in the inlined vector. + size_type size() const noexcept { return tag().size(); } + + // `InlinedVector::max_size()` + // + // Returns the maximum number of elements the vector can hold. + size_type max_size() const noexcept { + // One bit of the size storage is used to indicate whether the inlined + // vector is allocated. As a result, the maximum size of the container that + // we can express is half of the max for `size_type`. + return (std::numeric_limits<size_type>::max)() / 2; + } + + // `InlinedVector::capacity()` + // + // Returns the number of elements that can be stored in the inlined vector + // without requiring a reallocation of underlying memory. + // + // NOTE: For most inlined vectors, `capacity()` should equal the template + // parameter `N`. For inlined vectors which exceed this capacity, they + // will no longer be inlined and `capacity()` will equal its capacity on the + // allocated heap. + size_type capacity() const noexcept { + return allocated() ? allocation().capacity() : static_cast<size_type>(N); + } + + // `InlinedVector::data()` + // + // Returns a `pointer` to elements of the inlined vector. This pointer can be + // used to access and modify the contained elements. + // Only results within the range [`0`, `size()`) are defined. + pointer data() noexcept { + return allocated() ? allocated_space() : inlined_space(); + } + + // Overload of `InlinedVector::data()` to return a `const_pointer` to elements + // of the inlined vector. This pointer can be used to access (but not modify) + // the contained elements. + const_pointer data() const noexcept { + return allocated() ? allocated_space() : inlined_space(); + } + + // `InlinedVector::operator[]()` + // + // Returns a `reference` to the `i`th element of the inlined vector using the + // array operator. + reference operator[](size_type i) { + assert(i < size()); + return data()[i]; + } + + // Overload of `InlinedVector::operator[]()` to return a `const_reference` to + // the `i`th element of the inlined vector. + const_reference operator[](size_type i) const { + assert(i < size()); + return data()[i]; + } + + // `InlinedVector::at()` + // + // Returns a `reference` to the `i`th element of the inlined vector. + reference at(size_type i) { + if (ABSL_PREDICT_FALSE(i >= size())) { + base_internal::ThrowStdOutOfRange( + "`InlinedVector::at(size_type)` failed bounds check"); } + return data()[i]; + } + + // Overload of `InlinedVector::at()` to return a `const_reference` to the + // `i`th element of the inlined vector. + const_reference at(size_type i) const { + if (ABSL_PREDICT_FALSE(i >= size())) { + base_internal::ThrowStdOutOfRange( + "`InlinedVector::at(size_type) const` failed bounds check"); + } + return data()[i]; + } + + // `InlinedVector::front()` + // + // Returns a `reference` to the first element of the inlined vector. + reference front() { + assert(!empty()); + return at(0); + } + + // Overload of `InlinedVector::front()` returns a `const_reference` to the + // first element of the inlined vector. + const_reference front() const { + assert(!empty()); + return at(0); + } + + // `InlinedVector::back()` + // + // Returns a `reference` to the last element of the inlined vector. + reference back() { + assert(!empty()); + return at(size() - 1); + } + + // Overload of `InlinedVector::back()` to return a `const_reference` to the + // last element of the inlined vector. + const_reference back() const { + assert(!empty()); + return at(size() - 1); + } + + // `InlinedVector::begin()` + // + // Returns an `iterator` to the beginning of the inlined vector. + iterator begin() noexcept { return data(); } + + // Overload of `InlinedVector::begin()` to return a `const_iterator` to + // the beginning of the inlined vector. + const_iterator begin() const noexcept { return data(); } + + // `InlinedVector::end()` + // + // Returns an `iterator` to the end of the inlined vector. + iterator end() noexcept { return data() + size(); } + + // Overload of `InlinedVector::end()` to return a `const_iterator` to the + // end of the inlined vector. + const_iterator end() const noexcept { return data() + size(); } + + // `InlinedVector::cbegin()` + // + // Returns a `const_iterator` to the beginning of the inlined vector. + const_iterator cbegin() const noexcept { return begin(); } + + // `InlinedVector::cend()` + // + // Returns a `const_iterator` to the end of the inlined vector. + const_iterator cend() const noexcept { return end(); } + + // `InlinedVector::rbegin()` + // + // Returns a `reverse_iterator` from the end of the inlined vector. + reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + + // Overload of `InlinedVector::rbegin()` to return a + // `const_reverse_iterator` from the end of the inlined vector. + const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator(end()); + } + + // `InlinedVector::rend()` + // + // Returns a `reverse_iterator` from the beginning of the inlined vector. + reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + + // Overload of `InlinedVector::rend()` to return a `const_reverse_iterator` + // from the beginning of the inlined vector. + const_reverse_iterator rend() const noexcept { + return const_reverse_iterator(begin()); + } + + // `InlinedVector::crbegin()` + // + // Returns a `const_reverse_iterator` from the end of the inlined vector. + const_reverse_iterator crbegin() const noexcept { return rbegin(); } + + // `InlinedVector::crend()` + // + // Returns a `const_reverse_iterator` from the beginning of the inlined + // vector. + const_reverse_iterator crend() const noexcept { return rend(); } + + // `InlinedVector::get_allocator()` + // + // Returns a copy of the allocator of the inlined vector. + allocator_type get_allocator() const { return allocator(); } + + // --------------------------------------------------------------------------- + // InlinedVector Member Mutators + // --------------------------------------------------------------------------- + + // `InlinedVector::operator=()` + // + // Replaces the contents of the inlined vector with copies of the elements in + // the provided `std::initializer_list`. + InlinedVector& operator=(std::initializer_list<value_type> list) { + AssignForwardRange(list.begin(), list.end()); + return *this; + } + + // Overload of `InlinedVector::operator=()` to replace the contents of the + // inlined vector with the contents of `other`. + InlinedVector& operator=(const InlinedVector& other) { + if (ABSL_PREDICT_FALSE(this == &other)) return *this; + // Optimized to avoid reallocation. // Prefer reassignment to copy construction for elements. - if (size() < v.size()) { // grow - reserve(v.size()); - std::copy(v.begin(), v.begin() + size(), begin()); - std::copy(v.begin() + size(), v.end(), std::back_inserter(*this)); + if (size() < other.size()) { // grow + reserve(other.size()); + std::copy(other.begin(), other.begin() + size(), begin()); + std::copy(other.begin() + size(), other.end(), std::back_inserter(*this)); } else { // maybe shrink - erase(begin() + v.size(), end()); - std::copy(v.begin(), v.end(), begin()); + erase(begin() + other.size(), end()); + std::copy(other.begin(), other.end(), begin()); } return *this; } - InlinedVector& operator=(InlinedVector&& v) { - if (this == &v) { - return *this; - } - if (v.allocated()) { + // Overload of `InlinedVector::operator=()` to replace the contents of the + // inlined vector with the contents of `other`. + // + // NOTE: As a result of calling this overload, `other` may be empty or it's + // contents may be left in a moved-from state. + InlinedVector& operator=(InlinedVector&& other) { + if (ABSL_PREDICT_FALSE(this == &other)) return *this; + + if (other.allocated()) { clear(); - tag().set_allocated_size(v.size()); - init_allocation(v.allocation()); - v.tag() = Tag(); + tag().set_allocated_size(other.size()); + init_allocation(other.allocation()); + other.tag() = Tag(); } else { if (allocated()) clear(); // Both are inlined now. - if (size() < v.size()) { - auto mid = std::make_move_iterator(v.begin() + size()); - std::copy(std::make_move_iterator(v.begin()), mid, begin()); - UninitializedCopy(mid, std::make_move_iterator(v.end()), end()); + if (size() < other.size()) { + auto mid = std::make_move_iterator(other.begin() + size()); + std::copy(std::make_move_iterator(other.begin()), mid, begin()); + UninitializedCopy(mid, std::make_move_iterator(other.end()), end()); } else { - auto new_end = std::copy(std::make_move_iterator(v.begin()), - std::make_move_iterator(v.end()), begin()); + auto new_end = std::copy(std::make_move_iterator(other.begin()), + std::make_move_iterator(other.end()), begin()); Destroy(new_end, end()); } - tag().set_inline_size(v.size()); + tag().set_inline_size(other.size()); } return *this; } - InlinedVector& operator=(std::initializer_list<value_type> init) { - AssignRange(init.begin(), init.end()); - return *this; - } - - // InlinedVector::assign() + // `InlinedVector::assign()` // - // Replaces the contents of the inlined vector with copies of those in the - // iterator range [first, last). - template <typename InputIterator> - void assign( - InputIterator first, InputIterator last, - typename std::enable_if<!std::is_integral<InputIterator>::value>::type* = - nullptr) { - AssignRange(first, last); - } - - // Overload of `InlinedVector::assign()` to take values from elements of an - // initializer list - void assign(std::initializer_list<value_type> init) { - AssignRange(init.begin(), init.end()); - } - - // Overload of `InlinedVector::assign()` to replace the first `n` elements of - // the inlined vector with `elem` values. - void assign(size_type n, const value_type& elem) { + // Replaces the contents of the inlined vector with `n` copies of `v`. + void assign(size_type n, const_reference v) { if (n <= size()) { // Possibly shrink - std::fill_n(begin(), n, elem); + std::fill_n(begin(), n, v); erase(begin() + n, end()); return; } // Grow reserve(n); - std::fill_n(begin(), size(), elem); + std::fill_n(begin(), size(), v); if (allocated()) { - UninitializedFill(allocated_space() + size(), allocated_space() + n, - elem); + UninitializedFill(allocated_space() + size(), allocated_space() + n, v); tag().set_allocated_size(n); } else { - UninitializedFill(inlined_space() + size(), inlined_space() + n, elem); + UninitializedFill(inlined_space() + size(), inlined_space() + n, v); tag().set_inline_size(n); } } - // InlinedVector::size() - // - // Returns the number of elements in the inlined vector. - size_type size() const noexcept { return tag().size(); } - - // InlinedVector::empty() - // - // Checks if the inlined vector has no elements. - bool empty() const noexcept { return (size() == 0); } - - // InlinedVector::capacity() - // - // Returns the number of elements that can be stored in an inlined vector - // without requiring a reallocation of underlying memory. Note that for - // most inlined vectors, `capacity()` should equal its initial size `N`; for - // inlined vectors which exceed this capacity, they will no longer be inlined, - // and `capacity()` will equal its capacity on the allocated heap. - size_type capacity() const noexcept { - return allocated() ? allocation().capacity() : N; + // Overload of `InlinedVector::assign()` to replace the contents of the + // inlined vector with copies of the values in the provided + // `std::initializer_list`. + void assign(std::initializer_list<value_type> list) { + AssignForwardRange(list.begin(), list.end()); } - // InlinedVector::max_size() - // - // Returns the maximum number of elements the vector can hold. - size_type max_size() const noexcept { - // One bit of the size storage is used to indicate whether the inlined - // vector is allocated; as a result, the maximum size of the container that - // we can express is half of the max for our size type. - return std::numeric_limits<size_type>::max() / 2; + // Overload of `InlinedVector::assign()` to replace the contents of the + // inlined vector with the forward iterator range [`first`, `last`). + template <typename ForwardIterator, + EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr> + void assign(ForwardIterator first, ForwardIterator last) { + AssignForwardRange(first, last); } - // InlinedVector::data() - // - // Returns a const T* pointer to elements of the inlined vector. This pointer - // can be used to access (but not modify) the contained elements. - // Only results within the range `[0,size())` are defined. - const_pointer data() const noexcept { - return allocated() ? allocated_space() : inlined_space(); + // Overload of `InlinedVector::assign()` to replace the contents of the + // inlined vector with the input iterator range [`first`, `last`). + template <typename InputIterator, + DisableIfAtLeastForwardIterator<InputIterator>* = nullptr> + void assign(InputIterator first, InputIterator last) { + size_type assign_index = 0; + for (; (assign_index < size()) && (first != last); + static_cast<void>(++assign_index), static_cast<void>(++first)) { + *(data() + assign_index) = *first; + } + erase(data() + assign_index, data() + size()); + std::copy(first, last, std::back_inserter(*this)); } - // Overload of InlinedVector::data() to return a T* pointer to elements of the - // inlined vector. This pointer can be used to access and modify the contained - // elements. - pointer data() noexcept { - return allocated() ? allocated_space() : inlined_space(); - } - - // InlinedVector::clear() + // `InlinedVector::resize()` // - // Removes all elements from the inlined vector. - void clear() noexcept { + // Resizes the inlined vector to contain `n` elements. If `n` is smaller than + // the inlined vector's current size, extra elements are destroyed. If `n` is + // larger than the initial size, new elements are value-initialized. + void resize(size_type n) { size_type s = size(); + if (n < s) { + erase(begin() + n, end()); + return; + } + reserve(n); + assert(capacity() >= n); + + // Fill new space with elements constructed in-place. if (allocated()) { - Destroy(allocated_space(), allocated_space() + s); - allocation().Dealloc(allocator()); - } else if (s != 0) { // do nothing for empty vectors - Destroy(inlined_space(), inlined_space() + s); + UninitializedFill(allocated_space() + s, allocated_space() + n); + tag().set_allocated_size(n); + } else { + UninitializedFill(inlined_space() + s, inlined_space() + n); + tag().set_inline_size(n); } - tag() = Tag(); } - // InlinedVector::at() - // - // Returns the ith element of an inlined vector. - const value_type& at(size_type i) const { - if (ABSL_PREDICT_FALSE(i >= size())) { - base_internal::ThrowStdOutOfRange( - "InlinedVector::at failed bounds check"); - } - return data()[i]; - } - - // InlinedVector::operator[] - // - // Returns the ith element of an inlined vector using the array operator. - const value_type& operator[](size_type i) const { - assert(i < size()); - return data()[i]; - } - - // Overload of InlinedVector::at() to return the ith element of an inlined - // vector. - value_type& at(size_type i) { - if (i >= size()) { - base_internal::ThrowStdOutOfRange( - "InlinedVector::at failed bounds check"); - } - return data()[i]; - } - - // Overload of InlinedVector::operator[] to return the ith element of an - // inlined vector. - value_type& operator[](size_type i) { - assert(i < size()); - return data()[i]; - } - - // InlinedVector::back() - // - // Returns a reference to the last element of an inlined vector. - value_type& back() { - assert(!empty()); - return at(size() - 1); - } - - // Overload of InlinedVector::back() returns a reference to the last element - // of an inlined vector of const values. - const value_type& back() const { - assert(!empty()); - return at(size() - 1); - } - - // InlinedVector::front() - // - // Returns a reference to the first element of an inlined vector. - value_type& front() { - assert(!empty()); - return at(0); - } - - // Overload of InlinedVector::front() returns a reference to the first element - // of an inlined vector of const values. - const value_type& front() const { - assert(!empty()); - return at(0); - } - - // InlinedVector::emplace_back() - // - // Constructs and appends an object to the inlined vector. - // - // Returns a reference to the inserted element. - template <typename... Args> - value_type& emplace_back(Args&&... args) { + // Overload of `InlinedVector::resize()` to resize the inlined vector to + // contain `n` elements where, if `n` is larger than `size()`, the new values + // will be copy-constructed from `v`. + void resize(size_type n, const_reference v) { size_type s = size(); - assert(s <= capacity()); + if (n < s) { + erase(begin() + n, end()); + return; + } + reserve(n); + assert(capacity() >= n); + + // Fill new space with copies of `v`. + if (allocated()) { + UninitializedFill(allocated_space() + s, allocated_space() + n, v); + tag().set_allocated_size(n); + } else { + UninitializedFill(inlined_space() + s, inlined_space() + n, v); + tag().set_inline_size(n); + } + } + + // `InlinedVector::insert()` + // + // Copies `v` into `pos`, returning an `iterator` pointing to the newly + // inserted element. + iterator insert(const_iterator pos, const_reference v) { + return emplace(pos, v); + } + + // Overload of `InlinedVector::insert()` for moving `v` into `pos`, returning + // an iterator pointing to the newly inserted element. + iterator insert(const_iterator pos, rvalue_reference v) { + return emplace(pos, std::move(v)); + } + + // Overload of `InlinedVector::insert()` for inserting `n` contiguous copies + // of `v` starting at `pos`. Returns an `iterator` pointing to the first of + // the newly inserted elements. + iterator insert(const_iterator pos, size_type n, const_reference v) { + return InsertWithCount(pos, n, v); + } + + // Overload of `InlinedVector::insert()` for copying the contents of the + // `std::initializer_list` into the vector starting at `pos`. Returns an + // `iterator` pointing to the first of the newly inserted elements. + iterator insert(const_iterator pos, std::initializer_list<value_type> list) { + return insert(pos, list.begin(), list.end()); + } + + // Overload of `InlinedVector::insert()` for inserting elements constructed + // from the forward iterator range [`first`, `last`). Returns an `iterator` + // pointing to the first of the newly inserted elements. + // + // NOTE: The `enable_if` is intended to disambiguate the two three-argument + // overloads of `insert()`. + template <typename ForwardIterator, + EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr> + iterator insert(const_iterator pos, ForwardIterator first, + ForwardIterator last) { + return InsertWithForwardRange(pos, first, last); + } + + // Overload of `InlinedVector::insert()` for inserting elements constructed + // from the input iterator range [`first`, `last`). Returns an `iterator` + // pointing to the first of the newly inserted elements. + template <typename InputIterator, + DisableIfAtLeastForwardIterator<InputIterator>* = nullptr> + iterator insert(const_iterator pos, InputIterator first, InputIterator last) { + size_type initial_insert_index = std::distance(cbegin(), pos); + for (size_type insert_index = initial_insert_index; first != last; + static_cast<void>(++insert_index), static_cast<void>(++first)) { + insert(data() + insert_index, *first); + } + return iterator(data() + initial_insert_index); + } + + // `InlinedVector::emplace()` + // + // Constructs and inserts an object in the inlined vector at the given `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()); + if (ABSL_PREDICT_FALSE(pos == end())) { + emplace_back(std::forward<Args>(args)...); + return end() - 1; + } + + T new_t = T(std::forward<Args>(args)...); + + auto range = ShiftRight(pos, 1); + if (range.first == range.second) { + // constructing into uninitialized memory + Construct(range.first, std::move(new_t)); + } else { + // assigning into moved-from object + *range.first = T(std::move(new_t)); + } + + return range.first; + } + + // `InlinedVector::emplace_back()` + // + // Constructs and appends a new element to the end of the inlined vector, + // returning a `reference` to the emplaced element. + template <typename... Args> + reference emplace_back(Args&&... args) { + size_type s = size(); if (ABSL_PREDICT_FALSE(s == capacity())) { return GrowAndEmplaceBack(std::forward<Args>(args)...); } - assert(s < capacity()); - - value_type* space; + pointer space; if (allocated()) { tag().set_allocated_size(s + 1); space = allocated_space(); @@ -388,19 +698,22 @@ return Construct(space + s, std::forward<Args>(args)...); } - // InlinedVector::push_back() + // `InlinedVector::push_back()` // - // Appends a const element to the inlined vector. - void push_back(const value_type& t) { emplace_back(t); } + // Appends a copy of `v` to the end of the inlined vector. + void push_back(const_reference v) { static_cast<void>(emplace_back(v)); } - // Overload of InlinedVector::push_back() to append a move-only element to the - // inlined vector. - void push_back(value_type&& t) { emplace_back(std::move(t)); } + // Overload of `InlinedVector::push_back()` for moving `v` into a newly + // appended element. + void push_back(rvalue_reference v) { + static_cast<void>(emplace_back(std::move(v))); + } - // InlinedVector::pop_back() + // `InlinedVector::pop_back()` // - // Removes the last element (which is destroyed) in the inlined vector. - void pop_back() { + // Destroys the element at the end of the inlined vector and shrinks the size + // by `1` (unless the inlined vector is empty, in which case this is a no-op). + void pop_back() noexcept { assert(!empty()); size_type s = size(); if (allocated()) { @@ -412,161 +725,75 @@ } } - // InlinedVector::resize() + // `InlinedVector::erase()` // - // Resizes the inlined vector to contain `n` elements. If `n` is smaller than - // the inlined vector's current size, extra elements are destroyed. If `n` is - // larger than the initial size, new elements are value-initialized. - void resize(size_type n); - - // Overload of InlinedVector::resize() to resize the inlined vector to contain - // `n` elements. If `n` is larger than the current size, enough copies of - // `elem` are appended to increase its size to `n`. - void resize(size_type n, const value_type& elem); - - // InlinedVector::begin() + // Erases the element at `pos` of the inlined vector, returning an `iterator` + // pointing to the first element following the erased element. // - // Returns an iterator to the beginning of the inlined vector. - iterator begin() noexcept { return data(); } + // NOTE: May return the end iterator, which is not dereferencable. + iterator erase(const_iterator pos) { + assert(pos >= begin()); + assert(pos < end()); - // Overload of InlinedVector::begin() for returning a const iterator to the - // beginning of the inlined vector. - const_iterator begin() const noexcept { return data(); } - - // InlinedVector::cbegin() - // - // Returns a const iterator to the beginning of the inlined vector. - const_iterator cbegin() const noexcept { return begin(); } - - // InlinedVector::end() - // - // Returns an iterator to the end of the inlined vector. - iterator end() noexcept { return data() + size(); } - - // Overload of InlinedVector::end() for returning a const iterator to the end - // of the inlined vector. - const_iterator end() const noexcept { return data() + size(); } - - // InlinedVector::cend() - // - // Returns a const iterator to the end of the inlined vector. - const_iterator cend() const noexcept { return end(); } - - // InlinedVector::rbegin() - // - // Returns a reverse iterator from the end of the inlined vector. - reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } - - // Overload of InlinedVector::rbegin() for returning a const reverse iterator - // from the end of the inlined vector. - const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end()); - } - - // InlinedVector::crbegin() - // - // Returns a const reverse iterator from the end of the inlined vector. - const_reverse_iterator crbegin() const noexcept { return rbegin(); } - - // InlinedVector::rend() - // - // Returns a reverse iterator from the beginning of the inlined vector. - reverse_iterator rend() noexcept { return reverse_iterator(begin()); } - - // Overload of InlinedVector::rend() for returning a const reverse iterator - // from the beginning of the inlined vector. - const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin()); - } - - // InlinedVector::crend() - // - // Returns a reverse iterator from the beginning of the inlined vector. - const_reverse_iterator crend() const noexcept { return rend(); } - - // InlinedVector::emplace() - // - // Constructs and inserts an object to the inlined vector at the given - // `position`, returning an iterator pointing to the newly emplaced element. - template <typename... Args> - iterator emplace(const_iterator position, Args&&... args); - - // InlinedVector::insert() - // - // Inserts an element of the specified value at `position`, returning an - // iterator pointing to the newly inserted element. - iterator insert(const_iterator position, const value_type& v) { - return emplace(position, v); - } - - // Overload of InlinedVector::insert() for inserting an element of the - // specified rvalue, returning an iterator pointing to the newly inserted - // element. - iterator insert(const_iterator position, value_type&& v) { - return emplace(position, std::move(v)); - } - - // Overload of InlinedVector::insert() for inserting `n` elements of the - // specified value at `position`, returning an iterator pointing to the first - // of the newly inserted elements. - iterator insert(const_iterator position, size_type n, const value_type& v) { - return InsertWithCount(position, n, v); - } - - // Overload of `InlinedVector::insert()` to disambiguate the two - // three-argument overloads of `insert()`, returning an iterator pointing to - // the first of the newly inserted elements. - template <typename InputIterator, - typename = typename std::enable_if<std::is_convertible< - typename std::iterator_traits<InputIterator>::iterator_category, - std::input_iterator_tag>::value>::type> - iterator insert(const_iterator position, InputIterator first, - InputIterator last) { - using IterType = - typename std::iterator_traits<InputIterator>::iterator_category; - return InsertWithRange(position, first, last, IterType()); - } - - // Overload of InlinedVector::insert() for inserting a list of elements at - // `position`, returning an iterator pointing to the first of the newly - // inserted elements. - iterator insert(const_iterator position, - std::initializer_list<value_type> init) { - return insert(position, init.begin(), init.end()); - } - - // InlinedVector::erase() - // - // Erases the element at `position` of the inlined vector, returning an - // iterator pointing to the following element or the container's end if the - // last element was erased. - iterator erase(const_iterator position) { - assert(position >= begin()); - assert(position < end()); - - iterator pos = const_cast<iterator>(position); - std::move(pos + 1, end(), pos); + iterator position = const_cast<iterator>(pos); + std::move(position + 1, end(), position); pop_back(); - return pos; + return position; } - // Overload of InlinedVector::erase() for erasing all elements in the - // iterator range [first, last) in the inlined vector, returning an iterator - // pointing to the first element following the range erased, or the - // container's end if range included the container's last element. - iterator erase(const_iterator first, const_iterator last); + // Overload of `InlinedVector::erase()` for erasing all elements in the + // range [`from`, `to`) in the inlined vector. Returns an `iterator` pointing + // to the first element following the range erased or the end iterator if `to` + // was the end iterator. + iterator erase(const_iterator from, const_iterator to) { + assert(begin() <= from); + assert(from <= to); + assert(to <= end()); - // InlinedVector::reserve() + iterator range_start = const_cast<iterator>(from); + iterator range_end = const_cast<iterator>(to); + + size_type s = size(); + ptrdiff_t erase_gap = std::distance(range_start, range_end); + if (erase_gap > 0) { + pointer space; + if (allocated()) { + space = allocated_space(); + tag().set_allocated_size(s - erase_gap); + } else { + space = inlined_space(); + tag().set_inline_size(s - erase_gap); + } + std::move(range_end, space + s, range_start); + Destroy(space + s - erase_gap, space + s); + } + return range_start; + } + + // `InlinedVector::clear()` + // + // Destroys all elements in the inlined vector, sets the size of `0` and + // deallocates the heap allocation if the inlined vector was allocated. + void clear() noexcept { + size_type s = size(); + if (allocated()) { + Destroy(allocated_space(), allocated_space() + s); + allocation().Dealloc(allocator()); + } else if (s != 0) { // do nothing for empty vectors + Destroy(inlined_space(), inlined_space() + s); + } + tag() = Tag(); + } + + // `InlinedVector::reserve()` // // Enlarges the underlying representation of the inlined vector so it can hold // at least `n` elements. This method does not change `size()` or the actual // contents of the vector. // - // Note that if `n` does not exceed the inlined vector's initial size `N`, - // `reserve()` will have no effect; if it does exceed its initial size, - // `reserve()` will trigger an initial allocation and move the inlined vector - // onto the heap. If the vector already exists on the heap and the requested - // size exceeds it, a reallocation will be performed. + // NOTE: If `n` does not exceed `capacity()`, `reserve()` will have no + // effects. Otherwise, `reserve()` will reallocate, performing an n-time + // element-wise move of everything contained. void reserve(size_type n) { if (n > capacity()) { // Make room for new elements @@ -574,26 +801,25 @@ } } - // InlinedVector::shrink_to_fit() + // `InlinedVector::shrink_to_fit()` // - // Reduces memory usage by freeing unused memory. - // After this call `capacity()` will be equal to `max(N, size())`. + // Reduces memory usage by freeing unused memory. After this call, calls to + // `capacity()` will be equal to `max(N, size())`. // // If `size() <= N` and the elements are currently stored on the heap, they - // will be moved to the inlined storage and the heap memory deallocated. - // If `size() > N` and `size() < capacity()` the elements will be moved to - // a reallocated storage on heap. + // will be moved to the inlined storage and the heap memory will be + // deallocated. + // + // If `size() > N` and `size() < capacity()` the elements will be moved to a + // smaller heap allocation. void shrink_to_fit() { const auto s = size(); - if (!allocated() || s == capacity()) { - // There's nothing to deallocate. - return; - } + if (ABSL_PREDICT_FALSE(!allocated() || s == capacity())) return; if (s <= N) { // Move the elements to the inlined storage. - // We have to do this using a temporary, because inlined_storage and - // allocation_storage are in a union field. + // We have to do this using a temporary, because `inlined_storage` and + // `allocation_storage` are in a union field. auto temp = std::move(*this); assign(std::make_move_iterator(temp.begin()), std::make_move_iterator(temp.end())); @@ -601,8 +827,8 @@ } // Reallocate storage and move elements. - // We can't simply use the same approach as above, because assign() would - // call into reserve() internally and reserve larger capacity than we need. + // We can't simply use the same approach as above, because `assign()` would + // call into `reserve()` internally and reserve larger capacity than we need Allocation new_allocation(allocator(), s); UninitializedCopy(std::make_move_iterator(allocated_space()), std::make_move_iterator(allocated_space() + s), @@ -610,129 +836,62 @@ ResetAllocation(new_allocation, s); } - // InlinedVector::swap() + // `InlinedVector::swap()` // // Swaps the contents of this inlined vector with the contents of `other`. - void swap(InlinedVector& other); + void swap(InlinedVector& other) { + if (ABSL_PREDICT_FALSE(this == &other)) return; - // InlinedVector::get_allocator() - // - // Returns the allocator of this inlined vector. - allocator_type get_allocator() const { return allocator(); } - - template <typename H> - friend H AbslHashValue(H h, const InlinedVector& v) { - return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()), - v.size()); + SwapImpl(other); } private: - static_assert(N > 0, "inlined vector with nonpositive size"); + template <typename H, typename TheT, size_t TheN, typename TheA> + friend auto AbslHashValue(H h, const InlinedVector<TheT, TheN, TheA>& v) -> H; - // It holds whether the vector is allocated or not in the lowest bit. - // The size is held in the high bits: - // size_ = (size << 1) | is_allocated; - // - // Maintainer's Note: size_type is user defined. The contract is limited to - // arithmetic operators to avoid depending on compliant overloaded bitwise - // operators. - class Tag { - public: - Tag() : size_(0) {} - size_type size() const { return size_ / 2; } - void add_size(size_type n) { size_ += n * 2; } - void set_inline_size(size_type n) { size_ = n * 2; } - void set_allocated_size(size_type n) { size_ = (n * 2) + 1; } - bool allocated() const { return size_ % 2; } + const Tag& tag() const { return storage_.allocator_and_tag_.tag(); } - private: - size_type size_; - }; - - // Derives from allocator_type to use the empty base class optimization. - // If the allocator_type is stateless, we can 'store' - // our instance of it for free. - class AllocatorAndTag : private allocator_type { - public: - explicit AllocatorAndTag(const allocator_type& a) : allocator_type(a) {} - Tag& tag() { return tag_; } - const Tag& tag() const { return tag_; } - allocator_type& allocator() { return *this; } - const allocator_type& allocator() const { return *this; } - - private: - Tag tag_; - }; - - class Allocation { - public: - Allocation(allocator_type& a, // NOLINT(runtime/references) - size_type capacity) - : capacity_(capacity), - buffer_(AllocatorTraits::allocate(a, capacity_)) {} - - void Dealloc(allocator_type& a) { // NOLINT(runtime/references) - AllocatorTraits::deallocate(a, buffer(), capacity()); - } - - size_type capacity() const { return capacity_; } - const value_type* buffer() const { return buffer_; } - value_type* buffer() { return buffer_; } - - private: - size_type capacity_; - value_type* buffer_; - }; - - const Tag& tag() const { return allocator_and_tag_.tag(); } - Tag& tag() { return allocator_and_tag_.tag(); } + Tag& tag() { return storage_.allocator_and_tag_.tag(); } Allocation& allocation() { - return reinterpret_cast<Allocation&>(rep_.allocation_storage.allocation); + return reinterpret_cast<Allocation&>( + storage_.rep_.allocation_storage.allocation); } + const Allocation& allocation() const { return reinterpret_cast<const Allocation&>( - rep_.allocation_storage.allocation); + storage_.rep_.allocation_storage.allocation); } + void init_allocation(const Allocation& allocation) { - new (&rep_.allocation_storage.allocation) Allocation(allocation); + new (&storage_.rep_.allocation_storage.allocation) Allocation(allocation); } // TODO(absl-team): investigate whether the reinterpret_cast is appropriate. - value_type* inlined_space() { - return reinterpret_cast<value_type*>( - std::addressof(rep_.inlined_storage.inlined[0])); - } - const value_type* inlined_space() const { - return reinterpret_cast<const value_type*>( - std::addressof(rep_.inlined_storage.inlined[0])); + pointer inlined_space() { + return reinterpret_cast<pointer>( + std::addressof(storage_.rep_.inlined_storage.inlined[0])); } - value_type* allocated_space() { return allocation().buffer(); } - const value_type* allocated_space() const { return allocation().buffer(); } + const_pointer inlined_space() const { + return reinterpret_cast<const_pointer>( + std::addressof(storage_.rep_.inlined_storage.inlined[0])); + } + + pointer allocated_space() { return allocation().buffer(); } + + const_pointer allocated_space() const { return allocation().buffer(); } const allocator_type& allocator() const { - return allocator_and_tag_.allocator(); + return storage_.allocator_and_tag_.allocator(); } - allocator_type& allocator() { return allocator_and_tag_.allocator(); } + + allocator_type& allocator() { + return storage_.allocator_and_tag_.allocator(); + } bool allocated() const { return tag().allocated(); } - // Enlarge the underlying representation so we can store size_ + delta elems. - // The size is not changed, and any newly added memory is not initialized. - void EnlargeBy(size_type delta); - - // Shift all elements from position to end() n places to the right. - // If the vector needs to be enlarged, memory will be allocated. - // Returns iterators pointing to the start of the previously-initialized - // portion and the start of the uninitialized portion of the created gap. - // The number of initialized spots is pair.second - pair.first; - // the number of raw spots is n - (pair.second - pair.first). - // - // Updates the size of the InlinedVector internally. - std::pair<iterator, iterator> ShiftRight(const_iterator position, - size_type n); - void ResetAllocation(Allocation new_allocation, size_type new_size) { if (allocated()) { Destroy(allocated_space(), allocated_space() + size()); @@ -747,13 +906,137 @@ } template <typename... Args> - value_type& GrowAndEmplaceBack(Args&&... args) { + reference Construct(pointer p, Args&&... args) { + std::allocator_traits<allocator_type>::construct( + allocator(), p, std::forward<Args>(args)...); + return *p; + } + + template <typename Iterator> + void UninitializedCopy(Iterator src, Iterator src_last, pointer dst) { + for (; src != src_last; ++dst, ++src) Construct(dst, *src); + } + + template <typename... Args> + void UninitializedFill(pointer dst, pointer dst_last, const Args&... args) { + for (; dst != dst_last; ++dst) Construct(dst, args...); + } + + // Destroy [`from`, `to`) in place. + void Destroy(pointer from, pointer to) { + for (pointer cur = from; cur != to; ++cur) { + std::allocator_traits<allocator_type>::destroy(allocator(), cur); + } +#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. + if (from != to) { + auto len = sizeof(value_type) * std::distance(from, to); + std::memset(reinterpret_cast<void*>(from), 0xab, len); + } +#endif // !defined(NDEBUG) + } + + // Enlarge the underlying representation so we can store `size_ + delta` elems + // in allocated space. The size is not changed, and any newly added memory is + // not initialized. + void EnlargeBy(size_type delta) { + const size_type s = size(); + assert(s <= capacity()); + + size_type target = (std::max)(N, s + delta); + + // Compute new capacity by repeatedly doubling current capacity + // TODO(psrc): Check and avoid overflow? + size_type new_capacity = capacity(); + while (new_capacity < target) { + new_capacity <<= 1; + } + + Allocation new_allocation(allocator(), new_capacity); + + UninitializedCopy(std::make_move_iterator(data()), + std::make_move_iterator(data() + s), + new_allocation.buffer()); + + ResetAllocation(new_allocation, s); + } + + // Shift all elements from `position` to `end()` by `n` places to the right. + // If the vector needs to be enlarged, memory will be allocated. + // Returns `iterator`s pointing to the start of the previously-initialized + // portion and the start of the uninitialized portion of the created gap. + // The number of initialized spots is `pair.second - pair.first`. The number + // of raw spots is `n - (pair.second - pair.first)`. + // + // Updates the size of the InlinedVector internally. + std::pair<iterator, iterator> ShiftRight(const_iterator position, + size_type n) { + iterator start_used = const_cast<iterator>(position); + iterator start_raw = const_cast<iterator>(position); + size_type s = size(); + size_type required_size = s + n; + + if (required_size > capacity()) { + // Compute new capacity by repeatedly doubling current capacity + size_type new_capacity = capacity(); + while (new_capacity < required_size) { + new_capacity <<= 1; + } + // Move everyone into the new allocation, leaving a gap of `n` for the + // requested shift. + Allocation new_allocation(allocator(), new_capacity); + size_type index = position - begin(); + UninitializedCopy(std::make_move_iterator(data()), + std::make_move_iterator(data() + index), + new_allocation.buffer()); + UninitializedCopy(std::make_move_iterator(data() + index), + std::make_move_iterator(data() + s), + new_allocation.buffer() + index + n); + ResetAllocation(new_allocation, s); + + // New allocation means our iterator is invalid, so we'll recalculate. + // Since the entire gap is in new space, there's no used space to reuse. + start_raw = begin() + index; + start_used = start_raw; + } else { + // If we had enough space, it's a two-part move. Elements going into + // previously-unoccupied space need an `UninitializedCopy()`. Elements + // going into a previously-occupied space are just a `std::move()`. + iterator pos = const_cast<iterator>(position); + iterator raw_space = end(); + size_type slots_in_used_space = raw_space - pos; + size_type new_elements_in_used_space = (std::min)(n, slots_in_used_space); + size_type new_elements_in_raw_space = n - new_elements_in_used_space; + size_type old_elements_in_used_space = + slots_in_used_space - new_elements_in_used_space; + + UninitializedCopy( + std::make_move_iterator(pos + old_elements_in_used_space), + std::make_move_iterator(raw_space), + raw_space + new_elements_in_raw_space); + std::move_backward(pos, pos + old_elements_in_used_space, raw_space); + + // If the gap is entirely in raw space, the used space starts where the + // raw space starts, leaving no elements in used space. If the gap is + // entirely in used space, the raw space starts at the end of the gap, + // leaving all elements accounted for within the used space. + start_used = pos; + start_raw = pos + new_elements_in_used_space; + } + tag().add_size(n); + return std::make_pair(start_used, start_raw); + } + + template <typename... Args> + reference GrowAndEmplaceBack(Args&&... args) { assert(size() == capacity()); const size_type s = size(); Allocation new_allocation(allocator(), 2 * capacity()); - value_type& new_element = + reference new_element = Construct(new_allocation.buffer() + s, std::forward<Args>(args)...); UninitializedCopy(std::make_move_iterator(data()), std::make_move_iterator(data() + s), @@ -764,628 +1047,268 @@ return new_element; } - void InitAssign(size_type n); - void InitAssign(size_type n, const value_type& t); - - template <typename... Args> - value_type& Construct(pointer p, Args&&... args) { - AllocatorTraits::construct(allocator(), p, std::forward<Args>(args)...); - return *p; + void InitAssign(size_type n) { + if (n > N) { + Allocation new_allocation(allocator(), n); + init_allocation(new_allocation); + UninitializedFill(allocated_space(), allocated_space() + n); + tag().set_allocated_size(n); + } else { + UninitializedFill(inlined_space(), inlined_space() + n); + tag().set_inline_size(n); + } } - template <typename Iter> - void UninitializedCopy(Iter src, Iter src_last, value_type* dst) { - for (; src != src_last; ++dst, ++src) Construct(dst, *src); + void InitAssign(size_type n, const_reference v) { + if (n > N) { + Allocation new_allocation(allocator(), n); + init_allocation(new_allocation); + UninitializedFill(allocated_space(), allocated_space() + n, v); + tag().set_allocated_size(n); + } else { + UninitializedFill(inlined_space(), inlined_space() + n, v); + tag().set_inline_size(n); + } } - template <typename... Args> - void UninitializedFill(value_type* dst, value_type* dst_last, - const Args&... args) { - for (; dst != dst_last; ++dst) Construct(dst, args...); + template <typename ForwardIt> + void AssignForwardRange(ForwardIt first, ForwardIt last) { + static_assert(IsAtLeastForwardIterator<ForwardIt>::value, ""); + + auto length = std::distance(first, last); + + // Prefer reassignment to copy construction for elements. + if (static_cast<size_type>(length) <= size()) { + erase(std::copy(first, last, begin()), end()); + return; + } + + reserve(length); + iterator out = begin(); + for (; out != end(); ++first, ++out) *out = *first; + if (allocated()) { + UninitializedCopy(first, last, out); + tag().set_allocated_size(length); + } else { + UninitializedCopy(first, last, out); + tag().set_inline_size(length); + } } - // Destroy [ptr, ptr_last) in place. - void Destroy(value_type* ptr, value_type* ptr_last); + template <typename ForwardIt> + void AppendForwardRange(ForwardIt first, ForwardIt last) { + static_assert(IsAtLeastForwardIterator<ForwardIt>::value, ""); - template <typename Iter> - void AppendRange(Iter first, Iter last, std::input_iterator_tag) { - std::copy(first, last, std::back_inserter(*this)); - } - - // Faster path for forward iterators. - template <typename Iter> - void AppendRange(Iter first, Iter last, std::forward_iterator_tag); - - template <typename Iter> - void AppendRange(Iter first, Iter last) { - using IterTag = typename std::iterator_traits<Iter>::iterator_category; - AppendRange(first, last, IterTag()); - } - - template <typename Iter> - void AssignRange(Iter first, Iter last, std::input_iterator_tag); - - // Faster path for forward iterators. - template <typename Iter> - void AssignRange(Iter first, Iter last, std::forward_iterator_tag); - - template <typename Iter> - void AssignRange(Iter first, Iter last) { - using IterTag = typename std::iterator_traits<Iter>::iterator_category; - AssignRange(first, last, IterTag()); + auto length = std::distance(first, last); + reserve(size() + length); + if (allocated()) { + UninitializedCopy(first, last, allocated_space() + size()); + tag().set_allocated_size(size() + length); + } else { + UninitializedCopy(first, last, inlined_space() + size()); + tag().set_inline_size(size() + length); + } } iterator InsertWithCount(const_iterator position, size_type n, - const value_type& v); + const_reference v) { + assert(position >= begin() && position <= end()); + if (ABSL_PREDICT_FALSE(n == 0)) return const_cast<iterator>(position); - template <typename InputIter> - iterator InsertWithRange(const_iterator position, InputIter first, - InputIter last, std::input_iterator_tag); - template <typename ForwardIter> - iterator InsertWithRange(const_iterator position, ForwardIter first, - ForwardIter last, std::forward_iterator_tag); + value_type copy = v; + std::pair<iterator, iterator> it_pair = ShiftRight(position, n); + std::fill(it_pair.first, it_pair.second, copy); + UninitializedFill(it_pair.second, it_pair.first + n, copy); - AllocatorAndTag allocator_and_tag_; + return it_pair.first; + } - // Either the inlined or allocated representation - union Rep { - // Use struct to perform indirection that solves a bizarre compilation - // error on Visual Studio (all known versions). - struct { - typename std::aligned_storage<sizeof(value_type), - alignof(value_type)>::type inlined[N]; - } inlined_storage; - struct { - typename std::aligned_storage<sizeof(Allocation), - alignof(Allocation)>::type allocation; - } allocation_storage; - } rep_; + template <typename ForwardIt> + iterator InsertWithForwardRange(const_iterator position, ForwardIt first, + ForwardIt last) { + static_assert(IsAtLeastForwardIterator<ForwardIt>::value, ""); + assert(position >= begin() && position <= end()); + + if (ABSL_PREDICT_FALSE(first == last)) + return const_cast<iterator>(position); + + auto n = std::distance(first, last); + std::pair<iterator, iterator> it_pair = ShiftRight(position, n); + size_type used_spots = it_pair.second - it_pair.first; + auto open_spot = std::next(first, used_spots); + std::copy(first, open_spot, it_pair.first); + UninitializedCopy(open_spot, last, it_pair.second); + return it_pair.first; + } + + void SwapImpl(InlinedVector& other) { + using std::swap; // Augment ADL with `std::swap`. + + if (allocated() && other.allocated()) { + // Both out of line, so just swap the tag, allocation, and allocator. + swap(tag(), other.tag()); + swap(allocation(), other.allocation()); + swap(allocator(), other.allocator()); + return; + } + if (!allocated() && !other.allocated()) { + // Both inlined: swap up to smaller size, then move remaining elements. + InlinedVector* a = this; + InlinedVector* b = &other; + if (size() < other.size()) { + swap(a, b); + } + + const size_type a_size = a->size(); + const size_type b_size = b->size(); + assert(a_size >= b_size); + // `a` is larger. Swap the elements up to the smaller array size. + std::swap_ranges(a->inlined_space(), a->inlined_space() + b_size, + b->inlined_space()); + + // Move the remaining elements: + // [`b_size`, `a_size`) from `a` -> [`b_size`, `a_size`) from `b` + b->UninitializedCopy(a->inlined_space() + b_size, + a->inlined_space() + a_size, + b->inlined_space() + b_size); + a->Destroy(a->inlined_space() + b_size, a->inlined_space() + a_size); + + swap(a->tag(), b->tag()); + swap(a->allocator(), b->allocator()); + assert(b->size() == a_size); + assert(a->size() == b_size); + return; + } + + // One is out of line, one is inline. + // We first move the elements from the inlined vector into the + // inlined space in the other vector. We then put the other vector's + // pointer/capacity into the originally inlined vector and swap + // the tags. + InlinedVector* a = this; + InlinedVector* b = &other; + if (a->allocated()) { + swap(a, b); + } + assert(!a->allocated()); + assert(b->allocated()); + const size_type a_size = a->size(); + const size_type b_size = b->size(); + // In an optimized build, `b_size` would be unused. + static_cast<void>(b_size); + + // Made Local copies of `size()`, don't need `tag()` accurate anymore + swap(a->tag(), b->tag()); + + // Copy `b_allocation` out before `b`'s union gets clobbered by + // `inline_space` + Allocation b_allocation = b->allocation(); + + b->UninitializedCopy(a->inlined_space(), a->inlined_space() + a_size, + b->inlined_space()); + a->Destroy(a->inlined_space(), a->inlined_space() + a_size); + + a->allocation() = b_allocation; + + if (a->allocator() != b->allocator()) { + swap(a->allocator(), b->allocator()); + } + + assert(b->size() == a_size); + assert(a->size() == b_size); + } + + Storage storage_; }; // ----------------------------------------------------------------------------- // InlinedVector Non-Member Functions // ----------------------------------------------------------------------------- -// swap() +// `swap()` // // Swaps the contents of two inlined vectors. This convenience function -// simply calls InlinedVector::swap(other_inlined_vector). +// simply calls `InlinedVector::swap()`. template <typename T, size_t N, typename A> -void swap(InlinedVector<T, N, A>& a, - InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) { +auto swap(InlinedVector<T, N, A>& a, + InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) -> void { a.swap(b); } -// operator==() +// `operator==()` // // Tests the equivalency of the contents of two inlined vectors. template <typename T, size_t N, typename A> -bool operator==(const InlinedVector<T, N, A>& a, - const InlinedVector<T, N, A>& b) { +auto operator==(const InlinedVector<T, N, A>& a, + const InlinedVector<T, N, A>& b) -> bool { return absl::equal(a.begin(), a.end(), b.begin(), b.end()); } -// operator!=() +// `operator!=()` // // Tests the inequality of the contents of two inlined vectors. template <typename T, size_t N, typename A> -bool operator!=(const InlinedVector<T, N, A>& a, - const InlinedVector<T, N, A>& b) { +auto operator!=(const InlinedVector<T, N, A>& a, + const InlinedVector<T, N, A>& b) -> bool { return !(a == b); } -// operator<() +// `operator<()` // // Tests whether the contents of one inlined vector are less than the contents // of another through a lexicographical comparison operation. template <typename T, size_t N, typename A> -bool operator<(const InlinedVector<T, N, A>& a, - const InlinedVector<T, N, A>& b) { +auto operator<(const InlinedVector<T, N, A>& a, const InlinedVector<T, N, A>& b) + -> bool { return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); } -// operator>() +// `operator>()` // // Tests whether the contents of one inlined vector are greater than the // contents of another through a lexicographical comparison operation. template <typename T, size_t N, typename A> -bool operator>(const InlinedVector<T, N, A>& a, - const InlinedVector<T, N, A>& b) { +auto operator>(const InlinedVector<T, N, A>& a, const InlinedVector<T, N, A>& b) + -> bool { return b < a; } -// operator<=() +// `operator<=()` // // Tests whether the contents of one inlined vector are less than or equal to // the contents of another through a lexicographical comparison operation. template <typename T, size_t N, typename A> -bool operator<=(const InlinedVector<T, N, A>& a, - const InlinedVector<T, N, A>& b) { +auto operator<=(const InlinedVector<T, N, A>& a, + const InlinedVector<T, N, A>& b) -> bool { return !(b < a); } -// operator>=() +// `operator>=()` // // Tests whether the contents of one inlined vector are greater than or equal to // the contents of another through a lexicographical comparison operation. template <typename T, size_t N, typename A> -bool operator>=(const InlinedVector<T, N, A>& a, - const InlinedVector<T, N, A>& b) { +auto operator>=(const InlinedVector<T, N, A>& a, + const InlinedVector<T, N, A>& b) -> bool { return !(a < b); } +// AbslHashValue() +// +// Provides `absl::Hash` support for inlined vectors. You do not normally call +// this function directly. +template <typename H, typename TheT, size_t TheN, typename TheA> +auto AbslHashValue(H h, const InlinedVector<TheT, TheN, TheA>& v) -> H { + auto p = v.data(); + auto n = v.size(); + return H::combine(H::combine_contiguous(std::move(h), p, n), n); +} +} // namespace absl + // ----------------------------------------------------------------------------- // Implementation of InlinedVector -// ----------------------------------------------------------------------------- // -// Do not depend on any implementation details below this line. - -template <typename T, size_t N, typename A> -InlinedVector<T, N, A>::InlinedVector(const InlinedVector& v) - : allocator_and_tag_(v.allocator()) { - reserve(v.size()); - if (allocated()) { - UninitializedCopy(v.begin(), v.end(), allocated_space()); - tag().set_allocated_size(v.size()); - } else { - UninitializedCopy(v.begin(), v.end(), inlined_space()); - tag().set_inline_size(v.size()); - } -} - -template <typename T, size_t N, typename A> -InlinedVector<T, N, A>::InlinedVector(const InlinedVector& v, - const allocator_type& alloc) - : allocator_and_tag_(alloc) { - reserve(v.size()); - if (allocated()) { - UninitializedCopy(v.begin(), v.end(), allocated_space()); - tag().set_allocated_size(v.size()); - } else { - UninitializedCopy(v.begin(), v.end(), inlined_space()); - tag().set_inline_size(v.size()); - } -} - -template <typename T, size_t N, typename A> -InlinedVector<T, N, A>::InlinedVector(InlinedVector&& v) noexcept( - absl::allocator_is_nothrow<allocator_type>::value || - std::is_nothrow_move_constructible<value_type>::value) - : allocator_and_tag_(v.allocator_and_tag_) { - if (v.allocated()) { - // We can just steal the underlying buffer from the source. - // That leaves the source empty, so we clear its size. - init_allocation(v.allocation()); - v.tag() = Tag(); - } else { - UninitializedCopy(std::make_move_iterator(v.inlined_space()), - std::make_move_iterator(v.inlined_space() + v.size()), - inlined_space()); - } -} - -template <typename T, size_t N, typename A> -InlinedVector<T, N, A>::InlinedVector( - InlinedVector&& v, - const allocator_type& - alloc) noexcept(absl::allocator_is_nothrow<allocator_type>::value) - : allocator_and_tag_(alloc) { - if (v.allocated()) { - if (alloc == v.allocator()) { - // We can just steal the allocation from the source. - tag() = v.tag(); - init_allocation(v.allocation()); - v.tag() = Tag(); - } else { - // We need to use our own allocator - reserve(v.size()); - UninitializedCopy(std::make_move_iterator(v.begin()), - std::make_move_iterator(v.end()), allocated_space()); - tag().set_allocated_size(v.size()); - } - } else { - UninitializedCopy(std::make_move_iterator(v.inlined_space()), - std::make_move_iterator(v.inlined_space() + v.size()), - inlined_space()); - tag().set_inline_size(v.size()); - } -} - -template <typename T, size_t N, typename A> -void InlinedVector<T, N, A>::InitAssign(size_type n, const value_type& t) { - if (n > static_cast<size_type>(N)) { - Allocation new_allocation(allocator(), n); - init_allocation(new_allocation); - UninitializedFill(allocated_space(), allocated_space() + n, t); - tag().set_allocated_size(n); - } else { - UninitializedFill(inlined_space(), inlined_space() + n, t); - tag().set_inline_size(n); - } -} - -template <typename T, size_t N, typename A> -void InlinedVector<T, N, A>::InitAssign(size_type n) { - if (n > static_cast<size_type>(N)) { - Allocation new_allocation(allocator(), n); - init_allocation(new_allocation); - UninitializedFill(allocated_space(), allocated_space() + n); - tag().set_allocated_size(n); - } else { - UninitializedFill(inlined_space(), inlined_space() + n); - tag().set_inline_size(n); - } -} - -template <typename T, size_t N, typename A> -void InlinedVector<T, N, A>::resize(size_type n) { - size_type s = size(); - if (n < s) { - erase(begin() + n, end()); - return; - } - reserve(n); - assert(capacity() >= n); - - // Fill new space with elements constructed in-place. - if (allocated()) { - UninitializedFill(allocated_space() + s, allocated_space() + n); - tag().set_allocated_size(n); - } else { - UninitializedFill(inlined_space() + s, inlined_space() + n); - tag().set_inline_size(n); - } -} - -template <typename T, size_t N, typename A> -void InlinedVector<T, N, A>::resize(size_type n, const value_type& elem) { - size_type s = size(); - if (n < s) { - erase(begin() + n, end()); - return; - } - reserve(n); - assert(capacity() >= n); - - // Fill new space with copies of 'elem'. - if (allocated()) { - UninitializedFill(allocated_space() + s, allocated_space() + n, elem); - tag().set_allocated_size(n); - } else { - UninitializedFill(inlined_space() + s, inlined_space() + n, elem); - tag().set_inline_size(n); - } -} - -template <typename T, size_t N, typename A> -template <typename... Args> -typename InlinedVector<T, N, A>::iterator InlinedVector<T, N, A>::emplace( - const_iterator position, Args&&... args) { - assert(position >= begin()); - assert(position <= end()); - if (position == end()) { - emplace_back(std::forward<Args>(args)...); - return end() - 1; - } - - T new_t = T(std::forward<Args>(args)...); - - auto range = ShiftRight(position, 1); - if (range.first == range.second) { - // constructing into uninitialized memory - Construct(range.first, std::move(new_t)); - } else { - // assigning into moved-from object - *range.first = T(std::move(new_t)); - } - - return range.first; -} - -template <typename T, size_t N, typename A> -typename InlinedVector<T, N, A>::iterator InlinedVector<T, N, A>::erase( - const_iterator first, const_iterator last) { - assert(begin() <= first); - assert(first <= last); - assert(last <= end()); - - iterator range_start = const_cast<iterator>(first); - iterator range_end = const_cast<iterator>(last); - - size_type s = size(); - ptrdiff_t erase_gap = std::distance(range_start, range_end); - if (erase_gap > 0) { - pointer space; - if (allocated()) { - space = allocated_space(); - tag().set_allocated_size(s - erase_gap); - } else { - space = inlined_space(); - tag().set_inline_size(s - erase_gap); - } - std::move(range_end, space + s, range_start); - Destroy(space + s - erase_gap, space + s); - } - return range_start; -} - -template <typename T, size_t N, typename A> -void InlinedVector<T, N, A>::swap(InlinedVector& other) { - using std::swap; // Augment ADL with std::swap. - if (&other == this) { - return; - } - if (allocated() && other.allocated()) { - // Both out of line, so just swap the tag, allocation, and allocator. - swap(tag(), other.tag()); - swap(allocation(), other.allocation()); - swap(allocator(), other.allocator()); - return; - } - if (!allocated() && !other.allocated()) { - // Both inlined: swap up to smaller size, then move remaining elements. - InlinedVector* a = this; - InlinedVector* b = &other; - if (size() < other.size()) { - swap(a, b); - } - - const size_type a_size = a->size(); - const size_type b_size = b->size(); - assert(a_size >= b_size); - // 'a' is larger. Swap the elements up to the smaller array size. - std::swap_ranges(a->inlined_space(), a->inlined_space() + b_size, - b->inlined_space()); - - // Move the remaining elements: A[b_size,a_size) -> B[b_size,a_size) - b->UninitializedCopy(a->inlined_space() + b_size, - a->inlined_space() + a_size, - b->inlined_space() + b_size); - a->Destroy(a->inlined_space() + b_size, a->inlined_space() + a_size); - - swap(a->tag(), b->tag()); - swap(a->allocator(), b->allocator()); - assert(b->size() == a_size); - assert(a->size() == b_size); - return; - } - // One is out of line, one is inline. - // We first move the elements from the inlined vector into the - // inlined space in the other vector. We then put the other vector's - // pointer/capacity into the originally inlined vector and swap - // the tags. - InlinedVector* a = this; - InlinedVector* b = &other; - if (a->allocated()) { - swap(a, b); - } - assert(!a->allocated()); - assert(b->allocated()); - const size_type a_size = a->size(); - const size_type b_size = b->size(); - // In an optimized build, b_size would be unused. - (void)b_size; - - // Made Local copies of size(), don't need tag() accurate anymore - swap(a->tag(), b->tag()); - - // Copy b_allocation out before b's union gets clobbered by inline_space. - Allocation b_allocation = b->allocation(); - - b->UninitializedCopy(a->inlined_space(), a->inlined_space() + a_size, - b->inlined_space()); - a->Destroy(a->inlined_space(), a->inlined_space() + a_size); - - a->allocation() = b_allocation; - - if (a->allocator() != b->allocator()) { - swap(a->allocator(), b->allocator()); - } - - assert(b->size() == a_size); - assert(a->size() == b_size); -} - -template <typename T, size_t N, typename A> -void InlinedVector<T, N, A>::EnlargeBy(size_type delta) { - const size_type s = size(); - assert(s <= capacity()); - - size_type target = std::max(static_cast<size_type>(N), s + delta); - - // Compute new capacity by repeatedly doubling current capacity - // TODO(psrc): Check and avoid overflow? - size_type new_capacity = capacity(); - while (new_capacity < target) { - new_capacity <<= 1; - } - - Allocation new_allocation(allocator(), new_capacity); - - UninitializedCopy(std::make_move_iterator(data()), - std::make_move_iterator(data() + s), - new_allocation.buffer()); - - ResetAllocation(new_allocation, s); -} - -template <typename T, size_t N, typename A> -auto InlinedVector<T, N, A>::ShiftRight(const_iterator position, size_type n) - -> std::pair<iterator, iterator> { - iterator start_used = const_cast<iterator>(position); - iterator start_raw = const_cast<iterator>(position); - size_type s = size(); - size_type required_size = s + n; - - if (required_size > capacity()) { - // Compute new capacity by repeatedly doubling current capacity - size_type new_capacity = capacity(); - while (new_capacity < required_size) { - new_capacity <<= 1; - } - // Move everyone into the new allocation, leaving a gap of n for the - // requested shift. - Allocation new_allocation(allocator(), new_capacity); - size_type index = position - begin(); - UninitializedCopy(std::make_move_iterator(data()), - std::make_move_iterator(data() + index), - new_allocation.buffer()); - UninitializedCopy(std::make_move_iterator(data() + index), - std::make_move_iterator(data() + s), - new_allocation.buffer() + index + n); - ResetAllocation(new_allocation, s); - - // New allocation means our iterator is invalid, so we'll recalculate. - // Since the entire gap is in new space, there's no used space to reuse. - start_raw = begin() + index; - start_used = start_raw; - } else { - // If we had enough space, it's a two-part move. Elements going into - // previously-unoccupied space need an UninitializedCopy. Elements - // going into a previously-occupied space are just a move. - iterator pos = const_cast<iterator>(position); - iterator raw_space = end(); - size_type slots_in_used_space = raw_space - pos; - size_type new_elements_in_used_space = std::min(n, slots_in_used_space); - size_type new_elements_in_raw_space = n - new_elements_in_used_space; - size_type old_elements_in_used_space = - slots_in_used_space - new_elements_in_used_space; - - UninitializedCopy(std::make_move_iterator(pos + old_elements_in_used_space), - std::make_move_iterator(raw_space), - raw_space + new_elements_in_raw_space); - std::move_backward(pos, pos + old_elements_in_used_space, raw_space); - - // If the gap is entirely in raw space, the used space starts where the raw - // space starts, leaving no elements in used space. If the gap is entirely - // in used space, the raw space starts at the end of the gap, leaving all - // elements accounted for within the used space. - start_used = pos; - start_raw = pos + new_elements_in_used_space; - } - tag().add_size(n); - return std::make_pair(start_used, start_raw); -} - -template <typename T, size_t N, typename A> -void InlinedVector<T, N, A>::Destroy(value_type* ptr, value_type* ptr_last) { - for (value_type* p = ptr; p != ptr_last; ++p) { - AllocatorTraits::destroy(allocator(), p); - } - - // Overwrite unused memory with 0xab so we can catch uninitialized usage. - // Cast to void* to tell the compiler that we don't care that we might be - // scribbling on a vtable pointer. -#ifndef NDEBUG - if (ptr != ptr_last) { - memset(reinterpret_cast<void*>(ptr), 0xab, sizeof(*ptr) * (ptr_last - ptr)); - } -#endif -} - -template <typename T, size_t N, typename A> -template <typename Iter> -void InlinedVector<T, N, A>::AppendRange(Iter first, Iter last, - std::forward_iterator_tag) { - using Length = typename std::iterator_traits<Iter>::difference_type; - Length length = std::distance(first, last); - reserve(size() + length); - if (allocated()) { - UninitializedCopy(first, last, allocated_space() + size()); - tag().set_allocated_size(size() + length); - } else { - UninitializedCopy(first, last, inlined_space() + size()); - tag().set_inline_size(size() + length); - } -} - -template <typename T, size_t N, typename A> -template <typename Iter> -void InlinedVector<T, N, A>::AssignRange(Iter first, Iter last, - std::input_iterator_tag) { - // Optimized to avoid reallocation. - // Prefer reassignment to copy construction for elements. - iterator out = begin(); - for (; first != last && out != end(); ++first, ++out) { - *out = *first; - } - erase(out, end()); - std::copy(first, last, std::back_inserter(*this)); -} - -template <typename T, size_t N, typename A> -template <typename Iter> -void InlinedVector<T, N, A>::AssignRange(Iter first, Iter last, - std::forward_iterator_tag) { - using Length = typename std::iterator_traits<Iter>::difference_type; - Length length = std::distance(first, last); - // Prefer reassignment to copy construction for elements. - if (static_cast<size_type>(length) <= size()) { - erase(std::copy(first, last, begin()), end()); - return; - } - reserve(length); - iterator out = begin(); - for (; out != end(); ++first, ++out) *out = *first; - if (allocated()) { - UninitializedCopy(first, last, out); - tag().set_allocated_size(length); - } else { - UninitializedCopy(first, last, out); - tag().set_inline_size(length); - } -} - -template <typename T, size_t N, typename A> -auto InlinedVector<T, N, A>::InsertWithCount(const_iterator position, - size_type n, const value_type& v) - -> iterator { - assert(position >= begin() && position <= end()); - if (n == 0) return const_cast<iterator>(position); - - value_type copy = v; - std::pair<iterator, iterator> it_pair = ShiftRight(position, n); - std::fill(it_pair.first, it_pair.second, copy); - UninitializedFill(it_pair.second, it_pair.first + n, copy); - - return it_pair.first; -} - -template <typename T, size_t N, typename A> -template <typename InputIter> -auto InlinedVector<T, N, A>::InsertWithRange(const_iterator position, - InputIter first, InputIter last, - std::input_iterator_tag) - -> iterator { - assert(position >= begin() && position <= end()); - size_type index = position - cbegin(); - size_type i = index; - while (first != last) insert(begin() + i++, *first++); - return begin() + index; -} - -// Overload of InlinedVector::InsertWithRange() -template <typename T, size_t N, typename A> -template <typename ForwardIter> -auto InlinedVector<T, N, A>::InsertWithRange(const_iterator position, - ForwardIter first, - ForwardIter last, - std::forward_iterator_tag) - -> iterator { - assert(position >= begin() && position <= end()); - if (first == last) { - return const_cast<iterator>(position); - } - using Length = typename std::iterator_traits<ForwardIter>::difference_type; - Length n = std::distance(first, last); - std::pair<iterator, iterator> it_pair = ShiftRight(position, n); - size_type used_spots = it_pair.second - it_pair.first; - ForwardIter open_spot = std::next(first, used_spots); - std::copy(first, open_spot, it_pair.first); - UninitializedCopy(open_spot, last, it_pair.second); - return it_pair.first; -} - -} // namespace absl +// Do not depend on any below implementation details! +// ----------------------------------------------------------------------------- #endif // ABSL_CONTAINER_INLINED_VECTOR_H_
diff --git a/absl/container/inlined_vector_benchmark.cc b/absl/container/inlined_vector_benchmark.cc index a3ad0f8..867a29e 100644 --- a/absl/container/inlined_vector_benchmark.cc +++ b/absl/container/inlined_vector_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -23,17 +23,13 @@ namespace { -using IntVec = absl::InlinedVector<int, 8>; - void BM_InlinedVectorFill(benchmark::State& state) { - const int len = state.range(0); + absl::InlinedVector<int, 8> v; + int val = 10; for (auto _ : state) { - IntVec v; - for (int i = 0; i < len; i++) { - v.push_back(i); - } + benchmark::DoNotOptimize(v); + v.push_back(val); } - state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len); } BENCHMARK(BM_InlinedVectorFill)->Range(0, 1024); @@ -43,23 +39,25 @@ for (int i = 0; i < len; i++) { ia[i] = i; } + auto* from = ia.get(); + auto* to = from + len; for (auto _ : state) { - IntVec v(ia.get(), ia.get() + len); + benchmark::DoNotOptimize(from); + benchmark::DoNotOptimize(to); + absl::InlinedVector<int, 8> v(from, to); benchmark::DoNotOptimize(v); } - state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len); } BENCHMARK(BM_InlinedVectorFillRange)->Range(0, 1024); void BM_StdVectorFill(benchmark::State& state) { - const int len = state.range(0); + std::vector<int> v; + int val = 10; for (auto _ : state) { - std::vector<int> v; - for (int i = 0; i < len; i++) { - v.push_back(i); - } + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(val); + v.push_back(val); } - state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len); } BENCHMARK(BM_StdVectorFill)->Range(0, 1024); @@ -89,7 +87,7 @@ const int len = state.range(0); const int no_sso = GetNonShortStringOptimizationSize(); std::string strings[4] = {std::string(no_sso, 'A'), std::string(no_sso, 'B'), - std::string(no_sso, 'C'), std::string(no_sso, 'D')}; + std::string(no_sso, 'C'), std::string(no_sso, 'D')}; for (auto _ : state) { absl::InlinedVector<std::string, 8> v; @@ -105,7 +103,7 @@ const int len = state.range(0); const int no_sso = GetNonShortStringOptimizationSize(); std::string strings[4] = {std::string(no_sso, 'A'), std::string(no_sso, 'B'), - std::string(no_sso, 'C'), std::string(no_sso, 'D')}; + std::string(no_sso, 'C'), std::string(no_sso, 'D')}; for (auto _ : state) { std::vector<std::string> v; @@ -124,7 +122,7 @@ void* user_data; }; -void BM_InlinedVectorTenAssignments(benchmark::State& state) { +void BM_InlinedVectorAssignments(benchmark::State& state) { const int len = state.range(0); using BufferVec = absl::InlinedVector<Buffer, 2>; @@ -133,18 +131,25 @@ BufferVec dst; for (auto _ : state) { - for (int i = 0; i < 10; ++i) { - dst = src; - } + benchmark::DoNotOptimize(dst); + benchmark::DoNotOptimize(src); + dst = src; } } -BENCHMARK(BM_InlinedVectorTenAssignments) - ->Arg(0)->Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(20); +BENCHMARK(BM_InlinedVectorAssignments) + ->Arg(0) + ->Arg(1) + ->Arg(2) + ->Arg(3) + ->Arg(4) + ->Arg(20); void BM_CreateFromContainer(benchmark::State& state) { for (auto _ : state) { - absl::InlinedVector<int, 4> x(absl::InlinedVector<int, 4>{1, 2, 3}); - benchmark::DoNotOptimize(x); + absl::InlinedVector<int, 4> src{1, 2, 3}; + benchmark::DoNotOptimize(src); + absl::InlinedVector<int, 4> dst(std::move(src)); + benchmark::DoNotOptimize(dst); } } BENCHMARK(BM_CreateFromContainer); @@ -159,15 +164,14 @@ struct LargeCopyableSwappable { LargeCopyableSwappable() : d(1024, 17) {} + LargeCopyableSwappable(const LargeCopyableSwappable& o) = default; - LargeCopyableSwappable(LargeCopyableSwappable&& o) = delete; LargeCopyableSwappable& operator=(LargeCopyableSwappable o) { using std::swap; swap(*this, o); return *this; } - LargeCopyableSwappable& operator=(LargeCopyableSwappable&& o) = delete; friend void swap(LargeCopyableSwappable& a, LargeCopyableSwappable& b) { using std::swap; @@ -215,6 +219,8 @@ Vec b; for (auto _ : state) { using std::swap; + benchmark::DoNotOptimize(a); + benchmark::DoNotOptimize(b); swap(a, b); } } @@ -260,60 +266,44 @@ void BM_InlinedVectorIndexInlined(benchmark::State& state) { absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7}; for (auto _ : state) { - for (int i = 0; i < 1000; ++i) { - benchmark::DoNotOptimize(v); - benchmark::DoNotOptimize(v[4]); - } + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v[4]); } - state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations())); } BENCHMARK(BM_InlinedVectorIndexInlined); void BM_InlinedVectorIndexExternal(benchmark::State& state) { absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; for (auto _ : state) { - for (int i = 0; i < 1000; ++i) { - benchmark::DoNotOptimize(v); - benchmark::DoNotOptimize(v[4]); - } + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v[4]); } - state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations())); } BENCHMARK(BM_InlinedVectorIndexExternal); void BM_StdVectorIndex(benchmark::State& state) { std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; for (auto _ : state) { - for (int i = 0; i < 1000; ++i) { - benchmark::DoNotOptimize(v); - benchmark::DoNotOptimize(v[4]); - } + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v[4]); } - state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations())); } BENCHMARK(BM_StdVectorIndex); -#define UNROLL_2(x) \ - benchmark::DoNotOptimize(x); \ - benchmark::DoNotOptimize(x); - -#define UNROLL_4(x) UNROLL_2(x) UNROLL_2(x) -#define UNROLL_8(x) UNROLL_4(x) UNROLL_4(x) -#define UNROLL_16(x) UNROLL_8(x) UNROLL_8(x); - void BM_InlinedVectorDataInlined(benchmark::State& state) { absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7}; for (auto _ : state) { - UNROLL_16(v.data()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v.data()); } - state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); } BENCHMARK(BM_InlinedVectorDataInlined); void BM_InlinedVectorDataExternal(benchmark::State& state) { absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; for (auto _ : state) { - UNROLL_16(v.data()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v.data()); } state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); } @@ -322,7 +312,8 @@ void BM_StdVectorData(benchmark::State& state) { std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; for (auto _ : state) { - UNROLL_16(v.data()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v.data()); } state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); } @@ -331,54 +322,54 @@ void BM_InlinedVectorSizeInlined(benchmark::State& state) { absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7}; for (auto _ : state) { - UNROLL_16(v.size()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v.size()); } - state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); } BENCHMARK(BM_InlinedVectorSizeInlined); void BM_InlinedVectorSizeExternal(benchmark::State& state) { absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; for (auto _ : state) { - UNROLL_16(v.size()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v.size()); } - state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); } BENCHMARK(BM_InlinedVectorSizeExternal); void BM_StdVectorSize(benchmark::State& state) { std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; for (auto _ : state) { - UNROLL_16(v.size()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v.size()); } - state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); } BENCHMARK(BM_StdVectorSize); void BM_InlinedVectorEmptyInlined(benchmark::State& state) { absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7}; for (auto _ : state) { - UNROLL_16(v.empty()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v.empty()); } - state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); } BENCHMARK(BM_InlinedVectorEmptyInlined); void BM_InlinedVectorEmptyExternal(benchmark::State& state) { absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; for (auto _ : state) { - UNROLL_16(v.empty()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v.empty()); } - state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); } BENCHMARK(BM_InlinedVectorEmptyExternal); void BM_StdVectorEmpty(benchmark::State& state) { std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; for (auto _ : state) { - UNROLL_16(v.empty()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v.empty()); } - state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); } BENCHMARK(BM_StdVectorEmpty);
diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc index 08dcd3e..6037001 100644 --- a/absl/container/inlined_vector_test.cc +++ b/absl/container/inlined_vector_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -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/container/internal/counting_allocator.h" #include "absl/container/internal/test_instance_tracker.h" #include "absl/hash/hash_testing.h" #include "absl/memory/memory.h" @@ -37,6 +38,7 @@ namespace { +using absl::container_internal::CountingAllocator; using absl::test_internal::CopyableMovableInstance; using absl::test_internal::CopyableOnlyInstance; using absl::test_internal::InstanceTracker; @@ -68,7 +70,7 @@ // test_instance_tracker.h. template <typename T> class InstanceTest : public ::testing::Test {}; -TYPED_TEST_CASE_P(InstanceTest); +TYPED_TEST_SUITE_P(InstanceTest); // A simple reference counted class to make sure that the proper elements are // destroyed in the erase(begin, end) test. @@ -138,57 +140,6 @@ return v; } -// This is a stateful allocator, but the state lives outside of the -// allocator (in whatever test is using the allocator). This is odd -// but helps in tests where the allocator is propagated into nested -// containers - that chain of allocators uses the same state and is -// thus easier to query for aggregate allocation information. -template <typename T> -class CountingAllocator : public std::allocator<T> { - public: - using Alloc = std::allocator<T>; - using pointer = typename Alloc::pointer; - using size_type = typename Alloc::size_type; - - CountingAllocator() : bytes_used_(nullptr) {} - explicit CountingAllocator(int64_t* b) : bytes_used_(b) {} - - template <typename U> - CountingAllocator(const CountingAllocator<U>& x) - : Alloc(x), bytes_used_(x.bytes_used_) {} - - pointer allocate(size_type n, - std::allocator<void>::const_pointer hint = nullptr) { - assert(bytes_used_ != nullptr); - *bytes_used_ += n * sizeof(T); - return Alloc::allocate(n, hint); - } - - void deallocate(pointer p, size_type n) { - Alloc::deallocate(p, n); - assert(bytes_used_ != nullptr); - *bytes_used_ -= n * sizeof(T); - } - - template<typename U> - class rebind { - public: - using other = CountingAllocator<U>; - }; - - friend bool operator==(const CountingAllocator& a, - const CountingAllocator& b) { - return a.bytes_used_ == b.bytes_used_; - } - - friend bool operator!=(const CountingAllocator& a, - const CountingAllocator& b) { - return !(a == b); - } - - int64_t* bytes_used_; -}; - TEST(IntVec, SimpleOps) { for (int len = 0; len < 20; len++) { IntVec v; @@ -906,6 +857,8 @@ InstanceTracker tracker; InstanceVec a, b; const size_t inlined_capacity = a.capacity(); + auto min_len = std::min(l1, l2); + auto max_len = std::max(l1, l2); for (int i = 0; i < l1; i++) a.push_back(Instance(i)); for (int i = 0; i < l2; i++) b.push_back(Instance(100+i)); EXPECT_EQ(tracker.instances(), l1 + l2); @@ -919,15 +872,15 @@ EXPECT_EQ(tracker.swaps(), 0); // Allocations are swapped. EXPECT_EQ(tracker.moves(), 0); } else if (a.size() <= inlined_capacity && b.size() <= inlined_capacity) { - EXPECT_EQ(tracker.swaps(), std::min(l1, l2)); - // TODO(bsamwel): This should use moves when the type is movable. - EXPECT_EQ(tracker.copies(), std::max(l1, l2) - std::min(l1, l2)); + EXPECT_EQ(tracker.swaps(), min_len); + EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()), + max_len - min_len); } else { // One is allocated and the other isn't. The allocation is transferred // without copying elements, and the inlined instances are copied/moved. EXPECT_EQ(tracker.swaps(), 0); - // TODO(bsamwel): This should use moves when the type is movable. - EXPECT_EQ(tracker.copies(), std::min(l1, l2)); + EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()), + min_len); } EXPECT_EQ(l1, b.size()); @@ -1726,39 +1679,58 @@ std::scoped_allocator_adaptor<CountingAllocator<StdVector>>; using AllocVec = absl::InlinedVector<StdVector, 4, MyAlloc>; + // MSVC 2017's std::vector allocates different amounts of memory in debug + // versus opt mode. + int64_t test_allocated = 0; + StdVector v(CountingAllocator<int>{&test_allocated}); + // The amount of memory allocated by a default constructed vector<int> + auto default_std_vec_allocated = test_allocated; + v.push_back(1); + // The amound of memory allocated by a copy-constructed vector<int> with one + // element. + int64_t one_element_std_vec_copy_allocated = test_allocated; + int64_t allocated = 0; AllocVec vec(MyAlloc{CountingAllocator<StdVector>{&allocated}}); EXPECT_EQ(allocated, 0); // This default constructs a vector<int>, but the allocator should pass itself - // into the vector<int>. + // into the vector<int>, so check allocation compared to that. // The absl::InlinedVector does not allocate any memory. - // The vector<int> does not allocate any memory. + // The vector<int> may allocate any memory. + auto expected = default_std_vec_allocated; vec.resize(1); - EXPECT_EQ(allocated, 0); + EXPECT_EQ(allocated, expected); // We make vector<int> allocate memory. // It must go through the allocator even though we didn't construct the - // vector directly. + // vector directly. This assumes that vec[0] doesn't need to grow its + // allocation. + expected += sizeof(int); vec[0].push_back(1); - EXPECT_EQ(allocated, sizeof(int) * 1); + EXPECT_EQ(allocated, expected); // Another allocating vector. + expected += one_element_std_vec_copy_allocated; vec.push_back(vec[0]); - EXPECT_EQ(allocated, sizeof(int) * 2); + EXPECT_EQ(allocated, expected); // Overflow the inlined memory. // The absl::InlinedVector will now allocate. + expected += sizeof(StdVector) * 8 + default_std_vec_allocated * 3; vec.resize(5); - EXPECT_EQ(allocated, sizeof(int) * 2 + sizeof(StdVector) * 8); + EXPECT_EQ(allocated, expected); // Adding one more in external mode should also work. + expected += one_element_std_vec_copy_allocated; vec.push_back(vec[0]); - EXPECT_EQ(allocated, sizeof(int) * 3 + sizeof(StdVector) * 8); + EXPECT_EQ(allocated, expected); - // And extending these should still work. + // And extending these should still work. This assumes that vec[0] does not + // need to grow its allocation. + expected += sizeof(int); vec[0].push_back(1); - EXPECT_EQ(allocated, sizeof(int) * 4 + sizeof(StdVector) * 8); + EXPECT_EQ(allocated, expected); vec.clear(); EXPECT_EQ(allocated, 0); @@ -1790,4 +1762,23 @@ } } +TEST(InlinedVectorTest, AbslHashValueWorks) { + using V = absl::InlinedVector<int, 4>; + std::vector<V> cases; + + // Generate a variety of vectors some of these are small enough for the inline + // space but are stored out of line. + for (int i = 0; i < 10; ++i) { + V v; + for (int j = 0; j < i; ++j) { + v.push_back(j); + } + cases.push_back(v); + v.resize(i % 4); + cases.push_back(v); + } + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases)); +} + } // anonymous namespace
diff --git a/absl/container/internal/common.h b/absl/container/internal/common.h new file mode 100644 index 0000000..b06e711 --- /dev/null +++ b/absl/container/internal/common.h
@@ -0,0 +1,183 @@ +// 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_CONTAINER_INTERNAL_CONTAINER_H_ +#define ABSL_CONTAINER_INTERNAL_CONTAINER_H_ + +#include <cassert> +#include <type_traits> + +#include "absl/meta/type_traits.h" +#include "absl/types/optional.h" + +namespace absl { +namespace container_internal { + +template <class, class = void> +struct IsTransparent : std::false_type {}; +template <class T> +struct IsTransparent<T, absl::void_t<typename T::is_transparent>> + : std::true_type {}; + +template <bool is_transparent> +struct KeyArg { + // Transparent. Forward `K`. + template <typename K, typename key_type> + using type = K; +}; + +template <> +struct KeyArg<false> { + // Not transparent. Always use `key_type`. + template <typename K, typename key_type> + using type = key_type; +}; + +// The node_handle concept from C++17. +// We specialize node_handle for sets and maps. node_handle_base holds the +// common API of both. +template <typename PolicyTraits, typename Alloc> +class node_handle_base { + protected: + using slot_type = typename PolicyTraits::slot_type; + + public: + using allocator_type = Alloc; + + constexpr node_handle_base() {} + node_handle_base(node_handle_base&& other) noexcept { + *this = std::move(other); + } + ~node_handle_base() { destroy(); } + node_handle_base& operator=(node_handle_base&& other) noexcept { + destroy(); + if (!other.empty()) { + alloc_ = other.alloc_; + PolicyTraits::transfer(alloc(), slot(), other.slot()); + other.reset(); + } + return *this; + } + + bool empty() const noexcept { return !alloc_; } + explicit operator bool() const noexcept { return !empty(); } + allocator_type get_allocator() const { return *alloc_; } + + protected: + friend struct CommonAccess; + + node_handle_base(const allocator_type& a, slot_type* s) : alloc_(a) { + PolicyTraits::transfer(alloc(), slot(), s); + } + + void destroy() { + if (!empty()) { + PolicyTraits::destroy(alloc(), slot()); + reset(); + } + } + + void reset() { + assert(alloc_.has_value()); + alloc_ = absl::nullopt; + } + + slot_type* slot() const { + assert(!empty()); + return reinterpret_cast<slot_type*>(std::addressof(slot_space_)); + } + 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_; +}; + +// 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; + + public: + using value_type = typename PolicyTraits::value_type; + + constexpr node_handle() {} + + value_type& value() const { return PolicyTraits::element(this->slot()); } + + private: + friend struct CommonAccess; + + node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {} +}; + +// For maps. +template <typename Policy, typename PolicyTraits, typename Alloc> +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; + + public: + using key_type = typename Policy::key_type; + using mapped_type = typename Policy::mapped_type; + + constexpr node_handle() {} + + auto key() const -> decltype(PolicyTraits::key(this->slot())) { + return PolicyTraits::key(this->slot()); + } + + mapped_type& mapped() const { + return PolicyTraits::value(&PolicyTraits::element(this->slot())); + } + + private: + friend struct CommonAccess; + + node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {} +}; + +// Provide access to non-public node-handle functions. +struct CommonAccess { + template <typename Node> + static auto GetSlot(const Node& node) -> decltype(node.slot()) { + return node.slot(); + } + + template <typename Node> + static void Reset(Node* node) { + node->reset(); + } + + template <typename T, typename... Args> + static T Make(Args&&... args) { + return T(std::forward<Args>(args)...); + } +}; + +// Implement the insert_return_type<> concept of C++17. +template <class Iterator, class NodeType> +struct InsertReturnType { + Iterator position; + bool inserted; + NodeType node; +}; + +} // namespace container_internal +} // namespace absl + +#endif // ABSL_CONTAINER_INTERNAL_CONTAINER_H_
diff --git a/absl/container/internal/compressed_tuple.h b/absl/container/internal/compressed_tuple.h index cc52614..b9bd91a 100644 --- a/absl/container/internal/compressed_tuple.h +++ b/absl/container/internal/compressed_tuple.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -27,7 +27,7 @@ // const T2& t2 = value.get<2>(); // ... // -// http://en.cppreference.com/w/cpp/language/ebo +// https://en.cppreference.com/w/cpp/language/ebo #ifndef ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_ #define ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_ @@ -89,8 +89,10 @@ T value; constexpr Storage() = default; explicit constexpr Storage(T&& v) : value(absl::forward<T>(v)) {} - constexpr const T& get() const { return value; } - T& get() { return value; } + constexpr const T& get() const& { return value; } + T& get() & { return value; } + constexpr const T&& get() const&& { return absl::move(*this).value; } + T&& get() && { return std::move(*this).value; } }; template <typename D, size_t I> @@ -99,8 +101,10 @@ using T = internal_compressed_tuple::ElemT<D, I>; constexpr Storage() = default; explicit constexpr Storage(T&& v) : T(absl::forward<T>(v)) {} - constexpr const T& get() const { return *this; } - T& get() { return *this; } + constexpr const T& get() const& { return *this; } + T& get() & { return *this; } + constexpr const T&& get() const&& { return absl::move(*this); } + T&& get() && { return std::move(*this); } }; template <typename D, typename I> @@ -137,7 +141,7 @@ // const T2& t2 = value.get<2>(); // ... // -// http://en.cppreference.com/w/cpp/language/ebo +// https://en.cppreference.com/w/cpp/language/ebo template <typename... Ts> class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple : private internal_compressed_tuple::CompressedTupleImpl< @@ -152,14 +156,26 @@ : CompressedTuple::CompressedTupleImpl(absl::forward<Ts>(base)...) {} template <int I> - ElemT<I>& get() { + ElemT<I>& get() & { return internal_compressed_tuple::Storage<CompressedTuple, I>::get(); } template <int I> - constexpr const ElemT<I>& get() const { + constexpr const ElemT<I>& get() const& { return internal_compressed_tuple::Storage<CompressedTuple, I>::get(); } + + template <int I> + ElemT<I>&& get() && { + return std::move(*this) + .internal_compressed_tuple::template Storage<CompressedTuple, I>::get(); + } + + template <int I> + constexpr const ElemT<I>&& get() const&& { + return absl::move(*this) + .internal_compressed_tuple::template Storage<CompressedTuple, I>::get(); + } }; // Explicit specialization for a zero-element tuple
diff --git a/absl/container/internal/compressed_tuple_test.cc b/absl/container/internal/compressed_tuple_test.cc index 45030c6..28e7741 100644 --- a/absl/container/internal/compressed_tuple_test.cc +++ b/absl/container/internal/compressed_tuple_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -14,17 +14,25 @@ #include "absl/container/internal/compressed_tuple.h" +#include <memory> #include <string> #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/memory/memory.h" +#include "absl/utility/utility.h" namespace absl { namespace container_internal { namespace { +enum class CallType { kConstRef, kConstMove }; + template <int> -struct Empty {}; +struct Empty { + constexpr CallType value() const& { return CallType::kConstRef; } + constexpr CallType value() const&& { return CallType::kConstMove; } +}; template <typename T> struct NotEmpty { @@ -140,15 +148,44 @@ EXPECT_TRUE(std::is_empty<CompressedTuple<>>::value); } +TEST(CompressedTupleTest, MoveOnlyElements) { + CompressedTuple<std::unique_ptr<std::string>> str_tup( + absl::make_unique<std::string>("str")); + + CompressedTuple<CompressedTuple<std::unique_ptr<std::string>>, + std::unique_ptr<int>> + x(std::move(str_tup), absl::make_unique<int>(5)); + + EXPECT_EQ(*x.get<0>().get<0>(), "str"); + EXPECT_EQ(*x.get<1>(), 5); + + std::unique_ptr<std::string> x0 = std::move(x.get<0>()).get<0>(); + std::unique_ptr<int> x1 = std::move(x).get<1>(); + + EXPECT_EQ(*x0, "str"); + EXPECT_EQ(*x1, 5); +} + TEST(CompressedTupleTest, Constexpr) { - constexpr CompressedTuple<int, double, CompressedTuple<int>> x( - 7, 1.25, CompressedTuple<int>(5)); + constexpr CompressedTuple<int, double, CompressedTuple<int>, Empty<0>> x( + 7, 1.25, CompressedTuple<int>(5), {}); constexpr int x0 = x.get<0>(); constexpr double x1 = x.get<1>(); constexpr int x2 = x.get<2>().get<0>(); + constexpr CallType x3 = x.get<3>().value(); + EXPECT_EQ(x0, 7); EXPECT_EQ(x1, 1.25); EXPECT_EQ(x2, 5); + EXPECT_EQ(x3, CallType::kConstRef); + +#if defined(__clang__) + // An apparent bug in earlier versions of gcc claims these are ambiguous. + constexpr int x2m = absl::move(x.get<2>()).get<0>(); + constexpr CallType x3m = absl::move(x).get<3>().value(); + EXPECT_EQ(x2m, 5); + EXPECT_EQ(x3m, CallType::kConstMove); +#endif } #if defined(__clang__) || defined(__GNUC__)
diff --git a/absl/container/internal/container_memory.h b/absl/container/internal/container_memory.h index 56c5d2d..e5bb977 100644 --- a/absl/container/internal/container_memory.h +++ b/absl/container/internal/container_memory.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -286,13 +286,48 @@ } // namespace memory_internal -// If kMutableKeys is false, only the value member is accessed. +// The internal storage type for key-value containers like flat_hash_map. // -// If kMutableKeys is true, key is accessed through all slots while value and -// mutable_value are accessed only via INITIALIZED slots. Slots are created and -// destroyed via mutable_value so that the key can be moved later. +// It is convenient for the value_type of a flat_hash_map<K, V> to be +// pair<const K, V>; the "const K" prevents accidental modification of the key +// when dealing with the reference returned from find() and similar methods. +// However, this creates other problems; we want to be able to emplace(K, V) +// efficiently with move operations, and similarly be able to move a +// pair<K, V> in insert(). +// +// The solution is this union, which aliases the const and non-const versions +// of the pair. This also allows flat_hash_map<const K, V> to work, even though +// that has the same efficiency issues with move in emplace() and insert() - +// but people do it anyway. +// +// If kMutableKeys is false, only the value member can be accessed. +// +// If kMutableKeys is true, key can be accessed through all slots while value +// and mutable_value must be accessed only via INITIALIZED slots. Slots are +// created and destroyed via mutable_value so that the key can be moved later. +// +// Accessing one of the union fields while the other is active is safe as +// long as they are layout-compatible, which is guaranteed by the definition of +// kMutableKeys. For C++11, the relevant section of the standard is +// https://timsong-cpp.github.io/cppwp/n3337/class.mem#19 (9.2.19) template <class K, class V> -union slot_type { +union map_slot_type { + map_slot_type() {} + ~map_slot_type() = delete; + using value_type = std::pair<const K, V>; + using mutable_value_type = std::pair<K, V>; + + value_type value; + mutable_value_type mutable_value; + K key; +}; + +template <class K, class V> +struct map_slot_policy { + using slot_type = map_slot_type<K, V>; + using value_type = std::pair<const K, V>; + using mutable_value_type = std::pair<K, V>; + private: static void emplace(slot_type* slot) { // The construction of union doesn't do anything at runtime but it allows us @@ -302,19 +337,17 @@ // If pair<const K, V> and pair<K, V> are layout-compatible, we can accept one // or the other via slot_type. We are also free to access the key via // slot_type::key in this case. - using kMutableKeys = - std::integral_constant<bool, - memory_internal::IsLayoutCompatible<K, V>::value>; + using kMutableKeys = memory_internal::IsLayoutCompatible<K, V>; public: - slot_type() {} - ~slot_type() = delete; - using value_type = std::pair<const K, V>; - using mutable_value_type = std::pair<K, V>; + static value_type& element(slot_type* slot) { return slot->value; } + static const value_type& element(const slot_type* slot) { + return slot->value; + } - value_type value; - mutable_value_type mutable_value; - K key; + static const K& key(const slot_type* slot) { + return kMutableKeys::value ? slot->key : slot->value.first; + } template <class Allocator, class... Args> static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
diff --git a/absl/container/internal/container_memory_test.cc b/absl/container/internal/container_memory_test.cc index f1c4058..d6b0495 100644 --- a/absl/container/internal/container_memory_test.cc +++ b/absl/container/internal/container_memory_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/container/internal/counting_allocator.h b/absl/container/internal/counting_allocator.h new file mode 100644 index 0000000..4e717be --- /dev/null +++ b/absl/container/internal/counting_allocator.h
@@ -0,0 +1,79 @@ +// 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_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_ +#define ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_ + +#include <cassert> +#include <cstdint> +#include <memory> + +namespace absl { +namespace container_internal { + +// This is a stateful allocator, but the state lives outside of the +// allocator (in whatever test is using the allocator). This is odd +// but helps in tests where the allocator is propagated into nested +// containers - that chain of allocators uses the same state and is +// thus easier to query for aggregate allocation information. +template <typename T> +class CountingAllocator : public std::allocator<T> { + public: + using Alloc = std::allocator<T>; + using pointer = typename Alloc::pointer; + using size_type = typename Alloc::size_type; + + CountingAllocator() : bytes_used_(nullptr) {} + explicit CountingAllocator(int64_t* b) : bytes_used_(b) {} + + template <typename U> + CountingAllocator(const CountingAllocator<U>& x) + : Alloc(x), bytes_used_(x.bytes_used_) {} + + pointer allocate(size_type n, + std::allocator<void>::const_pointer hint = nullptr) { + assert(bytes_used_ != nullptr); + *bytes_used_ += n * sizeof(T); + return Alloc::allocate(n, hint); + } + + void deallocate(pointer p, size_type n) { + Alloc::deallocate(p, n); + assert(bytes_used_ != nullptr); + *bytes_used_ -= n * sizeof(T); + } + + template<typename U> + class rebind { + public: + using other = CountingAllocator<U>; + }; + + friend bool operator==(const CountingAllocator& a, + const CountingAllocator& b) { + return a.bytes_used_ == b.bytes_used_; + } + + friend bool operator!=(const CountingAllocator& a, + const CountingAllocator& b) { + return !(a == b); + } + + int64_t* bytes_used_; +}; + +} // namespace container_internal +} // namespace absl + +#endif // ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
diff --git a/absl/container/internal/hash_function_defaults.h b/absl/container/internal/hash_function_defaults.h index 1f0d794..cb8f03c 100644 --- a/absl/container/internal/hash_function_defaults.h +++ b/absl/container/internal/hash_function_defaults.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -39,8 +39,8 @@ // equal functions are still bound to T. This is important because some type U // can be hashed by/tested for equality differently depending on T. A notable // example is `const char*`. `const char*` is treated as a c-style string when -// the hash function is hash<string> but as a pointer when the hash function is -// hash<void*>. +// the hash function is hash<std::string> but as a pointer when the hash +// function is hash<void*>. // #ifndef ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_ #define ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_ @@ -83,6 +83,7 @@ } }; }; + template <> struct HashEq<std::string> : StringHashEq {}; template <>
diff --git a/absl/container/internal/hash_function_defaults_test.cc b/absl/container/internal/hash_function_defaults_test.cc index 464baae..82708db 100644 --- a/absl/container/internal/hash_function_defaults_test.cc +++ b/absl/container/internal/hash_function_defaults_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -77,14 +77,14 @@ hash_default_eq<T> key_eq; }; -TYPED_TEST_CASE(EqString, StringTypes); +TYPED_TEST_SUITE(EqString, StringTypes); template <class T> struct HashString : ::testing::Test { hash_default_hash<T> hasher; }; -TYPED_TEST_CASE(HashString, StringTypes); +TYPED_TEST_SUITE(HashString, StringTypes); TYPED_TEST(EqString, Works) { auto eq = this->key_eq; @@ -121,14 +121,14 @@ hash_default_eq<T> key_eq; }; -TYPED_TEST_CASE(EqPointer, PointerTypes); +TYPED_TEST_SUITE(EqPointer, PointerTypes); template <class T> struct HashPointer : ::testing::Test { hash_default_hash<T> hasher; }; -TYPED_TEST_CASE(HashPointer, PointerTypes); +TYPED_TEST_SUITE(HashPointer, PointerTypes); TYPED_TEST(EqPointer, Works) { int dummy; @@ -202,15 +202,11 @@ EXPECT_NE(hash(&dummy), hash(cuptr)); } -// Cartesian product of (string, std::string, absl::string_view) -// with (string, std::string, absl::string_view, const char*). +// Cartesian product of (std::string, absl::string_view) +// with (std::string, absl::string_view, const char*). using StringTypesCartesianProduct = Types< // clang-format off - std::pair<std::string, std::string>, - std::pair<std::string, absl::string_view>, - std::pair<std::string, const char*>, - std::pair<absl::string_view, std::string>, std::pair<absl::string_view, absl::string_view>, std::pair<absl::string_view, const char*>>; @@ -248,7 +244,7 @@ EXPECT_NE(this->hash(this->a1), this->hash(this->b2)); } -TYPED_TEST_CASE(StringLikeTest, StringTypesCartesianProduct); +TYPED_TEST_SUITE(StringLikeTest, StringTypesCartesianProduct); } // namespace } // namespace container_internal
diff --git a/absl/container/internal/hash_generator_testing.cc b/absl/container/internal/hash_generator_testing.cc index 0d6a9df..37a23d6 100644 --- a/absl/container/internal/hash_generator_testing.cc +++ b/absl/container/internal/hash_generator_testing.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -39,9 +39,9 @@ } // namespace -std::mt19937_64* GetThreadLocalRng() { +std::mt19937_64* GetSharedRng() { RandomDeviceSeedSeq seed_seq; - thread_local auto* rng = new std::mt19937_64(seed_seq); + static auto* rng = new std::mt19937_64(seed_seq); return rng; } @@ -51,7 +51,7 @@ std::string res; res.resize(32); std::generate(res.begin(), res.end(), - [&]() { return chars(*GetThreadLocalRng()); }); + [&]() { return chars(*GetSharedRng()); }); return res; } @@ -63,7 +63,7 @@ auto& res = arena->back(); res.resize(32); std::generate(res.begin(), res.end(), - [&]() { return chars(*GetThreadLocalRng()); }); + [&]() { return chars(*GetSharedRng()); }); return res; }
diff --git a/absl/container/internal/hash_generator_testing.h b/absl/container/internal/hash_generator_testing.h index 50d7710..27fb84f 100644 --- a/absl/container/internal/hash_generator_testing.h +++ b/absl/container/internal/hash_generator_testing.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -43,7 +43,7 @@ } // namespace generator_internal -std::mt19937_64* GetThreadLocalRng(); +std::mt19937_64* GetSharedRng(); enum Enum { kEnumEmpty, @@ -66,7 +66,7 @@ struct Generator<T, typename std::enable_if<std::is_integral<T>::value>::type> { T operator()() const { std::uniform_int_distribution<T> dist; - return dist(*GetThreadLocalRng()); + return dist(*GetSharedRng()); } }; @@ -76,7 +76,7 @@ std::uniform_int_distribution<typename std::underlying_type<Enum>::type> dist; while (true) { - auto variate = dist(*GetThreadLocalRng()); + auto variate = dist(*GetSharedRng()); if (variate != kEnumEmpty && variate != kEnumDeleted) return static_cast<Enum>(variate); } @@ -90,7 +90,7 @@ typename std::underlying_type<EnumClass>::type> dist; while (true) { - EnumClass variate = static_cast<EnumClass>(dist(*GetThreadLocalRng())); + EnumClass variate = static_cast<EnumClass>(dist(*GetSharedRng())); if (variate != EnumClass::kEmpty && variate != EnumClass::kDeleted) return static_cast<EnumClass>(variate); }
diff --git a/absl/container/internal/hash_policy_testing.h b/absl/container/internal/hash_policy_testing.h index ffc76ea..c57407a 100644 --- a/absl/container/internal/hash_policy_testing.h +++ b/absl/container/internal/hash_policy_testing.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -139,7 +139,7 @@ friend bool operator!=(const Alloc& a, const Alloc& b) { return !(a == b); } private: - size_t id_ = std::numeric_limits<size_t>::max(); + size_t id_ = (std::numeric_limits<size_t>::max)(); }; template <class Map> @@ -169,7 +169,11 @@ // take allocator arguments. This test is defined ad-hoc for the platforms // we care about (notably Crosstool 17) because libstdcxx's useless // versioning scheme precludes a more principled solution. -#if defined(__GLIBCXX__) && __GLIBCXX__ <= 20140425 +// From GCC-4.9 Changelog: (src: https://gcc.gnu.org/gcc-4.9/changes.html) +// "the unordered associative containers in <unordered_map> and <unordered_set> +// meet the allocator-aware container requirements;" +#if (defined(__GLIBCXX__) && __GLIBCXX__ <= 20140425 ) || \ +( __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 9 )) #define ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS 0 #else #define ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS 1
diff --git a/absl/container/internal/hash_policy_testing_test.cc b/absl/container/internal/hash_policy_testing_test.cc index c215c42..0c95eb5 100644 --- a/absl/container/internal/hash_policy_testing_test.cc +++ b/absl/container/internal/hash_policy_testing_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/container/internal/hash_policy_traits.h b/absl/container/internal/hash_policy_traits.h index 029e47e..fd007de 100644 --- a/absl/container/internal/hash_policy_traits.h +++ b/absl/container/internal/hash_policy_traits.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -84,7 +84,7 @@ } // Transfers the `old_slot` to `new_slot`. Any memory allocated by the - // allocator inside `old_slot` to `new_slot` can be transfered. + // allocator inside `old_slot` to `new_slot` can be transferred. // // OPTIONAL: defaults to: //
diff --git a/absl/container/internal/hash_policy_traits_test.cc b/absl/container/internal/hash_policy_traits_test.cc index 423f154..e643d18 100644 --- a/absl/container/internal/hash_policy_traits_test.cc +++ b/absl/container/internal/hash_policy_traits_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/container/internal/hashtable_debug.h b/absl/container/internal/hashtable_debug.h index c3bd65c..7193000 100644 --- a/absl/container/internal/hashtable_debug.h +++ b/absl/container/internal/hashtable_debug.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -60,7 +60,7 @@ size_t num_probes = GetHashtableDebugNumProbes( container, absl::container_internal::hashtable_debug_internal::GetKey<C>(*it, 0)); - v.resize(std::max(v.size(), num_probes + 1)); + v.resize((std::max)(v.size(), num_probes + 1)); v[num_probes]++; } return v;
diff --git a/absl/container/internal/hashtable_debug_hooks.h b/absl/container/internal/hashtable_debug_hooks.h index 8f21972..371ce81 100644 --- a/absl/container/internal/hashtable_debug_hooks.h +++ b/absl/container/internal/hashtable_debug_hooks.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/container/internal/hashtablez_sampler.cc b/absl/container/internal/hashtablez_sampler.cc new file mode 100644 index 0000000..6667d3a --- /dev/null +++ b/absl/container/internal/hashtablez_sampler.cc
@@ -0,0 +1,308 @@ +// 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/hashtablez_sampler.h" + +#include <atomic> +#include <cassert> +#include <cmath> +#include <functional> +#include <limits> + +#include "absl/base/attributes.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 { +namespace container_internal { +constexpr int HashtablezInfo::kMaxStackDepth; + +namespace { +ABSL_CONST_INIT std::atomic<bool> g_hashtablez_enabled{ + false +}; +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); +} + +} // namespace + +HashtablezSampler& HashtablezSampler::Global() { + static auto* sampler = new HashtablezSampler(); + return *sampler; +} + +HashtablezSampler::DisposeCallback HashtablezSampler::SetDisposeCallback( + DisposeCallback f) { + return dispose_.exchange(f, std::memory_order_relaxed); +} + +HashtablezInfo::HashtablezInfo() { PrepareForSampling(); } +HashtablezInfo::~HashtablezInfo() = default; + +void HashtablezInfo::PrepareForSampling() { + capacity.store(0, std::memory_order_relaxed); + size.store(0, std::memory_order_relaxed); + num_erases.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); + hashes_bitwise_and.store(~size_t{}, std::memory_order_relaxed); + + create_time = absl::Now(); + // The inliner makes hardcoded skip_count difficult (especially when combined + // with LTO). We use the ability to exclude stacks by regex when encoding + // instead. + depth = absl::GetStackTrace(stack, HashtablezInfo::kMaxStackDepth, + /* skip_count= */ 0); + dead = nullptr; +} + +HashtablezSampler::HashtablezSampler() + : dropped_samples_(0), size_estimate_(0), all_(nullptr), dispose_(nullptr) { + absl::MutexLock l(&graveyard_.init_mu); + graveyard_.dead = &graveyard_; +} + +HashtablezSampler::~HashtablezSampler() { + HashtablezInfo* s = all_.load(std::memory_order_acquire); + while (s != nullptr) { + HashtablezInfo* next = s->next; + delete s; + s = next; + } +} + +void HashtablezSampler::PushNew(HashtablezInfo* sample) { + sample->next = all_.load(std::memory_order_relaxed); + while (!all_.compare_exchange_weak(sample->next, sample, + std::memory_order_release, + std::memory_order_relaxed)) { + } +} + +void HashtablezSampler::PushDead(HashtablezInfo* sample) { + if (auto* dispose = dispose_.load(std::memory_order_relaxed)) { + dispose(*sample); + } + + absl::MutexLock graveyard_lock(&graveyard_.init_mu); + absl::MutexLock sample_lock(&sample->init_mu); + sample->dead = graveyard_.dead; + graveyard_.dead = sample; +} + +HashtablezInfo* HashtablezSampler::PopDead() { + absl::MutexLock graveyard_lock(&graveyard_.init_mu); + + // The list is circular, so eventually it collapses down to + // graveyard_.dead == &graveyard_ + // when it is empty. + HashtablezInfo* sample = graveyard_.dead; + if (sample == &graveyard_) return nullptr; + + absl::MutexLock sample_lock(&sample->init_mu); + graveyard_.dead = sample->dead; + sample->PrepareForSampling(); + return sample; +} + +HashtablezInfo* HashtablezSampler::Register() { + int64_t size = size_estimate_.fetch_add(1, std::memory_order_relaxed); + if (size > g_hashtablez_max_samples.load(std::memory_order_relaxed)) { + size_estimate_.fetch_sub(1, std::memory_order_relaxed); + dropped_samples_.fetch_add(1, std::memory_order_relaxed); + return nullptr; + } + + HashtablezInfo* sample = PopDead(); + if (sample == nullptr) { + // Resurrection failed. Hire a new warlock. + sample = new HashtablezInfo(); + PushNew(sample); + } + + return sample; +} + +void HashtablezSampler::Unregister(HashtablezInfo* sample) { + PushDead(sample); + size_estimate_.fetch_sub(1, std::memory_order_relaxed); +} + +int64_t HashtablezSampler::Iterate( + const std::function<void(const HashtablezInfo& stack)>& f) { + HashtablezInfo* s = all_.load(std::memory_order_acquire); + while (s != nullptr) { + absl::MutexLock l(&s->init_mu); + if (s->dead == nullptr) { + f(*s); + } + s = s->next; + } + + return dropped_samples_.load(std::memory_order_relaxed); +} + +HashtablezInfo* SampleSlow(int64_t* next_sample) { + if (kAbslContainerInternalSampleEverything) { + *next_sample = 1; + return HashtablezSampler::Global().Register(); + } + + bool first = *next_sample < 0; + *next_sample = GetGeometricVariable( + g_hashtablez_sample_parameter.load(std::memory_order_relaxed)); + + // 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 + // the default sampling rate. + if (!g_hashtablez_enabled.load(std::memory_order_relaxed)) return nullptr; + + // We will only be negative on our first count, so we should just retry in + // that case. + if (first) { + if (ABSL_PREDICT_TRUE(--*next_sample > 0)) return nullptr; + return SampleSlow(next_sample); + } + + return HashtablezSampler::Global().Register(); +} + +#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); +} + +void RecordInsertSlow(HashtablezInfo* info, size_t hash, + size_t distance_from_desired) { + // 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 + probe_length /= 16; +#else + probe_length /= 8; +#endif + + info->hashes_bitwise_and.fetch_and(hash, std::memory_order_relaxed); + info->hashes_bitwise_or.fetch_or(hash, std::memory_order_relaxed); + info->max_probe_length.store( + std::max(info->max_probe_length.load(std::memory_order_relaxed), + probe_length), + std::memory_order_relaxed); + info->total_probe_length.fetch_add(probe_length, std::memory_order_relaxed); + info->size.fetch_add(1, std::memory_order_relaxed); +} + +void SetHashtablezEnabled(bool enabled) { + g_hashtablez_enabled.store(enabled, std::memory_order_release); +} + +void SetHashtablezSampleParameter(int32_t rate) { + if (rate > 0) { + g_hashtablez_sample_parameter.store(rate, std::memory_order_release); + } else { + ABSL_RAW_LOG(ERROR, "Invalid hashtablez sample rate: %lld", + static_cast<long long>(rate)); // NOLINT(runtime/int) + } +} + +void SetHashtablezMaxSamples(int32_t max) { + if (max > 0) { + g_hashtablez_max_samples.store(max, std::memory_order_release); + } else { + ABSL_RAW_LOG(ERROR, "Invalid hashtablez max samples: %lld", + static_cast<long long>(max)); // NOLINT(runtime/int) + } +} + +} // namespace container_internal +} // namespace absl
diff --git a/absl/container/internal/hashtablez_sampler.h b/absl/container/internal/hashtablez_sampler.h new file mode 100644 index 0000000..a308e78 --- /dev/null +++ b/absl/container/internal/hashtablez_sampler.h
@@ -0,0 +1,288 @@ +// 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: hashtablez_sampler.h +// ----------------------------------------------------------------------------- +// +// This header file defines the API for a low level library to sample hashtables +// and collect runtime statistics about them. +// +// `HashtablezSampler` controls the lifecycle of `HashtablezInfo` objects which +// store information about a single sample. +// +// `Record*` methods store information into samples. +// `Sample()` and `Unsample()` make use of a single global sampler with +// properties controlled by the flags hashtablez_enabled, +// hashtablez_sample_rate, and hashtablez_max_samples. +// +// WARNING +// +// Using this sampling API may cause sampled Swiss tables to use the global +// allocator (operator `new`) in addition to any custom allocator. If you +// are using a table in an unusual circumstance where allocation or calling a +// linux syscall is unacceptable, this could interfere. +// +// This utility is internal-only. Use at your own risk. + +#ifndef ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_ +#define ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_ + +#include <atomic> +#include <functional> +#include <memory> +#include <vector> + +#include "absl/base/internal/per_thread_tls.h" +#include "absl/base/optimization.h" +#include "absl/container/internal/have_sse.h" +#include "absl/synchronization/mutex.h" +#include "absl/utility/utility.h" + +namespace absl { +namespace container_internal { + +// Stores information about a sampled hashtable. All mutations to this *must* +// be made through `Record*` functions below. All reads from this *must* only +// occur in the callback to `HashtablezSampler::Iterate`. +struct HashtablezInfo { + // Constructs the object but does not fill in any fields. + HashtablezInfo(); + ~HashtablezInfo(); + HashtablezInfo(const HashtablezInfo&) = delete; + HashtablezInfo& operator=(const HashtablezInfo&) = delete; + + // Puts the object into a clean state, fills in the logically `const` members, + // blocking for any readers that are currently sampling the object. + void PrepareForSampling() EXCLUSIVE_LOCKS_REQUIRED(init_mu); + + // These fields are mutated by the various Record* APIs and need to be + // thread-safe. + std::atomic<size_t> capacity; + std::atomic<size_t> size; + std::atomic<size_t> num_erases; + std::atomic<size_t> max_probe_length; + std::atomic<size_t> total_probe_length; + std::atomic<size_t> hashes_bitwise_or; + std::atomic<size_t> hashes_bitwise_and; + + // `HashtablezSampler` maintains intrusive linked lists for all samples. See + // comments on `HashtablezSampler::all_` for details on these. `init_mu` + // guards the ability to restore the sample to a pristine state. This + // prevents races with sampling and resurrecting an object. + absl::Mutex init_mu; + HashtablezInfo* next; + HashtablezInfo* dead GUARDED_BY(init_mu); + + // All of the fields below are set by `PrepareForSampling`, they must not be + // mutated in `Record*` functions. They are logically `const` in that sense. + // These are guarded by init_mu, but that is not externalized to clients, who + // can only read them during `HashtablezSampler::Iterate` which will hold the + // lock. + static constexpr int kMaxStackDepth = 64; + absl::Time create_time; + int32_t depth; + void* stack[kMaxStackDepth]; +}; + +inline void RecordRehashSlow(HashtablezInfo* info, size_t total_probe_length) { +#if SWISSTABLE_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); +} + +inline void RecordStorageChangedSlow(HashtablezInfo* info, size_t size, + size_t capacity) { + info->size.store(size, std::memory_order_relaxed); + info->capacity.store(capacity, std::memory_order_relaxed); + if (size == 0) { + // This is a clear, reset the total/num_erases too. + RecordRehashSlow(info, 0); + } +} + +void RecordInsertSlow(HashtablezInfo* info, size_t hash, + size_t distance_from_desired); + +inline void RecordEraseSlow(HashtablezInfo* info) { + info->size.fetch_sub(1, std::memory_order_relaxed); + info->num_erases.fetch_add(1, std::memory_order_relaxed); +} + +HashtablezInfo* SampleSlow(int64_t* next_sample); +void UnsampleSlow(HashtablezInfo* info); + +class HashtablezInfoHandle { + public: + explicit HashtablezInfoHandle() : info_(nullptr) {} + explicit HashtablezInfoHandle(HashtablezInfo* info) : info_(info) {} + ~HashtablezInfoHandle() { + if (ABSL_PREDICT_TRUE(info_ == nullptr)) return; + UnsampleSlow(info_); + } + + HashtablezInfoHandle(const HashtablezInfoHandle&) = delete; + HashtablezInfoHandle& operator=(const HashtablezInfoHandle&) = delete; + + HashtablezInfoHandle(HashtablezInfoHandle&& o) noexcept + : info_(absl::exchange(o.info_, nullptr)) {} + HashtablezInfoHandle& operator=(HashtablezInfoHandle&& o) noexcept { + if (ABSL_PREDICT_FALSE(info_ != nullptr)) { + UnsampleSlow(info_); + } + info_ = absl::exchange(o.info_, nullptr); + return *this; + } + + inline void RecordStorageChanged(size_t size, size_t capacity) { + if (ABSL_PREDICT_TRUE(info_ == nullptr)) return; + RecordStorageChangedSlow(info_, size, capacity); + } + + inline void RecordRehash(size_t total_probe_length) { + if (ABSL_PREDICT_TRUE(info_ == nullptr)) return; + RecordRehashSlow(info_, total_probe_length); + } + + inline void RecordInsert(size_t hash, size_t distance_from_desired) { + if (ABSL_PREDICT_TRUE(info_ == nullptr)) return; + RecordInsertSlow(info_, hash, distance_from_desired); + } + + inline void RecordErase() { + if (ABSL_PREDICT_TRUE(info_ == nullptr)) return; + RecordEraseSlow(info_); + } + + friend inline void swap(HashtablezInfoHandle& lhs, + HashtablezInfoHandle& rhs) { + std::swap(lhs.info_, rhs.info_); + } + + private: + friend class HashtablezInfoHandlePeer; + HashtablezInfo* info_; +}; + +#if ABSL_PER_THREAD_TLS == 1 +extern ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample; +#endif // ABSL_PER_THREAD_TLS + +// Returns an RAII sampling handle that manages registration and unregistation +// with the global sampler. +inline HashtablezInfoHandle Sample() { +#if ABSL_PER_THREAD_TLS == 0 + static auto* mu = new absl::Mutex; + static int64_t global_next_sample = 0; + absl::MutexLock l(mu); +#endif // !ABSL_HAVE_THREAD_LOCAL + + if (ABSL_PREDICT_TRUE(--global_next_sample > 0)) { + return HashtablezInfoHandle(nullptr); + } + return HashtablezInfoHandle(SampleSlow(&global_next_sample)); +} + +// Holds samples and their associated stack traces with a soft limit of +// `SetHashtablezMaxSamples()`. +// +// Thread safe. +class HashtablezSampler { + public: + // Returns a global Sampler. + static HashtablezSampler& Global(); + + HashtablezSampler(); + ~HashtablezSampler(); + + // Registers for sampling. Returns an opaque registration info. + HashtablezInfo* Register(); + + // Unregisters the sample. + void Unregister(HashtablezInfo* sample); + + // The dispose callback will be called on all samples the moment they are + // being unregistered. Only affects samples that are unregistered after the + // callback has been set. + // Returns the previous callback. + using DisposeCallback = void (*)(const HashtablezInfo&); + DisposeCallback SetDisposeCallback(DisposeCallback f); + + // Iterates over all the registered `StackInfo`s. Returning the number of + // samples that have been dropped. + int64_t Iterate(const std::function<void(const HashtablezInfo& stack)>& f); + + private: + void PushNew(HashtablezInfo* sample); + void PushDead(HashtablezInfo* sample); + HashtablezInfo* PopDead(); + + std::atomic<size_t> dropped_samples_; + std::atomic<size_t> size_estimate_; + + // Intrusive lock free linked lists for tracking samples. + // + // `all_` records all samples (they are never removed from this list) and is + // terminated with a `nullptr`. + // + // `graveyard_.dead` is a circular linked list. When it is empty, + // `graveyard_.dead == &graveyard`. The list is circular so that + // every item on it (even the last) has a non-null dead pointer. This allows + // `Iterate` to determine if a given sample is live or dead using only + // information on the sample itself. + // + // For example, nodes [A, B, C, D, E] with [A, C, E] alive and [B, D] dead + // looks like this (G is the Graveyard): + // + // +---+ +---+ +---+ +---+ +---+ + // all -->| A |--->| B |--->| C |--->| D |--->| E | + // | | | | | | | | | | + // +---+ | | +->| |-+ | | +->| |-+ | | + // | G | +---+ | +---+ | +---+ | +---+ | +---+ + // | | | | | | + // | | --------+ +--------+ | + // +---+ | + // ^ | + // +--------------------------------------+ + // + std::atomic<HashtablezInfo*> all_; + HashtablezInfo graveyard_; + + std::atomic<DisposeCallback> dispose_; +}; + +// Enables or disables sampling for Swiss tables. +void SetHashtablezEnabled(bool enabled); + +// Sets the rate at which Swiss tables will be sampled. +void SetHashtablezSampleParameter(int32_t rate); + +// Sets a soft max for the number of samples that will be kept. +void SetHashtablezMaxSamples(int32_t max); + +// Configuration override. +// This allows process-wide sampling without depending on order of +// 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; + +} // namespace container_internal +} // namespace absl + +#endif // ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
diff --git a/absl/container/internal/hashtablez_sampler_force_weak_definition.cc b/absl/container/internal/hashtablez_sampler_force_weak_definition.cc new file mode 100644 index 0000000..4ca6ffd --- /dev/null +++ b/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
@@ -0,0 +1,27 @@ +// 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/hashtablez_sampler.h" + +#include "absl/base/attributes.h" + +namespace absl { +namespace container_internal { + +// See hashtablez_sampler.h for details. +extern "C" ABSL_ATTRIBUTE_WEAK const bool + kAbslContainerInternalSampleEverything = false; + +} // namespace container_internal +} // namespace absl
diff --git a/absl/container/internal/hashtablez_sampler_test.cc b/absl/container/internal/hashtablez_sampler_test.cc new file mode 100644 index 0000000..d2435ed --- /dev/null +++ b/absl/container/internal/hashtablez_sampler_test.cc
@@ -0,0 +1,355 @@ +// 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/hashtablez_sampler.h" + +#include <atomic> +#include <limits> +#include <random> + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/base/attributes.h" +#include "absl/container/internal/have_sse.h" +#include "absl/synchronization/blocking_counter.h" +#include "absl/synchronization/internal/thread_pool.h" +#include "absl/synchronization/mutex.h" +#include "absl/synchronization/notification.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" + +#if SWISSTABLE_HAVE_SSE2 +constexpr int kProbeLength = 16; +#else +constexpr int kProbeLength = 8; +#endif + +namespace absl { +namespace container_internal { +class HashtablezInfoHandlePeer { + public: + static bool IsSampled(const HashtablezInfoHandle& h) { + return h.info_ != nullptr; + } + + static HashtablezInfo* GetInfo(HashtablezInfoHandle* h) { return h->info_; } +}; + +namespace { +using ::absl::synchronization_internal::ThreadPool; +using ::testing::IsEmpty; +using ::testing::UnorderedElementsAre; + +std::vector<size_t> GetSizes(HashtablezSampler* s) { + std::vector<size_t> res; + s->Iterate([&](const HashtablezInfo& info) { + res.push_back(info.size.load(std::memory_order_acquire)); + }); + return res; +} + +HashtablezInfo* Register(HashtablezSampler* s, size_t size) { + auto* info = s->Register(); + assert(info != nullptr); + info->size.store(size); + return info; +} + +TEST(HashtablezInfoTest, PrepareForSampling) { + absl::Time test_start = absl::Now(); + HashtablezInfo info; + absl::MutexLock l(&info.init_mu); + info.PrepareForSampling(); + + EXPECT_EQ(info.capacity.load(), 0); + EXPECT_EQ(info.size.load(), 0); + EXPECT_EQ(info.num_erases.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); + EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{}); + EXPECT_GE(info.create_time, test_start); + + info.capacity.store(1, std::memory_order_relaxed); + info.size.store(1, std::memory_order_relaxed); + info.num_erases.store(1, std::memory_order_relaxed); + info.max_probe_length.store(1, std::memory_order_relaxed); + info.total_probe_length.store(1, std::memory_order_relaxed); + info.hashes_bitwise_or.store(1, std::memory_order_relaxed); + info.hashes_bitwise_and.store(1, std::memory_order_relaxed); + info.create_time = test_start - absl::Hours(20); + + info.PrepareForSampling(); + EXPECT_EQ(info.capacity.load(), 0); + EXPECT_EQ(info.size.load(), 0); + EXPECT_EQ(info.num_erases.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); + EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{}); + EXPECT_GE(info.create_time, test_start); +} + +TEST(HashtablezInfoTest, RecordStorageChanged) { + HashtablezInfo info; + absl::MutexLock l(&info.init_mu); + info.PrepareForSampling(); + RecordStorageChangedSlow(&info, 17, 47); + EXPECT_EQ(info.size.load(), 17); + EXPECT_EQ(info.capacity.load(), 47); + RecordStorageChangedSlow(&info, 20, 20); + EXPECT_EQ(info.size.load(), 20); + EXPECT_EQ(info.capacity.load(), 20); +} + +TEST(HashtablezInfoTest, RecordInsert) { + HashtablezInfo info; + absl::MutexLock l(&info.init_mu); + info.PrepareForSampling(); + EXPECT_EQ(info.max_probe_length.load(), 0); + RecordInsertSlow(&info, 0x0000FF00, 6 * kProbeLength); + EXPECT_EQ(info.max_probe_length.load(), 6); + EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000FF00); + EXPECT_EQ(info.hashes_bitwise_or.load(), 0x0000FF00); + RecordInsertSlow(&info, 0x000FF000, 4 * kProbeLength); + EXPECT_EQ(info.max_probe_length.load(), 6); + EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000F000); + EXPECT_EQ(info.hashes_bitwise_or.load(), 0x000FFF00); + RecordInsertSlow(&info, 0x00FF0000, 12 * kProbeLength); + EXPECT_EQ(info.max_probe_length.load(), 12); + EXPECT_EQ(info.hashes_bitwise_and.load(), 0x00000000); + EXPECT_EQ(info.hashes_bitwise_or.load(), 0x00FFFF00); +} + +TEST(HashtablezInfoTest, RecordErase) { + HashtablezInfo info; + absl::MutexLock l(&info.init_mu); + info.PrepareForSampling(); + EXPECT_EQ(info.num_erases.load(), 0); + EXPECT_EQ(info.size.load(), 0); + RecordInsertSlow(&info, 0x0000FF00, 6 * kProbeLength); + EXPECT_EQ(info.size.load(), 1); + RecordEraseSlow(&info); + EXPECT_EQ(info.size.load(), 0); + EXPECT_EQ(info.num_erases.load(), 1); +} + +TEST(HashtablezInfoTest, RecordRehash) { + HashtablezInfo info; + absl::MutexLock l(&info.init_mu); + info.PrepareForSampling(); + RecordInsertSlow(&info, 0x1, 0); + RecordInsertSlow(&info, 0x2, kProbeLength); + RecordInsertSlow(&info, 0x4, kProbeLength); + RecordInsertSlow(&info, 0x8, 2 * kProbeLength); + EXPECT_EQ(info.size.load(), 4); + EXPECT_EQ(info.total_probe_length.load(), 4); + + RecordEraseSlow(&info); + RecordEraseSlow(&info); + EXPECT_EQ(info.size.load(), 2); + EXPECT_EQ(info.total_probe_length.load(), 4); + EXPECT_EQ(info.num_erases.load(), 2); + + RecordRehashSlow(&info, 3 * kProbeLength); + EXPECT_EQ(info.size.load(), 2); + EXPECT_EQ(info.total_probe_length.load(), 3); + EXPECT_EQ(info.num_erases.load(), 0); +} + +TEST(HashtablezSamplerTest, SmallSampleParameter) { + SetHashtablezEnabled(true); + SetHashtablezSampleParameter(100); + + for (int i = 0; i < 1000; ++i) { + int64_t next_sample = 0; + HashtablezInfo* sample = SampleSlow(&next_sample); + EXPECT_GT(next_sample, 0); + EXPECT_NE(sample, nullptr); + UnsampleSlow(sample); + } +} + +TEST(HashtablezSamplerTest, LargeSampleParameter) { + SetHashtablezEnabled(true); + SetHashtablezSampleParameter(std::numeric_limits<int32_t>::max()); + + for (int i = 0; i < 1000; ++i) { + int64_t next_sample = 0; + HashtablezInfo* sample = SampleSlow(&next_sample); + EXPECT_GT(next_sample, 0); + EXPECT_NE(sample, nullptr); + UnsampleSlow(sample); + } +} + +TEST(HashtablezSamplerTest, Sample) { + SetHashtablezEnabled(true); + SetHashtablezSampleParameter(100); + int64_t num_sampled = 0; + int64_t total = 0; + double sample_rate; + for (int i = 0; i < 1000000; ++i) { + HashtablezInfoHandle h = Sample(); + ++total; + if (HashtablezInfoHandlePeer::IsSampled(h)) { + ++num_sampled; + } + sample_rate = static_cast<double>(num_sampled) / total; + if (0.005 < sample_rate && sample_rate < 0.015) break; + } + EXPECT_NEAR(sample_rate, 0.01, 0.005); +} + +TEST(HashtablezSamplerTest, Handle) { + auto& sampler = HashtablezSampler::Global(); + HashtablezInfoHandle h(sampler.Register()); + auto* info = HashtablezInfoHandlePeer::GetInfo(&h); + info->hashes_bitwise_and.store(0x12345678, std::memory_order_relaxed); + + bool found = false; + sampler.Iterate([&](const HashtablezInfo& h) { + if (&h == info) { + EXPECT_EQ(h.hashes_bitwise_and.load(), 0x12345678); + found = true; + } + }); + EXPECT_TRUE(found); + + h = HashtablezInfoHandle(); + found = false; + sampler.Iterate([&](const HashtablezInfo& h) { + if (&h == info) { + // this will only happen if some other thread has resurrected the info + // the old handle was using. + if (h.hashes_bitwise_and.load() == 0x12345678) { + found = true; + } + } + }); + EXPECT_FALSE(found); +} + +TEST(HashtablezSamplerTest, Registration) { + HashtablezSampler sampler; + auto* info1 = Register(&sampler, 1); + EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(1)); + + auto* info2 = Register(&sampler, 2); + EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(1, 2)); + info1->size.store(3); + EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(3, 2)); + + sampler.Unregister(info1); + sampler.Unregister(info2); +} + +TEST(HashtablezSamplerTest, Unregistration) { + HashtablezSampler sampler; + std::vector<HashtablezInfo*> infos; + for (size_t i = 0; i < 3; ++i) { + infos.push_back(Register(&sampler, i)); + } + EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(0, 1, 2)); + + sampler.Unregister(infos[1]); + EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(0, 2)); + + infos.push_back(Register(&sampler, 3)); + infos.push_back(Register(&sampler, 4)); + EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(0, 2, 3, 4)); + sampler.Unregister(infos[3]); + EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(0, 2, 4)); + + sampler.Unregister(infos[0]); + sampler.Unregister(infos[2]); + sampler.Unregister(infos[4]); + EXPECT_THAT(GetSizes(&sampler), IsEmpty()); +} + +TEST(HashtablezSamplerTest, MultiThreaded) { + HashtablezSampler sampler; + Notification stop; + ThreadPool pool(10); + + for (int i = 0; i < 10; ++i) { + pool.Schedule([&sampler, &stop]() { + std::random_device rd; + std::mt19937 gen(rd()); + + std::vector<HashtablezInfo*> infoz; + while (!stop.HasBeenNotified()) { + if (infoz.empty()) { + infoz.push_back(sampler.Register()); + } + switch (std::uniform_int_distribution<>(0, 2)(gen)) { + case 0: { + infoz.push_back(sampler.Register()); + break; + } + case 1: { + size_t p = + std::uniform_int_distribution<>(0, infoz.size() - 1)(gen); + HashtablezInfo* info = infoz[p]; + infoz[p] = infoz.back(); + infoz.pop_back(); + sampler.Unregister(info); + break; + } + case 2: { + absl::Duration oldest = absl::ZeroDuration(); + sampler.Iterate([&](const HashtablezInfo& info) { + oldest = std::max(oldest, absl::Now() - info.create_time); + }); + ASSERT_GE(oldest, absl::ZeroDuration()); + break; + } + } + } + }); + } + // The threads will hammer away. Give it a little bit of time for tsan to + // spot errors. + absl::SleepFor(absl::Seconds(3)); + stop.Notify(); +} + +TEST(HashtablezSamplerTest, Callback) { + HashtablezSampler sampler; + + auto* info1 = Register(&sampler, 1); + auto* info2 = Register(&sampler, 2); + + static const HashtablezInfo* expected; + + auto callback = [](const HashtablezInfo& info) { + // We can't use `info` outside of this callback because the object will be + // disposed as soon as we return from here. + EXPECT_EQ(&info, expected); + }; + + // Set the callback. + EXPECT_EQ(sampler.SetDisposeCallback(callback), nullptr); + expected = info1; + sampler.Unregister(info1); + + // Unset the callback. + EXPECT_EQ(callback, sampler.SetDisposeCallback(nullptr)); + expected = nullptr; // no more calls. + sampler.Unregister(info2); +} + +} // namespace +} // namespace container_internal +} // namespace absl
diff --git a/absl/container/internal/have_sse.h b/absl/container/internal/have_sse.h new file mode 100644 index 0000000..4341441 --- /dev/null +++ b/absl/container/internal/have_sse.h
@@ -0,0 +1,49 @@ +// 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. +// +// Shared config probing for SSE instructions used in Swiss tables. +#ifndef ABSL_CONTAINER_INTERNAL_HAVE_SSE_H_ +#define ABSL_CONTAINER_INTERNAL_HAVE_SSE_H_ + +#ifndef SWISSTABLE_HAVE_SSE2 +#if defined(__SSE2__) || \ + (defined(_MSC_VER) && \ + (defined(_M_X64) || (defined(_M_IX86) && _M_IX86_FP >= 2))) +#define SWISSTABLE_HAVE_SSE2 1 +#else +#define SWISSTABLE_HAVE_SSE2 0 +#endif +#endif + +#ifndef SWISSTABLE_HAVE_SSSE3 +#ifdef __SSSE3__ +#define SWISSTABLE_HAVE_SSSE3 1 +#else +#define SWISSTABLE_HAVE_SSSE3 0 +#endif +#endif + +#if SWISSTABLE_HAVE_SSSE3 && !SWISSTABLE_HAVE_SSE2 +#error "Bad configuration!" +#endif + +#if SWISSTABLE_HAVE_SSE2 +#include <emmintrin.h> +#endif + +#if SWISSTABLE_HAVE_SSSE3 +#include <tmmintrin.h> +#endif + +#endif // ABSL_CONTAINER_INTERNAL_HAVE_SSE_H_
diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h new file mode 100644 index 0000000..24059d9 --- /dev/null +++ b/absl/container/internal/inlined_vector.h
@@ -0,0 +1,126 @@ +// 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_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_ +#define ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_ + +#include <cstddef> +#include <iterator> +#include <memory> + +#include "absl/meta/type_traits.h" + +namespace absl { +namespace inlined_vector_internal { + +template <typename InlinedVector> +class Storage; + +template <template <typename, size_t, typename> class InlinedVector, typename T, + size_t N, typename A> +class Storage<InlinedVector<T, N, A>> { + public: + using allocator_type = A; + using value_type = typename allocator_type::value_type; + using pointer = typename allocator_type::pointer; + using const_pointer = typename allocator_type::const_pointer; + using reference = typename allocator_type::reference; + using const_reference = typename allocator_type::const_reference; + using rvalue_reference = typename allocator_type::value_type&&; + using size_type = typename allocator_type::size_type; + using difference_type = typename allocator_type::difference_type; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + + explicit Storage(const allocator_type& a) : allocator_and_tag_(a) {} + + // TODO(johnsoncj): Make the below types and members private after migration + + // Holds whether the vector is allocated or not in the lowest bit and the size + // in the high bits: + // `size_ = (size << 1) | is_allocated;` + class Tag { + size_type size_; + + public: + Tag() : size_(0) {} + size_type size() const { return size_ / 2; } + void add_size(size_type n) { size_ += n * 2; } + void set_inline_size(size_type n) { size_ = n * 2; } + void set_allocated_size(size_type n) { size_ = (n * 2) + 1; } + bool allocated() const { return size_ % 2; } + }; + + // Derives from `allocator_type` to use the empty base class optimization. + // If the `allocator_type` is stateless, we can store our instance for free. + class AllocatorAndTag : private allocator_type { + Tag tag_; + + public: + explicit AllocatorAndTag(const allocator_type& a) : allocator_type(a) {} + Tag& tag() { return tag_; } + const Tag& tag() const { return tag_; } + allocator_type& allocator() { return *this; } + const allocator_type& allocator() const { return *this; } + }; + + class Allocation { + size_type capacity_; + pointer buffer_; + + public: + Allocation(allocator_type& a, size_type capacity) + : capacity_(capacity), buffer_(Create(a, capacity)) {} + void Dealloc(allocator_type& a) { + std::allocator_traits<allocator_type>::deallocate(a, buffer_, capacity_); + } + size_type capacity() const { return capacity_; } + const_pointer buffer() const { return buffer_; } + pointer buffer() { return buffer_; } + static pointer Create(allocator_type& a, size_type n) { + return std::allocator_traits<allocator_type>::allocate(a, n); + } + }; + + // Stores either the inlined or allocated representation + union Rep { + using ValueTypeBuffer = + absl::aligned_storage_t<sizeof(value_type), alignof(value_type)>; + using AllocationBuffer = + absl::aligned_storage_t<sizeof(Allocation), alignof(Allocation)>; + + // Structs wrap the buffers to perform indirection that solves a bizarre + // compilation error on Visual Studio (all known versions). + struct InlinedRep { + ValueTypeBuffer inlined[N]; + }; + + struct AllocatedRep { + AllocationBuffer allocation; + }; + + InlinedRep inlined_storage; + AllocatedRep allocation_storage; + }; + + AllocatorAndTag allocator_and_tag_; + Rep rep_; +}; + +} // namespace inlined_vector_internal +} // namespace absl + +#endif // ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_
diff --git a/absl/container/internal/layout.h b/absl/container/internal/layout.h index 676c7d6..bbdde50 100644 --- a/absl/container/internal/layout.h +++ b/absl/container/internal/layout.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -232,13 +232,17 @@ template <class T, size_t N> struct SizeOf<Aligned<T, N>> : std::integral_constant<size_t, sizeof(T)> {}; +// Note: workaround for https://gcc.gnu.org/PR88115 template <class T> -struct AlignOf : NotAligned<T>, std::integral_constant<size_t, alignof(T)> {}; +struct AlignOf : NotAligned<T> { + static constexpr size_t value = alignof(T); +}; template <class T, size_t N> -struct AlignOf<Aligned<T, N>> : std::integral_constant<size_t, N> { +struct AlignOf<Aligned<T, N>> { static_assert(N % alignof(T) == 0, "Custom alignment can't be lower than the type's alignment"); + static constexpr size_t value = N; }; // Does `Ts...` contain `T`? @@ -249,8 +253,10 @@ using CopyConst = typename std::conditional<std::is_const<From>::value, const To, To>::type; +// Note: We're not qualifying this with absl:: because it doesn't compile under +// MSVC. template <class T> -using SliceType = absl::Span<T>; +using SliceType = Span<T>; // This namespace contains no types. It prevents functions defined in it from // being found by ADL. @@ -290,7 +296,7 @@ #ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE demangled = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status); #endif - if (status == 0 && demangled != nullptr) { // Demangling succeeeded. + if (status == 0 && demangled != nullptr) { // Demangling succeeded. absl::StrAppend(&out, "<", demangled, ">"); free(demangled); } else { @@ -396,7 +402,7 @@ static_assert(N < NumOffsets, "Index out of bounds"); return adl_barrier::Align( Offset<N - 1>() + SizeOf<ElementType<N - 1>>() * size_[N - 1], - ElementAlignment<N>()); + ElementAlignment<N>::value); } // Offset in bytes of the array with the specified element type. There must @@ -445,7 +451,7 @@ return Size<ElementIndex<T>()>(); } - // The number of elements of all arrays for which they are known. + // The number of elements of all arrays for which they are known. constexpr std::array<size_t, NumSizes> Sizes() const { return {{Size<SizeSeq>()...}}; } @@ -610,7 +616,7 @@ #ifdef ADDRESS_SANITIZER PoisonPadding<Char, N - 1>(p); // The `if` is an optimization. It doesn't affect the observable behaviour. - if (ElementAlignment<N - 1>() % ElementAlignment<N>()) { + if (ElementAlignment<N - 1>::value % ElementAlignment<N>::value) { size_t start = Offset<N - 1>() + SizeOf<ElementType<N - 1>>() * size_[N - 1]; ASAN_POISON_MEMORY_REGION(p + start, Offset<N>() - start); @@ -637,7 +643,8 @@ std::string DebugString() const { const auto offsets = Offsets(); const size_t sizes[] = {SizeOf<ElementType<OffsetSeq>>()...}; - const std::string types[] = {adl_barrier::TypeName<ElementType<OffsetSeq>>()...}; + const std::string types[] = { + adl_barrier::TypeName<ElementType<OffsetSeq>>()...}; std::string res = absl::StrCat("@0", types[0], "(", sizes[0], ")"); for (size_t i = 0; i != NumOffsets - 1; ++i) { absl::StrAppend(&res, "[", size_[i], "]; @", offsets[i + 1], types[i + 1], @@ -690,7 +697,7 @@ // // It's allowed to pass fewer array sizes than the number of arrays. E.g., // if all you need is to the offset of the second array, you only need to - // pass one argument -- the number of elements in the first arrays. + // pass one argument -- the number of elements in the first array. // // // int[3] followed by 4 bytes of padding and an unknown number of // // doubles.
diff --git a/absl/container/internal/layout_test.cc b/absl/container/internal/layout_test.cc index f35157a..33b72bd 100644 --- a/absl/container/internal/layout_test.cc +++ b/absl/container/internal/layout_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -45,7 +45,25 @@ return val; } -using Int128 = int64_t[2]; +// Helper classes to test different size and alignments. +struct alignas(8) Int128 { + uint64_t a, b; + friend bool operator==(Int128 lhs, Int128 rhs) { + return std::tie(lhs.a, lhs.b) == std::tie(rhs.a, rhs.b); + } + + static std::string Name() { + return internal_layout::adl_barrier::TypeName<Int128>(); + } +}; + +// int64_t is *not* 8-byte aligned on all platforms! +struct alignas(8) Int64 { + int64_t a; + friend bool operator==(Int64 lhs, Int64 rhs) { + return lhs.a == rhs.a; + } +}; // Properties of types that this test relies on. static_assert(sizeof(int8_t) == 1, ""); @@ -54,6 +72,8 @@ static_assert(alignof(int16_t) == 2, ""); static_assert(sizeof(int32_t) == 4, ""); static_assert(alignof(int32_t) == 4, ""); +static_assert(sizeof(Int64) == 8, ""); +static_assert(alignof(Int64) == 8, ""); static_assert(sizeof(Int128) == 16, ""); static_assert(alignof(Int128) == 8, ""); @@ -1271,14 +1291,14 @@ TEST(Layout, Alignment) { static_assert(Layout<int8_t>::Alignment() == 1, ""); static_assert(Layout<int32_t>::Alignment() == 4, ""); - static_assert(Layout<int64_t>::Alignment() == 8, ""); + static_assert(Layout<Int64>::Alignment() == 8, ""); static_assert(Layout<Aligned<int8_t, 64>>::Alignment() == 64, ""); - static_assert(Layout<int8_t, int32_t, int64_t>::Alignment() == 8, ""); - static_assert(Layout<int8_t, int64_t, int32_t>::Alignment() == 8, ""); - static_assert(Layout<int32_t, int8_t, int64_t>::Alignment() == 8, ""); - static_assert(Layout<int32_t, int64_t, int8_t>::Alignment() == 8, ""); - static_assert(Layout<int64_t, int8_t, int32_t>::Alignment() == 8, ""); - static_assert(Layout<int64_t, int32_t, int8_t>::Alignment() == 8, ""); + static_assert(Layout<int8_t, int32_t, Int64>::Alignment() == 8, ""); + static_assert(Layout<int8_t, Int64, int32_t>::Alignment() == 8, ""); + static_assert(Layout<int32_t, int8_t, Int64>::Alignment() == 8, ""); + static_assert(Layout<int32_t, Int64, int8_t>::Alignment() == 8, ""); + static_assert(Layout<Int64, int8_t, int32_t>::Alignment() == 8, ""); + static_assert(Layout<Int64, int32_t, int8_t>::Alignment() == 8, ""); } TEST(Layout, ConstexprPartial) { @@ -1313,7 +1333,7 @@ } TEST(Layout, PoisonPadding) { - using L = Layout<int8_t, int64_t, int32_t, Int128>; + using L = Layout<int8_t, Int64, int32_t, Int128>; constexpr size_t n = L::Partial(1, 2, 3, 4).AllocSize(); { @@ -1361,12 +1381,6 @@ } TEST(Layout, DebugString) { - const std::string int64_type = -#ifdef _MSC_VER - "__int64"; -#else // _MSC_VER - std::is_same<int64_t, long long>::value ? "long long" : "long"; // NOLINT -#endif // _MSC_VER { constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(); EXPECT_EQ("@0<signed char>(1)", x.DebugString()); @@ -1384,24 +1398,24 @@ 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<" + - int64_type + " [2]>(16)", + "@16" + + Int128::Name() + "(16)", x.DebugString()); } { 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<" + - int64_type + " [2]>(16)[4]", + "@16" + + Int128::Name() + "(16)[4]", x.DebugString()); } { constexpr Layout<int8_t, int32_t, int8_t, Int128> x(1, 2, 3, 4); EXPECT_EQ( "@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; " - "@16<" + - int64_type + " [2]>(16)[4]", + "@16" + + Int128::Name() + "(16)[4]", x.DebugString()); } } @@ -1528,8 +1542,7 @@ const char* c_str() const { // Equivalent to reinterpret_cast<char*>(p.get() + sizeof(size_t)). // The argument in Partial(1) specifies that we have size_t[1] in front of - // the - // characters. + // the characters. return L::Partial(1).Pointer<char>(p_.get()); }
diff --git a/absl/container/internal/node_hash_policy.h b/absl/container/internal/node_hash_policy.h index 065e700..19b4fc0 100644 --- a/absl/container/internal/node_hash_policy.h +++ b/absl/container/internal/node_hash_policy.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/container/internal/node_hash_policy_test.cc b/absl/container/internal/node_hash_policy_test.cc index 43d287e..f1d3ec3 100644 --- a/absl/container/internal/node_hash_policy_test.cc +++ b/absl/container/internal/node_hash_policy_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/container/internal/raw_hash_map.h b/absl/container/internal/raw_hash_map.h index 1edc007..0014cf8 100644 --- a/absl/container/internal/raw_hash_map.h +++ b/absl/container/internal/raw_hash_map.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -39,11 +39,14 @@ using MappedConstReference = decltype(P::value( std::addressof(std::declval<typename raw_hash_map::const_reference>()))); + using KeyArgImpl = + KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>; + public: using key_type = typename Policy::key_type; using mapped_type = typename Policy::mapped_type; - template <typename K> - using key_arg = typename raw_hash_map::raw_hash_set::template key_arg<K>; + template <class K> + using key_arg = typename KeyArgImpl::template type<K, key_type>; static_assert(!std::is_reference<key_type>::value, ""); // TODO(alkis): remove this assertion and verify that reference mapped_type is
diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc index 1015312..ac2d10a 100644 --- a/absl/container/internal/raw_hash_set.cc +++ b/absl/container/internal/raw_hash_set.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -14,6 +14,7 @@ #include "absl/container/internal/raw_hash_set.h" +#include <atomic> #include <cstddef> #include "absl/base/config.h" @@ -29,7 +30,7 @@ static thread_local size_t counter = 0; size_t value = ++counter; #else // ABSL_HAVE_THREAD_LOCAL - static std::atomic<size_t> counter; + static std::atomic<size_t> counter(0); size_t value = counter.fetch_add(1, std::memory_order_relaxed); #endif // ABSL_HAVE_THREAD_LOCAL return value ^ static_cast<size_t>(reinterpret_cast<uintptr_t>(&counter));
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 70da90f..85e3334 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -91,30 +91,6 @@ #ifndef ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_ #define ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_ -#ifndef SWISSTABLE_HAVE_SSE2 -#ifdef __SSE2__ -#define SWISSTABLE_HAVE_SSE2 1 -#else -#define SWISSTABLE_HAVE_SSE2 0 -#endif -#endif - -#ifndef SWISSTABLE_HAVE_SSSE3 -#ifdef __SSSE3__ -#define SWISSTABLE_HAVE_SSSE3 1 -#else -#define SWISSTABLE_HAVE_SSSE3 0 -#endif -#endif - -#if SWISSTABLE_HAVE_SSSE3 && !SWISSTABLE_HAVE_SSE2 -#error "Bad configuration!" -#endif - -#if SWISSTABLE_HAVE_SSE2 -#include <x86intrin.h> -#endif - #include <algorithm> #include <cmath> #include <cstdint> @@ -129,14 +105,16 @@ #include "absl/base/internal/bits.h" #include "absl/base/internal/endian.h" #include "absl/base/port.h" +#include "absl/container/internal/common.h" #include "absl/container/internal/compressed_tuple.h" #include "absl/container/internal/container_memory.h" #include "absl/container/internal/hash_policy_traits.h" #include "absl/container/internal/hashtable_debug_hooks.h" +#include "absl/container/internal/hashtablez_sampler.h" +#include "absl/container/internal/have_sse.h" #include "absl/container/internal/layout.h" #include "absl/memory/memory.h" #include "absl/meta/type_traits.h" -#include "absl/types/optional.h" #include "absl/utility/utility.h" namespace absl { @@ -187,12 +165,6 @@ std::declval<Ts>()...))>, Policy, Hash, Eq, Ts...> : std::true_type {}; -template <class, class = void> -struct IsTransparent : std::false_type {}; -template <class T> -struct IsTransparent<T, absl::void_t<typename T::is_transparent>> - : std::true_type {}; - // TODO(alkis): Switch to std::is_nothrow_swappable when gcc/clang supports it. template <class T> constexpr bool IsNoThrowSwappable() { @@ -202,14 +174,17 @@ template <typename T> int TrailingZeros(T x) { - return sizeof(T) == 8 ? base_internal::CountTrailingZerosNonZero64(x) - : base_internal::CountTrailingZerosNonZero32(x); + return sizeof(T) == 8 ? base_internal::CountTrailingZerosNonZero64( + static_cast<uint64_t>(x)) + : base_internal::CountTrailingZerosNonZero32( + static_cast<uint32_t>(x)); } template <typename T> int LeadingZeros(T x) { - return sizeof(T) == 8 ? base_internal::CountLeadingZeros64(x) - : base_internal::CountLeadingZeros32(x); + return sizeof(T) == 8 + ? base_internal::CountLeadingZeros64(static_cast<uint64_t>(x)) + : base_internal::CountLeadingZeros32(static_cast<uint32_t>(x)); } // An abstraction over a bitmask. It provides an easy way to iterate through the @@ -337,10 +312,27 @@ inline bool IsEmptyOrDeleted(ctrl_t c) { return c < kSentinel; } #if SWISSTABLE_HAVE_SSE2 -struct Group { + +// https://github.com/abseil/abseil-cpp/issues/209 +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87853 +// _mm_cmpgt_epi8 is broken under GCC with -funsigned-char +// Work around this by using the portable implementation of Group +// when using -funsigned-char under GCC. +inline __m128i _mm_cmpgt_epi8_fixed(__m128i a, __m128i b) { +#if defined(__GNUC__) && !defined(__clang__) + if (std::is_unsigned<char>::value) { + const __m128i mask = _mm_set1_epi8(0x80); + const __m128i diff = _mm_subs_epi8(b, a); + return _mm_cmpeq_epi8(_mm_and_si128(diff, mask), mask); + } +#endif + return _mm_cmpgt_epi8(a, b); +} + +struct GroupSse2Impl { static constexpr size_t kWidth = 16; // the number of slots per group - explicit Group(const ctrl_t* pos) { + explicit GroupSse2Impl(const ctrl_t* pos) { ctrl = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pos)); } @@ -366,23 +358,24 @@ BitMask<uint32_t, kWidth> MatchEmptyOrDeleted() const { auto special = _mm_set1_epi8(kSentinel); return BitMask<uint32_t, kWidth>( - _mm_movemask_epi8(_mm_cmpgt_epi8(special, ctrl))); + _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl))); } // 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(special, ctrl)) + 1); + return TrailingZeros( + _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1); } void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const { - auto msbs = _mm_set1_epi8(0x80); + auto msbs = _mm_set1_epi8(static_cast<char>(-128)); auto x126 = _mm_set1_epi8(126); #if SWISSTABLE_HAVE_SSSE3 auto res = _mm_or_si128(_mm_shuffle_epi8(x126, ctrl), msbs); #else auto zero = _mm_setzero_si128(); - auto special_mask = _mm_cmpgt_epi8(zero, ctrl); + auto special_mask = _mm_cmpgt_epi8_fixed(zero, ctrl); auto res = _mm_or_si128(msbs, _mm_andnot_si128(special_mask, x126)); #endif _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), res); @@ -390,11 +383,13 @@ __m128i ctrl; }; -#else -struct Group { +#endif // SWISSTABLE_HAVE_SSE2 + +struct GroupPortableImpl { static constexpr size_t kWidth = 8; - explicit Group(const ctrl_t* pos) : ctrl(little_endian::Load64(pos)) {} + explicit GroupPortableImpl(const ctrl_t* pos) + : ctrl(little_endian::Load64(pos)) {} BitMask<uint64_t, kWidth, 3> Match(h2_t hash) const { // For the technique, see: @@ -441,15 +436,17 @@ uint64_t ctrl; }; -#endif // SWISSTABLE_HAVE_SSE2 + +#if SWISSTABLE_HAVE_SSE2 +using Group = GroupSse2Impl; +#else +using Group = GroupPortableImpl; +#endif template <class Policy, class Hash, class Eq, class Alloc> class raw_hash_set; - -inline bool IsValidCapacity(size_t n) { - return ((n + 1) & n) == 0 && n >= Group::kWidth - 1; -} +inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; } // PRECONDITION: // IsValidCapacity(capacity) @@ -471,152 +468,32 @@ ctrl[capacity] = kSentinel; } -// Rounds up the capacity to the next power of 2 minus 1 and ensures it is -// greater or equal to Group::kWidth - 1. +// Rounds up the capacity to the next power of 2 minus 1, with a minimum of 1. inline size_t NormalizeCapacity(size_t n) { - constexpr size_t kMinCapacity = Group::kWidth - 1; - return n <= kMinCapacity - ? kMinCapacity - : std::numeric_limits<size_t>::max() >> LeadingZeros(n); + return n ? ~size_t{} >> LeadingZeros(n) : 1; } -// The node_handle concept from C++17. -// We specialize node_handle for sets and maps. node_handle_base holds the -// common API of both. -template <typename Policy, typename Alloc> -class node_handle_base { - protected: - using PolicyTraits = hash_policy_traits<Policy>; - using slot_type = typename PolicyTraits::slot_type; - - public: - using allocator_type = Alloc; - - constexpr node_handle_base() {} - node_handle_base(node_handle_base&& other) noexcept { - *this = std::move(other); +// We use 7/8th as maximum load factor. +// For 16-wide groups, that gives an average of two empty slots per group. +inline size_t CapacityToGrowth(size_t capacity) { + assert(IsValidCapacity(capacity)); + // `capacity*7/8` + if (Group::kWidth == 8 && capacity == 7) { + // x-x/8 does not work when x==7. + return 6; } - ~node_handle_base() { destroy(); } - node_handle_base& operator=(node_handle_base&& other) { - destroy(); - if (!other.empty()) { - alloc_ = other.alloc_; - PolicyTraits::transfer(alloc(), slot(), other.slot()); - other.reset(); - } - return *this; + return capacity - capacity / 8; +} +// From desired "growth" to a lowerbound of the necessary capacity. +// Might not be a valid one and required NormalizeCapacity(). +inline size_t GrowthToLowerboundCapacity(size_t growth) { + // `growth*8/7` + if (Group::kWidth == 8 && growth == 7) { + // x+(x-1)/7 does not work when x==7. + return 8; } - - bool empty() const noexcept { return !alloc_; } - explicit operator bool() const noexcept { return !empty(); } - allocator_type get_allocator() const { return *alloc_; } - - protected: - template <typename, typename, typename, typename> - friend class raw_hash_set; - - node_handle_base(const allocator_type& a, slot_type* s) : alloc_(a) { - PolicyTraits::transfer(alloc(), slot(), s); - } - - void destroy() { - if (!empty()) { - PolicyTraits::destroy(alloc(), slot()); - reset(); - } - } - - void reset() { - assert(alloc_.has_value()); - alloc_ = absl::nullopt; - } - - slot_type* slot() const { - assert(!empty()); - return reinterpret_cast<slot_type*>(std::addressof(slot_space_)); - } - 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_; -}; - -// For sets. -template <typename Policy, typename Alloc, typename = void> -class node_handle : public node_handle_base<Policy, Alloc> { - using Base = typename node_handle::node_handle_base; - - public: - using value_type = typename Base::PolicyTraits::value_type; - - constexpr node_handle() {} - - value_type& value() const { - return Base::PolicyTraits::element(this->slot()); - } - - private: - template <typename, typename, typename, typename> - friend class raw_hash_set; - - node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {} -}; - -// For maps. -template <typename Policy, typename Alloc> -class node_handle<Policy, Alloc, absl::void_t<typename Policy::mapped_type>> - : public node_handle_base<Policy, Alloc> { - using Base = typename node_handle::node_handle_base; - - public: - using key_type = typename Policy::key_type; - using mapped_type = typename Policy::mapped_type; - - constexpr node_handle() {} - - auto key() const -> decltype(Base::PolicyTraits::key(this->slot())) { - return Base::PolicyTraits::key(this->slot()); - } - - mapped_type& mapped() const { - return Base::PolicyTraits::value( - &Base::PolicyTraits::element(this->slot())); - } - - private: - template <typename, typename, typename, typename> - friend class raw_hash_set; - - node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {} -}; - -// Implement the insert_return_type<> concept of C++17. -template <class Iterator, class NodeType> -struct insert_return_type { - Iterator position; - bool inserted; - NodeType node; -}; - -// Helper trait to allow or disallow arbitrary keys when the hash and -// eq functions are transparent. -// It is very important that the inner template is an alias and that the type it -// produces is not a dependent type. Otherwise, type deduction would fail. -template <bool is_transparent> -struct KeyArg { - // Transparent. Forward `K`. - template <typename K, typename key_type> - using type = K; -}; - -template <> -struct KeyArg<false> { - // Not transparent. Always use `key_type`. - template <typename K, typename key_type> - using type = key_type; -}; + return growth + static_cast<size_t>((static_cast<int64_t>(growth) - 1) / 7); +} // Policy: a policy defines how to perform different operations on // the slots of the hashtable (see hash_policy_traits.h for the full interface @@ -632,14 +509,14 @@ // 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 [http://devdocs.io/cpp/concept/allocator] with which +// Allocator: an Allocator [https://devdocs.io/cpp/concept/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> class raw_hash_set { using PolicyTraits = hash_policy_traits<Policy>; - using KeyArgImpl = container_internal::KeyArg<IsTransparent<Eq>::value && - IsTransparent<Hash>::value>; + using KeyArgImpl = + KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>; public: using init_type = typename PolicyTraits::init_type; @@ -662,7 +539,7 @@ allocator_type>::template rebind_traits<value_type>::const_pointer; // Alias used for heterogeneous lookup functions. - // `key_arg<K>` evaluates to `K` when the functors are tranparent and to + // `key_arg<K>` evaluates to `K` when the functors are transparent and to // `key_type` otherwise. It permits template argument deduction on `K` for the // transparent case. template <class K> @@ -780,7 +657,11 @@ } ctrl_t* ctrl_ = nullptr; - slot_type* slot_; + // To avoid uninitialized member warnigs, put slot_ in an anonymous union. + // The member is not initialized on singleton and end iterators. + union { + slot_type* slot_; + }; }; class const_iterator { @@ -820,7 +701,8 @@ iterator inner_; }; - using node_type = container_internal::node_handle<Policy, Alloc>; + using node_type = node_handle<Policy, hash_policy_traits<Policy>, Alloc>; + using insert_return_type = InsertReturnType<iterator, node_type>; raw_hash_set() noexcept( std::is_nothrow_default_constructible<hasher>::value&& @@ -833,7 +715,7 @@ : ctrl_(EmptyGroup()), settings_(0, hash, eq, alloc) { if (bucket_count) { capacity_ = NormalizeCapacity(bucket_count); - growth_left() = static_cast<size_t>(capacity_ * kMaxLoadFactor); + reset_growth_left(); initialize_slots(); } } @@ -875,8 +757,8 @@ // that accept std::initializer_list<T> and std::initializer_list<init_type>. // This is advantageous for performance. // - // // Turns {"abc", "def"} into std::initializer_list<std::string>, then copies - // // the strings into the set. + // // Turns {"abc", "def"} into std::initializer_list<std::string>, then + // // copies the strings into the set. // std::unordered_set<std::string> s = {"abc", "def"}; // // // Turns {"abc", "def"} into std::initializer_list<const char*>, then @@ -939,9 +821,10 @@ // than a full `insert`. for (const auto& v : that) { const size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, v); - const size_t i = find_first_non_full(hash); - set_ctrl(i, H2(hash)); - emplace_at(i, v); + auto target = find_first_non_full(hash); + set_ctrl(target.offset, H2(hash)); + emplace_at(target.offset, v); + infoz_.RecordInsert(hash, target.probe_length); } size_ = that.size(); growth_left() -= that.size(); @@ -955,6 +838,7 @@ slots_(absl::exchange(that.slots_, nullptr)), size_(absl::exchange(that.size_, 0)), capacity_(absl::exchange(that.capacity_, 0)), + infoz_(absl::exchange(that.infoz_, HashtablezInfoHandle())), // Hash, equality and allocator are copied instead of moved because // `that` must be left valid. If Hash is std::function<Key>, moving it // would create a nullptr functor that cannot be called. @@ -975,6 +859,7 @@ std::swap(size_, that.size_); std::swap(capacity_, that.capacity_); std::swap(growth_left(), that.growth_left()); + std::swap(infoz_, that.infoz_); } else { reserve(that.size()); // Note: this will copy elements of dense_set and unordered_set instead of @@ -1022,9 +907,9 @@ bool empty() const { return !size(); } size_t size() const { return size_; } size_t capacity() const { return capacity_; } - size_t max_size() const { return std::numeric_limits<size_t>::max(); } + size_t max_size() const { return (std::numeric_limits<size_t>::max)(); } - void clear() { + ABSL_ATTRIBUTE_REINITIALIZES void clear() { // Iterating over this container is O(bucket_count()). When bucket_count() // is much greater than size(), iteration becomes prohibitively expensive. // For clear() it is more important to reuse the allocated array when the @@ -1042,9 +927,10 @@ } size_ = 0; reset_ctrl(); - growth_left() = static_cast<size_t>(capacity_ * kMaxLoadFactor); + reset_growth_left(); } assert(empty()); + infoz_.RecordStorageChanged(0, capacity_); } // This overload kicks in when the argument is an rvalue of insertable and @@ -1124,13 +1010,14 @@ insert(ilist.begin(), ilist.end()); } - insert_return_type<iterator, node_type> insert(node_type&& node) { + insert_return_type insert(node_type&& node) { if (!node) return {end(), false, node_type()}; - const auto& elem = PolicyTraits::element(node.slot()); + const auto& elem = PolicyTraits::element(CommonAccess::GetSlot(node)); auto res = PolicyTraits::apply( - InsertSlot<false>{*this, std::move(*node.slot())}, elem); + InsertSlot<false>{*this, std::move(*CommonAccess::GetSlot(node))}, + elem); if (res.second) { - node.reset(); + CommonAccess::Reset(&node); return {res.first, true, node_type()}; } else { return {res.first, false, std::move(node)}; @@ -1294,7 +1181,8 @@ } node_type extract(const_iterator position) { - node_type node(alloc_ref(), position.inner_.slot_); + auto node = + CommonAccess::Make<node_type>(alloc_ref(), position.inner_.slot_); erase_meta_only(position); return node; } @@ -1319,6 +1207,7 @@ swap(growth_left(), that.growth_left()); 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 { @@ -1329,17 +1218,21 @@ void rehash(size_t n) { if (n == 0 && capacity_ == 0) return; - if (n == 0 && size_ == 0) return destroy_slots(); - auto m = NormalizeCapacity(std::max(n, NumSlotsFast(size()))); + if (n == 0 && size_ == 0) { + destroy_slots(); + infoz_.RecordStorageChanged(0, 0); + return; + } + // bitor is a faster way of doing `max` here. We will round up to the next + // power-of-2-minus-1, so bitor is good enough. + auto m = NormalizeCapacity(n | GrowthToLowerboundCapacity(size())); // n == 0 unconditionally rehashes as per the standard. if (n == 0 || m > capacity_) { resize(m); } } - void reserve(size_t n) { - rehash(NumSlotsFast(n)); - } + void reserve(size_t n) { rehash(GrowthToLowerboundCapacity(n)); } // Extension API: support for heterogeneous keys. // @@ -1517,13 +1410,6 @@ slot_type&& slot; }; - // Computes std::ceil(n / kMaxLoadFactor). Faster than calling std::ceil. - static inline size_t NumSlotsFast(size_t n) { - return static_cast<size_t>( - (n * kMaxLoadFactorDenominator + (kMaxLoadFactorNumerator - 1)) / - kMaxLoadFactorNumerator); - } - // "erases" the object from the container, except that it doesn't actually // destroy the object. It only updates all the metadata of the class. // This can be used in conjunction with Policy::transfer to move the object to @@ -1546,17 +1432,23 @@ set_ctrl(index, was_never_full ? kEmpty : kDeleted); growth_left() += was_never_full; + infoz_.RecordErase(); } void initialize_slots() { assert(capacity_); + if (slots_ == nullptr) { + infoz_ = Sample(); + } + auto layout = MakeLayout(capacity_); char* mem = static_cast<char*>( Allocate<Layout::Alignment()>(&alloc_ref(), layout.AllocSize())); ctrl_ = reinterpret_cast<ctrl_t*>(layout.template Pointer<0>(mem)); slots_ = layout.template Pointer<1>(mem); reset_ctrl(); - growth_left() = static_cast<size_t>(capacity_ * kMaxLoadFactor) - size_; + reset_growth_left(); + infoz_.RecordStorageChanged(size_, capacity_); } void destroy_slots() { @@ -1585,11 +1477,14 @@ capacity_ = new_capacity; initialize_slots(); + size_t total_probe_length = 0; for (size_t i = 0; i != old_capacity; ++i) { if (IsFull(old_ctrl[i])) { size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, PolicyTraits::element(old_slots + i)); - size_t new_i = find_first_non_full(hash); + auto target = find_first_non_full(hash); + size_t new_i = target.offset; + total_probe_length += target.probe_length; set_ctrl(new_i, H2(hash)); PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, old_slots + i); } @@ -1601,10 +1496,12 @@ Deallocate<Layout::Alignment()>(&alloc_ref(), old_ctrl, layout.AllocSize()); } + infoz_.RecordRehash(total_probe_length); } void drop_deletes_without_resize() ABSL_ATTRIBUTE_NOINLINE { assert(IsValidCapacity(capacity_)); + assert(!is_small()); // Algorithm: // - mark all DELETED slots as EMPTY // - mark all FULL slots as DELETED @@ -1624,12 +1521,15 @@ ConvertDeletedToEmptyAndFullToDeleted(ctrl_, capacity_); typename std::aligned_storage<sizeof(slot_type), alignof(slot_type)>::type raw; + 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)); - size_t new_i = find_first_non_full(hash); + auto target = find_first_non_full(hash); + size_t new_i = target.offset; + total_probe_length += target.probe_length; // Verify if the old and new i fall within the same group wrt the hash. // If they do, we don't need to move the object as it falls already in the @@ -1661,13 +1561,14 @@ --i; // repeat } } - growth_left() = static_cast<size_t>(capacity_ * kMaxLoadFactor) - size_; + reset_growth_left(); + infoz_.RecordRehash(total_probe_length); } void rehash_and_grow_if_necessary() { if (capacity_ == 0) { - resize(Group::kWidth - 1); - } else if (size() <= kMaxLoadFactor / 2 * capacity_) { + resize(1); + } else if (size() <= CapacityToGrowth(capacity()) / 2) { // Squash DELETED without growing if there is enough capacity. drop_deletes_without_resize(); } else { @@ -1702,24 +1603,26 @@ // - the input is already a set // - there are enough slots // - the element with the hash is not in the table - size_t find_first_non_full(size_t hash) { + 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 force small tables to have random entries too, so - // in debug build we will randomly insert in either the front or back of + // 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 (ShouldInsertBackwards(hash, ctrl_)) - return seq.offset(mask.HighestBitSet()); - else - return seq.offset(mask.LowestBitSet()); -#else - return seq.offset(mask.LowestBitSet()); + 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(); @@ -1758,15 +1661,17 @@ } size_t prepare_insert(size_t hash) ABSL_ATTRIBUTE_NOINLINE { - size_t target = find_first_non_full(hash); - if (ABSL_PREDICT_FALSE(growth_left() == 0 && !IsDeleted(ctrl_[target]))) { + auto target = find_first_non_full(hash); + if (ABSL_PREDICT_FALSE(growth_left() == 0 && + !IsDeleted(ctrl_[target.offset]))) { rehash_and_grow_if_necessary(); target = find_first_non_full(hash); } ++size_; - growth_left() -= IsEmpty(ctrl_[target]); - set_ctrl(target, H2(hash)); - return target; + growth_left() -= IsEmpty(ctrl_[target.offset]); + set_ctrl(target.offset, H2(hash)); + infoz_.RecordInsert(hash, target.probe_length); + return target.offset; } // Constructs the value in the space pointed by the iterator. This only works @@ -1804,6 +1709,10 @@ SanitizerPoisonMemoryRegion(slots_, sizeof(slot_type) * capacity_); } + void reset_growth_left() { + growth_left() = CapacityToGrowth(capacity()) - size_; + } + // Sets the control byte, and if `i < Group::kWidth`, set the cloned byte at // the end too. void set_ctrl(size_t i, ctrl_t h) { @@ -1816,11 +1725,28 @@ } ctrl_[i] = h; - ctrl_[((i - Group::kWidth) & capacity_) + Group::kWidth] = h; + ctrl_[((i - Group::kWidth) & capacity_) + 1 + + ((Group::kWidth - 1) & capacity_)] = h; } 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>(); } @@ -1830,12 +1756,6 @@ return settings_.template get<3>(); } - // On average each group has 2 empty slot (for the vectorized case). - static constexpr int64_t kMaxLoadFactorNumerator = 14; - static constexpr int64_t kMaxLoadFactorDenominator = 16; - static constexpr float kMaxLoadFactor = - 1.0 * kMaxLoadFactorNumerator / kMaxLoadFactorDenominator; - // TODO(alkis): Investigate removing some of these fields: // - ctrl/slots can be derived from each other // - size can be moved into the slot array @@ -1843,6 +1763,7 @@ slot_type* slots_ = nullptr; // [capacity * slot_type] size_t size_ = 0; // number of full slots size_t capacity_ = 0; // total number of slots + HashtablezInfoHandle infoz_; absl::container_internal::CompressedTuple<size_t /* growth_left */, hasher, key_equal, allocator_type> settings_{0, hasher{}, key_equal{}, allocator_type{}}; @@ -1895,10 +1816,9 @@ } static size_t LowerBoundAllocatedByteSize(size_t size) { - size_t capacity = container_internal::NormalizeCapacity( - std::ceil(size / Set::kMaxLoadFactor)); + size_t capacity = GrowthToLowerboundCapacity(size); if (capacity == 0) return 0; - auto layout = Set::MakeLayout(capacity); + auto layout = Set::MakeLayout(NormalizeCapacity(capacity)); size_t m = layout.AllocSize(); size_t per_slot = Traits::space_used(static_cast<const Slot*>(nullptr)); if (per_slot != ~size_t{}) {
diff --git a/absl/container/internal/raw_hash_set_allocator_test.cc b/absl/container/internal/raw_hash_set_allocator_test.cc index 891fa45..a5eff0b 100644 --- a/absl/container/internal/raw_hash_set_allocator_test.cc +++ b/absl/container/internal/raw_hash_set_allocator_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index cd33a3a..02fd0bf 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -14,7 +14,6 @@ #include "absl/container/internal/raw_hash_set.h" -#include <array> #include <cmath> #include <cstdint> #include <deque> @@ -49,18 +48,47 @@ using ::testing::DoubleNear; using ::testing::ElementsAre; +using ::testing::Ge; +using ::testing::Lt; using ::testing::Optional; using ::testing::Pair; using ::testing::UnorderedElementsAre; TEST(Util, NormalizeCapacity) { - constexpr size_t kMinCapacity = Group::kWidth - 1; - EXPECT_EQ(kMinCapacity, NormalizeCapacity(0)); - EXPECT_EQ(kMinCapacity, NormalizeCapacity(1)); - EXPECT_EQ(kMinCapacity, NormalizeCapacity(2)); - EXPECT_EQ(kMinCapacity, NormalizeCapacity(kMinCapacity)); - EXPECT_EQ(kMinCapacity * 2 + 1, NormalizeCapacity(kMinCapacity + 1)); - EXPECT_EQ(kMinCapacity * 2 + 1, NormalizeCapacity(kMinCapacity + 2)); + EXPECT_EQ(1, NormalizeCapacity(0)); + EXPECT_EQ(1, NormalizeCapacity(1)); + EXPECT_EQ(3, NormalizeCapacity(2)); + EXPECT_EQ(3, NormalizeCapacity(3)); + EXPECT_EQ(7, NormalizeCapacity(4)); + EXPECT_EQ(7, NormalizeCapacity(7)); + EXPECT_EQ(15, NormalizeCapacity(8)); + EXPECT_EQ(15, NormalizeCapacity(15)); + EXPECT_EQ(15 * 2 + 1, NormalizeCapacity(15 + 1)); + EXPECT_EQ(15 * 2 + 1, NormalizeCapacity(15 + 2)); +} + +TEST(Util, GrowthAndCapacity) { + // Verify that GrowthToCapacity gives the minimum capacity that has enough + // growth. + for (size_t growth = 0; growth < 10000; ++growth) { + SCOPED_TRACE(growth); + size_t capacity = NormalizeCapacity(GrowthToLowerboundCapacity(growth)); + // The capacity is large enough for `growth` + EXPECT_THAT(CapacityToGrowth(capacity), Ge(growth)); + if (growth != 0 && capacity > 1) { + // There is no smaller capacity that works. + EXPECT_THAT(CapacityToGrowth(capacity / 2), Lt(growth)); + } + } + + for (size_t capacity = Group::kWidth - 1; capacity < 10000; + capacity = 2 * capacity + 1) { + SCOPED_TRACE(capacity); + size_t growth = CapacityToGrowth(capacity); + EXPECT_THAT(growth, Lt(capacity)); + EXPECT_LE(GrowthToLowerboundCapacity(growth), capacity); + EXPECT_EQ(NormalizeCapacity(GrowthToLowerboundCapacity(growth)), capacity); + } } TEST(Util, probe_seq) { @@ -107,14 +135,14 @@ } TEST(BitMask, LeadingTrailing) { - EXPECT_EQ((BitMask<uint32_t, 16>(0b0001101001000000).LeadingZeros()), 3); - EXPECT_EQ((BitMask<uint32_t, 16>(0b0001101001000000).TrailingZeros()), 6); + EXPECT_EQ((BitMask<uint32_t, 16>(0x00001a40).LeadingZeros()), 3); + EXPECT_EQ((BitMask<uint32_t, 16>(0x00001a40).TrailingZeros()), 6); - EXPECT_EQ((BitMask<uint32_t, 16>(0b0000000000000001).LeadingZeros()), 15); - EXPECT_EQ((BitMask<uint32_t, 16>(0b0000000000000001).TrailingZeros()), 0); + EXPECT_EQ((BitMask<uint32_t, 16>(0x00000001).LeadingZeros()), 15); + EXPECT_EQ((BitMask<uint32_t, 16>(0x00000001).TrailingZeros()), 0); - EXPECT_EQ((BitMask<uint32_t, 16>(0b1000000000000000).LeadingZeros()), 0); - EXPECT_EQ((BitMask<uint32_t, 16>(0b1000000000000000).TrailingZeros()), 15); + EXPECT_EQ((BitMask<uint32_t, 16>(0x00008000).LeadingZeros()), 0); + EXPECT_EQ((BitMask<uint32_t, 16>(0x00008000).TrailingZeros()), 15); EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000008080808000).LeadingZeros()), 3); EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000008080808000).TrailingZeros()), 1); @@ -130,45 +158,50 @@ for (h2_t h = 0; h != 128; ++h) EXPECT_FALSE(Group{EmptyGroup()}.Match(h)); } -#if SWISSTABLE_HAVE_SSE2 TEST(Group, Match) { - ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7, - 7, 5, 3, 1, 1, 1, 1, 1}; - EXPECT_THAT(Group{group}.Match(0), ElementsAre()); - EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 11, 12, 13, 14, 15)); - EXPECT_THAT(Group{group}.Match(3), ElementsAre(3, 10)); - EXPECT_THAT(Group{group}.Match(5), ElementsAre(5, 9)); - EXPECT_THAT(Group{group}.Match(7), ElementsAre(7, 8)); + if (Group::kWidth == 16) { + ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7, + 7, 5, 3, 1, 1, 1, 1, 1}; + EXPECT_THAT(Group{group}.Match(0), ElementsAre()); + EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 11, 12, 13, 14, 15)); + EXPECT_THAT(Group{group}.Match(3), ElementsAre(3, 10)); + EXPECT_THAT(Group{group}.Match(5), ElementsAre(5, 9)); + EXPECT_THAT(Group{group}.Match(7), ElementsAre(7, 8)); + } else if (Group::kWidth == 8) { + ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1}; + EXPECT_THAT(Group{group}.Match(0), ElementsAre()); + EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 5, 7)); + EXPECT_THAT(Group{group}.Match(2), ElementsAre(2, 4)); + } else { + FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth; + } } TEST(Group, MatchEmpty) { - ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7, - 7, 5, 3, 1, 1, 1, 1, 1}; - EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0, 4)); + if (Group::kWidth == 16) { + ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7, + 7, 5, 3, 1, 1, 1, 1, 1}; + EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0, 4)); + } else if (Group::kWidth == 8) { + ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1}; + EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0)); + } else { + FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth; + } } TEST(Group, MatchEmptyOrDeleted) { - ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7, - 7, 5, 3, 1, 1, 1, 1, 1}; - EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 2, 4)); + if (Group::kWidth == 16) { + ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7, + 7, 5, 3, 1, 1, 1, 1, 1}; + EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 2, 4)); + } else if (Group::kWidth == 8) { + ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1}; + EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 3)); + } else { + FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth; + } } -#else -TEST(Group, Match) { - ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1}; - EXPECT_THAT(Group{group}.Match(0), ElementsAre()); - EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 5, 7)); - EXPECT_THAT(Group{group}.Match(2), ElementsAre(2, 4)); -} -TEST(Group, MatchEmpty) { - ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1}; - EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0)); -} - -TEST(Group, MatchEmptyOrDeleted) { - ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1}; - EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 3)); -} -#endif TEST(Batch, DropDeletes) { constexpr size_t kCapacity = 63; @@ -338,6 +371,7 @@ size_t size; size_t capacity; size_t growth_left; + void* infoz; }; struct StatelessHash { size_t operator()(absl::string_view) const { return 0; } @@ -386,7 +420,8 @@ !defined(UNDEFINED_BEHAVIOR_SANITIZER) const auto now = [] { return absl::base_internal::CycleClock::Now(); }; - static constexpr int size = 1000000; + // 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; @@ -687,7 +722,7 @@ Modulo1000HashTable t; // Adding the same length (and the same hash) strings // to have at least kMinFullGroups groups - // with Group::kWidth collisions. Then feel upto MaxDensitySize; + // with Group::kWidth collisions. Then fill up to MaxDensitySize; const size_t kMinFullGroups = 7; std::vector<int> keys; for (size_t i = 0; i < MaxDensitySize(Group::kWidth * kMinFullGroups); ++i) { @@ -779,7 +814,7 @@ TEST(Table, ClearBug) { IntTable t; constexpr size_t capacity = container_internal::Group::kWidth - 1; - constexpr size_t max_size = capacity / 2; + constexpr size_t max_size = capacity / 2 + 1; for (size_t i = 0; i < max_size; ++i) { t.insert(i); } @@ -810,6 +845,25 @@ EXPECT_TRUE(t.find(0) == t.end()); } +TEST(Table, EraseMaintainsValidIterator) { + IntTable t; + const int kNumElements = 100; + for (int i = 0; i < kNumElements; i ++) { + EXPECT_TRUE(t.emplace(i).second); + } + EXPECT_EQ(t.size(), kNumElements); + + int num_erase_calls = 0; + auto it = t.begin(); + while (it != t.end()) { + t.erase(it++); + num_erase_calls++; + } + + EXPECT_TRUE(t.empty()); + EXPECT_EQ(num_erase_calls, kNumElements); +} + // Collect N bad keys by following algorithm: // 1. Create an empty table and reserve it to 2 * N. // 2. Insert N random elements. @@ -1029,7 +1083,6 @@ {{0.95, 0.1}}, {{0.95, 0}, {0.99, 2}, {0.999, 4}, {0.9999, 10}}}; } - break; case 16: if (kRandomizesInserts) { return {0.1, @@ -1042,12 +1095,11 @@ {{0.95, 0.05}}, {{0.95, 0}, {0.99, 1}, {0.999, 4}, {0.9999, 10}}}; } - break; - default: - ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width"); } + ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width"); return {}; } + TEST(Table, DISABLED_EnsureNonQuadraticTopNXorSeedByProbeSeqLength) { ProbeStatsPerSize stats; std::vector<size_t> sizes = {Group::kWidth << 5, Group::kWidth << 10}; @@ -1125,7 +1177,6 @@ {{0.95, 0.3}}, {{0.95, 0}, {0.99, 3}, {0.999, 15}, {0.9999, 25}}}; } - break; case 16: if (kRandomizesInserts) { return {0.1, @@ -1138,12 +1189,11 @@ {{0.95, 0.1}}, {{0.95, 0}, {0.99, 1}, {0.999, 6}, {0.9999, 10}}}; } - break; - default: - ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width"); } + ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width"); return {}; } + TEST(Table, DISABLED_EnsureNonQuadraticTopNLinearTransformByProbeSeqLength) { ProbeStatsPerSize stats; std::vector<size_t> sizes = {Group::kWidth << 5, Group::kWidth << 10}; @@ -1431,7 +1481,8 @@ TEST(Table, Equality) { StringTable t; - std::vector<std::pair<std::string, std::string>> v = {{"a", "b"}, {"aa", "bb"}}; + std::vector<std::pair<std::string, std::string>> v = {{"a", "b"}, + {"aa", "bb"}}; t.insert(std::begin(v), std::end(v)); StringTable u = t; EXPECT_EQ(u, t); @@ -1439,20 +1490,24 @@ TEST(Table, Equality2) { StringTable t; - std::vector<std::pair<std::string, std::string>> v1 = {{"a", "b"}, {"aa", "bb"}}; + std::vector<std::pair<std::string, std::string>> v1 = {{"a", "b"}, + {"aa", "bb"}}; t.insert(std::begin(v1), std::end(v1)); StringTable u; - std::vector<std::pair<std::string, std::string>> v2 = {{"a", "a"}, {"aa", "aa"}}; + std::vector<std::pair<std::string, std::string>> v2 = {{"a", "a"}, + {"aa", "aa"}}; u.insert(std::begin(v2), std::end(v2)); EXPECT_NE(u, t); } TEST(Table, Equality3) { StringTable t; - std::vector<std::pair<std::string, std::string>> v1 = {{"b", "b"}, {"bb", "bb"}}; + std::vector<std::pair<std::string, std::string>> v1 = {{"b", "b"}, + {"bb", "bb"}}; t.insert(std::begin(v1), std::end(v1)); StringTable u; - std::vector<std::pair<std::string, std::string>> v2 = {{"a", "a"}, {"aa", "aa"}}; + std::vector<std::pair<std::string, std::string>> v2 = {{"a", "a"}, + {"aa", "aa"}}; u.insert(std::begin(v2), std::end(v2)); EXPECT_NE(u, t); } @@ -1677,7 +1732,7 @@ EXPECT_FALSE(node.empty()); StringTable t2; - auto res = t2.insert(std::move(node)); + StringTable::insert_return_type res = t2.insert(std::move(node)); EXPECT_TRUE(res.inserted); EXPECT_THAT(*res.position, Pair(k0, "")); EXPECT_FALSE(res.node); @@ -1707,73 +1762,49 @@ EXPECT_FALSE(node); } -StringTable MakeSimpleTable(size_t size) { - StringTable t; - for (size_t i = 0; i < size; ++i) t.emplace(std::string(1, 'A' + i), ""); +IntTable MakeSimpleTable(size_t size) { + IntTable t; + while (t.size() < size) t.insert(t.size()); return t; } -std::string OrderOfIteration(const StringTable& t) { - std::string order; - for (auto& p : t) order += p.first; - return order; +std::vector<int> OrderOfIteration(const IntTable& t) { + return {t.begin(), t.end()}; } +// These IterationOrderChanges tests depend on non-deterministic behavior. +// We are injecting non-determinism from the pointer of the table, but do so in +// a way that only the page matters. We have to retry enough times to make sure +// we are touching different memory pages to cause the ordering to change. +// We also need to keep the old tables around to avoid getting the same memory +// blocks over and over. TEST(Table, IterationOrderChangesByInstance) { - // Needs to be more than kWidth elements to be able to affect order. - const StringTable reference = MakeSimpleTable(20); + for (size_t size : {2, 6, 12, 20}) { + const auto reference_table = MakeSimpleTable(size); + const auto reference = OrderOfIteration(reference_table); - // Since order is non-deterministic we can't just try once and verify. - // We'll try until we find that order changed. It should not take many tries - // for that. - // Important: we have to keep the old tables around. Otherwise tcmalloc will - // just give us the same blocks and we would be doing the same order again. - std::vector<StringTable> garbage; - for (int i = 0; i < 10; ++i) { - auto trial = MakeSimpleTable(20); - if (OrderOfIteration(trial) != OrderOfIteration(reference)) { - // We are done. - return; + std::vector<IntTable> tables; + bool found_difference = false; + for (int i = 0; !found_difference && i < 500; ++i) { + tables.push_back(MakeSimpleTable(size)); + found_difference = OrderOfIteration(tables.back()) != reference; } - garbage.push_back(std::move(trial)); + if (!found_difference) { + FAIL() + << "Iteration order remained the same across many attempts with size " + << size; + } } - FAIL(); } TEST(Table, IterationOrderChangesOnRehash) { - // Since order is non-deterministic we can't just try once and verify. - // We'll try until we find that order changed. It should not take many tries - // for that. - // Important: we have to keep the old tables around. Otherwise tcmalloc will - // just give us the same blocks and we would be doing the same order again. - std::vector<StringTable> garbage; - for (int i = 0; i < 10; ++i) { - // Needs to be more than kWidth elements to be able to affect order. - StringTable t = MakeSimpleTable(20); - const std::string reference = OrderOfIteration(t); + std::vector<IntTable> garbage; + for (int i = 0; i < 500; ++i) { + auto t = MakeSimpleTable(20); + const auto reference = OrderOfIteration(t); // Force rehash to the same size. t.rehash(0); - std::string trial = OrderOfIteration(t); - if (trial != reference) { - // We are done. - return; - } - garbage.push_back(std::move(t)); - } - FAIL(); -} - -TEST(Table, IterationOrderChangesForSmallTables) { - // Since order is non-deterministic we can't just try once and verify. - // We'll try until we find that order changed. - // Important: we have to keep the old tables around. Otherwise tcmalloc will - // just give us the same blocks and we would be doing the same order again. - StringTable reference_table = MakeSimpleTable(5); - const std::string reference = OrderOfIteration(reference_table); - std::vector<StringTable> garbage; - for (int i = 0; i < 50; ++i) { - StringTable t = MakeSimpleTable(5); - std::string trial = OrderOfIteration(t); + auto trial = OrderOfIteration(t); if (trial != reference) { // We are done. return; @@ -1783,136 +1814,22 @@ FAIL() << "Iteration order remained the same across many attempts."; } -// Fill the table to 3 different load factors (min, median, max) and evaluate -// the percentage of perfect hits using the debug API. -template <class Table, class AddFn> -std::vector<double> CollectPerfectRatios(Table t, AddFn add) { - using Key = typename Table::key_type; +// Verify that pointers are invalidated as soon as a second element is inserted. +// This prevents dependency on pointer stability on small tables. +TEST(Table, UnstablePointers) { + IntTable table; - // First, fill enough to have a good distribution. - constexpr size_t kMinSize = 10000; - std::vector<Key> keys; - while (t.size() < kMinSize) keys.push_back(add(t)); - // Then, insert until we reach min load factor. - double lf = t.load_factor(); - while (lf <= t.load_factor()) keys.push_back(add(t)); - - // We are now at min load factor. Take a snapshot. - size_t perfect = 0; - auto update_perfect = [&](Key k) { - perfect += GetHashtableDebugNumProbes(t, k) == 0; + const auto addr = [&](int i) { + return reinterpret_cast<uintptr_t>(&*table.find(i)); }; - for (const auto& k : keys) update_perfect(k); - std::vector<double> perfect_ratios; - // Keep going until we hit max load factor. - while (t.load_factor() < .6) { - perfect_ratios.push_back(1.0 * perfect / t.size()); - update_perfect(add(t)); - } - while (t.load_factor() > .5) { - perfect_ratios.push_back(1.0 * perfect / t.size()); - update_perfect(add(t)); - } - return perfect_ratios; -} + table.insert(0); + const uintptr_t old_ptr = addr(0); -std::vector<std::pair<double, double>> StringTablePefectRatios() { - constexpr bool kRandomizesInserts = -#if NDEBUG - false; -#else // NDEBUG - true; -#endif // NDEBUG + // This causes a rehash. + table.insert(1); - // The effective load factor is larger in non-opt mode because we insert - // elements out of order. - switch (container_internal::Group::kWidth) { - case 8: - if (kRandomizesInserts) { - return {{0.986, 0.02}, {0.95, 0.02}, {0.89, 0.02}}; - } else { - return {{0.995, 0.01}, {0.97, 0.01}, {0.89, 0.02}}; - } - break; - case 16: - if (kRandomizesInserts) { - return {{0.973, 0.01}, {0.965, 0.01}, {0.92, 0.02}}; - } else { - return {{0.995, 0.005}, {0.99, 0.005}, {0.94, 0.01}}; - } - break; - default: - // Ignore anything else. - return {}; - } -} - -// This is almost a change detector, but it allows us to know how we are -// affecting the probe distribution. -TEST(Table, EffectiveLoadFactorStrings) { - std::vector<double> perfect_ratios = - CollectPerfectRatios(StringTable(), [](StringTable& t) { - return t.emplace(std::to_string(t.size()), "").first->first; - }); - - auto ratios = StringTablePefectRatios(); - if (ratios.empty()) return; - - EXPECT_THAT(perfect_ratios.front(), - DoubleNear(ratios[0].first, ratios[0].second)); - EXPECT_THAT(perfect_ratios[perfect_ratios.size() / 2], - DoubleNear(ratios[1].first, ratios[1].second)); - EXPECT_THAT(perfect_ratios.back(), - DoubleNear(ratios[2].first, ratios[2].second)); -} - -std::vector<std::pair<double, double>> IntTablePefectRatios() { - constexpr bool kRandomizesInserts = -#ifdef NDEBUG - false; -#else // NDEBUG - true; -#endif // NDEBUG - - // The effective load factor is larger in non-opt mode because we insert - // elements out of order. - switch (container_internal::Group::kWidth) { - case 8: - if (kRandomizesInserts) { - return {{0.99, 0.02}, {0.985, 0.02}, {0.95, 0.05}}; - } else { - return {{0.99, 0.01}, {0.99, 0.01}, {0.95, 0.02}}; - } - break; - case 16: - if (kRandomizesInserts) { - return {{0.98, 0.02}, {0.978, 0.02}, {0.96, 0.02}}; - } else { - return {{0.998, 0.003}, {0.995, 0.01}, {0.975, 0.02}}; - } - break; - default: - // Ignore anything else. - return {}; - } -} - -// This is almost a change detector, but it allows us to know how we are -// affecting the probe distribution. -TEST(Table, EffectiveLoadFactorInts) { - std::vector<double> perfect_ratios = CollectPerfectRatios( - IntTable(), [](IntTable& t) { return *t.emplace(t.size()).first; }); - - auto ratios = IntTablePefectRatios(); - if (ratios.empty()) return; - - EXPECT_THAT(perfect_ratios.front(), - DoubleNear(ratios[0].first, ratios[0].second)); - EXPECT_THAT(perfect_ratios[perfect_ratios.size() / 2], - DoubleNear(ratios[1].first, ratios[1].second)); - EXPECT_THAT(perfect_ratios.back(), - DoubleNear(ratios[2].first, ratios[2].second)); + EXPECT_NE(old_ptr, addr(0)); } // Confirm that we assert if we try to erase() end(). @@ -1931,9 +1848,31 @@ EXPECT_DEATH_IF_SUPPORTED(t.erase(t.end()), kDeathMsg); } +TEST(RawHashSamplerTest, Sample) { + // Enable the feature even if the prod default is off. + SetHashtablezEnabled(true); + SetHashtablezSampleParameter(100); + + auto& sampler = HashtablezSampler::Global(); + size_t start_size = 0; + start_size += sampler.Iterate([&](const HashtablezInfo&) { ++start_size; }); + + std::vector<IntTable> tables; + for (int i = 0; i < 1000000; ++i) { + tables.emplace_back(); + tables.back().insert(1); + } + size_t end_size = 0; + end_size += sampler.Iterate([&](const HashtablezInfo&) { ++end_size; }); + + EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()), + 0.01, 0.005); +} + #ifdef ADDRESS_SANITIZER TEST(Sanitizer, PoisoningUnused) { IntTable t; + t.reserve(5); // Insert something to force an allocation. int64_t& v1 = *t.insert(0).first;
diff --git a/absl/container/internal/test_instance_tracker.cc b/absl/container/internal/test_instance_tracker.cc index b18e0bb..5a66cb4 100644 --- a/absl/container/internal/test_instance_tracker.cc +++ b/absl/container/internal/test_instance_tracker.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/container/internal/test_instance_tracker.h b/absl/container/internal/test_instance_tracker.h index ec45f57..032d16d 100644 --- a/absl/container/internal/test_instance_tracker.h +++ b/absl/container/internal/test_instance_tracker.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/container/internal/test_instance_tracker_test.cc b/absl/container/internal/test_instance_tracker_test.cc index 0ae5763..091f428 100644 --- a/absl/container/internal/test_instance_tracker_test.cc +++ b/absl/container/internal/test_instance_tracker_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/container/internal/tracked.h b/absl/container/internal/tracked.h index 7d14af0..75173ab 100644 --- a/absl/container/internal/tracked.h +++ b/absl/container/internal/tracked.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/container/internal/unordered_map_constructor_test.h b/absl/container/internal/unordered_map_constructor_test.h index 2ffb646..68817e4 100644 --- a/absl/container/internal/unordered_map_constructor_test.h +++ b/absl/container/internal/unordered_map_constructor_test.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -29,7 +29,7 @@ template <class UnordMap> class ConstructorTest : public ::testing::Test {}; -TYPED_TEST_CASE_P(ConstructorTest); +TYPED_TEST_SUITE_P(ConstructorTest); TYPED_TEST_P(ConstructorTest, NoArgs) { TypeParam m; @@ -83,8 +83,28 @@ EXPECT_GE(m.bucket_count(), 123); } -TYPED_TEST_P(ConstructorTest, BucketCountAlloc) { +template <typename T> +struct is_std_unordered_map : std::false_type {}; + +template <typename... T> +struct is_std_unordered_map<std::unordered_map<T...>> : std::true_type {}; + #if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17) +using has_cxx14_std_apis = std::true_type; +#else +using has_cxx14_std_apis = std::false_type; +#endif + +template <typename T> +using expect_cxx14_apis = + absl::disjunction<absl::negation<is_std_unordered_map<T>>, + has_cxx14_std_apis>; + +template <typename TypeParam> +void BucketCountAllocTest(std::false_type) {} + +template <typename TypeParam> +void BucketCountAllocTest(std::true_type) { using A = typename TypeParam::allocator_type; A alloc(0); TypeParam m(123, alloc); @@ -92,11 +112,17 @@ EXPECT_TRUE(m.empty()); EXPECT_THAT(m, ::testing::UnorderedElementsAre()); EXPECT_GE(m.bucket_count(), 123); -#endif } -TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) { -#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17) +TYPED_TEST_P(ConstructorTest, BucketCountAlloc) { + BucketCountAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>()); +} + +template <typename TypeParam> +void BucketCountHashAllocTest(std::false_type) {} + +template <typename TypeParam> +void BucketCountHashAllocTest(std::true_type) { using H = typename TypeParam::hasher; using A = typename TypeParam::allocator_type; H hasher; @@ -107,18 +133,38 @@ EXPECT_TRUE(m.empty()); EXPECT_THAT(m, ::testing::UnorderedElementsAre()); EXPECT_GE(m.bucket_count(), 123); -#endif } -TYPED_TEST_P(ConstructorTest, BucketAlloc) { +TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) { + BucketCountHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>()); +} + #if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS +using has_alloc_std_constructors = std::true_type; +#else +using has_alloc_std_constructors = std::false_type; +#endif + +template <typename T> +using expect_alloc_constructors = + absl::disjunction<absl::negation<is_std_unordered_map<T>>, + has_alloc_std_constructors>; + +template <typename TypeParam> +void AllocTest(std::false_type) {} + +template <typename TypeParam> +void AllocTest(std::true_type) { using A = typename TypeParam::allocator_type; A alloc(0); TypeParam m(alloc); EXPECT_EQ(m.get_allocator(), alloc); EXPECT_TRUE(m.empty()); EXPECT_THAT(m, ::testing::UnorderedElementsAre()); -#endif +} + +TYPED_TEST_P(ConstructorTest, Alloc) { + AllocTest<TypeParam>(expect_alloc_constructors<TypeParam>()); } TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashEqualAlloc) { @@ -140,8 +186,11 @@ EXPECT_GE(m.bucket_count(), 123); } -TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) { -#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17) +template <typename TypeParam> +void InputIteratorBucketAllocTest(std::false_type) {} + +template <typename TypeParam> +void InputIteratorBucketAllocTest(std::true_type) { using T = hash_internal::GeneratedType<TypeParam>; using A = typename TypeParam::allocator_type; A alloc(0); @@ -152,11 +201,17 @@ EXPECT_EQ(m.get_allocator(), alloc); EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values)); EXPECT_GE(m.bucket_count(), 123); -#endif } -TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) { -#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17) +TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) { + InputIteratorBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>()); +} + +template <typename TypeParam> +void InputIteratorBucketHashAllocTest(std::false_type) {} + +template <typename TypeParam> +void InputIteratorBucketHashAllocTest(std::true_type) { using T = hash_internal::GeneratedType<TypeParam>; using H = typename TypeParam::hasher; using A = typename TypeParam::allocator_type; @@ -170,7 +225,10 @@ EXPECT_EQ(m.get_allocator(), alloc); EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values)); EXPECT_GE(m.bucket_count(), 123); -#endif +} + +TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) { + InputIteratorBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>()); } TYPED_TEST_P(ConstructorTest, CopyConstructor) { @@ -190,8 +248,11 @@ EXPECT_EQ(m, n); } -TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) { -#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS +template <typename TypeParam> +void CopyConstructorAllocTest(std::false_type) {} + +template <typename TypeParam> +void CopyConstructorAllocTest(std::true_type) { using T = hash_internal::GeneratedType<TypeParam>; using H = typename TypeParam::hasher; using E = typename TypeParam::key_equal; @@ -206,7 +267,10 @@ EXPECT_EQ(m.key_eq(), n.key_eq()); EXPECT_NE(m.get_allocator(), n.get_allocator()); EXPECT_EQ(m, n); -#endif +} + +TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) { + CopyConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>()); } // TODO(alkis): Test non-propagating allocators on copy constructors. @@ -229,8 +293,11 @@ EXPECT_EQ(m, n); } -TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) { -#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS +template <typename TypeParam> +void MoveConstructorAllocTest(std::false_type) {} + +template <typename TypeParam> +void MoveConstructorAllocTest(std::true_type) { using T = hash_internal::GeneratedType<TypeParam>; using H = typename TypeParam::hasher; using E = typename TypeParam::key_equal; @@ -246,7 +313,10 @@ EXPECT_EQ(m.key_eq(), n.key_eq()); EXPECT_NE(m.get_allocator(), n.get_allocator()); EXPECT_EQ(m, n); -#endif +} + +TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) { + MoveConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>()); } // TODO(alkis): Test non-propagating allocators on move constructors. @@ -269,8 +339,11 @@ EXPECT_GE(m.bucket_count(), 123); } -TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) { -#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17) +template <typename TypeParam> +void InitializerListBucketAllocTest(std::false_type) {} + +template <typename TypeParam> +void InitializerListBucketAllocTest(std::true_type) { using T = hash_internal::GeneratedType<TypeParam>; using A = typename TypeParam::allocator_type; hash_internal::Generator<T> gen; @@ -280,11 +353,17 @@ EXPECT_EQ(m.get_allocator(), alloc); EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values)); EXPECT_GE(m.bucket_count(), 123); -#endif } -TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) { -#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17) +TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) { + InitializerListBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>()); +} + +template <typename TypeParam> +void InitializerListBucketHashAllocTest(std::false_type) {} + +template <typename TypeParam> +void InitializerListBucketHashAllocTest(std::true_type) { using T = hash_internal::GeneratedType<TypeParam>; using H = typename TypeParam::hasher; using A = typename TypeParam::allocator_type; @@ -297,7 +376,10 @@ EXPECT_EQ(m.get_allocator(), alloc); EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values)); EXPECT_GE(m.bucket_count(), 123); -#endif +} + +TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) { + InitializerListBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>()); } TYPED_TEST_P(ConstructorTest, Assignment) { @@ -390,15 +472,16 @@ REGISTER_TYPED_TEST_CASE_P( ConstructorTest, NoArgs, BucketCount, BucketCountHash, BucketCountHashEqual, - BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc, - BucketAlloc, InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc, + BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc, Alloc, + InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc, InputIteratorBucketHashAlloc, CopyConstructor, CopyConstructorAlloc, MoveConstructor, MoveConstructorAlloc, InitializerListBucketHashEqualAlloc, InitializerListBucketAlloc, InitializerListBucketHashAlloc, Assignment, - MoveAssignment, AssignmentFromInitializerList, - AssignmentOverwritesExisting, MoveAssignmentOverwritesExisting, + MoveAssignment, AssignmentFromInitializerList, AssignmentOverwritesExisting, + MoveAssignmentOverwritesExisting, AssignmentFromInitializerListOverwritesExisting, AssignmentOnSelf); } // namespace container_internal } // namespace absl + #endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_CONSTRUCTOR_TEST_H_
diff --git a/absl/container/internal/unordered_map_lookup_test.h b/absl/container/internal/unordered_map_lookup_test.h index 1f1b6b4..ebd3612 100644 --- a/absl/container/internal/unordered_map_lookup_test.h +++ b/absl/container/internal/unordered_map_lookup_test.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -26,7 +26,7 @@ template <class UnordMap> class LookupTest : public ::testing::Test {}; -TYPED_TEST_CASE_P(LookupTest); +TYPED_TEST_SUITE_P(LookupTest); TYPED_TEST_P(LookupTest, At) { using T = hash_internal::GeneratedType<TypeParam>; @@ -111,4 +111,5 @@ } // namespace container_internal } // namespace absl + #endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_LOOKUP_TEST_H_
diff --git a/absl/container/internal/unordered_map_members_test.h b/absl/container/internal/unordered_map_members_test.h new file mode 100644 index 0000000..1bf31ab --- /dev/null +++ b/absl/container/internal/unordered_map_members_test.h
@@ -0,0 +1,85 @@ +// 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_CONTAINER_INTERNAL_UNORDERED_MAP_MEMBERS_TEST_H_ +#define ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MEMBERS_TEST_H_ + +#include <type_traits> +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/meta/type_traits.h" + +namespace absl { +namespace container_internal { + +template <class UnordMap> +class MembersTest : public ::testing::Test {}; + +TYPED_TEST_SUITE_P(MembersTest); + +template <typename T> +void UseType() {} + +TYPED_TEST_P(MembersTest, Typedefs) { + EXPECT_TRUE((std::is_same<std::pair<const typename TypeParam::key_type, + typename TypeParam::mapped_type>, + typename TypeParam::value_type>())); + EXPECT_TRUE((absl::conjunction< + absl::negation<std::is_signed<typename TypeParam::size_type>>, + std::is_integral<typename TypeParam::size_type>>())); + EXPECT_TRUE((absl::conjunction< + std::is_signed<typename TypeParam::difference_type>, + std::is_integral<typename TypeParam::difference_type>>())); + EXPECT_TRUE((std::is_convertible< + decltype(std::declval<const typename TypeParam::hasher&>()( + std::declval<const typename TypeParam::key_type&>())), + size_t>())); + EXPECT_TRUE((std::is_convertible< + decltype(std::declval<const typename TypeParam::key_equal&>()( + std::declval<const typename TypeParam::key_type&>(), + std::declval<const typename TypeParam::key_type&>())), + bool>())); + EXPECT_TRUE((std::is_same<typename TypeParam::allocator_type::value_type, + typename TypeParam::value_type>())); + EXPECT_TRUE((std::is_same<typename TypeParam::value_type&, + typename TypeParam::reference>())); + EXPECT_TRUE((std::is_same<const typename TypeParam::value_type&, + typename TypeParam::const_reference>())); + EXPECT_TRUE((std::is_same<typename std::allocator_traits< + typename TypeParam::allocator_type>::pointer, + typename TypeParam::pointer>())); + EXPECT_TRUE( + (std::is_same<typename std::allocator_traits< + typename TypeParam::allocator_type>::const_pointer, + typename TypeParam::const_pointer>())); +} + +TYPED_TEST_P(MembersTest, SimpleFunctions) { + EXPECT_GT(TypeParam().max_size(), 0); +} + +TYPED_TEST_P(MembersTest, BeginEnd) { + TypeParam t = {typename TypeParam::value_type{}}; + EXPECT_EQ(t.begin(), t.cbegin()); + EXPECT_EQ(t.end(), t.cend()); + EXPECT_NE(t.begin(), t.end()); + EXPECT_NE(t.cbegin(), t.cend()); +} + +REGISTER_TYPED_TEST_SUITE_P(MembersTest, Typedefs, SimpleFunctions, BeginEnd); + +} // namespace container_internal +} // namespace absl + +#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MEMBERS_TEST_H_
diff --git a/absl/container/internal/unordered_map_modifiers_test.h b/absl/container/internal/unordered_map_modifiers_test.h index b6c633a..52a1092 100644 --- a/absl/container/internal/unordered_map_modifiers_test.h +++ b/absl/container/internal/unordered_map_modifiers_test.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -26,7 +26,7 @@ template <class UnordMap> class ModifiersTest : public ::testing::Test {}; -TYPED_TEST_CASE_P(ModifiersTest); +TYPED_TEST_SUITE_P(ModifiersTest); TYPED_TEST_P(ModifiersTest, Clear) { using T = hash_internal::GeneratedType<TypeParam>; @@ -269,4 +269,5 @@ } // namespace container_internal } // namespace absl + #endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MODIFIERS_TEST_H_
diff --git a/absl/container/internal/unordered_map_test.cc b/absl/container/internal/unordered_map_test.cc index 40e799c..72567ea 100644 --- a/absl/container/internal/unordered_map_test.cc +++ b/absl/container/internal/unordered_map_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -16,6 +16,7 @@ #include "absl/container/internal/unordered_map_constructor_test.h" #include "absl/container/internal/unordered_map_lookup_test.h" +#include "absl/container/internal/unordered_map_members_test.h" #include "absl/container/internal/unordered_map_modifiers_test.h" namespace absl { @@ -29,9 +30,10 @@ StatefulTestingEqual, Alloc<std::pair<const std::string, std::string>>>>; -INSTANTIATE_TYPED_TEST_CASE_P(UnorderedMap, ConstructorTest, MapTypes); -INSTANTIATE_TYPED_TEST_CASE_P(UnorderedMap, LookupTest, MapTypes); -INSTANTIATE_TYPED_TEST_CASE_P(UnorderedMap, ModifiersTest, MapTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedMap, ConstructorTest, MapTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedMap, LookupTest, MapTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedMap, MembersTest, MapTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedMap, ModifiersTest, MapTypes); } // namespace } // namespace container_internal
diff --git a/absl/container/internal/unordered_set_constructor_test.h b/absl/container/internal/unordered_set_constructor_test.h index cb59370..f484468 100644 --- a/absl/container/internal/unordered_set_constructor_test.h +++ b/absl/container/internal/unordered_set_constructor_test.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -16,12 +16,14 @@ #define ABSL_CONTAINER_INTERNAL_UNORDERED_SET_CONSTRUCTOR_TEST_H_ #include <algorithm> +#include <unordered_set> #include <vector> #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/container/internal/hash_generator_testing.h" #include "absl/container/internal/hash_policy_testing.h" +#include "absl/meta/type_traits.h" namespace absl { namespace container_internal { @@ -29,7 +31,7 @@ template <class UnordMap> class ConstructorTest : public ::testing::Test {}; -TYPED_TEST_CASE_P(ConstructorTest); +TYPED_TEST_SUITE_P(ConstructorTest); TYPED_TEST_P(ConstructorTest, NoArgs) { TypeParam m; @@ -91,8 +93,28 @@ EXPECT_GE(cm.bucket_count(), 123); } -TYPED_TEST_P(ConstructorTest, BucketCountAlloc) { +template <typename T> +struct is_std_unordered_set : std::false_type {}; + +template <typename... T> +struct is_std_unordered_set<std::unordered_set<T...>> : std::true_type {}; + #if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17) +using has_cxx14_std_apis = std::true_type; +#else +using has_cxx14_std_apis = std::false_type; +#endif + +template <typename T> +using expect_cxx14_apis = + absl::disjunction<absl::negation<is_std_unordered_set<T>>, + has_cxx14_std_apis>; + +template <typename TypeParam> +void BucketCountAllocTest(std::false_type) {} + +template <typename TypeParam> +void BucketCountAllocTest(std::true_type) { using A = typename TypeParam::allocator_type; A alloc(0); TypeParam m(123, alloc); @@ -100,11 +122,17 @@ EXPECT_TRUE(m.empty()); EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre()); EXPECT_GE(m.bucket_count(), 123); -#endif } -TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) { -#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17) +TYPED_TEST_P(ConstructorTest, BucketCountAlloc) { + BucketCountAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>()); +} + +template <typename TypeParam> +void BucketCountHashAllocTest(std::false_type) {} + +template <typename TypeParam> +void BucketCountHashAllocTest(std::true_type) { using H = typename TypeParam::hasher; using A = typename TypeParam::allocator_type; H hasher; @@ -115,18 +143,38 @@ EXPECT_TRUE(m.empty()); EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre()); EXPECT_GE(m.bucket_count(), 123); -#endif } -TYPED_TEST_P(ConstructorTest, BucketAlloc) { +TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) { + BucketCountHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>()); +} + #if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS +using has_alloc_std_constructors = std::true_type; +#else +using has_alloc_std_constructors = std::false_type; +#endif + +template <typename T> +using expect_alloc_constructors = + absl::disjunction<absl::negation<is_std_unordered_set<T>>, + has_alloc_std_constructors>; + +template <typename TypeParam> +void AllocTest(std::false_type) {} + +template <typename TypeParam> +void AllocTest(std::true_type) { using A = typename TypeParam::allocator_type; A alloc(0); TypeParam m(alloc); EXPECT_EQ(m.get_allocator(), alloc); EXPECT_TRUE(m.empty()); EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre()); -#endif +} + +TYPED_TEST_P(ConstructorTest, Alloc) { + AllocTest<TypeParam>(expect_alloc_constructors<TypeParam>()); } TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashEqualAlloc) { @@ -148,8 +196,11 @@ EXPECT_GE(m.bucket_count(), 123); } -TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) { -#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17) +template <typename TypeParam> +void InputIteratorBucketAllocTest(std::false_type) {} + +template <typename TypeParam> +void InputIteratorBucketAllocTest(std::true_type) { using T = hash_internal::GeneratedType<TypeParam>; using A = typename TypeParam::allocator_type; A alloc(0); @@ -160,11 +211,17 @@ EXPECT_EQ(m.get_allocator(), alloc); EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values)); EXPECT_GE(m.bucket_count(), 123); -#endif } -TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) { -#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17) +TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) { + InputIteratorBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>()); +} + +template <typename TypeParam> +void InputIteratorBucketHashAllocTest(std::false_type) {} + +template <typename TypeParam> +void InputIteratorBucketHashAllocTest(std::true_type) { using T = hash_internal::GeneratedType<TypeParam>; using H = typename TypeParam::hasher; using A = typename TypeParam::allocator_type; @@ -178,7 +235,10 @@ EXPECT_EQ(m.get_allocator(), alloc); EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values)); EXPECT_GE(m.bucket_count(), 123); -#endif +} + +TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) { + InputIteratorBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>()); } TYPED_TEST_P(ConstructorTest, CopyConstructor) { @@ -196,10 +256,14 @@ EXPECT_EQ(m.key_eq(), n.key_eq()); EXPECT_EQ(m.get_allocator(), n.get_allocator()); EXPECT_EQ(m, n); + EXPECT_NE(TypeParam(0, hasher, equal, alloc), n); } -TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) { -#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS +template <typename TypeParam> +void CopyConstructorAllocTest(std::false_type) {} + +template <typename TypeParam> +void CopyConstructorAllocTest(std::true_type) { using T = hash_internal::GeneratedType<TypeParam>; using H = typename TypeParam::hasher; using E = typename TypeParam::key_equal; @@ -214,7 +278,10 @@ EXPECT_EQ(m.key_eq(), n.key_eq()); EXPECT_NE(m.get_allocator(), n.get_allocator()); EXPECT_EQ(m, n); -#endif +} + +TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) { + CopyConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>()); } // TODO(alkis): Test non-propagating allocators on copy constructors. @@ -237,8 +304,11 @@ EXPECT_EQ(m, n); } -TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) { -#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS +template <typename TypeParam> +void MoveConstructorAllocTest(std::false_type) {} + +template <typename TypeParam> +void MoveConstructorAllocTest(std::true_type) { using T = hash_internal::GeneratedType<TypeParam>; using H = typename TypeParam::hasher; using E = typename TypeParam::key_equal; @@ -254,7 +324,10 @@ EXPECT_EQ(m.key_eq(), n.key_eq()); EXPECT_NE(m.get_allocator(), n.get_allocator()); EXPECT_EQ(m, n); -#endif +} + +TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) { + MoveConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>()); } // TODO(alkis): Test non-propagating allocators on move constructors. @@ -277,8 +350,11 @@ EXPECT_GE(m.bucket_count(), 123); } -TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) { -#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17) +template <typename TypeParam> +void InitializerListBucketAllocTest(std::false_type) {} + +template <typename TypeParam> +void InitializerListBucketAllocTest(std::true_type) { using T = hash_internal::GeneratedType<TypeParam>; using A = typename TypeParam::allocator_type; hash_internal::Generator<T> gen; @@ -288,11 +364,17 @@ EXPECT_EQ(m.get_allocator(), alloc); EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values)); EXPECT_GE(m.bucket_count(), 123); -#endif } -TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) { -#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17) +TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) { + InitializerListBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>()); +} + +template <typename TypeParam> +void InitializerListBucketHashAllocTest(std::false_type) {} + +template <typename TypeParam> +void InitializerListBucketHashAllocTest(std::true_type) { using T = hash_internal::GeneratedType<TypeParam>; using H = typename TypeParam::hasher; using A = typename TypeParam::allocator_type; @@ -305,10 +387,13 @@ EXPECT_EQ(m.get_allocator(), alloc); EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values)); EXPECT_GE(m.bucket_count(), 123); -#endif } -TYPED_TEST_P(ConstructorTest, Assignment) { +TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) { + InitializerListBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>()); +} + +TYPED_TEST_P(ConstructorTest, CopyAssignment) { using T = hash_internal::GeneratedType<TypeParam>; using H = typename TypeParam::hasher; using E = typename TypeParam::key_equal; @@ -394,15 +479,16 @@ REGISTER_TYPED_TEST_CASE_P( ConstructorTest, NoArgs, BucketCount, BucketCountHash, BucketCountHashEqual, - BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc, - BucketAlloc, InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc, + BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc, Alloc, + InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc, InputIteratorBucketHashAlloc, CopyConstructor, CopyConstructorAlloc, MoveConstructor, MoveConstructorAlloc, InitializerListBucketHashEqualAlloc, - InitializerListBucketAlloc, InitializerListBucketHashAlloc, Assignment, - MoveAssignment, AssignmentFromInitializerList, - AssignmentOverwritesExisting, MoveAssignmentOverwritesExisting, + InitializerListBucketAlloc, InitializerListBucketHashAlloc, CopyAssignment, + MoveAssignment, AssignmentFromInitializerList, AssignmentOverwritesExisting, + MoveAssignmentOverwritesExisting, AssignmentFromInitializerListOverwritesExisting, AssignmentOnSelf); } // namespace container_internal } // namespace absl + #endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_CONSTRUCTOR_TEST_H_
diff --git a/absl/container/internal/unordered_set_lookup_test.h b/absl/container/internal/unordered_set_lookup_test.h index aca9c6a..05b32b5 100644 --- a/absl/container/internal/unordered_set_lookup_test.h +++ b/absl/container/internal/unordered_set_lookup_test.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -26,7 +26,7 @@ template <class UnordSet> class LookupTest : public ::testing::Test {}; -TYPED_TEST_CASE_P(LookupTest); +TYPED_TEST_SUITE_P(LookupTest); TYPED_TEST_P(LookupTest, Count) { using T = hash_internal::GeneratedType<TypeParam>; @@ -85,4 +85,5 @@ } // namespace container_internal } // namespace absl + #endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_LOOKUP_TEST_H_
diff --git a/absl/container/internal/unordered_set_members_test.h b/absl/container/internal/unordered_set_members_test.h new file mode 100644 index 0000000..b96c945 --- /dev/null +++ b/absl/container/internal/unordered_set_members_test.h
@@ -0,0 +1,84 @@ +// 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_CONTAINER_INTERNAL_UNORDERED_SET_MEMBERS_TEST_H_ +#define ABSL_CONTAINER_INTERNAL_UNORDERED_SET_MEMBERS_TEST_H_ + +#include <type_traits> +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/meta/type_traits.h" + +namespace absl { +namespace container_internal { + +template <class UnordSet> +class MembersTest : public ::testing::Test {}; + +TYPED_TEST_SUITE_P(MembersTest); + +template <typename T> +void UseType() {} + +TYPED_TEST_P(MembersTest, Typedefs) { + EXPECT_TRUE((std::is_same<typename TypeParam::key_type, + typename TypeParam::value_type>())); + EXPECT_TRUE((absl::conjunction< + absl::negation<std::is_signed<typename TypeParam::size_type>>, + std::is_integral<typename TypeParam::size_type>>())); + EXPECT_TRUE((absl::conjunction< + std::is_signed<typename TypeParam::difference_type>, + std::is_integral<typename TypeParam::difference_type>>())); + EXPECT_TRUE((std::is_convertible< + decltype(std::declval<const typename TypeParam::hasher&>()( + std::declval<const typename TypeParam::key_type&>())), + size_t>())); + EXPECT_TRUE((std::is_convertible< + decltype(std::declval<const typename TypeParam::key_equal&>()( + std::declval<const typename TypeParam::key_type&>(), + std::declval<const typename TypeParam::key_type&>())), + bool>())); + EXPECT_TRUE((std::is_same<typename TypeParam::allocator_type::value_type, + typename TypeParam::value_type>())); + EXPECT_TRUE((std::is_same<typename TypeParam::value_type&, + typename TypeParam::reference>())); + EXPECT_TRUE((std::is_same<const typename TypeParam::value_type&, + typename TypeParam::const_reference>())); + EXPECT_TRUE((std::is_same<typename std::allocator_traits< + typename TypeParam::allocator_type>::pointer, + typename TypeParam::pointer>())); + EXPECT_TRUE( + (std::is_same<typename std::allocator_traits< + typename TypeParam::allocator_type>::const_pointer, + typename TypeParam::const_pointer>())); +} + +TYPED_TEST_P(MembersTest, SimpleFunctions) { + EXPECT_GT(TypeParam().max_size(), 0); +} + +TYPED_TEST_P(MembersTest, BeginEnd) { + TypeParam t = {typename TypeParam::value_type{}}; + EXPECT_EQ(t.begin(), t.cbegin()); + EXPECT_EQ(t.end(), t.cend()); + EXPECT_NE(t.begin(), t.end()); + EXPECT_NE(t.cbegin(), t.cend()); +} + +REGISTER_TYPED_TEST_SUITE_P(MembersTest, Typedefs, SimpleFunctions, BeginEnd); + +} // namespace container_internal +} // namespace absl + +#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_MEMBERS_TEST_H_
diff --git a/absl/container/internal/unordered_set_modifiers_test.h b/absl/container/internal/unordered_set_modifiers_test.h index 9beacf3..79a8d42 100644 --- a/absl/container/internal/unordered_set_modifiers_test.h +++ b/absl/container/internal/unordered_set_modifiers_test.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -26,7 +26,7 @@ template <class UnordSet> class ModifiersTest : public ::testing::Test {}; -TYPED_TEST_CASE_P(ModifiersTest); +TYPED_TEST_SUITE_P(ModifiersTest); TYPED_TEST_P(ModifiersTest, Clear) { using T = hash_internal::GeneratedType<TypeParam>; @@ -184,4 +184,5 @@ } // namespace container_internal } // namespace absl + #endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_MODIFIERS_TEST_H_
diff --git a/absl/container/internal/unordered_set_test.cc b/absl/container/internal/unordered_set_test.cc index 1281ce5..6478fac 100644 --- a/absl/container/internal/unordered_set_test.cc +++ b/absl/container/internal/unordered_set_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -16,21 +16,23 @@ #include "absl/container/internal/unordered_set_constructor_test.h" #include "absl/container/internal/unordered_set_lookup_test.h" +#include "absl/container/internal/unordered_set_members_test.h" #include "absl/container/internal/unordered_set_modifiers_test.h" namespace absl { namespace container_internal { namespace { -using SetTypes = - ::testing::Types<std::unordered_set<int, StatefulTestingHash, - StatefulTestingEqual, Alloc<int>>, - std::unordered_set<std::string, StatefulTestingHash, - StatefulTestingEqual, Alloc<std::string>>>; +using SetTypes = ::testing::Types< + std::unordered_set<int, StatefulTestingHash, StatefulTestingEqual, + Alloc<int>>, + std::unordered_set<std::string, StatefulTestingHash, StatefulTestingEqual, + Alloc<std::string>>>; -INSTANTIATE_TYPED_TEST_CASE_P(UnorderedSet, ConstructorTest, SetTypes); -INSTANTIATE_TYPED_TEST_CASE_P(UnorderedSet, LookupTest, SetTypes); -INSTANTIATE_TYPED_TEST_CASE_P(UnorderedSet, ModifiersTest, SetTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedSet, ConstructorTest, SetTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedSet, LookupTest, SetTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedSet, MembersTest, SetTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedSet, ModifiersTest, SetTypes); } // namespace } // namespace container_internal
diff --git a/absl/container/node_hash_map.h b/absl/container/node_hash_map.h index 6369ec3..a841f5a 100644 --- a/absl/container/node_hash_map.h +++ b/absl/container/node_hash_map.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -40,6 +40,7 @@ #include <type_traits> #include <utility> +#include "absl/algorithm/container.h" #include "absl/container/internal/container_memory.h" #include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export #include "absl/container/internal/node_hash_policy.h" @@ -71,7 +72,7 @@ // By default, `node_hash_map` uses the `absl::Hash` hashing framework. // All fundamental and Abseil types that support the `absl::Hash` framework have // a compatible equality operator for comparing insertions into `node_hash_map`. -// If your type is not yet supported by the `asbl::Hash` framework, see +// If your type is not yet supported by the `absl::Hash` framework, see // absl/hash/hash.h for information on extending Abseil hashing to user-defined // types. // @@ -91,7 +92,7 @@ // std::string search_key = "b"; // auto result = ducks.find(search_key); // if (result != ducks.end()) { -// std::cout << "Result: " << search_key->second << std::endl; +// std::cout << "Result: " << result->second << std::endl; // } template <class Key, class Value, class Hash = absl::container_internal::hash_default_hash<Key>, @@ -104,6 +105,46 @@ using Base = typename node_hash_map::raw_hash_map; public: + // Constructors and Assignment Operators + // + // A node_hash_map supports the same overload set as `std::unordered_map` + // for construction and assignment: + // + // * Default constructor + // + // // No allocation for the table's elements is made. + // absl::node_hash_map<int, std::string> map1; + // + // * Initializer List constructor + // + // absl::node_hash_map<int, std::string> map2 = + // {{1, "huey"}, {2, "dewey"}, {3, "louie"},}; + // + // * Copy constructor + // + // absl::node_hash_map<int, std::string> map3(map2); + // + // * Copy assignment operator + // + // // Hash functor and Comparator are copied as well + // absl::node_hash_map<int, std::string> map4; + // map4 = map3; + // + // * Move constructor + // + // // Move is guaranteed efficient + // absl::node_hash_map<int, std::string> map5(std::move(map4)); + // + // * Move assignment operator + // + // // May be efficient if allocators are compatible + // absl::node_hash_map<int, std::string> map6; + // map6 = std::move(map5); + // + // * Range constructor + // + // std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}}; + // absl::node_hash_map<int, std::string> map7(v.begin(), v.end()); node_hash_map() {} using Base::Base; @@ -526,5 +567,16 @@ static const Value& value(const value_type* elem) { return elem->second; } }; } // namespace container_internal + +namespace container_algorithm_internal { + +// Specialization of trait in absl/algorithm/container.h +template <class Key, class T, class Hash, class KeyEqual, class Allocator> +struct IsUnorderedContainer< + absl::node_hash_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type {}; + +} // namespace container_algorithm_internal + } // namespace absl + #endif // ABSL_CONTAINER_NODE_HASH_MAP_H_
diff --git a/absl/container/node_hash_map_test.cc b/absl/container/node_hash_map_test.cc index bd78964..0f2714a 100644 --- a/absl/container/node_hash_map_test.cc +++ b/absl/container/node_hash_map_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -17,6 +17,7 @@ #include "absl/container/internal/tracked.h" #include "absl/container/internal/unordered_map_constructor_test.h" #include "absl/container/internal/unordered_map_lookup_test.h" +#include "absl/container/internal/unordered_map_members_test.h" #include "absl/container/internal/unordered_map_modifiers_test.h" namespace absl { @@ -34,9 +35,10 @@ StatefulTestingEqual, Alloc<std::pair<const std::string, std::string>>>>; -INSTANTIATE_TYPED_TEST_CASE_P(NodeHashMap, ConstructorTest, MapTypes); -INSTANTIATE_TYPED_TEST_CASE_P(NodeHashMap, LookupTest, MapTypes); -INSTANTIATE_TYPED_TEST_CASE_P(NodeHashMap, ModifiersTest, MapTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashMap, ConstructorTest, MapTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashMap, LookupTest, MapTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashMap, MembersTest, MapTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashMap, ModifiersTest, MapTypes); using M = absl::node_hash_map<std::string, Tracked<int>>;
diff --git a/absl/container/node_hash_set.h b/absl/container/node_hash_set.h index 90d4ce0..0cd1fe5 100644 --- a/absl/container/node_hash_set.h +++ b/absl/container/node_hash_set.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -37,6 +37,7 @@ #include <type_traits> +#include "absl/algorithm/container.h" #include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export #include "absl/container/internal/node_hash_policy.h" #include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export @@ -67,7 +68,7 @@ // By default, `node_hash_set` uses the `absl::Hash` hashing framework. // All fundamental and Abseil types that support the `absl::Hash` framework have // a compatible equality operator for comparing insertions into `node_hash_set`. -// If your type is not yet supported by the `asbl::Hash` framework, see +// If your type is not yet supported by the `absl::Hash` framework, see // absl/hash/hash.h for information on extending Abseil hashing to user-defined // types. // @@ -96,6 +97,46 @@ using Base = typename node_hash_set::raw_hash_set; public: + // Constructors and Assignment Operators + // + // A node_hash_set supports the same overload set as `std::unordered_map` + // for construction and assignment: + // + // * Default constructor + // + // // No allocation for the table's elements is made. + // absl::node_hash_set<std::string> set1; + // + // * Initializer List constructor + // + // absl::node_hash_set<std::string> set2 = + // {{"huey"}, {"dewey"}, {"louie"},}; + // + // * Copy constructor + // + // absl::node_hash_set<std::string> set3(set2); + // + // * Copy assignment operator + // + // // Hash functor and Comparator are copied as well + // absl::node_hash_set<std::string> set4; + // set4 = set3; + // + // * Move constructor + // + // // Move is guaranteed efficient + // absl::node_hash_set<std::string> set5(std::move(set4)); + // + // * Move assignment operator + // + // // May be efficient if allocators are compatible + // absl::node_hash_set<std::string> set6; + // set6 = std::move(set5); + // + // * Range constructor + // + // std::vector<std::string> v = {"a", "b"}; + // absl::node_hash_set<std::string> set7(v.begin(), v.end()); node_hash_set() {} using Base::Base; @@ -232,8 +273,7 @@ // // The element may be constructed even if there already is an element with the // key in the container, in which case the newly constructed element will be - // destroyed immediately. Prefer `try_emplace()` unless your key is not - // copyable or moveable. + // destroyed immediately. // // If rehashing occurs due to the insertion, all iterators are invalidated. using Base::emplace; @@ -247,8 +287,7 @@ // // The element may be constructed even if there already is an element with the // key in the container, in which case the newly constructed element will be - // destroyed immediately. Prefer `try_emplace()` unless your key is not - // copyable or moveable. + // destroyed immediately. // // If rehashing occurs due to the insertion, all iterators are invalidated. using Base::emplace_hint; @@ -435,5 +474,15 @@ static size_t element_space_used(const T*) { return sizeof(T); } }; } // namespace container_internal + +namespace container_algorithm_internal { + +// Specialization of trait in absl/algorithm/container.h +template <class Key, class Hash, class KeyEqual, class Allocator> +struct IsUnorderedContainer<absl::node_hash_set<Key, Hash, KeyEqual, Allocator>> + : std::true_type {}; + +} // namespace container_algorithm_internal } // namespace absl + #endif // ABSL_CONTAINER_NODE_HASH_SET_H_
diff --git a/absl/container/node_hash_set_test.cc b/absl/container/node_hash_set_test.cc index 7e498f0..0ea76e7 100644 --- a/absl/container/node_hash_set_test.cc +++ b/absl/container/node_hash_set_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -16,6 +16,7 @@ #include "absl/container/internal/unordered_set_constructor_test.h" #include "absl/container/internal/unordered_set_lookup_test.h" +#include "absl/container/internal/unordered_set_members_test.h" #include "absl/container/internal/unordered_set_modifiers_test.h" namespace absl { @@ -29,14 +30,15 @@ using SetTypes = ::testing::Types< node_hash_set<int, StatefulTestingHash, StatefulTestingEqual, Alloc<int>>, node_hash_set<std::string, StatefulTestingHash, StatefulTestingEqual, - Alloc<int>>, + Alloc<std::string>>, node_hash_set<Enum, StatefulTestingHash, StatefulTestingEqual, Alloc<Enum>>, node_hash_set<EnumClass, StatefulTestingHash, StatefulTestingEqual, Alloc<EnumClass>>>; -INSTANTIATE_TYPED_TEST_CASE_P(NodeHashSet, ConstructorTest, SetTypes); -INSTANTIATE_TYPED_TEST_CASE_P(NodeHashSet, LookupTest, SetTypes); -INSTANTIATE_TYPED_TEST_CASE_P(NodeHashSet, ModifiersTest, SetTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashSet, ConstructorTest, SetTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashSet, LookupTest, SetTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashSet, MembersTest, SetTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashSet, ModifiersTest, SetTypes); TEST(NodeHashSet, MoveableNotCopyableCompiles) { node_hash_set<std::unique_ptr<void*>> t;
diff --git a/absl/copts.bzl b/absl/copts.bzl deleted file mode 100644 index 5c508f1..0000000 --- a/absl/copts.bzl +++ /dev/null
@@ -1,164 +0,0 @@ -"""absl specific copts. - -Flags specified here must not impact ABI. Code compiled with and without these -opts will be linked together, and in some cases headers compiled with and -without these options will be part of the same program. -""" -GCC_FLAGS = [ - "-Wall", - "-Wextra", - "-Wcast-qual", - "-Wconversion-null", - "-Wmissing-declarations", - "-Woverlength-strings", - "-Wpointer-arith", - "-Wunused-local-typedefs", - "-Wunused-result", - "-Wvarargs", - "-Wvla", # variable-length array - "-Wwrite-strings", - # Google style does not use unsigned integers, though STL containers - # have unsigned types. - "-Wno-sign-compare", -] - -GCC_TEST_FLAGS = [ - "-Wno-conversion-null", - "-Wno-missing-declarations", - "-Wno-sign-compare", - "-Wno-unused-function", - "-Wno-unused-parameter", - "-Wno-unused-private-field", -] - -# Docs on single flags is preceded by a comment. -# Docs on groups of flags is preceded by ###. - -LLVM_FLAGS = [ - "-Wall", - "-Wextra", - "-Weverything", - # 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-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-undef", - "-Wno-unknown-warning-option", - "-Wno-unreachable-code", - # Causes warnings on include guards - "-Wno-unused-macros", - "-Wno-weak-vtables", - ### - # 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_FLAGS = [ - "-Wno-c99-extensions", - "-Wno-missing-noreturn", - "-Wno-missing-prototypes", - "-Wno-missing-variable-declarations", - "-Wno-null-conversion", - "-Wno-shadow", - "-Wno-shift-sign-overflow", - "-Wno-sign-compare", - "-Wno-unused-function", - "-Wno-unused-member-function", - "-Wno-unused-parameter", - "-Wno-unused-private-field", - "-Wno-unused-template", - "-Wno-used-but-marked-unused", - "-Wno-zero-as-null-pointer-constant", - # gtest depends on this GNU extension being offered. - "-Wno-gnu-zero-variadic-macro-arguments", -] - -MSVC_FLAGS = [ - "/W3", - "/wd4005", # macro-redefinition - "/wd4068", # unknown pragma - "/wd4180", # qualifier applied to function type has no meaning; ignored - "/wd4244", # conversion from 'type1' to 'type2', possible loss of data - "/wd4267", # conversion from 'size_t' to 'type', possible loss of data - "/wd4800", # forcing value to bool 'true' or 'false' (performance warning) - "/DNOMINMAX", # Don't define min and max macros (windows.h) - "/DWIN32_LEAN_AND_MEAN", # Don't bloat namespace with incompatible winsock versions. - "/D_CRT_SECURE_NO_WARNINGS", # Don't warn about usage of insecure C functions -] - -MSVC_TEST_FLAGS = [ - "/wd4018", # signed/unsigned mismatch - "/wd4101", # unreferenced local variable - "/wd4503", # decorated name length exceeded, name was truncated -] - -# /Wall with msvc includes unhelpful warnings such as C4711, C4710, ... -ABSL_DEFAULT_COPTS = select({ - "//absl:windows": MSVC_FLAGS, - "//absl:llvm_compiler": LLVM_FLAGS, - "//conditions:default": GCC_FLAGS, -}) - -# in absence of modules (--compiler=gcc or -c opt), cc_tests leak their copts -# to their (included header) dependencies and fail to build outside absl -ABSL_TEST_COPTS = ABSL_DEFAULT_COPTS + select({ - "//absl:windows": MSVC_TEST_FLAGS, - "//absl:llvm_compiler": LLVM_TEST_FLAGS, - "//conditions:default": GCC_TEST_FLAGS, -}) - -ABSL_EXCEPTIONS_FLAG = select({ - "//absl:windows": ["/U_HAS_EXCEPTIONS", "/D_HAS_EXCEPTIONS=1", "/EHsc"], - "//conditions:default": ["-fexceptions"], -}) - -ABSL_EXCEPTIONS_FLAG_LINKOPTS = select({ - "//conditions:default": [], -})
diff --git a/absl/copts/AbseilConfigureCopts.cmake b/absl/copts/AbseilConfigureCopts.cmake new file mode 100644 index 0000000..5084958 --- /dev/null +++ b/absl/copts/AbseilConfigureCopts.cmake
@@ -0,0 +1,52 @@ +# See absl/copts/copts.py and absl/copts/generate_copts.py +include(GENERATED_AbseilCopts) + +set(ABSL_LSAN_LINKOPTS "") +set(ABSL_HAVE_LSAN OFF) + +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_EXCEPTIONS_FLAG "${ABSL_GCC_EXCEPTIONS_FLAGS}") +elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + # MATCHES so we get both Clang and AppleClang + if (MSVC) + # clang-cl is half MSVC, half LLVM + set(ABSL_DEFAULT_COPTS "${ABSL_CLANG_CL_FLAGS}") + set(ABSL_TEST_COPTS "${ABSL_CLANG_CL_FLAGS};${ABSL_CLANG_CL_TEST_FLAGS}") + set(ABSL_EXCEPTIONS_FLAG "${ABSL_CLANG_CL_EXCEPTIONS_FLAGS}") + else() + set(ABSL_DEFAULT_COPTS "${ABSL_LLVM_FLAGS}") + set(ABSL_TEST_COPTS "${ABSL_LLVM_FLAGS};${ABSL_LLVM_TEST_FLAGS}") + set(ABSL_EXCEPTIONS_FLAG "${ABSL_LLVM_EXCEPTIONS_FLAGS}") + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + # AppleClang doesn't have lsan + # https://developer.apple.com/documentation/code_diagnostics + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 3.5) + set(ABSL_LSAN_LINKOPTS "-fsanitize=leak") + set(ABSL_HAVE_LSAN ON) + endif() + endif() + endif() +elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + set(ABSL_DEFAULT_COPTS "${ABSL_MSVC_FLAGS}") + set(ABSL_TEST_COPTS "${ABSL_MSVC_FLAGS};${ABSL_MSVC_TEST_FLAGS}") + set(ABSL_EXCEPTIONS_FLAG "${ABSL_MSVC_EXCEPTIONS_FLAGS}") +else() + message(WARNING "Unknown compiler: ${CMAKE_CXX_COMPILER}. Building with no default flags") + set(ABSL_DEFAULT_COPTS "") + set(ABSL_TEST_COPTS "") + set(ABSL_EXCEPTIONS_FLAG "") +endif() + +# This flag is used internally for Bazel builds and is kept here for consistency +set(ABSL_EXCEPTIONS_FLAG_LINKOPTS "") + +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()
diff --git a/absl/copts/GENERATED_AbseilCopts.cmake b/absl/copts/GENERATED_AbseilCopts.cmake new file mode 100644 index 0000000..9031bfa --- /dev/null +++ b/absl/copts/GENERATED_AbseilCopts.cmake
@@ -0,0 +1,208 @@ +# GENERATED! DO NOT MANUALLY EDIT THIS FILE. +# +# (1) Edit absl/copts/copts.py. +# (2) Run `python <path_to_absl>/copts/generate_copts.py`. + +list(APPEND ABSL_CLANG_CL_EXCEPTIONS_FLAGS + "/U_HAS_EXCEPTIONS" + "/D_HAS_EXCEPTIONS=1" + "/EHsc" +) + +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-undef" + "-Wno-unknown-warning-option" + "-Wno-unreachable-code" + "-Wno-unused-macros" + "-Wno-weak-vtables" + "-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" + "/D_SCL_SECURE_NO_WARNINGS" + "/D_ENABLE_EXTENDED_ALIGNED_STORAGE" +) + +list(APPEND ABSL_CLANG_CL_TEST_FLAGS + "-Wno-c99-extensions" + "-Wno-missing-noreturn" + "-Wno-missing-prototypes" + "-Wno-missing-variable-declarations" + "-Wno-null-conversion" + "-Wno-shadow" + "-Wno-shift-sign-overflow" + "-Wno-sign-compare" + "-Wno-unused-function" + "-Wno-unused-member-function" + "-Wno-unused-parameter" + "-Wno-unused-private-field" + "-Wno-unused-template" + "-Wno-used-but-marked-unused" + "-Wno-zero-as-null-pointer-constant" + "-Wno-gnu-zero-variadic-macro-arguments" +) + +list(APPEND ABSL_GCC_EXCEPTIONS_FLAGS + "-fexceptions" +) + +list(APPEND ABSL_GCC_FLAGS + "-Wall" + "-Wextra" + "-Wcast-qual" + "-Wconversion-null" + "-Wmissing-declarations" + "-Woverlength-strings" + "-Wpointer-arith" + "-Wunused-local-typedefs" + "-Wunused-result" + "-Wvarargs" + "-Wvla" + "-Wwrite-strings" + "-Wno-missing-field-initializers" + "-Wno-sign-compare" +) + +list(APPEND ABSL_GCC_TEST_FLAGS + "-Wno-conversion-null" + "-Wno-missing-declarations" + "-Wno-sign-compare" + "-Wno-unused-function" + "-Wno-unused-parameter" + "-Wno-unused-private-field" +) + +list(APPEND ABSL_LLVM_EXCEPTIONS_FLAGS + "-fexceptions" +) + +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-undef" + "-Wno-unknown-warning-option" + "-Wno-unreachable-code" + "-Wno-unused-macros" + "-Wno-weak-vtables" + "-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" +) + +list(APPEND ABSL_LLVM_TEST_FLAGS + "-Wno-c99-extensions" + "-Wno-missing-noreturn" + "-Wno-missing-prototypes" + "-Wno-missing-variable-declarations" + "-Wno-null-conversion" + "-Wno-shadow" + "-Wno-shift-sign-overflow" + "-Wno-sign-compare" + "-Wno-unused-function" + "-Wno-unused-member-function" + "-Wno-unused-parameter" + "-Wno-unused-private-field" + "-Wno-unused-template" + "-Wno-used-but-marked-unused" + "-Wno-zero-as-null-pointer-constant" + "-Wno-gnu-zero-variadic-macro-arguments" +) + +list(APPEND ABSL_MSVC_EXCEPTIONS_FLAGS + "/U_HAS_EXCEPTIONS" + "/D_HAS_EXCEPTIONS=1" + "/EHsc" +) + +list(APPEND ABSL_MSVC_FLAGS + "/W3" + "/DNOMINMAX" + "/DWIN32_LEAN_AND_MEAN" + "/D_CRT_SECURE_NO_WARNINGS" + "/D_SCL_SECURE_NO_WARNINGS" + "/D_ENABLE_EXTENDED_ALIGNED_STORAGE" + "/wd4005" + "/wd4068" + "/wd4180" + "/wd4244" + "/wd4267" + "/wd4800" +) + +list(APPEND ABSL_MSVC_TEST_FLAGS + "/wd4018" + "/wd4101" + "/wd4503" +)
diff --git a/absl/copts/GENERATED_copts.bzl b/absl/copts/GENERATED_copts.bzl new file mode 100644 index 0000000..e05a58e --- /dev/null +++ b/absl/copts/GENERATED_copts.bzl
@@ -0,0 +1,209 @@ +"""GENERATED! DO NOT MANUALLY EDIT THIS FILE. + +(1) Edit absl/copts/copts.py. +(2) Run `python <path_to_absl>/copts/generate_copts.py`. +""" + +ABSL_CLANG_CL_EXCEPTIONS_FLAGS = [ + "/U_HAS_EXCEPTIONS", + "/D_HAS_EXCEPTIONS=1", + "/EHsc", +] + +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-undef", + "-Wno-unknown-warning-option", + "-Wno-unreachable-code", + "-Wno-unused-macros", + "-Wno-weak-vtables", + "-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", + "/D_SCL_SECURE_NO_WARNINGS", + "/D_ENABLE_EXTENDED_ALIGNED_STORAGE", +] + +ABSL_CLANG_CL_TEST_FLAGS = [ + "-Wno-c99-extensions", + "-Wno-missing-noreturn", + "-Wno-missing-prototypes", + "-Wno-missing-variable-declarations", + "-Wno-null-conversion", + "-Wno-shadow", + "-Wno-shift-sign-overflow", + "-Wno-sign-compare", + "-Wno-unused-function", + "-Wno-unused-member-function", + "-Wno-unused-parameter", + "-Wno-unused-private-field", + "-Wno-unused-template", + "-Wno-used-but-marked-unused", + "-Wno-zero-as-null-pointer-constant", + "-Wno-gnu-zero-variadic-macro-arguments", +] + +ABSL_GCC_EXCEPTIONS_FLAGS = [ + "-fexceptions", +] + +ABSL_GCC_FLAGS = [ + "-Wall", + "-Wextra", + "-Wcast-qual", + "-Wconversion-null", + "-Wmissing-declarations", + "-Woverlength-strings", + "-Wpointer-arith", + "-Wunused-local-typedefs", + "-Wunused-result", + "-Wvarargs", + "-Wvla", + "-Wwrite-strings", + "-Wno-missing-field-initializers", + "-Wno-sign-compare", +] + +ABSL_GCC_TEST_FLAGS = [ + "-Wno-conversion-null", + "-Wno-missing-declarations", + "-Wno-sign-compare", + "-Wno-unused-function", + "-Wno-unused-parameter", + "-Wno-unused-private-field", +] + +ABSL_LLVM_EXCEPTIONS_FLAGS = [ + "-fexceptions", +] + +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-undef", + "-Wno-unknown-warning-option", + "-Wno-unreachable-code", + "-Wno-unused-macros", + "-Wno-weak-vtables", + "-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", +] + +ABSL_LLVM_TEST_FLAGS = [ + "-Wno-c99-extensions", + "-Wno-missing-noreturn", + "-Wno-missing-prototypes", + "-Wno-missing-variable-declarations", + "-Wno-null-conversion", + "-Wno-shadow", + "-Wno-shift-sign-overflow", + "-Wno-sign-compare", + "-Wno-unused-function", + "-Wno-unused-member-function", + "-Wno-unused-parameter", + "-Wno-unused-private-field", + "-Wno-unused-template", + "-Wno-used-but-marked-unused", + "-Wno-zero-as-null-pointer-constant", + "-Wno-gnu-zero-variadic-macro-arguments", +] + +ABSL_MSVC_EXCEPTIONS_FLAGS = [ + "/U_HAS_EXCEPTIONS", + "/D_HAS_EXCEPTIONS=1", + "/EHsc", +] + +ABSL_MSVC_FLAGS = [ + "/W3", + "/DNOMINMAX", + "/DWIN32_LEAN_AND_MEAN", + "/D_CRT_SECURE_NO_WARNINGS", + "/D_SCL_SECURE_NO_WARNINGS", + "/D_ENABLE_EXTENDED_ALIGNED_STORAGE", + "/wd4005", + "/wd4068", + "/wd4180", + "/wd4244", + "/wd4267", + "/wd4800", +] + +ABSL_MSVC_TEST_FLAGS = [ + "/wd4018", + "/wd4101", + "/wd4503", +]
diff --git a/absl/copts/configure_copts.bzl b/absl/copts/configure_copts.bzl new file mode 100644 index 0000000..1655add --- /dev/null +++ b/absl/copts/configure_copts.bzl
@@ -0,0 +1,42 @@ +"""absl specific copts. + +This file simply selects the correct options from the generated files. To +change Abseil copts, edit absl/copts/copts.py +""" + +load( + "//absl:copts/GENERATED_copts.bzl", + "ABSL_GCC_EXCEPTIONS_FLAGS", + "ABSL_GCC_FLAGS", + "ABSL_GCC_TEST_FLAGS", + "ABSL_LLVM_EXCEPTIONS_FLAGS", + "ABSL_LLVM_FLAGS", + "ABSL_LLVM_TEST_FLAGS", + "ABSL_MSVC_EXCEPTIONS_FLAGS", + "ABSL_MSVC_FLAGS", + "ABSL_MSVC_TEST_FLAGS", +) + +ABSL_DEFAULT_COPTS = select({ + "//absl:windows": ABSL_MSVC_FLAGS, + "//absl:llvm_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, + "//conditions:default": ABSL_GCC_TEST_FLAGS, +}) + +ABSL_EXCEPTIONS_FLAG = select({ + "//absl:windows": ABSL_MSVC_EXCEPTIONS_FLAGS, + "//absl:llvm_compiler": ABSL_LLVM_EXCEPTIONS_FLAGS, + "//conditions:default": ABSL_GCC_EXCEPTIONS_FLAGS, +}) + +ABSL_EXCEPTIONS_FLAG_LINKOPTS = select({ + "//conditions:default": [], +})
diff --git a/absl/copts/copts.py b/absl/copts/copts.py new file mode 100644 index 0000000..3c9d429 --- /dev/null +++ b/absl/copts/copts.py
@@ -0,0 +1,178 @@ +"""Abseil compiler options. + +This is the source of truth for Abseil compiler options. To modify Abseil +compilation options: + + (1) Edit the appropriate list in this file based on the platform the flag is + needed on. + (2) Run `<path_to_absl>/copts/generate_copts.py`. + +The generated copts are consumed by configure_copts.bzl and +AbseilConfigureCopts.cmake. +""" + +# /Wall with msvc includes unhelpful warnings such as C4711, C4710, ... +MSVC_BIG_WARNING_FLAGS = [ + "/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-undef", + "-Wno-unknown-warning-option", + "-Wno-unreachable-code", + # Causes warnings on include guards + "-Wno-unused-macros", + "-Wno-weak-vtables", + ### + # 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-missing-noreturn", + "-Wno-missing-prototypes", + "-Wno-missing-variable-declarations", + "-Wno-null-conversion", + "-Wno-shadow", + "-Wno-shift-sign-overflow", + "-Wno-sign-compare", + "-Wno-unused-function", + "-Wno-unused-member-function", + "-Wno-unused-parameter", + "-Wno-unused-private-field", + "-Wno-unused-template", + "-Wno-used-but-marked-unused", + "-Wno-zero-as-null-pointer-constant", + # gtest depends on this GNU extension being offered. + "-Wno-gnu-zero-variadic-macro-arguments", +] + +MSVC_STYLE_EXCEPTIONS_FLAGS = [ + "/U_HAS_EXCEPTIONS", "/D_HAS_EXCEPTIONS=1", "/EHsc" +] + +MSVC_DEFINES = [ + "/DNOMINMAX", # Don't define min and max macros (windows.h) + # Don't bloat namespace with incompatible winsock versions. + "/DWIN32_LEAN_AND_MEAN", + # Don't warn about usage of insecure C functions. + "/D_CRT_SECURE_NO_WARNINGS", + "/D_SCL_SECURE_NO_WARNINGS", + # Introduced in VS 2017 15.8, allow overaligned types in aligned_storage + "/D_ENABLE_EXTENDED_ALIGNED_STORAGE", +] + +COPT_VARS = { + "ABSL_GCC_FLAGS": [ + "-Wall", + "-Wextra", + "-Wcast-qual", + "-Wconversion-null", + "-Wmissing-declarations", + "-Woverlength-strings", + "-Wpointer-arith", + "-Wunused-local-typedefs", + "-Wunused-result", + "-Wvarargs", + "-Wvla", # variable-length array + "-Wwrite-strings", + # gcc-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", + ], + "ABSL_GCC_TEST_FLAGS": [ + "-Wno-conversion-null", + "-Wno-missing-declarations", + "-Wno-sign-compare", + "-Wno-unused-function", + "-Wno-unused-parameter", + "-Wno-unused-private-field", + ], + "ABSL_GCC_EXCEPTIONS_FLAGS": ["-fexceptions"], + "ABSL_LLVM_FLAGS": LLVM_BIG_WARNING_FLAGS + LLVM_DISABLE_WARNINGS_FLAGS, + "ABSL_LLVM_TEST_FLAGS": LLVM_TEST_DISABLE_WARNINGS_FLAGS, + "ABSL_LLVM_EXCEPTIONS_FLAGS": ["-fexceptions"], + "ABSL_CLANG_CL_FLAGS": (MSVC_BIG_WARNING_FLAGS + + LLVM_DISABLE_WARNINGS_FLAGS + MSVC_DEFINES), + "ABSL_CLANG_CL_TEST_FLAGS": LLVM_TEST_DISABLE_WARNINGS_FLAGS, + "ABSL_CLANG_CL_EXCEPTIONS_FLAGS": MSVC_STYLE_EXCEPTIONS_FLAGS, + "ABSL_MSVC_FLAGS": MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES + [ + "/wd4005", # macro-redefinition + "/wd4068", # unknown pragma + "/wd4180", # qualifier applied to function type has no meaning; ignored + "/wd4244", # conversion from 'type1' to 'type2', possible loss of data + "/wd4267", # conversion from 'size_t' to 'type', possible loss of data + # forcing value to bool 'true' or 'false' (performance warning) + "/wd4800", + ], + "ABSL_MSVC_TEST_FLAGS": [ + "/wd4018", # signed/unsigned mismatch + "/wd4101", # unreferenced local variable + "/wd4503", # decorated name length exceeded, name was truncated + ], + "ABSL_MSVC_EXCEPTIONS_FLAGS": MSVC_STYLE_EXCEPTIONS_FLAGS, +}
diff --git a/absl/copts/generate_copts.py b/absl/copts/generate_copts.py new file mode 100755 index 0000000..28b677e --- /dev/null +++ b/absl/copts/generate_copts.py
@@ -0,0 +1,108 @@ +#!/usr/bin/python +"""Generate Abseil compile compile option configs. + +Usage: <path_to_absl>/copts/generate_copts.py + +The configs are generated from copts.py. +""" + +from os import path +import sys +from copts import COPT_VARS + + +# Helper functions +def file_header_lines(): + return [ + "GENERATED! DO NOT MANUALLY EDIT THIS FILE.", "", + "(1) Edit absl/copts/copts.py.", + "(2) Run `python <path_to_absl>/copts/generate_copts.py`." + ] + + +def flatten(*lists): + return [item for sublist in lists for item in sublist] + + +def relative_filename(filename): + return path.join(path.dirname(__file__), filename) + + +# Style classes. These contain all the syntactic styling needed to generate a +# copt file for different build tools. +class CMakeStyle(object): + """Style object for CMake copts file.""" + + def separator(self): + return "" + + def list_introducer(self, name): + return "list(APPEND " + name + + def list_closer(self): + return ")\n" + + def docstring(self): + return "\n".join((("# " + line).strip() for line in file_header_lines())) + + def filename(self): + return "GENERATED_AbseilCopts.cmake" + + +class StarlarkStyle(object): + """Style object for Starlark copts file.""" + + def separator(self): + return "," + + def list_introducer(self, name): + return name + " = [" + + def list_closer(self): + return "]\n" + + def docstring(self): + docstring_quotes = "\"\"\"" + return docstring_quotes + "\n".join( + flatten(file_header_lines(), [docstring_quotes])) + + def filename(self): + return "GENERATED_copts.bzl" + + +# Copt file generation +def copt_list(name, arg_list, style): + make_line = lambda s: " \"" + s + "\"" + style.separator() + external_str_list = [make_line(s) for s in arg_list] + + return "\n".join( + flatten( + [style.list_introducer(name)], + external_str_list, + [style.list_closer()])) + + +def generate_copt_file(style): + """Creates a generated copt file using the given style object. + + Args: + style: either StarlarkStyle() or CMakeStyle() + """ + with open(relative_filename(style.filename()), "w") as f: + f.write(style.docstring()) + f.write("\n") + for var_name, arg_list in sorted(COPT_VARS.items()): + f.write("\n") + f.write(copt_list(var_name, arg_list, style)) + + +def main(argv): + if len(argv) > 1: + raise RuntimeError("generate_copts needs no command line args") + + generate_copt_file(StarlarkStyle()) + generate_copt_file(CMakeStyle()) + + +if __name__ == "__main__": + main(sys.argv)
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel index e1e7fce..c9184f9 100644 --- a/absl/debugging/BUILD.bazel +++ b/absl/debugging/BUILD.bazel
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -15,7 +15,7 @@ # load( - "//absl:copts.bzl", + "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_TEST_COPTS", ) @@ -149,6 +149,7 @@ copts = ABSL_DEFAULT_COPTS, deps = [ "//absl/base", + "//absl/base:core_headers", "//absl/base:dynamic_annotations", ], ) @@ -180,22 +181,8 @@ cc_library( name = "leak_check", - srcs = select({ - # The leak checking interface depends on weak function - # declarations that may not necessarily have definitions. - # Windows doesn't support this, and ios requires - # guaranteed definitions for weak symbols. - "//absl:ios": [], - "//absl:windows": [], - "//conditions:default": [ - "leak_check.cc", - ], - }), - hdrs = select({ - "//absl:ios": [], - "//absl:windows": [], - "//conditions:default": ["leak_check.h"], - }), + srcs = ["leak_check.cc"], + hdrs = ["leak_check.h"], deps = ["//absl/base:core_headers"], )
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt index 4af2ec8..dccd4a5 100644 --- a/absl/debugging/CMakeLists.txt +++ b/absl/debugging/CMakeLists.txt
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -14,204 +14,292 @@ # limitations under the License. # -list(APPEND DEBUGGING_PUBLIC_HEADERS - "failure_signal_handler.h" - "leak_check.h" - "stacktrace.h" - "symbolize.h" -) - -# TODO(cohenjon) The below is all kinds of wrong. Make this match what we do in -# Bazel -list(APPEND DEBUGGING_INTERNAL_HEADERS - "internal/address_is_readable.h" - "internal/demangle.h" - "internal/elf_mem_image.h" - "internal/examine_stack.h" - "internal/stacktrace_config.h" - "internal/symbolize.h" - "internal/vdso_support.h" -) - -list(APPEND DEBUGGING_INTERNAL_SRC - "internal/address_is_readable.cc" - "internal/elf_mem_image.cc" - "internal/vdso_support.cc" -) - - -list(APPEND STACKTRACE_SRC - "stacktrace.cc" - ${DEBUGGING_INTERNAL_SRC} - ${DEBUGGING_PUBLIC_HEADERS} - ${DEBUGGING_INTERNAL_HEADERS} -) - -list(APPEND SYMBOLIZE_SRC - "symbolize.cc" - "symbolize_elf.inc" - "symbolize_unimplemented.inc" - "symbolize_win32.inc" - "internal/demangle.cc" - ${DEBUGGING_PUBLIC_HEADERS} - ${DEBUGGING_INTERNAL_HEADERS} - ${DEBUGGING_INTERNAL_SRC} -) - -list(APPEND FAILURE_SIGNAL_HANDLER_SRC - "failure_signal_handler.cc" - ${DEBUGGING_PUBLIC_HEADERS} -) - -list(APPEND EXAMINE_STACK_SRC - "internal/examine_stack.cc" - ${DEBUGGING_PUBLIC_HEADERS} - ${DEBUGGING_INTERNAL_HEADERS} -) - -absl_library( - TARGET - absl_stacktrace - SOURCES - ${STACKTRACE_SRC} - EXPORT_NAME +absl_cc_library( + NAME stacktrace + HDRS + "stacktrace.h" + SRCS + "stacktrace.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::debugging_internal + absl::base + absl::core_headers + PUBLIC ) -absl_library( - TARGET - absl_symbolize - SOURCES - ${SYMBOLIZE_SRC} - PUBLIC_LIBRARIES - absl::base - absl_malloc_internal - EXPORT_NAME +absl_cc_library( + NAME symbolize -) - -absl_library( - TARGET - absl_failure_signal_handler - SOURCES - ${FAILURE_SIGNAL_HANDLER_SRC} - PUBLIC_LIBRARIES - absl_base absl::examine_stack absl::stacktrace absl_synchronization - EXPORT_NAME - failure_signal_handler -) - -# Internal-only. Projects external to Abseil should not depend -# directly on this library. -absl_library( - TARGET - absl_examine_stack - SOURCES - ${EXAMINE_STACK_SRC} - EXPORT_NAME - examine_stack -) - -list(APPEND LEAK_CHECK_SRC - "leak_check.cc" -) - - -# leak_check library -absl_library( - TARGET - absl_leak_check - SOURCES - ${LEAK_CHECK_SRC} - PUBLIC_LIBRARIES - absl_base - EXPORT_NAME - leak_check -) - - -# component target -absl_header_library( - TARGET - absl_debugging - PUBLIC_LIBRARIES - absl_stacktrace absl_leak_check - EXPORT_NAME - debugging -) - -# -## TESTS -# - -list(APPEND STACK_CONSUMPTION_SRC - "internal/stack_consumption.cc" - "internal/stack_consumption.h" -) - -absl_library( - TARGET - absl_stack_consumption - SOURCES - ${STACK_CONSUMPTION_SRC} -) - -absl_test( - TARGET - absl_stack_consumption_test - SOURCES - "internal/stack_consumption_test.cc" - PUBLIC_LIBRARIES - absl_stack_consumption + HDRS + "symbolize.h" + "internal/symbolize.h" + SRCS + "symbolize.cc" + "symbolize_elf.inc" + "symbolize_unimplemented.inc" + "symbolize_win32.inc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::debugging_internal + absl::demangle_internal absl::base + absl::core_headers + absl::malloc_internal + PUBLIC ) -list(APPEND DEMANGLE_TEST_SRC "internal/demangle_test.cc") - -absl_test( - TARGET - demangle_test - SOURCES - ${DEMANGLE_TEST_SRC} - PUBLIC_LIBRARIES - absl_symbolize absl_stack_consumption -) - -list(APPEND SYMBOLIZE_TEST_SRC "symbolize_test.cc") - -absl_test( - TARGET +absl_cc_test( + NAME symbolize_test - SOURCES - ${SYMBOLIZE_TEST_SRC} - PUBLIC_LIBRARIES - absl::base absl::memory absl_symbolize absl_stack_consumption + SRCS + "symbolize_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::stack_consumption + absl::symbolize + absl::base + absl::core_headers + absl::memory + gmock ) -list(APPEND FAILURE_SIGNAL_HANDLER_TEST_SRC "failure_signal_handler_test.cc") +absl_cc_library( + NAME + examine_stack + HDRS + "internal/examine_stack.h" + SRCS + "internal/examine_stack.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::stacktrace + absl::symbolize + absl::base + absl::core_headers +) -absl_test( - TARGET +absl_cc_library( + NAME + failure_signal_handler + HDRS + "failure_signal_handler.h" + SRCS + "failure_signal_handler.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::examine_stack + absl::stacktrace + absl::base + absl::config + absl::core_headers + PUBLIC +) + +absl_cc_test( + NAME failure_signal_handler_test - SOURCES - ${FAILURE_SIGNAL_HANDLER_TEST_SRC} - PUBLIC_LIBRARIES - absl_examine_stack - absl_failure_signal_handler - absl_stacktrace - absl_symbolize + SRCS + "failure_signal_handler_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::failure_signal_handler + absl::stacktrace + absl::symbolize absl::base absl::strings + Threads::Threads + gmock ) -# test leak_check_test -list(APPEND LEAK_CHECK_TEST_SRC "leak_check_test.cc") +absl_cc_library( + NAME + debugging_internal + 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" + "internal/elf_mem_image.cc" + "internal/vdso_support.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::base + absl::core_headers + absl::dynamic_annotations +) -absl_test( - TARGET +absl_cc_library( + NAME + demangle_internal + HDRS + "internal/demangle.h" + SRCS + "internal/demangle.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::base + absl::core_headers + PUBLIC +) + +absl_cc_test( + NAME + demangle_test + SRCS + "internal/demangle_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::demangle_internal + absl::stack_consumption + absl::base + absl::core_headers + absl::memory + gmock_main +) + +absl_cc_library( + NAME + leak_check + HDRS + "leak_check.h" + SRCS + "leak_check.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::core_headers + PUBLIC +) + +absl_cc_library( + NAME + leak_check_disable + SRCS + "leak_check_disable.cc" + PUBLIC +) + +absl_cc_library( + NAME + leak_check_api_enabled_for_testing + HDRS + "leak_check.h" + SRCS + "leak_check.cc" + COPTS + $<$<BOOL:${ABSL_HAVE_LSAN}>:-DLEAK_SANITIZER> + TESTONLY +) + +absl_cc_library( + NAME + leak_check_api_disabled_for_testing + HDRS + "leak_check.h" + SRCS + "leak_check.cc" + COPTS + "-ULEAK_SANITIZER" + TESTONLY +) + +absl_cc_test( + NAME leak_check_test - SOURCES - ${LEAK_CHECK_TEST_SRC} - PUBLIC_LIBRARIES - absl_leak_check + SRCS + "leak_check_test.cc" + COPTS + "$<$<BOOL:${ABSL_HAVE_LSAN}>:-DABSL_EXPECT_LEAK_SANITIZER>" + LINKOPTS + "${ABSL_LSAN_LINKOPTS}" + DEPS + absl::leak_check_api_enabled_for_testing + absl::base + gmock_main +) + +absl_cc_test( + NAME + leak_check_no_lsan_test + SRCS + "leak_check_test.cc" + COPTS + "-UABSL_EXPECT_LEAK_SANITIZER" + DEPS + absl::leak_check_api_disabled_for_testing + absl::base + gmock_main +) + +absl_cc_test( + NAME + disabled_leak_check_test + SRCS + "leak_check_fail_test.cc" + LINKOPTS + "${ABSL_LSAN_LINKOPTS}" + DEPS + absl::leak_check_api_enabled_for_testing + absl::leak_check_disable + absl::base + gmock_main +) + +absl_cc_library( + NAME + stack_consumption + HDRS + "internal/stack_consumption.h" + SRCS + "internal/stack_consumption.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::base + absl::core_headers + TESTONLY +) + +absl_cc_test( + NAME + stack_consumption_test + SRCS + "internal/stack_consumption_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::stack_consumption + absl::base + absl::core_headers + gmock_main +) + +# component target +absl_cc_library( + NAME + debugging + DEPS + absl::stacktrace + absl::leak_check + PUBLIC )
diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc index d4b957b..c6a4d96 100644 --- a/absl/debugging/failure_signal_handler.cc +++ b/absl/debugging/failure_signal_handler.cc
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -119,7 +119,11 @@ #ifndef _WIN32 static bool SetupAlternateStackOnce() { +#if defined(__wasm__) || defined (__asjms__) const size_t page_mask = getpagesize() - 1; +#else + 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)
diff --git a/absl/debugging/failure_signal_handler.h b/absl/debugging/failure_signal_handler.h index c57954e..1beb78b 100644 --- a/absl/debugging/failure_signal_handler.h +++ b/absl/debugging/failure_signal_handler.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/failure_signal_handler_test.cc b/absl/debugging/failure_signal_handler_test.cc index ba52091..bb2cc48 100644 --- a/absl/debugging/failure_signal_handler_test.cc +++ b/absl/debugging/failure_signal_handler_test.cc
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -133,16 +133,17 @@ }; std::string SignalParamToString(const ::testing::TestParamInfo<int>& info) { - std::string result = absl::debugging_internal::FailureSignalToString(info.param); + std::string result = + absl::debugging_internal::FailureSignalToString(info.param); if (result.empty()) { result = absl::StrCat(info.param); } return result; } -INSTANTIATE_TEST_CASE_P(AbslDeathTest, FailureSignalHandlerDeathTest, - ::testing::ValuesIn(kFailureSignals), - SignalParamToString); +INSTANTIATE_TEST_SUITE_P(AbslDeathTest, FailureSignalHandlerDeathTest, + ::testing::ValuesIn(kFailureSignals), + SignalParamToString); #endif // GTEST_HAS_DEATH_TEST
diff --git a/absl/debugging/internal/address_is_readable.cc b/absl/debugging/internal/address_is_readable.cc index 7455aa0..99c4c64 100644 --- a/absl/debugging/internal/address_is_readable.cc +++ b/absl/debugging/internal/address_is_readable.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/internal/address_is_readable.h b/absl/debugging/internal/address_is_readable.h index 9d48030..ca8003e 100644 --- a/absl/debugging/internal/address_is_readable.h +++ b/absl/debugging/internal/address_is_readable.h
@@ -4,14 +4,13 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_ #define ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
diff --git a/absl/debugging/internal/demangle.cc b/absl/debugging/internal/demangle.cc index 4835445..52a553f 100644 --- a/absl/debugging/internal/demangle.cc +++ b/absl/debugging/internal/demangle.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -749,8 +749,8 @@ // <local-source-name> ::= L <source-name> [<discriminator>] // // References: -// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775 -// http://gcc.gnu.org/viewcvs?view=rev&revision=124467 +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775 +// https://gcc.gnu.org/viewcvs?view=rev&revision=124467 static bool ParseLocalSourceName(State *state) { ComplexityGuard guard(state); if (guard.IsTooComplex()) return false; @@ -1168,6 +1168,12 @@ } 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; @@ -1636,6 +1642,15 @@ } state->parse_state = copy; + // Pointer-to-member access expressions. This parses the same as a binary + // operator, but it's implemented separately because "ds" shouldn't be + // accepted in other contexts that parse an operator name. + if (ParseTwoCharToken(state, "ds") && ParseExpression(state) && + ParseExpression(state)) { + return true; + } + state->parse_state = copy; + // Parameter pack expansion if (ParseTwoCharToken(state, "sp") && ParseExpression(state)) { return true;
diff --git a/absl/debugging/internal/demangle.h b/absl/debugging/internal/demangle.h index 2e75564..81bb0df 100644 --- a/absl/debugging/internal/demangle.h +++ b/absl/debugging/internal/demangle.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc index b9d9008..883b92d 100644 --- a/absl/debugging/internal/demangle_test.cc +++ b/absl/debugging/internal/demangle_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -176,6 +176,7 @@ TEST(DemangleRegression, NegativeLength) { TestOnInput("_ZZn4"); } + TEST(DemangleRegression, DeeplyNestedArrayType) { const int depth = 100000; std::string data = "_ZStI";
diff --git a/absl/debugging/internal/elf_mem_image.cc b/absl/debugging/internal/elf_mem_image.cc index 3f747e7..e7408bc 100644 --- a/absl/debugging/internal/elf_mem_image.cc +++ b/absl/debugging/internal/elf_mem_image.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h index 3b57726..99b3758 100644 --- a/absl/debugging/internal/elf_mem_image.h +++ b/absl/debugging/internal/elf_mem_image.h
@@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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,
diff --git a/absl/debugging/internal/examine_stack.cc b/absl/debugging/internal/examine_stack.cc index faf8883..1ebc788 100644 --- a/absl/debugging/internal/examine_stack.cc +++ b/absl/debugging/internal/examine_stack.cc
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/internal/examine_stack.h b/absl/debugging/internal/examine_stack.h index a16c03b..56c9763 100644 --- a/absl/debugging/internal/examine_stack.h +++ b/absl/debugging/internal/examine_stack.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/internal/stack_consumption.cc b/absl/debugging/internal/stack_consumption.cc index 2b3b972..4b05f49 100644 --- a/absl/debugging/internal/stack_consumption.cc +++ b/absl/debugging/internal/stack_consumption.cc
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/internal/stack_consumption.h b/absl/debugging/internal/stack_consumption.h index 4c5fa0f..b860a3c 100644 --- a/absl/debugging/internal/stack_consumption.h +++ b/absl/debugging/internal/stack_consumption.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/internal/stack_consumption_test.cc b/absl/debugging/internal/stack_consumption_test.cc index 5ce3846..68bfa12 100644 --- a/absl/debugging/internal/stack_consumption_test.cc +++ b/absl/debugging/internal/stack_consumption_test.cc
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/internal/stacktrace_config.h b/absl/debugging/internal/stacktrace_config.h index dd713da..d4e8480 100644 --- a/absl/debugging/internal/stacktrace_config.h +++ b/absl/debugging/internal/stacktrace_config.h
@@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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, @@ -41,8 +41,9 @@ #define ABSL_STACKTRACE_INL_HEADER \ "absl/debugging/internal/stacktrace_aarch64-inl.inc" # elif defined(__arm__) +// Note: When using glibc this may require -funwind-tables to function properly. #define ABSL_STACKTRACE_INL_HEADER \ - "absl/debugging/internal/stacktrace_arm-inl.inc" + "absl/debugging/internal/stacktrace_generic-inl.inc" # else #define ABSL_STACKTRACE_INL_HEADER \ "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
diff --git a/absl/debugging/internal/stacktrace_generic-inl.inc b/absl/debugging/internal/stacktrace_generic-inl.inc index 2c9ca41..2e876fe 100644 --- a/absl/debugging/internal/stacktrace_generic-inl.inc +++ b/absl/debugging/internal/stacktrace_generic-inl.inc
@@ -12,13 +12,48 @@ #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_ #include <execinfo.h> +#include <atomic> #include <cstring> #include "absl/debugging/stacktrace.h" +// Sometimes, we can try to get a stack trace from within a stack +// trace, because we don't block signals inside this code (which would be too +// expensive: the two extra system calls per stack trace do matter here). +// That can cause a self-deadlock. +// Protect against such reentrant call by failing to get a stack trace. +// +// We use __thread here because the code here is extremely low level -- it is +// called while collecting stack traces from within malloc and mmap, and thus +// can not call anything which might call malloc or mmap itself. +static __thread int recursive = 0; + +// The stack trace function might be invoked very early in the program's +// execution (e.g. from the very first malloc if using tcmalloc). Also, the +// glibc implementation itself will trigger malloc the first time it is called. +// As such, we suppress usage of backtrace during this early stage of execution. +static std::atomic<bool> disable_stacktraces(true); // Disabled until healthy. +// Waiting until static initializers run seems to be late enough. +// This file is included into stacktrace.cc so this will only run once. +static int stacktraces_enabler = []() { + void* unused_stack[1]; + // Force the first backtrace to happen early to get the one-time shared lib + // loading (allocation) out of the way. After the first call it is much safer + // to use backtrace from a signal handler if we crash somewhere later. + backtrace(unused_stack, 1); + disable_stacktraces.store(false, std::memory_order_relaxed); + return 0; +}(); + template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, const void *ucp, int *min_dropped_frames) { + if (recursive || disable_stacktraces.load(std::memory_order_relaxed)) { + return 0; + } + ++recursive; + + static_cast<void>(ucp); // Unused. static const int kStackLength = 64; void * stack[kStackLength]; int size; @@ -45,6 +80,8 @@ } } + --recursive; + return result_count; }
diff --git a/absl/debugging/internal/stacktrace_powerpc-inl.inc b/absl/debugging/internal/stacktrace_powerpc-inl.inc index 860ac2b..9e0f2aa 100644 --- a/absl/debugging/internal/stacktrace_powerpc-inl.inc +++ b/absl/debugging/internal/stacktrace_powerpc-inl.inc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -14,8 +14,8 @@ // // Produce stack trace. I'm guessing (hoping!) the code is much like // for x86. For apple machines, at least, it seems to be; see -// http://developer.apple.com/documentation/mac/runtimehtml/RTArch-59.html -// http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK +// https://developer.apple.com/documentation/mac/runtimehtml/RTArch-59.html +// https://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK // Linux has similar code: http://patchwork.ozlabs.org/linuxppc/patch?id=8882 #ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_
diff --git a/absl/debugging/internal/stacktrace_win32-inl.inc b/absl/debugging/internal/stacktrace_win32-inl.inc index a8f8a56..b46491f 100644 --- a/absl/debugging/internal/stacktrace_win32-inl.inc +++ b/absl/debugging/internal/stacktrace_win32-inl.inc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -32,7 +32,7 @@ // server. // // This code is inspired by a patch from David Vitek: -// http://code.google.com/p/google-perftools/issues/detail?id=83 +// https://code.google.com/p/google-perftools/issues/detail?id=83 #ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_ #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
diff --git a/absl/debugging/internal/stacktrace_x86-inl.inc b/absl/debugging/internal/stacktrace_x86-inl.inc index ac85b92..25aa8bd 100644 --- a/absl/debugging/internal/stacktrace_x86-inl.inc +++ b/absl/debugging/internal/stacktrace_x86-inl.inc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -33,6 +33,7 @@ #include "absl/debugging/internal/address_is_readable.h" #include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems #include "absl/debugging/stacktrace.h" + #include "absl/base/internal/raw_logging.h" #if defined(__linux__) && defined(__i386__)
diff --git a/absl/debugging/internal/symbolize.h b/absl/debugging/internal/symbolize.h index 8d926fe..3e53789 100644 --- a/absl/debugging/internal/symbolize.h +++ b/absl/debugging/internal/symbolize.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -20,7 +20,6 @@ #include <cstddef> #include <cstdint> -#include "absl/base/port.h" // Needed for string vs std::string #ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE #error ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE cannot be directly set @@ -42,9 +41,9 @@ // Returns true on success; otherwise returns false in case of errors. // // This is not async-signal-safe. -bool ForEachSection( - int fd, const std::function<bool(const std::string& name, const ElfW(Shdr) &)>& - callback); +bool ForEachSection(int fd, + const std::function<bool(const std::string& name, + const ElfW(Shdr) &)>& callback); // Gets the section header for the given name, if it exists. Returns true on // success. Otherwise, returns false.
diff --git a/absl/debugging/internal/vdso_support.cc b/absl/debugging/internal/vdso_support.cc index e8129e8..23c3084 100644 --- a/absl/debugging/internal/vdso_support.cc +++ b/absl/debugging/internal/vdso_support.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/internal/vdso_support.h b/absl/debugging/internal/vdso_support.h index 8002c74..9895b48 100644 --- a/absl/debugging/internal/vdso_support.h +++ b/absl/debugging/internal/vdso_support.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/leak_check.cc b/absl/debugging/leak_check.cc index e01e5f8..ffe3d1b 100644 --- a/absl/debugging/leak_check.cc +++ b/absl/debugging/leak_check.cc
@@ -4,13 +4,14 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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. + // Wrappers around lsan_interface functions. // When lsan is not linked in, these functions are not available, // therefore Abseil code which depends on these functions is conditioned on the
diff --git a/absl/debugging/leak_check.h b/absl/debugging/leak_check.h index c930684..4d489c5 100644 --- a/absl/debugging/leak_check.h +++ b/absl/debugging/leak_check.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/leak_check_disable.cc b/absl/debugging/leak_check_disable.cc index df22c1c..924d6e3 100644 --- a/absl/debugging/leak_check_disable.cc +++ b/absl/debugging/leak_check_disable.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/leak_check_fail_test.cc b/absl/debugging/leak_check_fail_test.cc index bf541fe..2887cea 100644 --- a/absl/debugging/leak_check_fail_test.cc +++ b/absl/debugging/leak_check_fail_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/leak_check_test.cc b/absl/debugging/leak_check_test.cc index febd1ee..93a7edd 100644 --- a/absl/debugging/leak_check_test.cc +++ b/absl/debugging/leak_check_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/stacktrace.cc b/absl/debugging/stacktrace.cc index 463fad2..9de8782 100644 --- a/absl/debugging/stacktrace.cc +++ b/absl/debugging/stacktrace.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -46,6 +46,7 @@ #include ABSL_STACKTRACE_INL_HEADER #else # error Cannot calculate stack trace: will need to write for your environment + # include "absl/debugging/internal/stacktrace_aarch64-inl.inc" # include "absl/debugging/internal/stacktrace_arm-inl.inc" # include "absl/debugging/internal/stacktrace_generic-inl.inc" @@ -80,29 +81,29 @@ } // anonymous namespace -ABSL_ATTRIBUTE_NOINLINE -int GetStackFrames(void** result, int* sizes, int max_depth, int skip_count) { +ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackFrames( + void** result, int* sizes, int max_depth, int skip_count) { return Unwind<true, false>(result, sizes, max_depth, skip_count, nullptr, nullptr); } -ABSL_ATTRIBUTE_NOINLINE -int GetStackFramesWithContext(void** result, int* sizes, int max_depth, - int skip_count, const void* uc, - int* min_dropped_frames) { +ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int +GetStackFramesWithContext(void** result, int* sizes, int max_depth, + int skip_count, const void* uc, + int* min_dropped_frames) { return Unwind<true, true>(result, sizes, max_depth, skip_count, uc, min_dropped_frames); } -ABSL_ATTRIBUTE_NOINLINE -int GetStackTrace(void** result, int max_depth, int skip_count) { +ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackTrace( + void** result, int max_depth, int skip_count) { return Unwind<false, false>(result, nullptr, max_depth, skip_count, nullptr, nullptr); } -ABSL_ATTRIBUTE_NOINLINE -int GetStackTraceWithContext(void** result, int max_depth, int skip_count, - const void* uc, int* min_dropped_frames) { +ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int +GetStackTraceWithContext(void** result, int max_depth, int skip_count, + const void* uc, int* min_dropped_frames) { return Unwind<false, true>(result, nullptr, max_depth, skip_count, uc, min_dropped_frames); }
diff --git a/absl/debugging/stacktrace.h b/absl/debugging/stacktrace.h index 8b831e2..3fc1c03 100644 --- a/absl/debugging/stacktrace.h +++ b/absl/debugging/stacktrace.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/symbolize.cc b/absl/debugging/symbolize.cc index a35e24c..24e3a7f 100644 --- a/absl/debugging/symbolize.cc +++ b/absl/debugging/symbolize.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/symbolize.h b/absl/debugging/symbolize.h index 24e6e64..a73dbd9 100644 --- a/absl/debugging/symbolize.h +++ b/absl/debugging/symbolize.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/debugging/symbolize_elf.inc b/absl/debugging/symbolize_elf.inc index b16a42a..34def5c 100644 --- a/absl/debugging/symbolize_elf.inc +++ b/absl/debugging/symbolize_elf.inc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -333,7 +333,11 @@ } // namespace static int SymbolizerSize() { +#if defined(__wasm__) || defined(__asmjs__) int pagesize = getpagesize(); +#else + int pagesize = sysconf(_SC_PAGESIZE); +#endif return ((sizeof(Symbolizer) - 1) / pagesize + 1) * pagesize; } @@ -921,6 +925,14 @@ return p; } +// Normally we are only interested in "r?x" maps. +// On the PowerPC, function pointers point to descriptors in the .opd +// section. The descriptors themselves are not executable code, so +// we need to relax the check below to "r??". +static bool ShouldUseMapping(const char *const flags) { + return flags[0] == 'r' && (kPlatformUsesOPDSections || flags[2] == 'x'); +} + // Read /proc/self/maps and run "callback" for each mmapped file found. If // "callback" returns false, stop scanning and return true. Else continue // scanning /proc/self/maps. Return true if no parse error is found. @@ -990,12 +1002,8 @@ return false; } - // Check flags. Normally we are only interested in "r-x" maps. On - // the PowerPC, function pointers point to descriptors in the .opd - // section. The descriptors themselves are not executable code. So - // we need to relax the check below to "r**". - if (memcmp(flags_start, "r-x", 3) != 0 && // Not a "r-x" map. - !(kPlatformUsesOPDSections && flags_start[0] == 'r')) { + // Check flags. + if (!ShouldUseMapping(flags_start)) { continue; // We skip this map. } ++cursor; // Skip ' '.
diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc index 8029fbe..fc3ed93 100644 --- a/absl/debugging/symbolize_test.cc +++ b/absl/debugging/symbolize_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -392,16 +392,20 @@ extern "C" { inline void *ABSL_ATTRIBUTE_ALWAYS_INLINE inline_func() { void *pc = nullptr; -#if defined(__i386__) || defined(__x86_64__) - __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc)); +#if defined(__i386__) + __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc)); +#elif defined(__x86_64__) + __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [ PC ] "=r"(pc)); #endif return pc; } void *ABSL_ATTRIBUTE_NOINLINE non_inline_func() { void *pc = nullptr; -#if defined(__i386__) || defined(__x86_64__) - __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc)); +#if defined(__i386__) + __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc)); +#elif defined(__x86_64__) + __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [ PC ] "=r"(pc)); #endif return pc; }
diff --git a/absl/debugging/symbolize_unimplemented.inc b/absl/debugging/symbolize_unimplemented.inc index 2a3f4ac..7c580fe 100644 --- a/absl/debugging/symbolize_unimplemented.inc +++ b/absl/debugging/symbolize_unimplemented.inc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -26,6 +26,9 @@ bool RegisterFileMappingHint(const void *, const void *, uint64_t, const char *) { return false; } +bool GetFileMappingHint(const void **, const void **, uint64_t *, const char **) { + return false; +} } // namespace debugging_internal
diff --git a/absl/debugging/symbolize_win32.inc b/absl/debugging/symbolize_win32.inc index e3fff74..17ea618 100644 --- a/absl/debugging/symbolize_win32.inc +++ b/absl/debugging/symbolize_win32.inc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel index 50aa550..69860d9 100644 --- a/absl/hash/BUILD.bazel +++ b/absl/hash/BUILD.bazel
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -15,7 +15,7 @@ # load( - "//absl:copts.bzl", + "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_TEST_COPTS", ) @@ -93,7 +93,6 @@ srcs = ["internal/city.cc"], hdrs = [ "internal/city.h", - "internal/city_crc.h", ], copts = ABSL_DEFAULT_COPTS, deps = [
diff --git a/absl/hash/BUILD.gn b/absl/hash/BUILD.gn index 40b6b3a..cbe3abf 100644 --- a/absl/hash/BUILD.gn +++ b/absl/hash/BUILD.gn
@@ -91,7 +91,6 @@ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] public = [ "internal/city.h", - "internal/city_crc.h", ] sources = [ "internal/city.cc",
diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt index 35081e3..4cafc13 100644 --- a/absl/hash/CMakeLists.txt +++ b/absl/hash/CMakeLists.txt
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -14,67 +14,98 @@ # limitations under the License. # -list(APPEND HASH_PUBLIC_HEADERS - "hash.h" -) - -list(APPEND HASH_INTERNAL_HEADERS - "internal/city.h" - "internal/city_crc.h" - "internal/hash.h" -) - -# absl_hash library -list(APPEND HASH_SRC - "internal/city.cc" - "internal/hash.cc" - ${HASH_PUBLIC_HEADERS} - ${HASH_INTERNAL_HEADERS} -) - -set(HASH_PUBLIC_LIBRARIES absl::hash absl::container absl::strings absl::str_format absl::utility) - -absl_library( - TARGET - absl_hash - SOURCES - ${HASH_SRC} - PUBLIC_LIBRARIES - ${HASH_PUBLIC_LIBRARIES} - EXPORT_NAME +absl_cc_library( + NAME hash + HDRS + "hash.h" + SRCS + "internal/hash.cc" + "internal/hash.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::core_headers + absl::endian + absl::fixed_array + absl::meta + absl::int128 + absl::strings + absl::optional + absl::variant + absl::utility + absl::city + PUBLIC ) -# -## TESTS -# +absl_cc_library( + NAME + hash_testing + HDRS + "hash_testing.h" + DEPS + absl::spy_hash_state + absl::meta + absl::strings + absl::variant + gmock + TESTONLY +) -# testing support -set(HASH_TEST_HEADERS hash_testing.h internal/spy_hash_state.h) -set(HASH_TEST_PUBLIC_LIBRARIES absl::hash absl::container absl::numeric absl::strings absl::str_format) - -# hash_test -set(HASH_TEST_SRC "hash_test.cc" ${HASH_TEST_HEADERS}) - -absl_test( - TARGET +absl_cc_test( + NAME hash_test - SOURCES - ${HASH_TEST_SRC} - PUBLIC_LIBRARIES - ${HASH_TEST_PUBLIC_LIBRARIES} + SRCS + "hash_test.cc" + DEPS + absl::hash + absl::hash_testing + absl::core_headers + absl::flat_hash_set + absl::spy_hash_state + absl::meta + absl::int128 + gmock_main ) -# hash_test -set(CITY_TEST_SRC "internal/city_test.cc") +absl_cc_library( + NAME + spy_hash_state + HDRS + "internal/spy_hash_state.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::hash + absl::strings + absl::str_format + TESTONLY +) -absl_test( - TARGET +absl_cc_library( + NAME + city + HDRS + "internal/city.h" + SRCS + "internal/city.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::config + absl::core_headers + absl::endian +) + +absl_cc_test( + NAME city_test - SOURCES - ${CITY_TEST_SRC} - PUBLIC_LIBRARIES - ${HASH_TEST_PUBLIC_LIBRARIES} + SRCS + "internal/city_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::city + gmock_main ) -
diff --git a/absl/hash/hash.h b/absl/hash/hash.h index c7ba4c2..c0ede35 100644 --- a/absl/hash/hash.h +++ b/absl/hash/hash.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -25,8 +25,8 @@ // * `AbslHashValue`, an extension point that allows you to extend types to // support Abseil hashing without requiring you to define a hashing // algorithm. -// * `HashState`, a type-erased class which implement the manipulation of the -// hash state (H) itself. containing member functions `combine()` and +// * `HashState`, a type-erased class which implements the manipulation of the +// hash state (H) itself, contains member functions `combine()` and // `combine_contiguous()`, which you can use to contribute to an existing // hash state when hashing your types. // @@ -69,7 +69,7 @@ // `absl::Hash` // ----------------------------------------------------------------------------- // -// `absl::Hash<T>` is a convenient general-purpose hash functor for a type `T` +// `absl::Hash<T>` is a convenient general-purpose hash functor for any type `T` // satisfying any of the following conditions (in order): // // * T is an arithmetic or pointer type @@ -98,7 +98,7 @@ // * absl::string_view // * absl::InlinedVector // * absl::FixedArray -// * absl::unit128 +// * absl::uint128 // * absl::Time, absl::Duration, and absl::TimeZone // // Note: the list above is not meant to be exhaustive. Additional type support @@ -142,7 +142,7 @@ // // The "hash state" concept contains two member functions for mixing hash state: // -// * `H::combine()` +// * `H::combine(state, values...)` // // Combines an arbitrary number of values into a hash state, returning the // updated state. Note that the existing hash state is move-only and must be @@ -160,7 +160,7 @@ // state = H::combine(std::move(state), value2); // state = H::combine(std::move(state), value3); // -// * `H::combine_contiguous()` +// * `H::combine_contiguous(state, data, size)` // // Combines a contiguous array of `size` elements into a hash state, // returning the updated state. Note that the existing hash state is @@ -243,7 +243,7 @@ // absl::HashState::combine(std::move(state), v1_, v2_); // } // int v1_; -// string v2_; +// std::string v2_; // }; class HashState : public hash_internal::HashStateBase<HashState> { public: @@ -309,4 +309,5 @@ }; } // namespace absl + #endif // ABSL_HASH_HASH_H_
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc index 7b6fb2e..af95938 100644 --- a/absl/hash/hash_test.cc +++ b/absl/hash/hash_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -15,6 +15,7 @@ #include "absl/hash/hash.h" #include <array> +#include <bitset> #include <cstring> #include <deque> #include <forward_list> @@ -50,7 +51,7 @@ template <typename T> class HashValueIntTest : public testing::Test { }; -TYPED_TEST_CASE_P(HashValueIntTest); +TYPED_TEST_SUITE_P(HashValueIntTest); template <typename T> SpyHashState SpyHash(const T& value) { @@ -84,6 +85,345 @@ uint64_t, size_t>; INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueIntTest, IntTypes); +enum LegacyEnum { kValue1, kValue2, kValue3 }; + +enum class EnumClass { kValue4, kValue5, kValue6 }; + +TEST(HashValueTest, EnumAndBool) { + EXPECT_TRUE((is_hashable<LegacyEnum>::value)); + EXPECT_TRUE((is_hashable<EnumClass>::value)); + EXPECT_TRUE((is_hashable<bool>::value)); + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( + LegacyEnum::kValue1, LegacyEnum::kValue2, LegacyEnum::kValue3))); + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( + EnumClass::kValue4, EnumClass::kValue5, EnumClass::kValue6))); + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( + std::make_tuple(true, false))); +} + +TEST(HashValueTest, FloatingPoint) { + EXPECT_TRUE((is_hashable<float>::value)); + EXPECT_TRUE((is_hashable<double>::value)); + EXPECT_TRUE((is_hashable<long double>::value)); + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( + std::make_tuple(42.f, 0.f, -0.f, std::numeric_limits<float>::infinity(), + -std::numeric_limits<float>::infinity()))); + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( + std::make_tuple(42., 0., -0., std::numeric_limits<double>::infinity(), + -std::numeric_limits<double>::infinity()))); + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( + // Add some values with small exponent to test that NORMAL values also + // append their category. + .5L, 1.L, 2.L, 4.L, 42.L, 0.L, -0.L, + 17 * static_cast<long double>(std::numeric_limits<double>::max()), + std::numeric_limits<long double>::infinity(), + -std::numeric_limits<long double>::infinity()))); +} + +TEST(HashValueTest, Pointer) { + EXPECT_TRUE((is_hashable<int*>::value)); + + int i; + int* ptr = &i; + int* n = nullptr; + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( + std::make_tuple(&i, ptr, nullptr, ptr + 1, n))); +} + +TEST(HashValueTest, PointerAlignment) { + // We want to make sure that pointer alignment will not cause bits to be + // stuck. + + constexpr size_t kTotalSize = 1 << 20; + std::unique_ptr<char[]> data(new char[kTotalSize]); + constexpr size_t kLog2NumValues = 5; + constexpr size_t kNumValues = 1 << kLog2NumValues; + + for (size_t align = 1; align < kTotalSize / kNumValues; + align < 8 ? align += 1 : align < 1024 ? align += 8 : align += 32) { + SCOPED_TRACE(align); + ASSERT_LE(align * kNumValues, kTotalSize); + + size_t bits_or = 0; + size_t bits_and = ~size_t{}; + + for (size_t i = 0; i < kNumValues; ++i) { + size_t hash = absl::Hash<void*>()(data.get() + i * align); + bits_or |= hash; + bits_and &= hash; + } + + // Limit the scope to the bits we would be using for Swisstable. + constexpr size_t kMask = (1 << (kLog2NumValues + 7)) - 1; + size_t stuck_bits = (~bits_or | bits_and) & kMask; + EXPECT_EQ(stuck_bits, 0) << "0x" << std::hex << stuck_bits; + } +} + +TEST(HashValueTest, PairAndTuple) { + EXPECT_TRUE((is_hashable<std::pair<int, int>>::value)); + EXPECT_TRUE((is_hashable<std::pair<const int&, const int&>>::value)); + EXPECT_TRUE((is_hashable<std::tuple<int&, int&>>::value)); + EXPECT_TRUE((is_hashable<std::tuple<int&&, int&&>>::value)); + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( + std::make_pair(0, 42), std::make_pair(0, 42), std::make_pair(42, 0), + std::make_pair(0, 0), std::make_pair(42, 42), std::make_pair(1, 42)))); + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( + std::make_tuple(std::make_tuple(0, 0, 0), std::make_tuple(0, 0, 42), + std::make_tuple(0, 23, 0), std::make_tuple(17, 0, 0), + std::make_tuple(42, 0, 0), std::make_tuple(3, 9, 9), + std::make_tuple(0, 0, -42)))); + + // Test that tuples of lvalue references work (so we need a few lvalues): + int a = 0, b = 1, c = 17, d = 23; + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( + std::tie(a, a), std::tie(a, b), std::tie(b, c), std::tie(c, d)))); + + // Test that tuples of rvalue references work: + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( + std::forward_as_tuple(0, 0, 0), std::forward_as_tuple(0, 0, 42), + std::forward_as_tuple(0, 23, 0), std::forward_as_tuple(17, 0, 0), + std::forward_as_tuple(42, 0, 0), std::forward_as_tuple(3, 9, 9), + std::forward_as_tuple(0, 0, -42)))); +} + +TEST(HashValueTest, CombineContiguousWorks) { + std::vector<std::tuple<int>> v1 = {std::make_tuple(1), std::make_tuple(3)}; + std::vector<std::tuple<int>> v2 = {std::make_tuple(1), std::make_tuple(2)}; + + auto vh1 = SpyHash(v1); + auto vh2 = SpyHash(v2); + EXPECT_NE(vh1, vh2); +} + +struct DummyDeleter { + template <typename T> + void operator() (T* ptr) {} +}; + +struct SmartPointerEq { + template <typename T, typename U> + bool operator()(const T& t, const U& u) const { + return GetPtr(t) == GetPtr(u); + } + + template <typename T> + static auto GetPtr(const T& t) -> decltype(&*t) { + return t ? &*t : nullptr; + } + + static std::nullptr_t GetPtr(std::nullptr_t) { return nullptr; } +}; + +TEST(HashValueTest, SmartPointers) { + EXPECT_TRUE((is_hashable<std::unique_ptr<int>>::value)); + EXPECT_TRUE((is_hashable<std::unique_ptr<int, DummyDeleter>>::value)); + EXPECT_TRUE((is_hashable<std::shared_ptr<int>>::value)); + + int i, j; + std::unique_ptr<int, DummyDeleter> unique1(&i); + std::unique_ptr<int, DummyDeleter> unique2(&i); + std::unique_ptr<int, DummyDeleter> unique_other(&j); + std::unique_ptr<int, DummyDeleter> unique_null; + + std::shared_ptr<int> shared1(&i, DummyDeleter()); + std::shared_ptr<int> shared2(&i, DummyDeleter()); + std::shared_ptr<int> shared_other(&j, DummyDeleter()); + std::shared_ptr<int> shared_null; + + // Sanity check of the Eq function. + ASSERT_TRUE(SmartPointerEq{}(unique1, shared1)); + ASSERT_FALSE(SmartPointerEq{}(unique1, shared_other)); + ASSERT_TRUE(SmartPointerEq{}(unique_null, nullptr)); + ASSERT_FALSE(SmartPointerEq{}(shared2, nullptr)); + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( + std::forward_as_tuple(&i, nullptr, // + unique1, unique2, unique_null, // + absl::make_unique<int>(), // + shared1, shared2, shared_null, // + std::make_shared<int>()), + SmartPointerEq{})); +} + +TEST(HashValueTest, FunctionPointer) { + using Func = int (*)(); + EXPECT_TRUE(is_hashable<Func>::value); + + Func p1 = [] { return 2; }, p2 = [] { return 1; }; + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( + std::make_tuple(p1, p2, nullptr))); +} + +struct WrapInTuple { + template <typename T> + std::tuple<int, T, size_t> operator()(const T& t) const { + return std::make_tuple(7, t, 0xdeadbeef); + } +}; + +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'); + + 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)))); + + // 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))))); + + // Make sure that hashing a `const char*` does not use its std::string-value. + EXPECT_NE(SpyHash(static_cast<const char*>("ABC")), + SpyHash(absl::string_view("ABC"))); +} + +TEST(HashValueTest, StdArray) { + EXPECT_TRUE((is_hashable<std::array<int, 3>>::value)); + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( + std::make_tuple(std::array<int, 3>{}, std::array<int, 3>{{0, 23, 42}}))); +} + +TEST(HashValueTest, StdBitset) { + EXPECT_TRUE((is_hashable<std::bitset<257>>::value)); + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( + {std::bitset<2>("00"), std::bitset<2>("01"), std::bitset<2>("10"), + std::bitset<2>("11")})); + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( + {std::bitset<5>("10101"), std::bitset<5>("10001"), std::bitset<5>()})); + + constexpr int kNumBits = 256; + std::array<std::string, 6> bit_strings; + bit_strings.fill(std::string(kNumBits, '1')); + bit_strings[1][0] = '0'; + bit_strings[2][1] = '0'; + bit_strings[3][kNumBits / 3] = '0'; + bit_strings[4][kNumBits - 2] = '0'; + bit_strings[5][kNumBits - 1] = '0'; + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( + {std::bitset<kNumBits>(bit_strings[0].c_str()), + std::bitset<kNumBits>(bit_strings[1].c_str()), + std::bitset<kNumBits>(bit_strings[2].c_str()), + std::bitset<kNumBits>(bit_strings[3].c_str()), + std::bitset<kNumBits>(bit_strings[4].c_str()), + std::bitset<kNumBits>(bit_strings[5].c_str())})); +} // namespace + +template <typename T> +class HashValueSequenceTest : public testing::Test { +}; +TYPED_TEST_SUITE_P(HashValueSequenceTest); + +TYPED_TEST_P(HashValueSequenceTest, BasicUsage) { + EXPECT_TRUE((is_hashable<TypeParam>::value)); + + using ValueType = typename TypeParam::value_type; + auto a = static_cast<ValueType>(0); + auto b = static_cast<ValueType>(23); + auto c = static_cast<ValueType>(42); + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( + std::make_tuple(TypeParam(), TypeParam{}, TypeParam{a, b, c}, + TypeParam{a, b}, TypeParam{b, c}))); +} + +REGISTER_TYPED_TEST_CASE_P(HashValueSequenceTest, BasicUsage); +using IntSequenceTypes = + testing::Types<std::deque<int>, std::forward_list<int>, std::list<int>, + std::vector<int>, std::vector<bool>, std::set<int>, + std::multiset<int>>; +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. +// It uses std::abs() on the value to provide different bitwise representations +// of the same logical value. +struct Private { + int i; + template <typename H> + friend H AbslHashValue(H h, Private p) { + return H::combine(std::move(h), std::abs(p.i)); + } + + friend bool operator==(Private a, Private b) { + return std::abs(a.i) == std::abs(b.i); + } + + friend std::ostream& operator<<(std::ostream& o, Private p) { + return o << p.i; + } +}; + +TEST(HashValueTest, PrivateSanity) { + // Sanity check that Private is working as the tests below expect it to work. + EXPECT_TRUE(is_hashable<Private>::value); + EXPECT_NE(SpyHash(Private{0}), SpyHash(Private{1})); + EXPECT_EQ(SpyHash(Private{1}), SpyHash(Private{1})); +} + +TEST(HashValueTest, Optional) { + EXPECT_TRUE(is_hashable<absl::optional<Private>>::value); + + using O = absl::optional<Private>; + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( + std::make_tuple(O{}, O{{1}}, O{{-1}}, O{{10}}))); +} + +TEST(HashValueTest, Variant) { + using V = absl::variant<Private, std::string>; + EXPECT_TRUE(is_hashable<V>::value); + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( + V(Private{1}), V(Private{-1}), V(Private{2}), V("ABC"), V("BCD")))); + +#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ + struct S {}; + EXPECT_FALSE(is_hashable<absl::variant<S>>::value); +#endif +} + +TEST(HashValueTest, Maps) { + EXPECT_TRUE((is_hashable<std::map<int, std::string>>::value)); + + using M = std::map<int, std::string>; + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( + M{}, M{{0, "foo"}}, M{{1, "foo"}}, M{{0, "bar"}}, M{{1, "bar"}}, + M{{0, "foo"}, {42, "bar"}}, M{{1, "foo"}, {42, "bar"}}, + M{{1, "foo"}, {43, "bar"}}, M{{1, "foo"}, {43, "baz"}}))); + + using MM = std::multimap<int, std::string>; + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( + MM{}, MM{{0, "foo"}}, MM{{1, "foo"}}, MM{{0, "bar"}}, MM{{1, "bar"}}, + MM{{0, "foo"}, {0, "bar"}}, MM{{0, "bar"}, {0, "foo"}}, + MM{{0, "foo"}, {42, "bar"}}, MM{{1, "foo"}, {42, "bar"}}, + MM{{1, "foo"}, {1, "foo"}, {43, "bar"}}, MM{{1, "foo"}, {43, "baz"}}))); +} + template <typename T, typename = void> struct IsHashCallble : std::false_type {}; @@ -108,7 +448,8 @@ EXPECT_TRUE(IsHashCallble<int>::value); EXPECT_TRUE(IsAggregateInitializable<absl::Hash<int>>::value); } -#if ABSL_HASH_INTERNAL_CAN_POISON_ && !defined(__APPLE__) + +#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ TEST(IsHashableTest, PoisonHash) { struct X {}; EXPECT_FALSE((is_hashable<X>::value)); @@ -120,7 +461,7 @@ EXPECT_FALSE(IsHashCallble<X>::value); EXPECT_FALSE(IsAggregateInitializable<absl::Hash<X>>::value); } -#endif // ABSL_HASH_INTERNAL_CAN_POISON_ +#endif // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ // Hashable types // @@ -159,8 +500,16 @@ Int(4)); } }; +enum class InvokeTag { + kUniquelyRepresented, + kHashValue, +#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ + kLegacyHash, +#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ + kStdHash, + kNone +}; -using InvokeTag = absl::hash_internal::InvokeHashTag; template <InvokeTag T> using InvokeTagConstant = std::integral_constant<InvokeTag, T>; @@ -245,13 +594,13 @@ } void TestCustomHashType(InvokeTagConstant<InvokeTag::kNone>) { -#if ABSL_HASH_INTERNAL_CAN_POISON_ +#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ // is_hashable is false if we don't support any of the hooks. using type = CustomHashType<>; EXPECT_FALSE(is_hashable<type>()); EXPECT_FALSE(is_hashable<const type>()); EXPECT_FALSE(is_hashable<const type&>()); -#endif // ABSL_HASH_INTERNAL_CAN_POISON_ +#endif // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ } template <InvokeTag Tag, typename... T> @@ -273,7 +622,7 @@ template <typename T> class HashIntTest : public testing::Test { }; -TYPED_TEST_CASE_P(HashIntTest); +TYPED_TEST_SUITE_P(HashIntTest); TYPED_TEST_P(HashIntTest, BasicUsage) { EXPECT_NE(Hash<NoOp>()({}), Hash<TypeParam>()(0)); @@ -352,7 +701,8 @@ } TEST(HashTest, StandardHashContainerUsage) { - std::unordered_map<int, std::string, Hash<int>> map = {{0, "foo"}, { 42, "bar" }}; + std::unordered_map<int, std::string, Hash<int>> map = {{0, "foo"}, + {42, "bar"}}; EXPECT_NE(map.find(0), map.end()); EXPECT_EQ(map.find(1), map.end()); @@ -422,4 +772,24 @@ SpyHash(std::make_pair(size_t{7}, 17))); } +struct ValueWithBoolConversion { + operator bool() const { return false; } + int i; +}; + +} // namespace +namespace std { +template <> +struct hash<ValueWithBoolConversion> { + size_t operator()(ValueWithBoolConversion v) { return v.i; } +}; +} // namespace std + +namespace { + +TEST(HashTest, DoesNotUseImplicitConversionsToBool) { + EXPECT_NE(absl::Hash<ValueWithBoolConversion>()(ValueWithBoolConversion{0}), + absl::Hash<ValueWithBoolConversion>()(ValueWithBoolConversion{1})); +} + } // namespace
diff --git a/absl/hash/hash_testing.h b/absl/hash/hash_testing.h index 1e3cda6..c45bc15 100644 --- a/absl/hash/hash_testing.h +++ b/absl/hash/hash_testing.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -90,7 +90,7 @@ // template <typename H> // friend H AbslHashValue(H state, Bad2 x) { // // Uses a and b. -// return H::combine(x.a, x.b); +// return H::combine(std::move(state), x.a, x.b); // } // friend bool operator==(Bad2 x, Bad2 y) { // // Only uses a. @@ -107,7 +107,7 @@ // template <typename H> // friend H AbslHashValue(H state, Bad3 x) { // // Only uses a. -// return H::combine(x.a); +// return H::combine(std::move(state), x.a); // } // friend bool operator==(Bad3 x, Bad3 y) { // // Uses a and b. @@ -123,19 +123,21 @@ // int *p, size; // template <typename H> // friend H AbslHashValue(H state, Bad4 x) { -// return H::combine_range(x.p, x.p + x.size); +// return H::combine_contiguous(std::move(state), x.p, x.p + x.size); // } // friend bool operator==(Bad4 x, Bad4 y) { -// return std::equal(x.p, x.p + x.size, y.p, y.p + y.size); +// // Compare two ranges for equality. C++14 code can instead use std::equal. +// return absl::equal(x.p, x.p + x.size, y.p, y.p + y.size); // } // }; // // An easy solution to this is to combine the size after combining the range, // like so: -// template <typename H> -// friend H AbslHashValue(H state, Bad4 x) { -// return H::combine(H::combine_range(x.p, x.p + x.size), x.size); -// } +// template <typename H> +// friend H AbslHashValue(H state, Bad4 x) { +// return H::combine( +// H::combine_contiguous(std::move(state), x.p, x.p + x.size), x.size); +// } // template <int&... ExplicitBarrier, typename Container> ABSL_MUST_USE_RESULT testing::AssertionResult @@ -188,7 +190,9 @@ struct Info { const V& value; size_t index; - std::string ToString() const { return absl::visit(PrintVisitor{index}, value); } + std::string ToString() const { + return absl::visit(PrintVisitor{index}, value); + } SpyHashState expand() const { return absl::visit(ExpandVisitor{}, value); } }; @@ -227,7 +231,8 @@ // Now we verify that AbslHashValue is also correctly implemented. for (const auto& c : classes) { - // All elements of the equivalence class must have the same hash expansion. + // All elements of the equivalence class must have the same hash + // expansion. const SpyHashState expected = c[0].expand(); for (const Info& v : c) { if (v.expand() != v.expand()) { @@ -285,7 +290,7 @@ }; template <typename... T> -struct MakeTypeSet : TypeSet<>{}; +struct MakeTypeSet : TypeSet<> {}; template <typename T, typename... Ts> struct MakeTypeSet<T, Ts...> : MakeTypeSet<Ts...>::template Insert<T>::type {}; @@ -346,8 +351,7 @@ ABSL_MUST_USE_RESULT testing::AssertionResult VerifyTypeImplementsAbslHashCorrectly(const Container& values, Eq equals) { return hash_internal::VerifyTypeImplementsAbslHashCorrectly( - hash_internal::ContainerAsVector<Container>::Do(values), - equals); + hash_internal::ContainerAsVector<Container>::Do(values), equals); } template <int&..., typename T>
diff --git a/absl/hash/internal/city.cc b/absl/hash/internal/city.cc index 8f72dd1..dc7650a 100644 --- a/absl/hash/internal/city.cc +++ b/absl/hash/internal/city.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -340,251 +340,5 @@ return HashLen16(CityHash64(s, len) - seed0, seed1); } -// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings -// of any length representable in signed long. Based on City and Murmur. -static uint128 CityMurmur(const char *s, size_t len, uint128 seed) { - uint64_t a = Uint128Low64(seed); - uint64_t b = Uint128High64(seed); - uint64_t c = 0; - uint64_t d = 0; - int64_t l = len - 16; - if (l <= 0) { // len <= 16 - a = ShiftMix(a * k1) * k1; - c = b * k1 + HashLen0to16(s, len); - d = ShiftMix(a + (len >= 8 ? Fetch64(s) : c)); - } else { // len > 16 - c = HashLen16(Fetch64(s + len - 8) + k1, a); - d = HashLen16(b + len, c + Fetch64(s + len - 16)); - a += d; - do { - a ^= ShiftMix(Fetch64(s) * k1) * k1; - a *= k1; - b ^= a; - c ^= ShiftMix(Fetch64(s + 8) * k1) * k1; - c *= k1; - d ^= c; - s += 16; - l -= 16; - } while (l > 0); - } - a = HashLen16(a, c); - b = HashLen16(d, b); - return uint128(a ^ b, HashLen16(b, a)); -} - -uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) { - if (len < 128) { - return CityMurmur(s, len, seed); - } - - // We expect len >= 128 to be the common case. Keep 56 bytes of state: - // v, w, x, y, and z. - std::pair<uint64_t, uint64_t> v, w; - uint64_t x = Uint128Low64(seed); - uint64_t y = Uint128High64(seed); - uint64_t z = len * k1; - v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s); - v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8); - w.first = Rotate(y + z, 35) * k1 + x; - w.second = Rotate(x + Fetch64(s + 88), 53) * k1; - - // This is the same inner loop as CityHash64(), manually unrolled. - do { - x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1; - y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1; - x ^= w.second; - y += v.first + Fetch64(s + 40); - z = Rotate(z + w.first, 33) * k1; - v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); - w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16)); - std::swap(z, x); - s += 64; - x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1; - y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1; - x ^= w.second; - y += v.first + Fetch64(s + 40); - z = Rotate(z + w.first, 33) * k1; - v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); - w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16)); - std::swap(z, x); - s += 64; - len -= 128; - } while (ABSL_PREDICT_TRUE(len >= 128)); - x += Rotate(v.first + z, 49) * k0; - y = y * k0 + Rotate(w.second, 37); - z = z * k0 + Rotate(w.first, 27); - w.first *= 9; - v.first *= k0; - // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s. - for (size_t tail_done = 0; tail_done < len;) { - tail_done += 32; - y = Rotate(x + y, 42) * k0 + v.second; - w.first += Fetch64(s + len - tail_done + 16); - x = x * k0 + w.first; - z += w.second + Fetch64(s + len - tail_done); - w.second += v.first; - v = WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second); - v.first *= k0; - } - // At this point our 56 bytes of state should contain more than - // enough information for a strong 128-bit hash. We use two - // different 56-byte-to-8-byte hashes to get a 16-byte final result. - x = HashLen16(x, v.first); - y = HashLen16(y + z, w.first); - return uint128(HashLen16(x + v.second, w.second) + y, - HashLen16(x + w.second, y + v.second)); -} - -uint128 CityHash128(const char *s, size_t len) { - return len >= 16 - ? CityHash128WithSeed(s + 16, len - 16, - uint128(Fetch64(s), Fetch64(s + 8) + k0)) - : CityHash128WithSeed(s, len, uint128(k0, k1)); -} } // namespace hash_internal } // namespace absl - -#ifdef __SSE4_2__ -#include <nmmintrin.h> -#include "absl/hash/internal/city_crc.h" - -namespace absl { -namespace hash_internal { - -// Requires len >= 240. -static void CityHashCrc256Long(const char *s, size_t len, uint32_t seed, - uint64_t *result) { - uint64_t a = Fetch64(s + 56) + k0; - uint64_t b = Fetch64(s + 96) + k0; - uint64_t c = result[0] = HashLen16(b, len); - uint64_t d = result[1] = Fetch64(s + 120) * k0 + len; - uint64_t e = Fetch64(s + 184) + seed; - uint64_t f = 0; - uint64_t g = 0; - uint64_t h = c + d; - uint64_t x = seed; - uint64_t y = 0; - uint64_t z = 0; - - // 240 bytes of input per iter. - size_t iters = len / 240; - len -= iters * 240; - do { -#undef CHUNK -#define CHUNK(r) \ - PERMUTE3(x, z, y); \ - b += Fetch64(s); \ - c += Fetch64(s + 8); \ - d += Fetch64(s + 16); \ - e += Fetch64(s + 24); \ - f += Fetch64(s + 32); \ - a += b; \ - h += f; \ - b += c; \ - f += d; \ - g += e; \ - e += z; \ - g += x; \ - z = _mm_crc32_u64(z, b + g); \ - y = _mm_crc32_u64(y, e + h); \ - x = _mm_crc32_u64(x, f + a); \ - e = Rotate(e, r); \ - c += e; \ - s += 40 - - CHUNK(0); - PERMUTE3(a, h, c); - CHUNK(33); - PERMUTE3(a, h, f); - CHUNK(0); - PERMUTE3(b, h, f); - CHUNK(42); - PERMUTE3(b, h, d); - CHUNK(0); - PERMUTE3(b, h, e); - CHUNK(33); - PERMUTE3(a, h, e); - } while (--iters > 0); - - while (len >= 40) { - CHUNK(29); - e ^= Rotate(a, 20); - h += Rotate(b, 30); - g ^= Rotate(c, 40); - f += Rotate(d, 34); - PERMUTE3(c, h, g); - len -= 40; - } - if (len > 0) { - s = s + len - 40; - CHUNK(33); - e ^= Rotate(a, 43); - h += Rotate(b, 42); - g ^= Rotate(c, 41); - f += Rotate(d, 40); - } - result[0] ^= h; - result[1] ^= g; - g += h; - a = HashLen16(a, g + z); - x += y << 32; - b += x; - c = HashLen16(c, z) + h; - d = HashLen16(d, e + result[0]); - g += e; - h += HashLen16(x, f); - e = HashLen16(a, d) + g; - z = HashLen16(b, c) + a; - y = HashLen16(g, h) + c; - result[0] = e + z + y + x; - a = ShiftMix((a + y) * k0) * k0 + b; - result[1] += a + result[0]; - a = ShiftMix(a * k0) * k0 + c; - result[2] = a + result[1]; - a = ShiftMix((a + e) * k0) * k0; - result[3] = a + result[2]; -} - -// Requires len < 240. -static void CityHashCrc256Short(const char *s, size_t len, uint64_t *result) { - char buf[240]; - memcpy(buf, s, len); - memset(buf + len, 0, 240 - len); - CityHashCrc256Long(buf, 240, ~static_cast<uint32_t>(len), result); -} - -void CityHashCrc256(const char *s, size_t len, uint64_t *result) { - if (ABSL_PREDICT_TRUE(len >= 240)) { - CityHashCrc256Long(s, len, 0, result); - } else { - CityHashCrc256Short(s, len, result); - } -} - -uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed) { - if (len <= 900) { - return CityHash128WithSeed(s, len, seed); - } else { - uint64_t result[4]; - CityHashCrc256(s, len, result); - uint64_t u = Uint128High64(seed) + result[0]; - uint64_t v = Uint128Low64(seed) + result[1]; - return uint128(HashLen16(u, v + result[2]), - HashLen16(Rotate(v, 32), u * k0 + result[3])); - } -} - -uint128 CityHashCrc128(const char *s, size_t len) { - if (len <= 900) { - return CityHash128(s, len); - } else { - uint64_t result[4]; - CityHashCrc256(s, len, result); - return uint128(result[2], result[3]); - } -} - -} // namespace hash_internal -} // namespace absl - -#endif
diff --git a/absl/hash/internal/city.h b/absl/hash/internal/city.h index 55b37b8..b43d340 100644 --- a/absl/hash/internal/city.h +++ b/absl/hash/internal/city.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// http://code.google.com/p/cityhash/ +// https://code.google.com/p/cityhash/ // // This file provides a few functions for hashing strings. All of them are // high-quality functions in the sense that they pass standard tests such @@ -23,15 +23,6 @@ // is Murmur3. For 64-bit x86 code, CityHash64 is an excellent choice for hash // tables and most other hashing (excluding cryptography). // -// For 64-bit x86 code, on long strings, the picture is more complicated. -// On many recent Intel CPUs, such as Nehalem, Westmere, Sandy Bridge, etc., -// CityHashCrc128 appears to be faster than all competitors of comparable -// quality. CityHash128 is also good but not quite as fast. We believe our -// nearest competitor is Bob Jenkins' Spooky. We don't have great data for -// other 64-bit CPUs, but for long strings we know that Spooky is slightly -// faster than CityHash on some relatively recent AMD x86-64 CPUs, for example. -// Note that CityHashCrc128 is declared in citycrc.h. -// // For 32-bit x86 code, we don't know of anything faster than CityHash32 that // is of comparable quality. We believe our nearest competitor is Murmur3A. // (On 64-bit CPUs, it is typically faster to use the other CityHash variants.) @@ -58,7 +49,6 @@ #include <stdlib.h> // for size_t. #include <utility> - namespace absl { namespace hash_internal { @@ -79,13 +69,6 @@ uint64_t CityHash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1); -// Hash function for a byte array. -uint128 CityHash128(const char *s, size_t len); - -// Hash function for a byte array. For convenience, a 128-bit seed is also -// hashed into the result. -uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed); - // Hash function for a byte array. Most useful in 32-bit binaries. uint32_t CityHash32(const char *s, size_t len);
diff --git a/absl/hash/internal/city_crc.h b/absl/hash/internal/city_crc.h deleted file mode 100644 index 6be6557..0000000 --- a/absl/hash/internal/city_crc.h +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file declares the subset of the CityHash functions that require -// _mm_crc32_u64(). See the CityHash README for details. -// -// Functions in the CityHash family are not suitable for cryptography. - -#ifndef ABSL_HASH_INTERNAL_CITY_CRC_H_ -#define ABSL_HASH_INTERNAL_CITY_CRC_H_ - -#include "absl/hash/internal/city.h" - -namespace absl { -namespace hash_internal { - -// Hash function for a byte array. -uint128 CityHashCrc128(const char *s, size_t len); - -// Hash function for a byte array. For convenience, a 128-bit seed is also -// hashed into the result. -uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed); - -// Hash function for a byte array. Sets result[0] ... result[3]. -void CityHashCrc256(const char *s, size_t len, uint64_t *result); - -} // namespace hash_internal -} // namespace absl - -#endif // ABSL_HASH_INTERNAL_CITY_CRC_H_
diff --git a/absl/hash/internal/city_test.cc b/absl/hash/internal/city_test.cc index 678da53..71b4ecc 100644 --- a/absl/hash/internal/city_test.cc +++ b/absl/hash/internal/city_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -18,9 +18,6 @@ #include <cstdio> #include <iostream> #include "gtest/gtest.h" -#ifdef __SSE4_2__ -#include "absl/hash/internal/city_crc.h" -#endif namespace absl { namespace hash_internal { @@ -28,7 +25,6 @@ static const uint64_t k0 = 0xc3a5c85c97cb3127ULL; static const uint64_t kSeed0 = 1234567; static const uint64_t kSeed1 = k0; -static const uint128 kSeed128(kSeed0, kSeed1); static const int kDataSize = 1 << 20; static const int kTestSize = 300; @@ -49,1754 +45,539 @@ } #define C(x) 0x##x##ULL -static const uint64_t testdata[kTestSize][16] = { +static const uint64_t testdata[kTestSize][4] = { {C(9ae16a3b2f90404f), C(75106db890237a4a), C(3feac5f636039766), - C(3df09dfc64c09a2b), C(3cb540c392e51e29), C(6b56343feac0663), - C(5b7bc50fd8e8ad92), C(3df09dfc64c09a2b), C(3cb540c392e51e29), - C(6b56343feac0663), C(5b7bc50fd8e8ad92), C(95162f24e6a5f930), - C(6808bdf4f1eb06e0), C(b3b1f3a67b624d82), C(c9a62f12bd4cd80b), C(dc56d17a)}, {C(541150e87f415e96), C(1aef0d24b3148a1a), C(bacc300e1e82345a), - C(c3cdc41e1df33513), C(2c138ff2596d42f6), C(f58e9082aed3055f), - C(162e192b2957163d), C(c3cdc41e1df33513), C(2c138ff2596d42f6), - C(f58e9082aed3055f), C(162e192b2957163d), C(fb99e85e0d16f90c), - C(608462c15bdf27e8), C(e7d2c5c943572b62), C(1baaa9327642798c), C(99929334)}, - {C(f3786a4b25827c1), C(34ee1a2bf767bd1c), C(2f15ca2ebfb631f2), - C(3149ba1dac77270d), C(70e2e076e30703c), C(59bcc9659bc5296), - C(9ecbc8132ae2f1d7), C(3149ba1dac77270d), C(70e2e076e30703c), - C(59bcc9659bc5296), C(9ecbc8132ae2f1d7), C(a01d30789bad7cf2), - C(ae03fe371981a0e0), C(127e3883b8788934), C(d0ac3d4c0a6fca32), - C(4252edb7)}, + {C(f3786a4b25827c1), C(34ee1a2bf767bd1c), C(2f15ca2ebfb631f2), C(4252edb7)}, {C(ef923a7a1af78eab), C(79163b1e1e9a9b18), C(df3b2aca6e1e4a30), - C(2193fb7620cbf23b), C(8b6a8ff06cda8302), C(1a44469afd3e091f), - C(8b0449376612506), C(2193fb7620cbf23b), C(8b6a8ff06cda8302), - C(1a44469afd3e091f), C(8b0449376612506), C(e9d9d41c32ad91d1), - C(b44ab09f58e3c608), C(19e9175f9fcf784), C(839b3c9581b4a480), C(ebc34f3c)}, + C(ebc34f3c)}, {C(11df592596f41d88), C(843ec0bce9042f9c), C(cce2ea1e08b1eb30), - C(4d09e42f09cc3495), C(666236631b9f253b), C(d28b3763cd02b6a3), - C(43b249e57c4d0c1b), C(4d09e42f09cc3495), C(666236631b9f253b), - C(d28b3763cd02b6a3), C(43b249e57c4d0c1b), C(3887101c8adea101), - C(8a9355d4efc91df0), C(3e610944cc9fecfd), C(5bf9eb60b08ac0ce), C(26f2b463)}, {C(831f448bdc5600b3), C(62a24be3120a6919), C(1b44098a41e010da), - C(dc07df53b949c6b), C(d2b11b2081aeb002), C(d212b02c1b13f772), - C(c0bed297b4be1912), C(dc07df53b949c6b), C(d2b11b2081aeb002), - C(d212b02c1b13f772), C(c0bed297b4be1912), C(682d3d2ad304e4af), - C(40e9112a655437a1), C(268b09f7ee09843f), C(6b9698d43859ca47), C(b042c047)}, - {C(3eca803e70304894), C(d80de767e4a920a), C(a51cfbb292efd53d), - C(d183dcda5f73edfa), C(3a93cbf40f30128c), C(1a92544d0b41dbda), - C(aec2c4bee81975e1), C(d183dcda5f73edfa), C(3a93cbf40f30128c), - C(1a92544d0b41dbda), C(aec2c4bee81975e1), C(5f91814d1126ba4b), - C(f8ac57eee87fcf1f), C(c55c644a5d0023cd), C(adb761e827825ff2), - C(e73bb0a8)}, + {C(3eca803e70304894), C(d80de767e4a920a), C(a51cfbb292efd53d), C(e73bb0a8)}, {C(1b5a063fb4c7f9f1), C(318dbc24af66dee9), C(10ef7b32d5c719af), - C(b140a02ef5c97712), C(b7d00ef065b51b33), C(635121d532897d98), - C(532daf21b312a6d6), C(b140a02ef5c97712), C(b7d00ef065b51b33), - C(635121d532897d98), C(532daf21b312a6d6), C(c0b09b75d943910), - C(8c84dfb5ef2a8e96), C(e5c06034b0353433), C(3170faf1c33a45dd), C(91dfdd75)}, {C(a0f10149a0e538d6), C(69d008c20f87419f), C(41b36376185b3e9e), - C(26b6689960ccf81d), C(55f23b27bb9efd94), C(3a17f6166dd765db), - C(c891a8a62931e782), C(26b6689960ccf81d), C(55f23b27bb9efd94), - C(3a17f6166dd765db), C(c891a8a62931e782), C(23852dc37ddd2607), - C(8b7f1b1ec897829e), C(d1d69452a54eed8a), C(56431f2bd766ec24), C(c87f95de)}, {C(fb8d9c70660b910b), C(a45b0cc3476bff1b), C(b28d1996144f0207), - C(98ec31113e5e35d2), C(5e4aeb853f1b9aa7), C(bcf5c8fe4465b7c8), - C(b1ea3a8243996f15), C(98ec31113e5e35d2), C(5e4aeb853f1b9aa7), - C(bcf5c8fe4465b7c8), C(b1ea3a8243996f15), C(cabbccedb6407571), - C(d1e40a84c445ec3a), C(33302aa908cf4039), C(9f15f79211b5cdf8), C(3f5538ef)}, {C(236827beae282a46), C(e43970221139c946), C(4f3ac6faa837a3aa), - C(71fec0f972248915), C(2170ec2061f24574), C(9eb346b6caa36e82), - C(2908f0fdbca48e73), C(71fec0f972248915), C(2170ec2061f24574), - C(9eb346b6caa36e82), C(2908f0fdbca48e73), C(8101c99f07c64abb), - C(b9f4b02b1b6a96a7), C(583a2b10cd222f88), C(199dae4cf9db24c), C(70eb1a1f)}, + C(70eb1a1f)}, {C(c385e435136ecf7c), C(d9d17368ff6c4a08), C(1b31eed4e5251a67), - C(df01a322c43a6200), C(298b65a1714b5a7e), C(933b83f0aedf23c), - C(157bcb44d63f765a), C(df01a322c43a6200), C(298b65a1714b5a7e), - C(933b83f0aedf23c), C(157bcb44d63f765a), C(d6e9fc7a272d8b51), - C(3ee5073ef1a9b777), C(63149e31fac02c59), C(2f7979ff636ba1d8), C(cfd63b83)}, {C(e3f6828b6017086d), C(21b4d1900554b3b0), C(bef38be1809e24f1), - C(d93251758985ee6c), C(32a9e9f82ba2a932), C(3822aacaa95f3329), - C(db349b2f90a490d8), C(d93251758985ee6c), C(32a9e9f82ba2a932), - C(3822aacaa95f3329), C(db349b2f90a490d8), C(8d49194a894a19ca), - C(79a78b06e42738e6), C(7e0f1eda3d390c66), C(1c291d7e641100a5), C(894a52ef)}, {C(851fff285561dca0), C(4d1277d73cdf416f), C(28ccffa61010ebe2), - C(77a4ccacd131d9ee), C(e1d08eeb2f0e29aa), C(70b9e3051383fa45), - C(582d0120425caba), C(77a4ccacd131d9ee), C(e1d08eeb2f0e29aa), - C(70b9e3051383fa45), C(582d0120425caba), C(a740eef1846e4564), - C(572dddb74ac3ae00), C(fdb5ca9579163bbd), C(a649b9b799c615d2), C(9cde6a54)}, {C(61152a63595a96d9), C(d1a3a91ef3a7ba45), C(443b6bb4a493ad0c), - C(a154296d11362d06), C(d0f0bf1f1cb02fc1), C(ccb87e09309f90d1), - C(b24a8e4881911101), C(a154296d11362d06), C(d0f0bf1f1cb02fc1), - C(ccb87e09309f90d1), C(b24a8e4881911101), C(1a481b4528559f58), - C(bf837a3150896995), C(4989ef6b941a3757), C(2e725ab72d0b2948), C(6c4898d5)}, {C(44473e03be306c88), C(30097761f872472a), C(9fd1b669bfad82d7), - C(3bab18b164396783), C(47e385ff9d4c06f), C(18062081bf558df), - C(63416eb68f104a36), C(3bab18b164396783), C(47e385ff9d4c06f), - C(18062081bf558df), C(63416eb68f104a36), C(4abda1560c47ac80), - C(1ea0e63dc6587aee), C(33ec79d92ebc1de), C(94f9dccef771e048), C(13e1978e)}, - {C(3ead5f21d344056), C(fb6420393cfb05c3), C(407932394cbbd303), - C(ac059617f5906673), C(94d50d3dcd3069a7), C(2b26c3b92dea0f0), - C(99b7374cc78fc3fb), C(ac059617f5906673), C(94d50d3dcd3069a7), - C(2b26c3b92dea0f0), C(99b7374cc78fc3fb), C(1a8e3c73cdd40ee8), - C(cbb5fca06747f45b), C(ceec44238b291841), C(28bf35cce9c90a25), C(51b4ba8)}, + C(13e1978e)}, + {C(3ead5f21d344056), C(fb6420393cfb05c3), C(407932394cbbd303), C(51b4ba8)}, {C(6abbfde37ee03b5b), C(83febf188d2cc113), C(cda7b62d94d5b8ee), - C(a4375590b8ae7c82), C(168fd42f9ecae4ff), C(23bbde43de2cb214), - C(a8c333112a243c8c), C(a4375590b8ae7c82), C(168fd42f9ecae4ff), - C(23bbde43de2cb214), C(a8c333112a243c8c), C(10ac012e8c518b49), - C(64a44605d8b29458), C(a67e701d2a679075), C(3a3a20f43ec92303), C(b6b06e40)}, - {C(943e7ed63b3c080), C(1ef207e9444ef7f8), C(ef4a9f9f8c6f9b4a), - C(6b54fc38d6a84108), C(32f4212a47a4665), C(6b5a9a8f64ee1da6), - C(9f74e86c6da69421), C(6b54fc38d6a84108), C(32f4212a47a4665), - C(6b5a9a8f64ee1da6), C(9f74e86c6da69421), C(946dd0cb30c1a08e), - C(fdf376956907eaaa), C(a59074c6eec03028), C(b1a3abcf283f34ac), C(240a2f2)}, + {C(943e7ed63b3c080), C(1ef207e9444ef7f8), C(ef4a9f9f8c6f9b4a), C(240a2f2)}, {C(d72ce05171ef8a1a), C(c6bd6bd869203894), C(c760e6396455d23a), - C(f86af0b40dcce7b), C(8d3c15d613394d3c), C(491e400491cd4ece), - C(7c19d3530ea3547f), C(f86af0b40dcce7b), C(8d3c15d613394d3c), - C(491e400491cd4ece), C(7c19d3530ea3547f), C(1362963a1dc32af9), - C(fb9bc11762e1385c), C(9e164ef1f5376083), C(6c15819b5e828a7e), C(5dcefc30)}, {C(4182832b52d63735), C(337097e123eea414), C(b5a72ca0456df910), - C(7ebc034235bc122f), C(d9a7783d4edd8049), C(5f8b04a15ae42361), - C(fc193363336453dd), C(7ebc034235bc122f), C(d9a7783d4edd8049), - C(5f8b04a15ae42361), C(fc193363336453dd), C(9b6c50224ef8c4f8), - C(ba225c7942d16c3f), C(6f6d55226a73c412), C(abca061fe072152a), C(7a48b105)}, {C(d6cdae892584a2cb), C(58de0fa4eca17dcd), C(43df30b8f5f1cb00), - C(9e4ea5a4941e097d), C(547e048d5a9daaba), C(eb6ecbb0b831d185), - C(e0168df5fad0c670), C(9e4ea5a4941e097d), C(547e048d5a9daaba), - C(eb6ecbb0b831d185), C(e0168df5fad0c670), C(afa9705f98c2c96a), - C(749436f48137a96b), C(759c041fc21df486), C(b23bf400107aa2ec), C(fd55007b)}, {C(5c8e90bc267c5ee4), C(e9ae044075d992d9), C(f234cbfd1f0a1e59), - C(ce2744521944f14c), C(104f8032f99dc152), C(4e7f425bfac67ca7), - C(9461b911a1c6d589), C(ce2744521944f14c), C(104f8032f99dc152), - C(4e7f425bfac67ca7), C(9461b911a1c6d589), C(5e5ecc726db8b60d), - C(cce68b0586083b51), C(8a7f8e54a9cba0fc), C(42f010181d16f049), C(6b95894c)}, {C(bbd7f30ac310a6f3), C(b23b570d2666685f), C(fb13fb08c9814fe7), - C(4ee107042e512374), C(1e2c8c0d16097e13), C(210c7500995aa0e6), - C(6c13190557106457), C(4ee107042e512374), C(1e2c8c0d16097e13), - C(210c7500995aa0e6), C(6c13190557106457), C(a99b31c96777f381), - C(8312ae8301d386c0), C(ed5042b2a4fa96a3), C(d71d1bb23907fe97), C(3360e827)}, - {C(36a097aa49519d97), C(8204380a73c4065), C(77c2004bdd9e276a), - C(6ee1f817ce0b7aee), C(e9dcb3507f0596ca), C(6bc63c666b5100e2), - C(e0b056f1821752af), C(6ee1f817ce0b7aee), C(e9dcb3507f0596ca), - C(6bc63c666b5100e2), C(e0b056f1821752af), C(8ea1114e60292678), - C(904b80b46becc77), C(46cd9bb6e9dff52f), C(4c91e3b698355540), C(45177e0b)}, - {C(dc78cb032c49217), C(112464083f83e03a), C(96ae53e28170c0f5), - C(d367ff54952a958), C(cdad930657371147), C(aa24dc2a9573d5fe), - C(eb136daa89da5110), C(d367ff54952a958), C(cdad930657371147), - C(aa24dc2a9573d5fe), C(eb136daa89da5110), C(de623005f6d46057), - C(b50c0c92b95e9b7f), C(a8aa54050b81c978), C(573fb5c7895af9b5), - C(7c6fffe4)}, + {C(36a097aa49519d97), C(8204380a73c4065), C(77c2004bdd9e276a), C(45177e0b)}, + {C(dc78cb032c49217), C(112464083f83e03a), C(96ae53e28170c0f5), C(7c6fffe4)}, {C(441593e0da922dfe), C(936ef46061469b32), C(204a1921197ddd87), - C(50d8a70e7a8d8f56), C(256d150ae75dab76), C(e81f4c4a1989036a), - C(d0f8db365f9d7e00), C(50d8a70e7a8d8f56), C(256d150ae75dab76), - C(e81f4c4a1989036a), C(d0f8db365f9d7e00), C(753d686677b14522), - C(9f76e0cb6f2d0a66), C(ab14f95988ec0d39), C(97621d9da9c9812f), C(bbc78da4)}, {C(2ba3883d71cc2133), C(72f2bbb32bed1a3c), C(27e1bd96d4843251), - C(a90f761e8db1543a), C(c339e23c09703cd8), C(f0c6624c4b098fd3), - C(1bae2053e41fa4d9), C(a90f761e8db1543a), C(c339e23c09703cd8), - C(f0c6624c4b098fd3), C(1bae2053e41fa4d9), C(3589e273c22ba059), - C(63798246e5911a0b), C(18e710ec268fc5dc), C(714a122de1d074f3), C(c5c25d39)}, {C(f2b6d2adf8423600), C(7514e2f016a48722), C(43045743a50396ba), - C(23dacb811652ad4f), C(c982da480e0d4c7d), C(3a9c8ed5a399d0a9), - C(951b8d084691d4e4), C(23dacb811652ad4f), C(c982da480e0d4c7d), - C(3a9c8ed5a399d0a9), C(951b8d084691d4e4), C(d9f87b4988cff2f7), - C(217a191d986aa3bc), C(6ad23c56b480350), C(dd78673938ceb2e7), C(b6e5d06e)}, + C(b6e5d06e)}, {C(38fffe7f3680d63c), C(d513325255a7a6d1), C(31ed47790f6ca62f), - C(c801faaa0a2e331f), C(491dbc58279c7f88), C(9c0178848321c97a), - C(9d934f814f4d6a3c), C(c801faaa0a2e331f), C(491dbc58279c7f88), - C(9c0178848321c97a), C(9d934f814f4d6a3c), C(606a3e4fc8763192), - C(bc15cb36a677ee84), C(52d5904157e1fe71), C(1588dd8b1145b79b), C(6178504e)}, - {C(b7477bf0b9ce37c6), C(63b1c580a7fd02a4), C(f6433b9f10a5dac), - C(68dd76db9d64eca7), C(36297682b64b67), C(42b192d71f414b7a), - C(79692cef44fa0206), C(68dd76db9d64eca7), C(36297682b64b67), - C(42b192d71f414b7a), C(79692cef44fa0206), C(f0979252f4776d07), - C(4b87cd4f1c9bbf52), C(51b84bbc6312c710), C(150720fbf85428a7), - C(bd4c3637)}, + {C(b7477bf0b9ce37c6), C(63b1c580a7fd02a4), C(f6433b9f10a5dac), C(bd4c3637)}, {C(55bdb0e71e3edebd), C(c7ab562bcf0568bc), C(43166332f9ee684f), - C(b2e25964cd409117), C(a010599d6287c412), C(fa5d6461e768dda2), - C(cb3ce74e8ec4f906), C(b2e25964cd409117), C(a010599d6287c412), - C(fa5d6461e768dda2), C(cb3ce74e8ec4f906), C(6120abfd541a2610), - C(aa88b148cc95794d), C(2686ca35df6590e3), C(c6b02d18616ce94d), C(6e7ac474)}, - {C(782fa1b08b475e7), C(fb7138951c61b23b), C(9829105e234fb11e), - C(9a8c431f500ef06e), C(d848581a580b6c12), C(fecfe11e13a2bdb4), - C(6c4fa0273d7db08c), C(9a8c431f500ef06e), C(d848581a580b6c12), - C(fecfe11e13a2bdb4), C(6c4fa0273d7db08c), C(482f43bf5ae59fcb), - C(f651fbca105d79e6), C(f09f78695d865817), C(7a99d0092085cf47), - C(1fb4b518)}, + {C(782fa1b08b475e7), C(fb7138951c61b23b), C(9829105e234fb11e), C(1fb4b518)}, {C(c5dc19b876d37a80), C(15ffcff666cfd710), C(e8c30c72003103e2), - C(7870765b470b2c5d), C(78a9103ff960d82), C(7bb50ffc9fac74b3), - C(477e70ab2b347db2), C(7870765b470b2c5d), C(78a9103ff960d82), - C(7bb50ffc9fac74b3), C(477e70ab2b347db2), C(a625238bdf7c07cf), - C(1128d515174809f5), C(b0f1647e82f45873), C(17792d1c4f222c39), C(31d13d6d)}, {C(5e1141711d2d6706), C(b537f6dee8de6933), C(3af0a1fbbe027c54), - C(ea349dbc16c2e441), C(38a7455b6a877547), C(5f97b9750e365411), - C(e8cde7f93af49a3), C(ea349dbc16c2e441), C(38a7455b6a877547), - C(5f97b9750e365411), C(e8cde7f93af49a3), C(ba101925ec1f7e26), - C(d5e84cab8192c71e), C(e256427726fdd633), C(a4f38e2c6116890d), C(26fa72e3)}, - {C(782edf6da001234f), C(f48cbd5c66c48f3), C(808754d1e64e2a32), - C(5d9dde77353b1a6d), C(11f58c54581fa8b1), C(da90fa7c28c37478), - C(5e9a2eafc670a88a), C(5d9dde77353b1a6d), C(11f58c54581fa8b1), - C(da90fa7c28c37478), C(5e9a2eafc670a88a), C(e35e1bc172e011ef), - C(bf9255a4450ae7fe), C(55f85194e26bc55f), C(4f327873e14d0e54), - C(6a7433bf)}, + {C(782edf6da001234f), C(f48cbd5c66c48f3), C(808754d1e64e2a32), C(6a7433bf)}, {C(d26285842ff04d44), C(8f38d71341eacca9), C(5ca436f4db7a883c), - C(bf41e5376b9f0eec), C(2252d21eb7e1c0e9), C(f4b70a971855e732), - C(40c7695aa3662afd), C(bf41e5376b9f0eec), C(2252d21eb7e1c0e9), - C(f4b70a971855e732), C(40c7695aa3662afd), C(770fe19e16ab73bb), - C(d603ebda6393d749), C(e58c62439aa50dbd), C(96d51e5a02d2d7cf), C(4e6df758)}, {C(c6ab830865a6bae6), C(6aa8e8dd4b98815c), C(efe3846713c371e5), - C(a1924cbf0b5f9222), C(7f4872369c2b4258), C(cd6da30530f3ea89), - C(b7f8b9a704e6cea1), C(a1924cbf0b5f9222), C(7f4872369c2b4258), - C(cd6da30530f3ea89), C(b7f8b9a704e6cea1), C(fa06ff40433fd535), - C(fb1c36fe8f0737f1), C(bb7050561171f80), C(b1bc23235935d897), C(d57f63ea)}, - {C(44b3a1929232892), C(61dca0e914fc217), C(a607cc142096b964), - C(f7dbc8433c89b274), C(2f5f70581c9b7d32), C(39bf5e5fec82dcca), - C(8ade56388901a619), C(f7dbc8433c89b274), C(2f5f70581c9b7d32), - C(39bf5e5fec82dcca), C(8ade56388901a619), C(c1c6a725caab3ea9), - C(c1c7906c2f80b898), C(9c3871a04cc884e6), C(df01813cbbdf217f), - C(52ef73b3)}, - {C(4b603d7932a8de4f), C(fae64c464b8a8f45), C(8fafab75661d602a), - C(8ffe870ef4adc087), C(65bea2be41f55b54), C(82f3503f636aef1), - C(5f78a282378b6bb0), C(8ffe870ef4adc087), C(65bea2be41f55b54), - C(82f3503f636aef1), C(5f78a282378b6bb0), C(7bf2422c0beceddb), - C(9d238d4780114bd), C(7ad198311906597f), C(ec8f892c0422aca3), C(3cb36c3)}, + C(d57f63ea)}, + {C(44b3a1929232892), C(61dca0e914fc217), C(a607cc142096b964), C(52ef73b3)}, + {C(4b603d7932a8de4f), C(fae64c464b8a8f45), C(8fafab75661d602a), C(3cb36c3)}, {C(4ec0b54cf1566aff), C(30d2c7269b206bf4), C(77c22e82295e1061), - C(3df9b04434771542), C(feddce785ccb661f), C(a644aff716928297), - C(dd46aee73824b4ed), C(3df9b04434771542), C(feddce785ccb661f), - C(a644aff716928297), C(dd46aee73824b4ed), C(bf8d71879da29b02), - C(fc82dccbfc8022a0), C(31bfcd0d9f48d1d3), C(c64ee24d0e7b5f8b), C(72c39bea)}, {C(ed8b7a4b34954ff7), C(56432de31f4ee757), C(85bd3abaa572b155), - C(7d2c38a926dc1b88), C(5245b9eb4cd6791d), C(fb53ab03b9ad0855), - C(3664026c8fc669d7), C(7d2c38a926dc1b88), C(5245b9eb4cd6791d), - C(fb53ab03b9ad0855), C(3664026c8fc669d7), C(45024d5080bc196), - C(b236ebec2cc2740), C(27231ad0e3443be4), C(145780b63f809250), C(a65aa25c)}, + C(a65aa25c)}, {C(5d28b43694176c26), C(714cc8bc12d060ae), C(3437726273a83fe6), - C(864b1b28ec16ea86), C(6a78a5a4039ec2b9), C(8e959533e35a766), - C(347b7c22b75ae65f), C(864b1b28ec16ea86), C(6a78a5a4039ec2b9), - C(8e959533e35a766), C(347b7c22b75ae65f), C(5005892bb61e647c), - C(fe646519b4a1894d), C(cd801026f74a8a53), C(8713463e9a1ab9ce), C(74740539)}, {C(6a1ef3639e1d202e), C(919bc1bd145ad928), C(30f3f7e48c28a773), - C(2e8c49d7c7aaa527), C(5e2328fc8701db7c), C(89ef1afca81f7de8), - C(b1857db11985d296), C(2e8c49d7c7aaa527), C(5e2328fc8701db7c), - C(89ef1afca81f7de8), C(b1857db11985d296), C(17763d695f616115), - C(b8f7bf1fcdc8322c), C(cf0c61938ab07a27), C(1122d3e6edb4e866), C(c3ae3c26)}, - {C(159f4d9e0307b111), C(3e17914a5675a0c), C(af849bd425047b51), - C(3b69edadf357432b), C(3a2e311c121e6bf2), C(380fad1e288d57e5), - C(bf7c7e8ef0e3b83a), C(3b69edadf357432b), C(3a2e311c121e6bf2), - C(380fad1e288d57e5), C(bf7c7e8ef0e3b83a), C(92966d5f4356ae9b), - C(2a03fc66c4d6c036), C(2516d8bddb0d5259), C(b3ffe9737ff5090), C(f29db8a2)}, + {C(159f4d9e0307b111), C(3e17914a5675a0c), C(af849bd425047b51), C(f29db8a2)}, {C(cc0a840725a7e25b), C(57c69454396e193a), C(976eaf7eee0b4540), - C(cd7a46850b95e901), C(c57f7d060dda246f), C(6b9406ead64079bf), - C(11b28e20a573b7bd), C(cd7a46850b95e901), C(c57f7d060dda246f), - C(6b9406ead64079bf), C(11b28e20a573b7bd), C(2d6db356e9369ace), - C(dc0afe10fba193), C(5cdb10885dbbfce), C(5c700e205782e35a), C(1ef4cbf4)}, + C(1ef4cbf4)}, {C(a2b27ee22f63c3f1), C(9ebde0ce1b3976b2), C(2fe6a92a257af308), - C(8c1df927a930af59), C(a462f4423c9e384e), C(236542255b2ad8d9), - C(595d201a2c19d5bc), C(8c1df927a930af59), C(a462f4423c9e384e), - C(236542255b2ad8d9), C(595d201a2c19d5bc), C(22c87d4604a67f3), - C(585a06eb4bc44c4f), C(b4175a7ac7eabcd8), C(a457d3eeba14ab8c), C(a9be6c41)}, - {C(d8f2f234899bcab3), C(b10b037297c3a168), C(debea2c510ceda7f), - C(9498fefb890287ce), C(ae68c2be5b1a69a6), C(6189dfba34ed656c), - C(91658f95836e5206), C(9498fefb890287ce), C(ae68c2be5b1a69a6), - C(6189dfba34ed656c), C(91658f95836e5206), C(c0bb4fff32aecd4d), - C(94125f505a50eef9), C(6ac406e7cfbce5bb), C(344a4b1dcdb7f5d8), C(fa31801)}, + {C(d8f2f234899bcab3), C(b10b037297c3a168), C(debea2c510ceda7f), C(fa31801)}, {C(584f28543864844f), C(d7cee9fc2d46f20d), C(a38dca5657387205), - C(7a0b6dbab9a14e69), C(c6d0a9d6b0e31ac4), C(a674d85812c7cf6), - C(63538c0351049940), C(7a0b6dbab9a14e69), C(c6d0a9d6b0e31ac4), - C(a674d85812c7cf6), C(63538c0351049940), C(9710e5f0bc93d1d), - C(c2bea5bd7c54ddd4), C(48739af2bed0d32d), C(ba2c4e09e21fba85), C(8331c5d8)}, - {C(a94be46dd9aa41af), C(a57e5b7723d3f9bd), C(34bf845a52fd2f), - C(843b58463c8df0ae), C(74b258324e916045), C(bdd7353230eb2b38), - C(fad31fced7abade5), C(843b58463c8df0ae), C(74b258324e916045), - C(bdd7353230eb2b38), C(fad31fced7abade5), C(2436aeafb0046f85), - C(65bc9af9e5e33161), C(92733b1b3ae90628), C(f48143eaf78a7a89), - C(e9876db8)}, + {C(a94be46dd9aa41af), C(a57e5b7723d3f9bd), C(34bf845a52fd2f), C(e9876db8)}, {C(9a87bea227491d20), C(a468657e2b9c43e7), C(af9ba60db8d89ef7), - C(cc76f429ea7a12bb), C(5f30eaf2bb14870a), C(434e824cb3e0cd11), - C(431a4d382e39d16e), C(cc76f429ea7a12bb), C(5f30eaf2bb14870a), - C(434e824cb3e0cd11), C(431a4d382e39d16e), C(9e51f913c4773a8), - C(32ab1925823d0add), C(99c61b54c1d8f69d), C(38cfb80f02b43b1f), C(27b0604e)}, {C(27688c24958d1a5c), C(e3b4a1c9429cf253), C(48a95811f70d64bc), - C(328063229db22884), C(67e9c95f8ba96028), C(7c6bf01c60436075), - C(fa55161e7d9030b2), C(328063229db22884), C(67e9c95f8ba96028), - C(7c6bf01c60436075), C(fa55161e7d9030b2), C(dadbc2f0dab91681), - C(da39d7a4934ca11), C(162e845d24c1b45c), C(eb5b9dcd8c6ed31b), C(dcec07f2)}, + C(dcec07f2)}, {C(5d1d37790a1873ad), C(ed9cd4bcc5fa1090), C(ce51cde05d8cd96a), - C(f72c26e624407e66), C(a0eb541bdbc6d409), C(c3f40a2f40b3b213), - C(6a784de68794492d), C(f72c26e624407e66), C(a0eb541bdbc6d409), - C(c3f40a2f40b3b213), C(6a784de68794492d), C(10a38a23dbef7937), - C(6a5560f853252278), C(c3387bbf3c7b82ba), C(fbee7c12eb072805), C(cff0a82a)}, {C(1f03fd18b711eea9), C(566d89b1946d381a), C(6e96e83fc92563ab), - C(405f66cf8cae1a32), C(d7261740d8f18ce6), C(fea3af64a413d0b2), - C(d64d1810e83520fe), C(405f66cf8cae1a32), C(d7261740d8f18ce6), - C(fea3af64a413d0b2), C(d64d1810e83520fe), C(e1334a00a580c6e8), - C(454049e1b52c15f), C(8895d823d9778247), C(efa7f2e88b826618), C(fec83621)}, - {C(f0316f286cf527b6), C(f84c29538de1aa5a), C(7612ed3c923d4a71), - C(d4eccebe9393ee8a), C(2eb7867c2318cc59), C(1ce621fd700fe396), - C(686450d7a346878a), C(d4eccebe9393ee8a), C(2eb7867c2318cc59), - C(1ce621fd700fe396), C(686450d7a346878a), C(75a5f37579f8b4cb), - C(500cc16eb6541dc7), C(b7b02317b539d9a6), C(3519ddff5bc20a29), C(743d8dc)}, + C(fec83621)}, + {C(f0316f286cf527b6), C(f84c29538de1aa5a), C(7612ed3c923d4a71), C(743d8dc)}, {C(297008bcb3e3401d), C(61a8e407f82b0c69), C(a4a35bff0524fa0e), - C(7a61d8f552a53442), C(821d1d8d8cfacf35), C(7cc06361b86d0559), - C(119b617a8c2be199), C(7a61d8f552a53442), C(821d1d8d8cfacf35), - C(7cc06361b86d0559), C(119b617a8c2be199), C(2996487da6721759), - C(61a901376070b91d), C(d88dee12ae9c9b3c), C(5665491be1fa53a7), C(64d41d26)}, - {C(43c6252411ee3be), C(b4ca1b8077777168), C(2746dc3f7da1737f), - C(2247a4b2058d1c50), C(1b3fa184b1d7bcc0), C(deb85613995c06ed), - C(cbe1d957485a3ccd), C(2247a4b2058d1c50), C(1b3fa184b1d7bcc0), - C(deb85613995c06ed), C(cbe1d957485a3ccd), C(dfe241f8f33c96b6), - C(6597eb05019c2109), C(da344b2a63a219cf), C(79b8e3887612378a), - C(acd90c81)}, + {C(43c6252411ee3be), C(b4ca1b8077777168), C(2746dc3f7da1737f), C(acd90c81)}, {C(ce38a9a54fad6599), C(6d6f4a90b9e8755e), C(c3ecc79ff105de3f), - C(e8b9ee96efa2d0e), C(90122905c4ab5358), C(84f80c832d71979c), - C(229310f3ffbbf4c6), C(e8b9ee96efa2d0e), C(90122905c4ab5358), - C(84f80c832d71979c), C(229310f3ffbbf4c6), C(cc9eb42100cd63a7), - C(7a283f2f3da7b9f), C(359b061d314e7a72), C(d0d959720028862), C(7c746a4b)}, - {C(270a9305fef70cf), C(600193999d884f3a), C(f4d49eae09ed8a1), - C(2e091b85660f1298), C(bfe37fae1cdd64c9), C(8dddfbab930f6494), - C(2ccf4b08f5d417a), C(2e091b85660f1298), C(bfe37fae1cdd64c9), - C(8dddfbab930f6494), C(2ccf4b08f5d417a), C(365c2ee85582fe6), - C(dee027bcd36db62a), C(b150994d3c7e5838), C(fdfd1a0e692e436d), - C(b1047e99)}, + C(7c746a4b)}, + {C(270a9305fef70cf), C(600193999d884f3a), C(f4d49eae09ed8a1), C(b1047e99)}, {C(e71be7c28e84d119), C(eb6ace59932736e6), C(70c4397807ba12c5), - C(7a9d77781ac53509), C(4489c3ccfda3b39c), C(fa722d4f243b4964), - C(25f15800bffdd122), C(7a9d77781ac53509), C(4489c3ccfda3b39c), - C(fa722d4f243b4964), C(25f15800bffdd122), C(ed85e4157fbd3297), - C(aab1967227d59efd), C(2199631212eb3839), C(3e4c19359aae1cc2), C(d1fd1068)}, {C(b5b58c24b53aaa19), C(d2a6ab0773dd897f), C(ef762fe01ecb5b97), - C(9deefbcfa4cab1f1), C(b58f5943cd2492ba), C(a96dcc4d1f4782a7), - C(102b62a82309dde5), C(9deefbcfa4cab1f1), C(b58f5943cd2492ba), - C(a96dcc4d1f4782a7), C(102b62a82309dde5), C(35fe52684763b338), - C(afe2616651eaad1f), C(43e38715bdfa05e7), C(83c9ba83b5ec4a40), C(56486077)}, {C(44dd59bd301995cf), C(3ccabd76493ada1a), C(540db4c87d55ef23), - C(cfc6d7adda35797), C(14c7d1f32332cf03), C(2d553ffbff3be99d), - C(c91c4ee0cb563182), C(cfc6d7adda35797), C(14c7d1f32332cf03), - C(2d553ffbff3be99d), C(c91c4ee0cb563182), C(9aa5e507f49136f0), - C(760c5dd1a82c4888), C(beea7e974a1cfb5c), C(640b247774fe4bf7), C(6069be80)}, - {C(b4d4789eb6f2630b), C(bf6973263ce8ef0e), C(d1c75c50844b9d3), - C(bce905900c1ec6ea), C(c30f304f4045487d), C(a5c550166b3a142b), - C(2f482b4e35327287), C(bce905900c1ec6ea), C(c30f304f4045487d), - C(a5c550166b3a142b), C(2f482b4e35327287), C(15b21ddddf355438), - C(496471fa3006bab), C(2a8fd458d06c1a32), C(db91e8ae812f0b8d), C(2078359b)}, + {C(b4d4789eb6f2630b), C(bf6973263ce8ef0e), C(d1c75c50844b9d3), C(2078359b)}, {C(12807833c463737c), C(58e927ea3b3776b4), C(72dd20ef1c2f8ad0), - C(910b610de7a967bf), C(801bc862120f6bf5), C(9653efeed5897681), - C(f5367ff83e9ebbb3), C(910b610de7a967bf), C(801bc862120f6bf5), - C(9653efeed5897681), C(f5367ff83e9ebbb3), C(cf56d489afd1b0bf), - C(c7c793715cae3de8), C(631f91d64abae47c), C(5f1f42fb14a444a2), C(9ea21004)}, {C(e88419922b87176f), C(bcf32f41a7ddbf6f), C(d6ebefd8085c1a0f), - C(d1d44fe99451ef72), C(ec951ba8e51e3545), C(c0ca86b360746e96), - C(aa679cc066a8040b), C(d1d44fe99451ef72), C(ec951ba8e51e3545), - C(c0ca86b360746e96), C(aa679cc066a8040b), C(51065861ece6ffc1), - C(76777368a2997e11), C(87f278f46731100c), C(bbaa4140bdba4527), C(9c9cfe88)}, {C(105191e0ec8f7f60), C(5918dbfcca971e79), C(6b285c8a944767b9), - C(d3e86ac4f5eccfa4), C(e5399df2b106ca1), C(814aadfacd217f1d), - C(2754e3def1c405a9), C(d3e86ac4f5eccfa4), C(e5399df2b106ca1), - C(814aadfacd217f1d), C(2754e3def1c405a9), C(99290323b9f06e74), - C(a9782e043f271461), C(13c8b3b8c275a860), C(6038d620e581e9e7), C(b70a6ddd)}, {C(a5b88bf7399a9f07), C(fca3ddfd96461cc4), C(ebe738fdc0282fc6), - C(69afbc800606d0fb), C(6104b97a9db12df7), C(fcc09198bb90bf9f), - C(c5e077e41a65ba91), C(69afbc800606d0fb), C(6104b97a9db12df7), - C(fcc09198bb90bf9f), C(c5e077e41a65ba91), C(db261835ee8aa08e), - C(db0ee662e5796dc9), C(fc1880ecec499e5f), C(648866fbe1502034), C(dea37298)}, {C(d08c3f5747d84f50), C(4e708b27d1b6f8ac), C(70f70fd734888606), - C(909ae019d761d019), C(368bf4aab1b86ef9), C(308bd616d5460239), - C(4fd33269f76783ea), C(909ae019d761d019), C(368bf4aab1b86ef9), - C(308bd616d5460239), C(4fd33269f76783ea), C(7d53b37c19713eab), - C(6bba6eabda58a897), C(91abb50efc116047), C(4e902f347e0e0e35), C(8f480819)}, - {C(2f72d12a40044b4b), C(889689352fec53de), C(f03e6ad87eb2f36), - C(ef79f28d874b9e2d), C(b512089e8e63b76c), C(24dc06833bf193a9), - C(3c23308ba8e99d7e), C(ef79f28d874b9e2d), C(b512089e8e63b76c), - C(24dc06833bf193a9), C(3c23308ba8e99d7e), C(5ceff7b85cacefb7), - C(ef390338898cd73), C(b12967d7d2254f54), C(de874cbd8aef7b75), C(30b3b16)}, + {C(2f72d12a40044b4b), C(889689352fec53de), C(f03e6ad87eb2f36), C(30b3b16)}, {C(aa1f61fdc5c2e11e), C(c2c56cd11277ab27), C(a1e73069fdf1f94f), - C(8184bab36bb79df0), C(c81929ce8655b940), C(301b11bf8a4d8ce8), - C(73126fd45ab75de9), C(8184bab36bb79df0), C(c81929ce8655b940), - C(301b11bf8a4d8ce8), C(73126fd45ab75de9), C(4bd6f76e4888229a), - C(9aae355b54a756d5), C(ca3de9726f6e99d5), C(83f80cac5bc36852), C(f31bc4e8)}, {C(9489b36fe2246244), C(3355367033be74b8), C(5f57c2277cbce516), - C(bc61414f9802ecaf), C(8edd1e7a50562924), C(48f4ab74a35e95f2), - C(cc1afcfd99a180e7), C(bc61414f9802ecaf), C(8edd1e7a50562924), - C(48f4ab74a35e95f2), C(cc1afcfd99a180e7), C(517dd5e3acf66110), - C(7dd3ad9e8978b30d), C(1f6d5dfc70de812b), C(947daaba6441aaf3), C(419f953b)}, {C(358d7c0476a044cd), C(e0b7b47bcbd8854f), C(ffb42ec696705519), - C(d45e44c263e95c38), C(df61db53923ae3b1), C(f2bc948cc4fc027c), - C(8a8000c6066772a3), C(d45e44c263e95c38), C(df61db53923ae3b1), - C(f2bc948cc4fc027c), C(8a8000c6066772a3), C(9fd93c942d31fa17), - C(d7651ecebe09cbd3), C(68682cefb6a6f165), C(541eb99a2dcee40e), C(20e9e76d)}, {C(b0c48df14275265a), C(9da4448975905efa), C(d716618e414ceb6d), - C(30e888af70df1e56), C(4bee54bd47274f69), C(178b4059e1a0afe5), - C(6e2c96b7f58e5178), C(30e888af70df1e56), C(4bee54bd47274f69), - C(178b4059e1a0afe5), C(6e2c96b7f58e5178), C(bb429d3b9275e9bc), - C(c198013f09cafdc6), C(ec0a6ee4fb5de348), C(744e1e8ed2eb1eb0), C(646f0ff8)}, {C(daa70bb300956588), C(410ea6883a240c6d), C(f5c8239fb5673eb3), - C(8b1d7bb4903c105f), C(cfb1c322b73891d4), C(5f3b792b22f07297), - C(fd64061f8be86811), C(8b1d7bb4903c105f), C(cfb1c322b73891d4), - C(5f3b792b22f07297), C(fd64061f8be86811), C(1d2db712921cfc2b), - C(cd1b2b2f2cee18ae), C(6b6f8790dc7feb09), C(46c179efa3f0f518), C(eeb7eca8)}, - {C(4ec97a20b6c4c7c2), C(5913b1cd454f29fd), C(a9629f9daf06d685), - C(852c9499156a8f3), C(3a180a6abfb79016), C(9fc3c4764037c3c9), - C(2890c42fc0d972cf), C(852c9499156a8f3), C(3a180a6abfb79016), - C(9fc3c4764037c3c9), C(2890c42fc0d972cf), C(1f92231d4e537651), - C(fab8bb07aa54b7b9), C(e05d2d771c485ed4), C(d50b34bf808ca731), C(8112bb9)}, + {C(4ec97a20b6c4c7c2), C(5913b1cd454f29fd), C(a9629f9daf06d685), C(8112bb9)}, {C(5c3323628435a2e8), C(1bea45ce9e72a6e3), C(904f0a7027ddb52e), - C(939f31de14dcdc7b), C(a68fdf4379df068), C(f169e1f0b835279d), - C(7498e432f9619b27), C(939f31de14dcdc7b), C(a68fdf4379df068), - C(f169e1f0b835279d), C(7498e432f9619b27), C(1aa2a1f11088e785), - C(d6ad72f45729de78), C(9a63814157c80267), C(55538e35c648e435), C(85a6d477)}, {C(c1ef26bea260abdb), C(6ee423f2137f9280), C(df2118b946ed0b43), - C(11b87fb1b900cc39), C(e33e59b90dd815b1), C(aa6cb5c4bafae741), - C(739699951ca8c713), C(11b87fb1b900cc39), C(e33e59b90dd815b1), - C(aa6cb5c4bafae741), C(739699951ca8c713), C(2b4389a967310077), - C(1d5382568a31c2c9), C(55d1e787fbe68991), C(277c254bc31301e7), C(56f76c84)}, {C(6be7381b115d653a), C(ed046190758ea511), C(de6a45ffc3ed1159), - C(a64760e4041447d0), C(e3eac49f3e0c5109), C(dd86c4d4cb6258e2), - C(efa9857afd046c7f), C(a64760e4041447d0), C(e3eac49f3e0c5109), - C(dd86c4d4cb6258e2), C(efa9857afd046c7f), C(fab793dae8246f16), - C(c9e3b121b31d094c), C(a2a0f55858465226), C(dba6f0ff39436344), C(9af45d55)}, {C(ae3eece1711b2105), C(14fd3f4027f81a4a), C(abb7e45177d151db), - C(501f3e9b18861e44), C(465201170074e7d8), C(96d5c91970f2cb12), - C(40fd28c43506c95d), C(501f3e9b18861e44), C(465201170074e7d8), - C(96d5c91970f2cb12), C(40fd28c43506c95d), C(e86c4b07802aaff3), - C(f317d14112372a70), C(641b13e587711650), C(4915421ab1090eaa), C(d1c33760)}, {C(376c28588b8fb389), C(6b045e84d8491ed2), C(4e857effb7d4e7dc), - C(154dd79fd2f984b4), C(f11171775622c1c3), C(1fbe30982e78e6f0), - C(a460a15dcf327e44), C(154dd79fd2f984b4), C(f11171775622c1c3), - C(1fbe30982e78e6f0), C(a460a15dcf327e44), C(f359e0900cc3d582), - C(7e11070447976d00), C(324e6daf276ea4b5), C(7aa6e2df0cc94fa2), C(c56bbf69)}, {C(58d943503bb6748f), C(419c6c8e88ac70f6), C(586760cbf3d3d368), - C(b7e164979d5ccfc1), C(12cb4230d26bf286), C(f1bf910d44bd84cb), - C(b32c24c6a40272), C(b7e164979d5ccfc1), C(12cb4230d26bf286), - C(f1bf910d44bd84cb), C(b32c24c6a40272), C(11ed12e34c48c039), - C(b0c2538e51d0a6ac), C(4269bb773e1d553a), C(e35a9dbabd34867), C(abecfb9b)}, + C(abecfb9b)}, {C(dfff5989f5cfd9a1), C(bcee2e7ea3a96f83), C(681c7874adb29017), - C(3ff6c8ac7c36b63a), C(48bc8831d849e326), C(30b078e76b0214e2), - C(42954e6ad721b920), C(3ff6c8ac7c36b63a), C(48bc8831d849e326), - C(30b078e76b0214e2), C(42954e6ad721b920), C(f9aeb33d164b4472), - C(7b353b110831dbdc), C(16f64c82f44ae17b), C(b71244cc164b3b2b), C(8de13255)}, {C(7fb19eb1a496e8f5), C(d49e5dfdb5c0833f), C(c0d5d7b2f7c48dc7), - C(1a57313a32f22dde), C(30af46e49850bf8b), C(aa0fe8d12f808f83), - C(443e31d70873bb6b), C(1a57313a32f22dde), C(30af46e49850bf8b), - C(aa0fe8d12f808f83), C(443e31d70873bb6b), C(bbeb67c49c9fdc13), - C(18f1e2a88f59f9d5), C(fb1b05038e5def11), C(d0450b5ce4c39c52), C(a98ee299)}, {C(5dba5b0dadccdbaa), C(4ba8da8ded87fcdc), C(f693fdd25badf2f0), - C(e9029e6364286587), C(ae69f49ecb46726c), C(18e002679217c405), - C(bd6d66e85332ae9f), C(e9029e6364286587), C(ae69f49ecb46726c), - C(18e002679217c405), C(bd6d66e85332ae9f), C(6bf330b1c353dd2a), - C(74e9f2e71e3a4152), C(3f85560b50f6c413), C(d33a52a47eaed2b4), C(3015f556)}, {C(688bef4b135a6829), C(8d31d82abcd54e8e), C(f95f8a30d55036d7), - C(3d8c90e27aa2e147), C(2ec937ce0aa236b4), C(89b563996d3a0b78), - C(39b02413b23c3f08), C(3d8c90e27aa2e147), C(2ec937ce0aa236b4), - C(89b563996d3a0b78), C(39b02413b23c3f08), C(8d475a2e64faf2d2), - C(48567f7dca46ecaf), C(254cda08d5f87a6d), C(ec6ae9f729c47039), C(5a430e29)}, {C(d8323be05433a412), C(8d48fa2b2b76141d), C(3d346f23978336a5), - C(4d50c7537562033f), C(57dc7625b61dfe89), C(9723a9f4c08ad93a), - C(5309596f48ab456b), C(4d50c7537562033f), C(57dc7625b61dfe89), - C(9723a9f4c08ad93a), C(5309596f48ab456b), C(7e453088019d220f), - C(8776067ba6ab9714), C(67e1d06bd195de39), C(74a1a32f8994b918), C(2797add0)}, {C(3b5404278a55a7fc), C(23ca0b327c2d0a81), C(a6d65329571c892c), - C(45504801e0e6066b), C(86e6c6d6152a3d04), C(4f3db1c53eca2952), - C(d24d69b3e9ef10f3), C(45504801e0e6066b), C(86e6c6d6152a3d04), - C(4f3db1c53eca2952), C(d24d69b3e9ef10f3), C(93a0de2219e66a70), - C(8932c7115ccb1f8a), C(5ef503fdf2841a8c), C(38064dd9efa80a41), C(27d55016)}, {C(2a96a3f96c5e9bbc), C(8caf8566e212dda8), C(904de559ca16e45e), - C(f13bc2d9c2fe222e), C(be4ccec9a6cdccfd), C(37b2cbdd973a3ac9), - C(7b3223cd9c9497be), C(f13bc2d9c2fe222e), C(be4ccec9a6cdccfd), - C(37b2cbdd973a3ac9), C(7b3223cd9c9497be), C(d5904440f376f889), - C(62b13187699c473c), C(4751b89251f26726), C(9500d84fa3a61ba8), C(84945a82)}, {C(22bebfdcc26d18ff), C(4b4d8dcb10807ba1), C(40265eee30c6b896), - C(3752b423073b119a), C(377dc5eb7c662bdb), C(2b9f07f93a6c25b9), - C(96f24ede2bdc0718), C(3752b423073b119a), C(377dc5eb7c662bdb), - C(2b9f07f93a6c25b9), C(96f24ede2bdc0718), C(f7699b12c31417bd), - C(17b366f401c58b2), C(bf60188d5f437b37), C(484436e56df17f04), C(3ef7e224)}, + C(3ef7e224)}, {C(627a2249ec6bbcc2), C(c0578b462a46735a), C(4974b8ee1c2d4f1f), - C(ebdbb918eb6d837f), C(8fb5f218dd84147c), C(c77dd1f881df2c54), - C(62eac298ec226dc3), C(ebdbb918eb6d837f), C(8fb5f218dd84147c), - C(c77dd1f881df2c54), C(62eac298ec226dc3), C(43eded83c4b60bd0), - C(9a0a403b5487503b), C(25f305d9147f0bda), C(3ad417f511bc1e64), C(35ed8dc8)}, - {C(3abaf1667ba2f3e0), C(ee78476b5eeadc1), C(7e56ac0a6ca4f3f4), - C(f1b9b413df9d79ed), C(a7621b6fd02db503), C(d92f7ba9928a4ffe), - C(53f56babdcae96a6), C(f1b9b413df9d79ed), C(a7621b6fd02db503), - C(d92f7ba9928a4ffe), C(53f56babdcae96a6), C(5302b89fc48713ab), - C(d03e3b04dbe7a2f2), C(fa74ef8af6d376a7), C(103c8cdea1050ef2), - C(6a75e43d)}, + {C(3abaf1667ba2f3e0), C(ee78476b5eeadc1), C(7e56ac0a6ca4f3f4), C(6a75e43d)}, {C(3931ac68c5f1b2c9), C(efe3892363ab0fb0), C(40b707268337cd36), - C(a53a6b64b1ac85c9), C(d50e7f86ee1b832b), C(7bab08fdd26ba0a4), - C(7587743c18fe2475), C(a53a6b64b1ac85c9), C(d50e7f86ee1b832b), - C(7bab08fdd26ba0a4), C(7587743c18fe2475), C(e3b5d5d490cf5761), - C(dfc053f7d065edd5), C(42ffd8d5fb70129f), C(599ca38677cccdc3), C(235d9805)}, - {C(b98fb0606f416754), C(46a6e5547ba99c1e), C(c909d82112a8ed2), - C(dbfaae9642b3205a), C(f676a1339402bcb9), C(f4f12a5b1ac11f29), - C(7db8bad81249dee4), C(dbfaae9642b3205a), C(f676a1339402bcb9), - C(f4f12a5b1ac11f29), C(7db8bad81249dee4), C(b26e46f2da95922e), - C(2aaedd5e12e3c611), C(a0e2d9082966074), C(c64da8a167add63d), C(f7d69572)}, + {C(b98fb0606f416754), C(46a6e5547ba99c1e), C(c909d82112a8ed2), C(f7d69572)}, {C(7f7729a33e58fcc4), C(2e4bc1e7a023ead4), C(e707008ea7ca6222), - C(47418a71800334a0), C(d10395d8fc64d8a4), C(8257a30062cb66f), - C(6786f9b2dc1ff18a), C(47418a71800334a0), C(d10395d8fc64d8a4), - C(8257a30062cb66f), C(6786f9b2dc1ff18a), C(5633f437bb2f180f), - C(e5a3a405737d22d6), C(ca0ff1ef6f7f0b74), C(d0ae600684b16df8), C(bacd0199)}, {C(42a0aa9ce82848b3), C(57232730e6bee175), C(f89bb3f370782031), - C(caa33cf9b4f6619c), C(b2c8648ad49c209f), C(9e89ece0712db1c0), - C(101d8274a711a54b), C(caa33cf9b4f6619c), C(b2c8648ad49c209f), - C(9e89ece0712db1c0), C(101d8274a711a54b), C(538e79f1e70135cd), - C(e1f5a76f983c844e), C(653c082fd66088fc), C(1b9c9b464b654958), C(e428f50e)}, {C(6b2c6d38408a4889), C(de3ef6f68fb25885), C(20754f456c203361), - C(941f5023c0c943f9), C(dfdeb9564fd66f24), C(2140cec706b9d406), - C(7b22429b131e9c72), C(941f5023c0c943f9), C(dfdeb9564fd66f24), - C(2140cec706b9d406), C(7b22429b131e9c72), C(94215c22eb940f45), - C(d28b9ed474f7249a), C(6f25e88f2fbf9f56), C(b6718f9e605b38ac), C(81eaaad3)}, {C(930380a3741e862a), C(348d28638dc71658), C(89dedcfd1654ea0d), - C(7e7f61684080106), C(837ace9794582976), C(5ac8ca76a357eb1b), - C(32b58308625661fb), C(7e7f61684080106), C(837ace9794582976), - C(5ac8ca76a357eb1b), C(32b58308625661fb), C(c09705c4572025d9), - C(f9187f6af0291303), C(1c0edd8ee4b02538), C(e6cb105daa0578a), C(addbd3e3)}, + C(addbd3e3)}, {C(94808b5d2aa25f9a), C(cec72968128195e0), C(d9f4da2bdc1e130f), - C(272d8dd74f3006cc), C(ec6c2ad1ec03f554), C(4ad276b249a5d5dd), - C(549a22a17c0cde12), C(272d8dd74f3006cc), C(ec6c2ad1ec03f554), - C(4ad276b249a5d5dd), C(549a22a17c0cde12), C(602119cb824d7cde), - C(f4d3cef240ef35fa), C(e889895e01911bc7), C(785a7e5ac20e852b), C(e66dbca0)}, {C(b31abb08ae6e3d38), C(9eb9a95cbd9e8223), C(8019e79b7ee94ea9), - C(7b2271a7a3248e22), C(3b4f700e5a0ba523), C(8ebc520c227206fe), - C(da3f861490f5d291), C(7b2271a7a3248e22), C(3b4f700e5a0ba523), - C(8ebc520c227206fe), C(da3f861490f5d291), C(d08a689f9f3aa60e), - C(547c1b97a068661f), C(4b15a67fa29172f0), C(eaf40c085191d80f), C(afe11fd5)}, {C(dccb5534a893ea1a), C(ce71c398708c6131), C(fe2396315457c164), - C(3f1229f4d0fd96fb), C(33130aa5fa9d43f2), C(e42693d5b34e63ab), - C(2f4ef2be67f62104), C(3f1229f4d0fd96fb), C(33130aa5fa9d43f2), - C(e42693d5b34e63ab), C(2f4ef2be67f62104), C(372e5153516e37b9), - C(af9ec142ab12cc86), C(777920c09345e359), C(e7c4a383bef8adc6), C(a71a406f)}, {C(6369163565814de6), C(8feb86fb38d08c2f), C(4976933485cc9a20), - C(7d3e82d5ba29a90d), C(d5983cc93a9d126a), C(37e9dfd950e7b692), - C(80673be6a7888b87), C(7d3e82d5ba29a90d), C(d5983cc93a9d126a), - C(37e9dfd950e7b692), C(80673be6a7888b87), C(57f732dc600808bc), - C(59477199802cc78b), C(f824810eb8f2c2de), C(c4a3437f05b3b61c), C(9d90eaf5)}, {C(edee4ff253d9f9b3), C(96ef76fb279ef0ad), C(a4d204d179db2460), - C(1f3dcdfa513512d6), C(4dc7ec07283117e4), C(4438bae88ae28bf9), - C(aa7eae72c9244a0d), C(1f3dcdfa513512d6), C(4dc7ec07283117e4), - C(4438bae88ae28bf9), C(aa7eae72c9244a0d), C(b9aedc8d3ecc72df), - C(b75a8eb090a77d62), C(6b15677f9cd91507), C(51d8282cb3a9ddbf), C(6665db10)}, {C(941993df6e633214), C(929bc1beca5b72c6), C(141fc52b8d55572d), - C(b3b782ad308f21ed), C(4f2676485041dee0), C(bfe279aed5cb4bc8), - C(2a62508a467a22ff), C(b3b782ad308f21ed), C(4f2676485041dee0), - C(bfe279aed5cb4bc8), C(2a62508a467a22ff), C(e74d29eab742385d), - C(56b05cd90ecfc293), C(c603728ea73f8844), C(8638fcd21bc692c4), C(9c977cbf)}, {C(859838293f64cd4c), C(484403b39d44ad79), C(bf674e64d64b9339), - C(44d68afda9568f08), C(478568ed51ca1d65), C(679c204ad3d9e766), - C(b28e788878488dc1), C(44d68afda9568f08), C(478568ed51ca1d65), - C(679c204ad3d9e766), C(b28e788878488dc1), C(d001a84d3a84fae6), - C(d376958fe4cb913e), C(17435277e36c86f0), C(23657b263c347aa6), C(ee83ddd4)}, - {C(c19b5648e0d9f555), C(328e47b2b7562993), C(e756b92ba4bd6a51), - C(c3314e362764ddb8), C(6481c084ee9ec6b5), C(ede23fb9a251771), - C(bd617f2643324590), C(c3314e362764ddb8), C(6481c084ee9ec6b5), - C(ede23fb9a251771), C(bd617f2643324590), C(d2d30c9b95e030f5), - C(8a517312ffc5795e), C(8b1f325033bd535e), C(3ee6e867e03f2892), C(26519cc)}, + {C(c19b5648e0d9f555), C(328e47b2b7562993), C(e756b92ba4bd6a51), C(26519cc)}, {C(f963b63b9006c248), C(9e9bf727ffaa00bc), C(c73bacc75b917e3a), - C(2c6aa706129cc54c), C(17a706f59a49f086), C(c7c1eec455217145), - C(6adfdc6e07602d42), C(2c6aa706129cc54c), C(17a706f59a49f086), - C(c7c1eec455217145), C(6adfdc6e07602d42), C(fb75fca30d848dd2), - C(5228c9ed14653ed4), C(953958910153b1a2), C(a430103a24f42a5d), C(a485a53f)}, {C(6a8aa0852a8c1f3b), C(c8f1e5e206a21016), C(2aa554aed1ebb524), - C(fc3e3c322cd5d89b), C(b7e3911dc2bd4ebb), C(fcd6da5e5fae833a), - C(51ed3c41f87f9118), C(fc3e3c322cd5d89b), C(b7e3911dc2bd4ebb), - C(fcd6da5e5fae833a), C(51ed3c41f87f9118), C(f31750cbc19c420a), - C(186dab1abada1d86), C(ca7f88cb894b3cd7), C(2859eeb1c373790c), C(f62bc412)}, {C(740428b4d45e5fb8), C(4c95a4ce922cb0a5), C(e99c3ba78feae796), - C(914f1ea2fdcebf5c), C(9566453c07cd0601), C(9841bf66d0462cd), - C(79140c1c18536aeb), C(914f1ea2fdcebf5c), C(9566453c07cd0601), - C(9841bf66d0462cd), C(79140c1c18536aeb), C(a963b930b05820c2), - C(6a7d9fa0c8c45153), C(64214c40d07cf39b), C(7057daf1d806c014), C(8975a436)}, - {C(658b883b3a872b86), C(2f0e303f0f64827a), C(975337e23dc45e1), - C(99468a917986162b), C(7b31434aac6e0af0), C(f6915c1562c7d82f), - C(e4071d82a6dd71db), C(99468a917986162b), C(7b31434aac6e0af0), - C(f6915c1562c7d82f), C(e4071d82a6dd71db), C(5f5331f077b5d996), - C(7b314ba21b747a4f), C(5a73cb9521da17f5), C(12ed435fae286d86), - C(94ff7f41)}, - {C(6df0a977da5d27d4), C(891dd0e7cb19508), C(fd65434a0b71e680), - C(8799e4740e573c50), C(9e739b52d0f341e8), C(cdfd34ba7d7b03eb), - C(5061812ce6c88499), C(8799e4740e573c50), C(9e739b52d0f341e8), - C(cdfd34ba7d7b03eb), C(5061812ce6c88499), C(612b8d8f2411dc5c), - C(878bd883d29c7787), C(47a846727182bb), C(ec4949508c8b3b9a), C(760aa031)}, - {C(a900275464ae07ef), C(11f2cfda34beb4a3), C(9abf91e5a1c38e4), - C(8063d80ab26f3d6d), C(4177b4b9b4f0393f), C(6de42ba8672b9640), - C(d0bccdb72c51c18), C(8063d80ab26f3d6d), C(4177b4b9b4f0393f), - C(6de42ba8672b9640), C(d0bccdb72c51c18), C(af3f611b7f22cf12), - C(3863c41492645755), C(928c7a616a8f14f9), C(a82c78eb2eadc58b), - C(3bda76df)}, + {C(658b883b3a872b86), C(2f0e303f0f64827a), C(975337e23dc45e1), C(94ff7f41)}, + {C(6df0a977da5d27d4), C(891dd0e7cb19508), C(fd65434a0b71e680), C(760aa031)}, + {C(a900275464ae07ef), C(11f2cfda34beb4a3), C(9abf91e5a1c38e4), C(3bda76df)}, {C(810bc8aa0c40bcb0), C(448a019568d01441), C(f60ec52f60d3aeae), - C(52c44837aa6dfc77), C(15d8d8fccdd6dc5b), C(345b793ccfa93055), - C(932160fe802ca975), C(52c44837aa6dfc77), C(15d8d8fccdd6dc5b), - C(345b793ccfa93055), C(932160fe802ca975), C(a624b0dd93fc18cd), - C(d955b254c2037f1e), C(e540533d370a664c), C(2ba4ec12514e9d7), C(498e2e65)}, + C(498e2e65)}, {C(22036327deb59ed7), C(adc05ceb97026a02), C(48bff0654262672b), - C(c791b313aba3f258), C(443c7757a4727bee), C(e30e4b2372171bdf), - C(f3db986c4156f3cb), C(c791b313aba3f258), C(443c7757a4727bee), - C(e30e4b2372171bdf), C(f3db986c4156f3cb), C(a939aefab97c6e15), - C(dbeb8acf1d5b0e6c), C(1e0eab667a795bba), C(80dd539902df4d50), C(d38deb48)}, {C(7d14dfa9772b00c8), C(595735efc7eeaed7), C(29872854f94c3507), - C(bc241579d8348401), C(16dc832804d728f0), C(e9cc71ae64e3f09e), - C(bef634bc978bac31), C(bc241579d8348401), C(16dc832804d728f0), - C(e9cc71ae64e3f09e), C(bef634bc978bac31), C(7f64b1fa2a9129e), - C(71d831bd530ac7f3), C(c7ad0a8a6d5be6f1), C(82a7d3a815c7aaab), C(82b3fb6b)}, {C(2d777cddb912675d), C(278d7b10722a13f9), C(f5c02bfb7cc078af), - C(4283001239888836), C(f44ca39a6f79db89), C(ed186122d71bcc9f), - C(8620017ab5f3ba3b), C(4283001239888836), C(f44ca39a6f79db89), - C(ed186122d71bcc9f), C(8620017ab5f3ba3b), C(e787472187f176c), - C(267e64c4728cf181), C(f1ba4b3007c15e30), C(8e3a75d5b02ecfc0), C(e500e25f)}, {C(f2ec98824e8aa613), C(5eb7e3fb53fe3bed), C(12c22860466e1dd4), - C(374dd4288e0b72e5), C(ff8916db706c0df4), C(cb1a9e85de5e4b8d), - C(d4d12afb67a27659), C(374dd4288e0b72e5), C(ff8916db706c0df4), - C(cb1a9e85de5e4b8d), C(d4d12afb67a27659), C(feb69095d1ba175a), - C(e2003aab23a47fad), C(8163a3ecab894b49), C(46d356674ce041f6), C(bd2bb07c)}, {C(5e763988e21f487f), C(24189de8065d8dc5), C(d1519d2403b62aa0), - C(9136456740119815), C(4d8ff7733b27eb83), C(ea3040bc0c717ef8), - C(7617ab400dfadbc), C(9136456740119815), C(4d8ff7733b27eb83), - C(ea3040bc0c717ef8), C(7617ab400dfadbc), C(fb336770c10b17a1), - C(6123b68b5b31f151), C(1e147d5f295eccf2), C(9ecbb1333556f977), C(3a2b431d)}, {C(48949dc327bb96ad), C(e1fd21636c5c50b4), C(3f6eb7f13a8712b4), - C(14cf7f02dab0eee8), C(6d01750605e89445), C(4f1cf4006e613b78), - C(57c40c4db32bec3b), C(14cf7f02dab0eee8), C(6d01750605e89445), - C(4f1cf4006e613b78), C(57c40c4db32bec3b), C(1fde5a347f4a326e), - C(cb5a54308adb0e3f), C(14994b2ba447a23c), C(7067d0abb4257b68), C(7322a83d)}, {C(b7c4209fb24a85c5), C(b35feb319c79ce10), C(f0d3de191833b922), - C(570d62758ddf6397), C(5e0204fb68a7b800), C(4383a9236f8b5a2b), - C(7bc1a64641d803a4), C(570d62758ddf6397), C(5e0204fb68a7b800), - C(4383a9236f8b5a2b), C(7bc1a64641d803a4), C(5434d61285099f7a), - C(d49449aacdd5dd67), C(97855ba0e9a7d75d), C(da67328062f3a62f), C(a645ca1c)}, {C(9c9e5be0943d4b05), C(b73dc69e45201cbb), C(aab17180bfe5083d), - C(c738a77a9a55f0e2), C(705221addedd81df), C(fd9bd8d397abcfa3), - C(8ccf0004aa86b795), C(c738a77a9a55f0e2), C(705221addedd81df), - C(fd9bd8d397abcfa3), C(8ccf0004aa86b795), C(2bb5db2280068206), - C(8c22d29f307a01d), C(274a22de02f473c8), C(b8791870f4268182), C(8909a45a)}, + C(8909a45a)}, {C(3898bca4dfd6638d), C(f911ff35efef0167), C(24bdf69e5091fc88), - C(9b82567ab6560796), C(891b69462b41c224), C(8eccc7e4f3af3b51), - C(381e54c3c8f1c7d0), C(9b82567ab6560796), C(891b69462b41c224), - C(8eccc7e4f3af3b51), C(381e54c3c8f1c7d0), C(c80fbc489a558a55), - C(1ba88e062a663af7), C(af7b1ef1c0116303), C(bd20e1a5a6b1a0cd), C(bd30074c)}, - {C(5b5d2557400e68e7), C(98d610033574cee), C(dfd08772ce385deb), - C(3c13e894365dc6c2), C(26fc7bbcda3f0ef), C(dbb71106cdbfea36), - C(785239a742c6d26d), C(3c13e894365dc6c2), C(26fc7bbcda3f0ef), - C(dbb71106cdbfea36), C(785239a742c6d26d), C(f810c415ae05b2f4), - C(bb9b9e7398526088), C(70128f1bf830a32b), C(bcc73f82b6410899), - C(c17cf001)}, + {C(5b5d2557400e68e7), C(98d610033574cee), C(dfd08772ce385deb), C(c17cf001)}, {C(a927ed8b2bf09bb6), C(606e52f10ae94eca), C(71c2203feb35a9ee), - C(6e65ec14a8fb565), C(34bff6f2ee5a7f79), C(2e329a5be2c011b), - C(73161c93331b14f9), C(6e65ec14a8fb565), C(34bff6f2ee5a7f79), - C(2e329a5be2c011b), C(73161c93331b14f9), C(15d13f2408aecf88), - C(9f5b61b8a4b55b31), C(8fe25a43b296dba6), C(bdad03b7300f284e), C(26ffd25a)}, {C(8d25746414aedf28), C(34b1629d28b33d3a), C(4d5394aea5f82d7b), - C(379f76458a3c8957), C(79dd080f9843af77), C(c46f0a7847f60c1d), - C(af1579c5797703cc), C(379f76458a3c8957), C(79dd080f9843af77), - C(c46f0a7847f60c1d), C(af1579c5797703cc), C(8b7d31f338755c14), - C(2eff97679512aaa8), C(df07d68e075179ed), C(c8fa6c7a729e7f1f), C(f1d8ce3c)}, {C(b5bbdb73458712f2), C(1ff887b3c2a35137), C(7f7231f702d0ace9), - C(1e6f0910c3d25bd8), C(ad9e250862102467), C(1c842a07abab30cd), - C(cd8124176bac01ac), C(1e6f0910c3d25bd8), C(ad9e250862102467), - C(1c842a07abab30cd), C(cd8124176bac01ac), C(ea6ebe7a79b67edc), - C(73f598ac9db26713), C(4f4e72d7460b8fc), C(365dc4b9fdf13f21), C(3ee8fb17)}, + C(3ee8fb17)}, {C(3d32a26e3ab9d254), C(fc4070574dc30d3a), C(f02629579c2b27c9), - C(b1cf09b0184a4834), C(5c03db48eb6cc159), C(f18c7fcf34d1df47), - C(dfb043419ecf1fa9), C(b1cf09b0184a4834), C(5c03db48eb6cc159), - C(f18c7fcf34d1df47), C(dfb043419ecf1fa9), C(dcd78d13f9ca658f), - C(4355d408ffe8e49f), C(81eefee908b593b4), C(590c213c20e981a3), C(a77acc2a)}, - {C(9371d3c35fa5e9a5), C(42967cf4d01f30), C(652d1eeae704145c), - C(ceaf1a0d15234f15), C(1450a54e45ba9b9), C(65e9c1fd885aa932), - C(354d4bc034ba8cbe), C(ceaf1a0d15234f15), C(1450a54e45ba9b9), - C(65e9c1fd885aa932), C(354d4bc034ba8cbe), C(8fd4ff484c08fb4b), - C(bf46749866f69ba0), C(cf1c21ede82c9477), C(4217548c43da109), C(f4556dee)}, - {C(cbaa3cb8f64f54e0), C(76c3b48ee5c08417), C(9f7d24e87e61ce9), - C(85b8e53f22e19507), C(bb57137739ca486b), C(c77f131cca38f761), - C(c56ac3cf275be121), C(85b8e53f22e19507), C(bb57137739ca486b), - C(c77f131cca38f761), C(c56ac3cf275be121), C(9ec1a6c9109d2685), - C(3dad0922e76afdb0), C(fd58cbf952958103), C(7b04c908e78639a1), - C(de287a64)}, + {C(9371d3c35fa5e9a5), C(42967cf4d01f30), C(652d1eeae704145c), C(f4556dee)}, + {C(cbaa3cb8f64f54e0), C(76c3b48ee5c08417), C(9f7d24e87e61ce9), C(de287a64)}, {C(b2e23e8116c2ba9f), C(7e4d9c0060101151), C(3310da5e5028f367), - C(adc52dddb76f6e5e), C(4aad4e925a962b68), C(204b79b7f7168e64), - C(df29ed6671c36952), C(adc52dddb76f6e5e), C(4aad4e925a962b68), - C(204b79b7f7168e64), C(df29ed6671c36952), C(e02927cac396d210), - C(5d500e71742b638a), C(5c9998af7f27b124), C(3fba9a2573dc2f7), C(878e55b9)}, - {C(8aa77f52d7868eb9), C(4d55bd587584e6e2), C(d2db37041f495f5), - C(ce030d15b5fe2f4), C(86b4a7a0780c2431), C(ee070a9ae5b51db7), - C(edc293d9595be5d8), C(ce030d15b5fe2f4), C(86b4a7a0780c2431), - C(ee070a9ae5b51db7), C(edc293d9595be5d8), C(3dfc5ec108260a2b), - C(8afe28c7123bf4e2), C(da82ef38023a7a5f), C(3e1f77b0174b77c3), C(7648486)}, + C(878e55b9)}, + {C(8aa77f52d7868eb9), C(4d55bd587584e6e2), C(d2db37041f495f5), C(7648486)}, {C(858fea922c7fe0c3), C(cfe8326bf733bc6f), C(4e5e2018cf8f7dfc), - C(64fd1bc011e5bab7), C(5c9e858728015568), C(97ac42c2b00b29b1), - C(7f89caf08c109aee), C(64fd1bc011e5bab7), C(5c9e858728015568), - C(97ac42c2b00b29b1), C(7f89caf08c109aee), C(9a8af34fd0e9dacf), - C(bbc54161aa1507e0), C(7cda723ccbbfe5ee), C(2c289d839fb93f58), C(57ac0fb1)}, {C(46ef25fdec8392b1), C(e48d7b6d42a5cd35), C(56a6fe1c175299ca), - C(fdfa836b41dcef62), C(2f8db8030e847e1b), C(5ba0a49ac4f9b0f8), - C(dae897ed3e3fce44), C(fdfa836b41dcef62), C(2f8db8030e847e1b), - C(5ba0a49ac4f9b0f8), C(dae897ed3e3fce44), C(9c432e31aef626e7), - C(9a36e1c6cd6e3dd), C(5095a167c34d19d), C(a70005cfa6babbea), C(d01967ca)}, + C(d01967ca)}, {C(8d078f726b2df464), C(b50ee71cdcabb299), C(f4af300106f9c7ba), - C(7d222caae025158a), C(cc028d5fd40241b9), C(dd42515b639e6f97), - C(e08e86531a58f87f), C(7d222caae025158a), C(cc028d5fd40241b9), - C(dd42515b639e6f97), C(e08e86531a58f87f), C(d93612c835b37d7b), - C(91dd61729b2fa7f4), C(ba765a1bdda09db7), C(55258b451b2b1297), C(96ecdf74)}, {C(35ea86e6960ca950), C(34fe1fe234fc5c76), C(a00207a3dc2a72b7), - C(80395e48739e1a67), C(74a67d8f7f43c3d7), C(dd2bdd1d62246c6e), - C(a1f44298ba80acf6), C(80395e48739e1a67), C(74a67d8f7f43c3d7), - C(dd2bdd1d62246c6e), C(a1f44298ba80acf6), C(ad86d86c187bf38), - C(26feea1f2eee240d), C(ed7f1fd066b23897), C(a768cf1e0fbb502), C(779f5506)}, + C(779f5506)}, {C(8aee9edbc15dd011), C(51f5839dc8462695), C(b2213e17c37dca2d), - C(133b299a939745c5), C(796e2aac053f52b3), C(e8d9fe1521a4a222), - C(819a8863e5d1c290), C(133b299a939745c5), C(796e2aac053f52b3), - C(e8d9fe1521a4a222), C(819a8863e5d1c290), C(c0737f0fe34d36ad), - C(e6d6d4a267a5cc31), C(98300a7911674c23), C(bef189661c257098), C(3c94c2de)}, {C(c3e142ba98432dda), C(911d060cab126188), C(b753fbfa8365b844), - C(fd1a9ba5e71b08a2), C(7ac0dc2ed7778533), C(b543161ff177188a), - C(492fc08a6186f3f4), C(fd1a9ba5e71b08a2), C(7ac0dc2ed7778533), - C(b543161ff177188a), C(492fc08a6186f3f4), C(fc4745f516afd3b6), - C(88c30370a53080e), C(65a1bb34abc465e2), C(abbd14662911c8b3), C(39f98faf)}, + C(39f98faf)}, {C(123ba6b99c8cd8db), C(448e582672ee07c4), C(cebe379292db9e65), - C(938f5bbab544d3d6), C(d2a95f9f2d376d73), C(68b2f16149e81aa3), - C(ad7e32f82d86c79d), C(938f5bbab544d3d6), C(d2a95f9f2d376d73), - C(68b2f16149e81aa3), C(ad7e32f82d86c79d), C(4574015ae8626ce2), - C(455aa6137386a582), C(658ad2542e8ec20), C(e31d7be2ca35d00), C(7af31199)}, + C(7af31199)}, {C(ba87acef79d14f53), C(b3e0fcae63a11558), C(d5ac313a593a9f45), - C(eea5f5a9f74af591), C(578710bcc36fbea2), C(7a8393432188931d), - C(705cfc5ec7cc172), C(eea5f5a9f74af591), C(578710bcc36fbea2), - C(7a8393432188931d), C(705cfc5ec7cc172), C(da85ebe5fc427976), - C(bfa5c7a454df54c8), C(4632b72a81bf66d2), C(5dd72877db539ee2), C(e341a9d6)}, - {C(bcd3957d5717dc3), C(2da746741b03a007), C(873816f4b1ece472), - C(2b826f1a2c08c289), C(da50f56863b55e74), C(b18712f6b3eed83b), - C(bdc7cc05ab4c685f), C(2b826f1a2c08c289), C(da50f56863b55e74), - C(b18712f6b3eed83b), C(bdc7cc05ab4c685f), C(9e45fb833d1b0af), - C(d7213081db29d82e), C(d2a6b6c6a09ed55e), C(98a7686cba323ca9), - C(ca24aeeb)}, + {C(bcd3957d5717dc3), C(2da746741b03a007), C(873816f4b1ece472), C(ca24aeeb)}, {C(61442ff55609168e), C(6447c5fc76e8c9cf), C(6a846de83ae15728), - C(effc2663cffc777f), C(93214f8f463afbed), C(a156ef06066f4e4e), - C(a407b6ed8769d51e), C(effc2663cffc777f), C(93214f8f463afbed), - C(a156ef06066f4e4e), C(a407b6ed8769d51e), C(bb2f9ed29745c02a), - C(981eecd435b36ad9), C(461a5a05fb9cdff4), C(bd6cb2a87b9f910c), C(b2252b57)}, - {C(dbe4b1b2d174757f), C(506512da18712656), C(6857f3e0b8dd95f), - C(5a4fc2728a9bb671), C(ebb971522ec38759), C(1a5a093e6cf1f72b), - C(729b057fe784f504), C(5a4fc2728a9bb671), C(ebb971522ec38759), - C(1a5a093e6cf1f72b), C(729b057fe784f504), C(71fcbf42a767f9cf), - C(114cfe772da6cdd), C(60cdf9cb629d9d7a), C(e270d10ad088b24e), C(72c81da1)}, + {C(dbe4b1b2d174757f), C(506512da18712656), C(6857f3e0b8dd95f), C(72c81da1)}, {C(531e8e77b363161c), C(eece0b43e2dae030), C(8294b82c78f34ed1), - C(e777b1fd580582f2), C(7b880f58da112699), C(562c6b189a6333f4), - C(139d64f88a611d4), C(e777b1fd580582f2), C(7b880f58da112699), - C(562c6b189a6333f4), C(139d64f88a611d4), C(53d8ef17eda64fa4), - C(bf3eded14dc60a04), C(2b5c559cf5ec07c5), C(8895f7339d03a48a), C(6b9fce95)}, {C(f71e9c926d711e2b), C(d77af2853a4ceaa1), C(9aa0d6d76a36fae7), - C(dd16cd0fbc08393), C(29a414a5d8c58962), C(72793d8d1022b5b2), - C(2e8e69cf7cbffdf0), C(dd16cd0fbc08393), C(29a414a5d8c58962), - C(72793d8d1022b5b2), C(2e8e69cf7cbffdf0), C(3721c0473aa99c9a), - C(1cff4ed9c31cd91c), C(4990735033cc482b), C(7fdf8c701c72f577), C(19399857)}, {C(cb20ac28f52df368), C(e6705ee7880996de), C(9b665cc3ec6972f2), - C(4260e8c254e9924b), C(f197a6eb4591572d), C(8e867ff0fb7ab27c), - C(f95502fb503efaf3), C(4260e8c254e9924b), C(f197a6eb4591572d), - C(8e867ff0fb7ab27c), C(f95502fb503efaf3), C(30c41876b08e3e22), - C(958e2419e3cd22f4), C(f0f3aa1fe119a107), C(481662310a379100), C(3c57a994)}, {C(e4a794b4acb94b55), C(89795358057b661b), C(9c4cdcec176d7a70), - C(4890a83ee435bc8b), C(d8c1c00fceb00914), C(9e7111ba234f900f), - C(eb8dbab364d8b604), C(4890a83ee435bc8b), C(d8c1c00fceb00914), - C(9e7111ba234f900f), C(eb8dbab364d8b604), C(b3261452963eebb), - C(6cf94b02792c4f95), C(d88fa815ef1e8fc), C(2d687af66604c73), C(c053e729)}, + C(c053e729)}, {C(cb942e91443e7208), C(e335de8125567c2a), C(d4d74d268b86df1f), - C(8ba0fdd2ffc8b239), C(f413b366c1ffe02f), C(c05b2717c59a8a28), - C(981188eab4fcc8fb), C(8ba0fdd2ffc8b239), C(f413b366c1ffe02f), - C(c05b2717c59a8a28), C(981188eab4fcc8fb), C(e563f49a1d9072ba), - C(3c6a3aa4a26367dc), C(ba0db13448653f34), C(31065d756074d7d6), C(51cbbba7)}, {C(ecca7563c203f7ba), C(177ae2423ef34bb2), C(f60b7243400c5731), - C(cf1edbfe7330e94e), C(881945906bcb3cc6), C(4acf0293244855da), - C(65ae042c1c2a28c2), C(cf1edbfe7330e94e), C(881945906bcb3cc6), - C(4acf0293244855da), C(65ae042c1c2a28c2), C(b25fa0a1cab33559), - C(d98e8daa28124131), C(fce17f50b9c351b3), C(3f995ccf7386864b), C(1acde79a)}, {C(1652cb940177c8b5), C(8c4fe7d85d2a6d6d), C(f6216ad097e54e72), - C(f6521b912b368ae6), C(a9fe4eff81d03e73), C(d6f623629f80d1a3), - C(2b9604f32cb7dc34), C(f6521b912b368ae6), C(a9fe4eff81d03e73), - C(d6f623629f80d1a3), C(2b9604f32cb7dc34), C(2a43d84dcf59c7e2), - C(d0a197c70c5dae0b), C(6e84d4bbc71d76a0), C(c7e94620378c6cb2), C(2d160d13)}, {C(31fed0fc04c13ce8), C(3d5d03dbf7ff240a), C(727c5c9b51581203), - C(6b5ffc1f54fecb29), C(a8e8e7ad5b9a21d9), C(c4d5a32cd6aac22d), - C(d7e274ad22d4a79a), C(6b5ffc1f54fecb29), C(a8e8e7ad5b9a21d9), - C(c4d5a32cd6aac22d), C(d7e274ad22d4a79a), C(368841ea5731a112), - C(feaf7bc2e73ca48f), C(636fb272e9ea1f6), C(5d9cb7580c3f6207), C(787f5801)}, + C(787f5801)}, {C(e7b668947590b9b3), C(baa41ad32938d3fa), C(abcbc8d4ca4b39e4), - C(381ee1b7ea534f4e), C(da3759828e3de429), C(3e015d76729f9955), - C(cbbec51a6485fbde), C(381ee1b7ea534f4e), C(da3759828e3de429), - C(3e015d76729f9955), C(cbbec51a6485fbde), C(9b86605281f20727), - C(fc6fcf508676982a), C(3b135f7a813a1040), C(d3a4706bea1db9c9), C(c9629828)}, {C(1de2119923e8ef3c), C(6ab27c096cf2fe14), C(8c3658edca958891), - C(4cc8ed3ada5f0f2), C(4a496b77c1f1c04e), C(9085b0a862084201), - C(a1894bde9e3dee21), C(4cc8ed3ada5f0f2), C(4a496b77c1f1c04e), - C(9085b0a862084201), C(a1894bde9e3dee21), C(367fb472dc5b277d), - C(7d39ccca16fc6745), C(763f988d70db9106), C(a8b66f7fecb70f02), C(be139231)}, {C(1269df1e69e14fa7), C(992f9d58ac5041b7), C(e97fcf695a7cbbb4), - C(e5d0549802d15008), C(424c134ecd0db834), C(6fc44fd91be15c6c), - C(a1a5ef95d50e537d), C(e5d0549802d15008), C(424c134ecd0db834), - C(6fc44fd91be15c6c), C(a1a5ef95d50e537d), C(d1e3daf5d05f5308), - C(4c7f81600eaa1327), C(109d1b8d1f9d0d2b), C(871e8699e0aeb862), C(7df699ef)}, {C(820826d7aba567ff), C(1f73d28e036a52f3), C(41c4c5a73f3b0893), - C(aa0d74d4a98db89b), C(36fd486d07c56e1d), C(d0ad23cbb6660d8a), - C(1264a84665b35e19), C(aa0d74d4a98db89b), C(36fd486d07c56e1d), - C(d0ad23cbb6660d8a), C(1264a84665b35e19), C(789682bf7d781b33), - C(6bfa6abd2fb5722d), C(6779cb3623d33900), C(435ca5214e1ee5f0), C(8ce6b96d)}, {C(ffe0547e4923cef9), C(3534ed49b9da5b02), C(548a273700fba03d), - C(28ac84ca70958f7e), C(d8ae575a68faa731), C(2aaaee9b9dcffd4c), - C(6c7faab5c285c6da), C(28ac84ca70958f7e), C(d8ae575a68faa731), - C(2aaaee9b9dcffd4c), C(6c7faab5c285c6da), C(45d94235f99ba78f), - C(ab5ea16f39497f5b), C(fb4d6c86fccbdca3), C(8104e6310a5fd2c7), C(6f9ed99c)}, {C(72da8d1b11d8bc8b), C(ba94b56b91b681c6), C(4e8cc51bd9b0fc8c), - C(43505ed133be672a), C(e8f2f9d973c2774e), C(677b9b9c7cad6d97), - C(4e1f5d56ef17b906), C(43505ed133be672a), C(e8f2f9d973c2774e), - C(677b9b9c7cad6d97), C(4e1f5d56ef17b906), C(eea3a6038f983767), - C(87109f077f86db01), C(ecc1ca41f74d61cc), C(34a87e86e83bed17), C(e0244796)}, - {C(d62ab4e3f88fc797), C(ea86c7aeb6283ae4), C(b5b93e09a7fe465), - C(4344a1a0134afe2), C(ff5c17f02b62341d), C(3214c6a587ce4644), - C(a905e7ed0629d05c), C(4344a1a0134afe2), C(ff5c17f02b62341d), - C(3214c6a587ce4644), C(a905e7ed0629d05c), C(b5c72690cd716e82), - C(7c6097649e6ebe7b), C(7ceee8c6e56a4dcd), C(80ca849dc53eb9e4), - C(4ccf7e75)}, + {C(d62ab4e3f88fc797), C(ea86c7aeb6283ae4), C(b5b93e09a7fe465), C(4ccf7e75)}, {C(d0f06c28c7b36823), C(1008cb0874de4bb8), C(d6c7ff816c7a737b), - C(489b697fe30aa65f), C(4da0fb621fdc7817), C(dc43583b82c58107), - C(4b0261debdec3cd6), C(489b697fe30aa65f), C(4da0fb621fdc7817), - C(dc43583b82c58107), C(4b0261debdec3cd6), C(a9748d7b6c0e016c), - C(7e8828f7ba4b034b), C(da0fa54348a2512a), C(ebf9745c0962f9ad), C(915cef86)}, {C(99b7042460d72ec6), C(2a53e5e2b8e795c2), C(53a78132d9e1b3e3), - C(c043e67e6fc64118), C(ff0abfe926d844d3), C(f2a9fe5db2e910fe), - C(ce352cdc84a964dd), C(c043e67e6fc64118), C(ff0abfe926d844d3), - C(f2a9fe5db2e910fe), C(ce352cdc84a964dd), C(b89bc028aa5e6063), - C(a354e7fdac04459c), C(68d6547e6e980189), C(c968dddfd573773e), C(5cb59482)}, - {C(4f4dfcfc0ec2bae5), C(841233148268a1b8), C(9248a76ab8be0d3), - C(334c5a25b5903a8c), C(4c94fef443122128), C(743e7d8454655c40), - C(1ab1e6d1452ae2cd), C(334c5a25b5903a8c), C(4c94fef443122128), - C(743e7d8454655c40), C(1ab1e6d1452ae2cd), C(fec766de4a8e476c), - C(cc0929da9567e71b), C(5f9ef5b5f150c35a), C(87659cabd649768f), - C(6ca3f532)}, + {C(4f4dfcfc0ec2bae5), C(841233148268a1b8), C(9248a76ab8be0d3), C(6ca3f532)}, {C(fe86bf9d4422b9ae), C(ebce89c90641ef9c), C(1c84e2292c0b5659), - C(8bde625a10a8c50d), C(eb8271ded1f79a0b), C(14dc6844f0de7a3c), - C(f85b2f9541e7e6da), C(8bde625a10a8c50d), C(eb8271ded1f79a0b), - C(14dc6844f0de7a3c), C(f85b2f9541e7e6da), C(2fe22cfd1683b961), - C(ea1d75c5b7aa01ca), C(9eef60a44876bb95), C(950c818e505c6f7f), C(e24f3859)}, {C(a90d81060932dbb0), C(8acfaa88c5fbe92b), C(7c6f3447e90f7f3f), - C(dd52fc14c8dd3143), C(1bc7508516e40628), C(3059730266ade626), - C(ffa526822f391c2), C(dd52fc14c8dd3143), C(1bc7508516e40628), - C(3059730266ade626), C(ffa526822f391c2), C(e25232d7afc8a406), - C(d2b8a5a3f3b5f670), C(6630f33edb7dfe32), C(c71250ba68c4ea86), C(adf5a9c7)}, {C(17938a1b0e7f5952), C(22cadd2f56f8a4be), C(84b0d1183d5ed7c1), - C(c1336b92fef91bf6), C(80332a3945f33fa9), C(a0f68b86f726ff92), - C(a3db5282cf5f4c0b), C(c1336b92fef91bf6), C(80332a3945f33fa9), - C(a0f68b86f726ff92), C(a3db5282cf5f4c0b), C(82640b6fc4916607), - C(2dc2a3aa1a894175), C(8b4c852bdee7cc9), C(10b9d0a08b55ff83), C(32264b75)}, + C(32264b75)}, {C(de9e0cb0e16f6e6d), C(238e6283aa4f6594), C(4fb9c914c2f0a13b), - C(497cb912b670f3b), C(d963a3f02ff4a5b6), C(4fccefae11b50391), - C(42ba47db3f7672f), C(497cb912b670f3b), C(d963a3f02ff4a5b6), - C(4fccefae11b50391), C(42ba47db3f7672f), C(1d6b655a1889feef), - C(5f319abf8fafa19f), C(715c2e49deb14620), C(8d9153082ecdcea4), C(a64b3376)}, - {C(6d4b876d9b146d1a), C(aab2d64ce8f26739), C(d315f93600e83fe5), - C(2fe9fabdbe7fdd4), C(755db249a2d81a69), C(f27929f360446d71), - C(79a1bf957c0c1b92), C(2fe9fabdbe7fdd4), C(755db249a2d81a69), - C(f27929f360446d71), C(79a1bf957c0c1b92), C(3c8a28d4c936c9cd), - C(df0d3d13b2c6a902), C(c76702dd97cd2edd), C(1aa220f7be16517), C(d33890e)}, + {C(6d4b876d9b146d1a), C(aab2d64ce8f26739), C(d315f93600e83fe5), C(d33890e)}, {C(e698fa3f54e6ea22), C(bd28e20e7455358c), C(9ace161f6ea76e66), - C(d53fb7e3c93a9e4), C(737ae71b051bf108), C(7ac71feb84c2df42), - C(3d8075cd293a15b4), C(d53fb7e3c93a9e4), C(737ae71b051bf108), - C(7ac71feb84c2df42), C(3d8075cd293a15b4), C(bf8cee5e095d8a7c), - C(e7086b3c7608143a), C(e55b0c2fa938d70c), C(fffb5f58e643649c), C(926d4b63)}, {C(7bc0deed4fb349f7), C(1771aff25dc722fa), C(19ff0644d9681917), - C(cf7d7f25bd70cd2c), C(9464ed9baeb41b4f), C(b9064f5c3cb11b71), - C(237e39229b012b20), C(cf7d7f25bd70cd2c), C(9464ed9baeb41b4f), - C(b9064f5c3cb11b71), C(237e39229b012b20), C(dd54d3f5d982dffe), - C(7fc7562dbfc81dbf), C(5b0dd1924f70945), C(f1760537d8261135), C(d51ba539)}, + C(d51ba539)}, {C(db4b15e88533f622), C(256d6d2419b41ce9), C(9d7c5378396765d5), - C(9040e5b936b8661b), C(276e08fa53ac27fd), C(8c944d39c2bdd2cc), - C(e2514c9802a5743c), C(9040e5b936b8661b), C(276e08fa53ac27fd), - C(8c944d39c2bdd2cc), C(e2514c9802a5743c), C(e82107b11ac90386), - C(7d6a22bc35055e6), C(fd6ea9d1c438d8ae), C(be6015149e981553), C(7f37636d)}, + C(7f37636d)}, {C(922834735e86ecb2), C(363382685b88328e), C(e9c92960d7144630), - C(8431b1bfd0a2379c), C(90383913aea283f9), C(a6163831eb4924d2), - C(5f3921b4f9084aee), C(8431b1bfd0a2379c), C(90383913aea283f9), - C(a6163831eb4924d2), C(5f3921b4f9084aee), C(7a70061a1473e579), - C(5b19d80dcd2c6331), C(6196b97931faad27), C(869bf6828e237c3f), C(b98026c0)}, {C(30f1d72c812f1eb8), C(b567cd4a69cd8989), C(820b6c992a51f0bc), - C(c54677a80367125e), C(3204fbdba462e606), C(8563278afc9eae69), - C(262147dd4bf7e566), C(c54677a80367125e), C(3204fbdba462e606), - C(8563278afc9eae69), C(262147dd4bf7e566), C(2178b63e7ee2d230), - C(e9c61ad81f5bff26), C(9af7a81b3c501eca), C(44104a3859f0238f), C(b877767e)}, - {C(168884267f3817e9), C(5b376e050f637645), C(1c18314abd34497a), - C(9598f6ab0683fcc2), C(1c805abf7b80e1ee), C(dec9ac42ee0d0f32), - C(8cd72e3912d24663), C(9598f6ab0683fcc2), C(1c805abf7b80e1ee), - C(dec9ac42ee0d0f32), C(8cd72e3912d24663), C(1f025d405f1c1d87), - C(bf7b6221e1668f8f), C(52316f64e692dbb0), C(7bf43df61ec51b39), C(aefae77)}, - {C(82e78596ee3e56a7), C(25697d9c87f30d98), C(7600a8342834924d), - C(6ba372f4b7ab268b), C(8c3237cf1fe243df), C(3833fc51012903df), - C(8e31310108c5683f), C(6ba372f4b7ab268b), C(8c3237cf1fe243df), - C(3833fc51012903df), C(8e31310108c5683f), C(126593715c2de429), - C(48ca8f35a3f54b90), C(b9322b632f4f8b0), C(926bb169b7337693), C(f686911)}, + {C(168884267f3817e9), C(5b376e050f637645), C(1c18314abd34497a), C(aefae77)}, + {C(82e78596ee3e56a7), C(25697d9c87f30d98), C(7600a8342834924d), C(f686911)}, {C(aa2d6cf22e3cc252), C(9b4dec4f5e179f16), C(76fb0fba1d99a99a), - C(9a62af3dbba140da), C(27857ea044e9dfc1), C(33abce9da2272647), - C(b22a7993aaf32556), C(9a62af3dbba140da), C(27857ea044e9dfc1), - C(33abce9da2272647), C(b22a7993aaf32556), C(bf8f88f8019bedf0), - C(ed2d7f01fb273905), C(6b45f15901b481cd), C(f88ebb413ba6a8d5), C(3deadf12)}, {C(7bf5ffd7f69385c7), C(fc077b1d8bc82879), C(9c04e36f9ed83a24), - C(82065c62e6582188), C(8ef787fd356f5e43), C(2922e53e36e17dfa), - C(9805f223d385010b), C(82065c62e6582188), C(8ef787fd356f5e43), - C(2922e53e36e17dfa), C(9805f223d385010b), C(692154f3491b787d), - C(e7e64700e414fbf), C(757d4d4ab65069a0), C(cd029446a8e348e2), C(ccf02a4e)}, + C(ccf02a4e)}, {C(e89c8ff9f9c6e34b), C(f54c0f669a49f6c4), C(fc3e46f5d846adef), - C(22f2aa3df2221cc), C(f66fea90f5d62174), C(b75defaeaa1dd2a7), - C(9b994cd9a7214fd5), C(22f2aa3df2221cc), C(f66fea90f5d62174), - C(b75defaeaa1dd2a7), C(9b994cd9a7214fd5), C(fac675a31804b773), - C(98bcb3b820c50fc6), C(e14af64d28cf0885), C(27466fbd2b360eb5), C(176c1722)}, - {C(a18fbcdccd11e1f4), C(8248216751dfd65e), C(40c089f208d89d7c), - C(229b79ab69ae97d), C(a87aabc2ec26e582), C(be2b053721eb26d2), - C(10febd7f0c3d6fcb), C(229b79ab69ae97d), C(a87aabc2ec26e582), - C(be2b053721eb26d2), C(10febd7f0c3d6fcb), C(9cc5b9b2f6e3bf7b), - C(655d8495fe624a86), C(6381a9f3d1f2bd7e), C(79ebabbfc25c83e2), C(26f82ad)}, + {C(a18fbcdccd11e1f4), C(8248216751dfd65e), C(40c089f208d89d7c), C(26f82ad)}, {C(2d54f40cc4088b17), C(59d15633b0cd1399), C(a8cc04bb1bffd15b), - C(d332cdb073d8dc46), C(272c56466868cb46), C(7e7fcbe35ca6c3f3), - C(ee8f51e5a70399d4), C(d332cdb073d8dc46), C(272c56466868cb46), - C(7e7fcbe35ca6c3f3), C(ee8f51e5a70399d4), C(16737a9c7581fe7b), - C(ed04bf52f4b75dcb), C(9707ffb36bd30c1a), C(1390f236fdc0de3e), C(b5244f42)}, {C(69276946cb4e87c7), C(62bdbe6183be6fa9), C(3ba9773dac442a1a), - C(702e2afc7f5a1825), C(8c49b11ea8151fdc), C(caf3fef61f5a86fa), - C(ef0b2ee8649d7272), C(702e2afc7f5a1825), C(8c49b11ea8151fdc), - C(caf3fef61f5a86fa), C(ef0b2ee8649d7272), C(9e34a4e08d9441e1), - C(7bdc0cd64d5af533), C(a926b14d99e3d868), C(fca923a17788cce4), C(49a689e5)}, - {C(668174a3f443df1d), C(407299392da1ce86), C(c2a3f7d7f2c5be28), - C(a590b202a7a5807b), C(968d2593f7ccb54e), C(9dd8d669e3e95dec), - C(ee0cc5dd58b6e93a), C(a590b202a7a5807b), C(968d2593f7ccb54e), - C(9dd8d669e3e95dec), C(ee0cc5dd58b6e93a), C(ac65d5a9466fb483), - C(221be538b2c9d806), C(5cbe9441784f9fd9), C(d4c7d5d6e3c122b8), C(59fcdd3)}, - {C(5e29be847bd5046), C(b561c7f19c8f80c3), C(5e5abd5021ccaeaf), - C(7432d63888e0c306), C(74bbceeed479cb71), C(6471586599575fdf), - C(6a859ad23365cba2), C(7432d63888e0c306), C(74bbceeed479cb71), - C(6471586599575fdf), C(6a859ad23365cba2), C(f9ceec84acd18dcc), - C(74a242ff1907437c), C(f70890194e1ee913), C(777dfcb4bb01f0ba), - C(4f4b04e9)}, + {C(668174a3f443df1d), C(407299392da1ce86), C(c2a3f7d7f2c5be28), C(59fcdd3)}, + {C(5e29be847bd5046), C(b561c7f19c8f80c3), C(5e5abd5021ccaeaf), C(4f4b04e9)}, {C(cd0d79f2164da014), C(4c386bb5c5d6ca0c), C(8e771b03647c3b63), - C(69db23875cb0b715), C(ada8dd91504ae37f), C(46bf18dbf045ed6a), - C(e1b5f67b0645ab63), C(69db23875cb0b715), C(ada8dd91504ae37f), - C(46bf18dbf045ed6a), C(e1b5f67b0645ab63), C(877be8f5dcddff4), - C(6d471b5f9ca2e2d1), C(802c86d6f495b9bb), C(a1f9b9b22b3be704), C(8b00f891)}, {C(e0e6fc0b1628af1d), C(29be5fb4c27a2949), C(1c3f781a604d3630), - C(c4af7faf883033aa), C(9bd296c4e9453cac), C(ca45426c1f7e33f9), - C(a6bbdcf7074d40c5), C(c4af7faf883033aa), C(9bd296c4e9453cac), - C(ca45426c1f7e33f9), C(a6bbdcf7074d40c5), C(e13a005d7142733b), - C(c02b7925c5eeefaf), C(d39119a60441e2d5), C(3c24c710df8f4d43), C(16e114f3)}, {C(2058927664adfd93), C(6e8f968c7963baa5), C(af3dced6fff7c394), - C(42e34cf3d53c7876), C(9cddbb26424dc5e), C(64f6340a6d8eddad), - C(2196e488eb2a3a4b), C(42e34cf3d53c7876), C(9cddbb26424dc5e), - C(64f6340a6d8eddad), C(2196e488eb2a3a4b), C(c9e9da25911a16fd), - C(e21b4683f3e196a8), C(cb80bf1a4c6fdbb4), C(53792e9b3c3e67f8), C(d6b6dadc)}, {C(dc107285fd8e1af7), C(a8641a0609321f3f), C(db06e89ffdc54466), - C(bcc7a81ed5432429), C(b6d7bdc6ad2e81f1), C(93605ec471aa37db), - C(a2a73f8a85a8e397), C(bcc7a81ed5432429), C(b6d7bdc6ad2e81f1), - C(93605ec471aa37db), C(a2a73f8a85a8e397), C(10a012b8ca7ac24b), - C(aac5fd63351595cf), C(5bb4c648a226dea0), C(9d11ecb2b5c05c5f), C(897e20ac)}, - {C(fbba1afe2e3280f1), C(755a5f392f07fce), C(9e44a9a15402809a), - C(6226a32e25099848), C(ea895661ecf53004), C(4d7e0158db2228b9), - C(e5a7d82922f69842), C(6226a32e25099848), C(ea895661ecf53004), - C(4d7e0158db2228b9), C(e5a7d82922f69842), C(2cea7713b69840ca), - C(18de7b9ae938375b), C(f127cca08f3cc665), C(b1c22d727665ad2), C(f996e05d)}, + {C(fbba1afe2e3280f1), C(755a5f392f07fce), C(9e44a9a15402809a), C(f996e05d)}, {C(bfa10785ddc1011b), C(b6e1c4d2f670f7de), C(517d95604e4fcc1f), - C(ca6552a0dfb82c73), C(b024cdf09e34ba07), C(66cd8c5a95d7393b), - C(e3939acf790d4a74), C(ca6552a0dfb82c73), C(b024cdf09e34ba07), - C(66cd8c5a95d7393b), C(e3939acf790d4a74), C(97827541a1ef051e), - C(ac2fce47ebe6500c), C(b3f06d3bddf3bd6a), C(1d74afb25e1ce5fe), C(c4306af6)}, - {C(534cc35f0ee1eb4e), C(b703820f1f3b3dce), C(884aa164cf22363), - C(f14ef7f47d8a57a3), C(80d1f86f2e061d7c), C(401d6c2f151b5a62), - C(e988460224108944), C(f14ef7f47d8a57a3), C(80d1f86f2e061d7c), - C(401d6c2f151b5a62), C(e988460224108944), C(7804d4135f68cd19), - C(5487b4b39e69fe8e), C(8cc5999015358a27), C(8f3729b61c2d5601), - C(6dcad433)}, - {C(7ca6e3933995dac), C(fd118c77daa8188), C(3aceb7b5e7da6545), - C(c8389799445480db), C(5389f5df8aacd50d), C(d136581f22fab5f), - C(c2f31f85991da417), C(c8389799445480db), C(5389f5df8aacd50d), - C(d136581f22fab5f), C(c2f31f85991da417), C(aefbf9ff84035a43), - C(8accbaf44adadd7c), C(e57f3657344b67f5), C(21490e5e8abdec51), - C(3c07374d)}, + {C(534cc35f0ee1eb4e), C(b703820f1f3b3dce), C(884aa164cf22363), C(6dcad433)}, + {C(7ca6e3933995dac), C(fd118c77daa8188), C(3aceb7b5e7da6545), C(3c07374d)}, {C(f0d6044f6efd7598), C(e044d6ba4369856e), C(91968e4f8c8a1a4c), - C(70bd1968996bffc2), C(4c613de5d8ab32ac), C(fe1f4f97206f79d8), - C(ac0434f2c4e213a9), C(70bd1968996bffc2), C(4c613de5d8ab32ac), - C(fe1f4f97206f79d8), C(ac0434f2c4e213a9), C(7490e9d82cfe22ca), - C(5fbbf7f987454238), C(c39e0dc8368ce949), C(22201d3894676c71), C(f0f4602c)}, {C(3d69e52049879d61), C(76610636ea9f74fe), C(e9bf5602f89310c0), - C(8eeb177a86053c11), C(e390122c345f34a2), C(1e30e47afbaaf8d6), - C(7b892f68e5f91732), C(8eeb177a86053c11), C(e390122c345f34a2), - C(1e30e47afbaaf8d6), C(7b892f68e5f91732), C(b87922525fa44158), - C(f440a1ee1a1a766b), C(ee8efad279d08c5c), C(421f910c5b60216e), C(3e1ea071)}, - {C(79da242a16acae31), C(183c5f438e29d40), C(6d351710ae92f3de), - C(27233b28b5b11e9b), C(c7dfe8988a942700), C(570ed11c4abad984), - C(4b4c04632f48311a), C(27233b28b5b11e9b), C(c7dfe8988a942700), - C(570ed11c4abad984), C(4b4c04632f48311a), C(12f33235442cbf9), - C(a35315ca0b5b8cdb), C(d8abde62ead5506b), C(fc0fcf8478ad5266), - C(67580f0c)}, + {C(79da242a16acae31), C(183c5f438e29d40), C(6d351710ae92f3de), C(67580f0c)}, {C(461c82656a74fb57), C(d84b491b275aa0f7), C(8f262cb29a6eb8b2), - C(49fa3070bc7b06d0), C(f12ed446bd0c0539), C(6d43ac5d1dd4b240), - C(7609524fe90bec93), C(49fa3070bc7b06d0), C(f12ed446bd0c0539), - C(6d43ac5d1dd4b240), C(7609524fe90bec93), C(391c2b2e076ec241), - C(f5e62deda7839f7b), C(3c7b3186a10d870f), C(77ef4f2cba4f1005), C(4e109454)}, - {C(53c1a66d0b13003), C(731f060e6fe797fc), C(daa56811791371e3), - C(57466046cf6896ed), C(8ac37e0e8b25b0c6), C(3e6074b52ad3cf18), - C(aa491ce7b45db297), C(57466046cf6896ed), C(8ac37e0e8b25b0c6), - C(3e6074b52ad3cf18), C(aa491ce7b45db297), C(f7a9227c5e5e22c3), - C(3d92e0841e29ce28), C(2d30da5b2859e59d), C(ff37fa1c9cbfafc2), - C(88a474a7)}, - {C(d3a2efec0f047e9), C(1cabce58853e58ea), C(7a17b2eae3256be4), - C(c2dcc9758c910171), C(cb5cddaeff4ddb40), C(5d7cc5869baefef1), - C(9644c5853af9cfeb), C(c2dcc9758c910171), C(cb5cddaeff4ddb40), - C(5d7cc5869baefef1), C(9644c5853af9cfeb), C(255c968184694ee1), - C(4e4d726eda360927), C(7d27dd5b6d100377), C(9a300e2020ddea2c), C(5b5bedd)}, + {C(53c1a66d0b13003), C(731f060e6fe797fc), C(daa56811791371e3), C(88a474a7)}, + {C(d3a2efec0f047e9), C(1cabce58853e58ea), C(7a17b2eae3256be4), C(5b5bedd)}, {C(43c64d7484f7f9b2), C(5da002b64aafaeb7), C(b576c1e45800a716), - C(3ee84d3d5b4ca00b), C(5cbc6d701894c3f9), C(d9e946f5ae1ca95), - C(24ca06e67f0b1833), C(3ee84d3d5b4ca00b), C(5cbc6d701894c3f9), - C(d9e946f5ae1ca95), C(24ca06e67f0b1833), C(3413d46b4152650e), - C(cbdfdbc2ab516f9c), C(2aad8acb739e0c6c), C(2bfc950d9f9fa977), C(1aaddfa7)}, {C(a7dec6ad81cf7fa1), C(180c1ab708683063), C(95e0fd7008d67cff), - C(6b11c5073687208), C(7e0a57de0d453f3), C(e48c267d4f646867), - C(2168e9136375f9cb), C(6b11c5073687208), C(7e0a57de0d453f3), - C(e48c267d4f646867), C(2168e9136375f9cb), C(64da194aeeea7fdf), - C(a3b9f01fa5885678), C(c316f8ee2eb2bd17), C(a7e4d80f83e4427f), C(5be07fd8)}, - {C(5408a1df99d4aff), C(b9565e588740f6bd), C(abf241813b08006e), - C(7da9e81d89fda7ad), C(274157cabe71440d), C(2c22d9a480b331f7), - C(e835c8ac746472d5), C(7da9e81d89fda7ad), C(274157cabe71440d), - C(2c22d9a480b331f7), C(e835c8ac746472d5), C(2038ce817a201ae4), - C(46f3289dfe1c5e40), C(435578a42d4b7c56), C(f96d9f409fcf561), C(cbca8606)}, + {C(5408a1df99d4aff), C(b9565e588740f6bd), C(abf241813b08006e), C(cbca8606)}, {C(a8b27a6bcaeeed4b), C(aec1eeded6a87e39), C(9daf246d6fed8326), - C(d45a938b79f54e8f), C(366b219d6d133e48), C(5b14be3c25c49405), - C(fdd791d48811a572), C(d45a938b79f54e8f), C(366b219d6d133e48), - C(5b14be3c25c49405), C(fdd791d48811a572), C(3de67b8d9e95d335), - C(903c01307cfbeed5), C(af7d65f32274f1d1), C(4dba141b5fc03c42), C(bde64d01)}, {C(9a952a8246fdc269), C(d0dcfcac74ef278c), C(250f7139836f0f1f), - C(c83d3c5f4e5f0320), C(694e7adeb2bf32e5), C(7ad09538a3da27f5), - C(2b5c18f934aa5303), C(c83d3c5f4e5f0320), C(694e7adeb2bf32e5), - C(7ad09538a3da27f5), C(2b5c18f934aa5303), C(c4dad7703d34326e), - C(825569e2bcdc6a25), C(b83d267709ca900d), C(44ed05151f5d74e6), C(ee90cf33)}, {C(c930841d1d88684f), C(5eb66eb18b7f9672), C(e455d413008a2546), - C(bc271bc0df14d647), C(b071100a9ff2edbb), C(2b1a4c1cc31a119a), - C(b5d7caa1bd946cef), C(bc271bc0df14d647), C(b071100a9ff2edbb), - C(2b1a4c1cc31a119a), C(b5d7caa1bd946cef), C(e02623ae10f4aadd), - C(d79f600389cd06fd), C(1e8da7965303e62b), C(86f50e10eeab0925), C(4305c3ce)}, - {C(94dc6971e3cf071a), C(994c7003b73b2b34), C(ea16e85978694e5), - C(336c1b59a1fc19f6), C(c173acaecc471305), C(db1267d24f3f3f36), - C(e9a5ee98627a6e78), C(336c1b59a1fc19f6), C(c173acaecc471305), - C(db1267d24f3f3f36), C(e9a5ee98627a6e78), C(718f334204305ae5), - C(e3b53c148f98d22c), C(a184012df848926), C(6e96386127d51183), C(4b3a1d76)}, - {C(7fc98006e25cac9), C(77fee0484cda86a7), C(376ec3d447060456), - C(84064a6dcf916340), C(fbf55a26790e0ebb), C(2e7f84151c31a5c2), - C(9f7f6d76b950f9bf), C(84064a6dcf916340), C(fbf55a26790e0ebb), - C(2e7f84151c31a5c2), C(9f7f6d76b950f9bf), C(125e094fbee2b146), - C(5706aa72b2eef7c2), C(1c4a2daa905ee66e), C(83d48029b5451694), - C(a8bb6d80)}, - {C(bd781c4454103f6), C(612197322f49c931), C(b9cf17fd7e5462d5), - C(e38e526cd3324364), C(85f2b63a5b5e840a), C(485d7cef5aaadd87), - C(d2b837a462f6db6d), C(e38e526cd3324364), C(85f2b63a5b5e840a), - C(485d7cef5aaadd87), C(d2b837a462f6db6d), C(3e41cef031520d9a), - C(82df73902d7f67e), C(3ba6fd54c15257cb), C(22f91f079be42d40), C(1f9fa607)}, + {C(94dc6971e3cf071a), C(994c7003b73b2b34), C(ea16e85978694e5), C(4b3a1d76)}, + {C(7fc98006e25cac9), C(77fee0484cda86a7), C(376ec3d447060456), C(a8bb6d80)}, + {C(bd781c4454103f6), C(612197322f49c931), C(b9cf17fd7e5462d5), C(1f9fa607)}, {C(da60e6b14479f9df), C(3bdccf69ece16792), C(18ebf45c4fecfdc9), - C(16818ee9d38c6664), C(5519fa9a1e35a329), C(cbd0001e4b08ed8), - C(41a965e37a0c731b), C(16818ee9d38c6664), C(5519fa9a1e35a329), - C(cbd0001e4b08ed8), C(41a965e37a0c731b), C(66e7b5dcca1ca28f), - C(963b2d993614347d), C(9b6fc6f41d411106), C(aaaecaccf7848c0c), C(8d0e4ed2)}, - {C(4ca56a348b6c4d3), C(60618537c3872514), C(2fbb9f0e65871b09), - C(30278016830ddd43), C(f046646d9012e074), C(c62a5804f6e7c9da), - C(98d51f5830e2bc1e), C(30278016830ddd43), C(f046646d9012e074), - C(c62a5804f6e7c9da), C(98d51f5830e2bc1e), C(7b2cbe5d37e3f29e), - C(7b8c3ed50bda4aa0), C(3ea60cc24639e038), C(f7706de9fb0b5801), - C(1bf31347)}, + {C(4ca56a348b6c4d3), C(60618537c3872514), C(2fbb9f0e65871b09), C(1bf31347)}, {C(ebd22d4b70946401), C(6863602bf7139017), C(c0b1ac4e11b00666), - C(7d2782b82bd494b6), C(97159ba1c26b304b), C(42b3b0fd431b2ac2), - C(faa81f82691c830c), C(7d2782b82bd494b6), C(97159ba1c26b304b), - C(42b3b0fd431b2ac2), C(faa81f82691c830c), C(7cc6449234c7e185), - C(aeaa6fa643ca86a5), C(1412db1c0f2e0133), C(4df2fe3e4072934f), C(1ae3fc5b)}, - {C(3cc4693d6cbcb0c), C(501689ea1c70ffa), C(10a4353e9c89e364), - C(58c8aba7475e2d95), C(3e2f291698c9427a), C(e8710d19c9de9e41), - C(65dda22eb04cf953), C(58c8aba7475e2d95), C(3e2f291698c9427a), - C(e8710d19c9de9e41), C(65dda22eb04cf953), C(d7729c48c250cffa), - C(ef76162b2ddfba4b), C(52371e17f4d51f6d), C(ddd002112ff0c833), - C(459c3930)}, + {C(3cc4693d6cbcb0c), C(501689ea1c70ffa), C(10a4353e9c89e364), C(459c3930)}, {C(38908e43f7ba5ef0), C(1ab035d4e7781e76), C(41d133e8c0a68ff7), - C(d1090893afaab8bc), C(96c4fe6922772807), C(4522426c2b4205eb), - C(efad99a1262e7e0d), C(d1090893afaab8bc), C(96c4fe6922772807), - C(4522426c2b4205eb), C(efad99a1262e7e0d), C(c7696029abdb465e), - C(4e18eaf03d517651), C(d006bced54c86ac8), C(4330326d1021860c), C(e00c4184)}, - {C(34983ccc6aa40205), C(21802cad34e72bc4), C(1943e8fb3c17bb8), - C(fc947167f69c0da5), C(ae79cfdb91b6f6c1), C(7b251d04c26cbda3), - C(128a33a79060d25e), C(fc947167f69c0da5), C(ae79cfdb91b6f6c1), - C(7b251d04c26cbda3), C(128a33a79060d25e), C(1eca842dbfe018dd), - C(50a4cd2ee0ba9c63), C(c2f5c97d8399682f), C(3f929fc7cbe8ecbb), - C(ffc7a781)}, + {C(34983ccc6aa40205), C(21802cad34e72bc4), C(1943e8fb3c17bb8), C(ffc7a781)}, {C(86215c45dcac9905), C(ea546afe851cae4b), C(d85b6457e489e374), - C(b7609c8e70386d66), C(36e6ccc278d1636d), C(2f873307c08e6a1c), - C(10f252a758505289), C(b7609c8e70386d66), C(36e6ccc278d1636d), - C(2f873307c08e6a1c), C(10f252a758505289), C(c8977646e81ab4b6), - C(8017b745cd80213b), C(960687db359bea0), C(ef4a470660799488), C(6a125480)}, + C(6a125480)}, {C(420fc255c38db175), C(d503cd0f3c1208d1), C(d4684e74c825a0bc), - C(4c10537443152f3d), C(720451d3c895e25d), C(aff60c4d11f513fd), - C(881e8d6d2d5fb953), C(4c10537443152f3d), C(720451d3c895e25d), - C(aff60c4d11f513fd), C(881e8d6d2d5fb953), C(9dec034a043f1f55), - C(e27a0c22e7bfb39d), C(2220b959128324), C(53240272152dbd8b), C(88a1512b)}, + C(88a1512b)}, {C(1d7a31f5bc8fe2f9), C(4763991092dcf836), C(ed695f55b97416f4), - C(f265edb0c1c411d7), C(30e1e9ec5262b7e6), C(c2c3ba061ce7957a), - C(d975f93b89a16409), C(f265edb0c1c411d7), C(30e1e9ec5262b7e6), - C(c2c3ba061ce7957a), C(d975f93b89a16409), C(e9d703123f43450a), - C(41383fedfed67c82), C(6e9f43ecbbbd6004), C(c7ccd23a24e77b8), C(549bbbe5)}, + C(549bbbe5)}, {C(94129a84c376a26e), C(c245e859dc231933), C(1b8f74fecf917453), - C(e9369d2e9007e74b), C(b1375915d1136052), C(926c2021fe1d2351), - C(1d943addaaa2e7e6), C(e9369d2e9007e74b), C(b1375915d1136052), - C(926c2021fe1d2351), C(1d943addaaa2e7e6), C(f5f515869c246738), - C(7e309cd0e1c0f2a0), C(153c3c36cf523e3b), C(4931c66872ea6758), C(c133d38c)}, - {C(1d3a9809dab05c8d), C(adddeb4f71c93e8), C(ef342eb36631edb), - C(301d7a61c4b3dbca), C(861336c3f0552d61), C(12c6db947471300f), - C(a679ef0ed761deb9), C(301d7a61c4b3dbca), C(861336c3f0552d61), - C(12c6db947471300f), C(a679ef0ed761deb9), C(5f713b720efcd147), - C(37ac330a333aa6b), C(3309dc9ec1616eef), C(52301d7a908026b5), C(fcace348)}, + {C(1d3a9809dab05c8d), C(adddeb4f71c93e8), C(ef342eb36631edb), C(fcace348)}, {C(90fa3ccbd60848da), C(dfa6e0595b569e11), C(e585d067a1f5135d), - C(6cef866ec295abea), C(c486c0d9214beb2d), C(d6e490944d5fe100), - C(59df3175d72c9f38), C(6cef866ec295abea), C(c486c0d9214beb2d), - C(d6e490944d5fe100), C(59df3175d72c9f38), C(3f23aeb4c04d1443), - C(9bf0515cd8d24770), C(958554f60ccaade2), C(5182863c90132fe8), C(ed7b6f9a)}, {C(2dbb4fc71b554514), C(9650e04b86be0f82), C(60f2304fba9274d3), - C(fcfb9443e997cab), C(f13310d96dec2772), C(709cad2045251af2), - C(afd0d30cc6376dad), C(fcfb9443e997cab), C(f13310d96dec2772), - C(709cad2045251af2), C(afd0d30cc6376dad), C(59d4bed30d550d0d), - C(58006d4e22d8aad1), C(eee12d2362d1f13b), C(35cf1d7faaf1d228), C(6d907dda)}, {C(b98bf4274d18374a), C(1b669fd4c7f9a19a), C(b1f5972b88ba2b7a), - C(73119c99e6d508be), C(5d4036a187735385), C(8fa66e192fd83831), - C(2abf64b6b592ed57), C(73119c99e6d508be), C(5d4036a187735385), - C(8fa66e192fd83831), C(2abf64b6b592ed57), C(d4501f95dd84b08c), - C(bf1552439c8bea02), C(4f56fe753ba7e0ba), C(4ca8d35cc058cfcd), C(7a4d48d5)}, {C(d6781d0b5e18eb68), C(b992913cae09b533), C(58f6021caaee3a40), - C(aafcb77497b5a20b), C(411819e5e79b77a3), C(bd779579c51c77ce), - C(58d11f5dcf5d075d), C(aafcb77497b5a20b), C(411819e5e79b77a3), - C(bd779579c51c77ce), C(58d11f5dcf5d075d), C(9eae76cde1cb4233), - C(32fe25a9bf657970), C(1c0c807948edb06a), C(b8f29a3dfaee254d), C(e686f3db)}, - {C(226651cf18f4884c), C(595052a874f0f51c), C(c9b75162b23bab42), - C(3f44f873be4812ec), C(427662c1dbfaa7b2), C(a207ff9638fb6558), - C(a738d919e45f550f), C(3f44f873be4812ec), C(427662c1dbfaa7b2), - C(a207ff9638fb6558), C(a738d919e45f550f), C(cb186ea05717e7d6), - C(1ca7d68a5871fdc1), C(5d4c119ea8ef3750), C(72b6a10fa2ff9406), C(cce7c55)}, - {C(a734fb047d3162d6), C(e523170d240ba3a5), C(125a6972809730e8), - C(d396a297799c24a1), C(8fee992e3069bad5), C(2e3a01b0697ccf57), - C(ee9c7390bd901cfa), C(d396a297799c24a1), C(8fee992e3069bad5), - C(2e3a01b0697ccf57), C(ee9c7390bd901cfa), C(56f2d9da0af28af2), - C(3fdd37b2fe8437cb), C(3d13eeeb60d6aec0), C(2432ae62e800a5ce), C(f58b96b)}, + {C(226651cf18f4884c), C(595052a874f0f51c), C(c9b75162b23bab42), C(cce7c55)}, + {C(a734fb047d3162d6), C(e523170d240ba3a5), C(125a6972809730e8), C(f58b96b)}, {C(c6df6364a24f75a3), C(c294e2c84c4f5df8), C(a88df65c6a89313b), - C(895fe8443183da74), C(c7f2f6f895a67334), C(a0d6b6a506691d31), - C(24f51712b459a9f0), C(895fe8443183da74), C(c7f2f6f895a67334), - C(a0d6b6a506691d31), C(24f51712b459a9f0), C(173a699481b9e088), - C(1dee9b77bcbf45d3), C(32b98a646a8667d0), C(3adcd4ee28f42a0e), C(1bbf6f60)}, - {C(d8d1364c1fbcd10), C(2d7cc7f54832deaa), C(4e22c876a7c57625), - C(a3d5d1137d30c4bd), C(1e7d706a49bdfb9e), C(c63282b20ad86db2), - C(aec97fa07916bfd6), C(a3d5d1137d30c4bd), C(1e7d706a49bdfb9e), - C(c63282b20ad86db2), C(aec97fa07916bfd6), C(7c9ba3e52d44f73e), - C(af62fd245811185d), C(8a9d2dacd8737652), C(bd2cce277d5fbec0), - C(ce5e0cc2)}, + {C(d8d1364c1fbcd10), C(2d7cc7f54832deaa), C(4e22c876a7c57625), C(ce5e0cc2)}, {C(aae06f9146db885f), C(3598736441e280d9), C(fba339b117083e55), - C(b22bf08d9f8aecf7), C(c182730de337b922), C(2b9adc87a0450a46), - C(192c29a9cfc00aad), C(b22bf08d9f8aecf7), C(c182730de337b922), - C(2b9adc87a0450a46), C(192c29a9cfc00aad), C(9fd733f1d84a59d9), - C(d86bd5c9839ace15), C(af20b57303172876), C(9f63cb7161b5364c), C(584cfd6f)}, {C(8955ef07631e3bcc), C(7d70965ea3926f83), C(39aed4134f8b2db6), - C(882efc2561715a9c), C(ef8132a18a540221), C(b20a3c87a8c257c1), - C(f541b8628fad6c23), C(882efc2561715a9c), C(ef8132a18a540221), - C(b20a3c87a8c257c1), C(f541b8628fad6c23), C(9552aed57a6e0467), - C(4d9fdd56867611a7), C(c330279bf23b9eab), C(44dbbaea2fcb8eba), C(8f9bbc33)}, {C(ad611c609cfbe412), C(d3c00b18bf253877), C(90b2172e1f3d0bfd), - C(371a98b2cb084883), C(33a2886ee9f00663), C(be9568818ed6e6bd), - C(f244a0fa2673469a), C(371a98b2cb084883), C(33a2886ee9f00663), - C(be9568818ed6e6bd), C(f244a0fa2673469a), C(b447050bd3e559e9), - C(d3b695dae7a13383), C(ded0bb65be471188), C(ca3c7a2b78922cae), C(d7640d95)}, - {C(d5339adc295d5d69), C(b633cc1dcb8b586a), C(ee84184cf5b1aeaf), - C(89f3aab99afbd636), C(f420e004f8148b9a), C(6818073faa797c7c), - C(dd3b4e21cbbf42ca), C(89f3aab99afbd636), C(f420e004f8148b9a), - C(6818073faa797c7c), C(dd3b4e21cbbf42ca), C(6a2b7db261164844), - C(cbead63d1895852a), C(93d37e1eae05e2f9), C(5d06db2703fbc3ae), C(3d12a2b)}, + {C(d5339adc295d5d69), C(b633cc1dcb8b586a), C(ee84184cf5b1aeaf), C(3d12a2b)}, {C(40d0aeff521375a8), C(77ba1ad7ecebd506), C(547c6f1a7d9df427), - C(21c2be098327f49b), C(7e035065ac7bbef5), C(6d7348e63023fb35), - C(9d427dc1b67c3830), C(21c2be098327f49b), C(7e035065ac7bbef5), - C(6d7348e63023fb35), C(9d427dc1b67c3830), C(4e3d018a43858341), - C(cf924bb44d6b43c5), C(4618b6a26e3446ae), C(54d3013fac3ed469), C(aaeafed0)}, {C(8b2d54ae1a3df769), C(11e7adaee3216679), C(3483781efc563e03), - C(9d097dd3152ab107), C(51e21d24126e8563), C(cba56cac884a1354), - C(39abb1b595f0a977), C(9d097dd3152ab107), C(51e21d24126e8563), - C(cba56cac884a1354), C(39abb1b595f0a977), C(81e6dd1c1109848f), - C(1644b209826d7b15), C(6ac67e4e4b4812f0), C(b3a9f5622c935bf7), C(95b9b814)}, {C(99c175819b4eae28), C(932e8ff9f7a40043), C(ec78dcab07ca9f7c), - C(c1a78b82ba815b74), C(458cbdfc82eb322a), C(17f4a192376ed8d7), - C(6f9e92968bc8ccef), C(c1a78b82ba815b74), C(458cbdfc82eb322a), - C(17f4a192376ed8d7), C(6f9e92968bc8ccef), C(93e098c333b39905), - C(d59b1cace44b7fdc), C(f7a64ed78c64c7c5), C(7c6eca5dd87ec1ce), C(45fbe66e)}, {C(2a418335779b82fc), C(af0295987849a76b), C(c12bc5ff0213f46e), - C(5aeead8d6cb25bb9), C(739315f7743ec3ff), C(9ab48d27111d2dcc), - C(5b87bd35a975929b), C(5aeead8d6cb25bb9), C(739315f7743ec3ff), - C(9ab48d27111d2dcc), C(5b87bd35a975929b), C(c3dd8d6d95a46bb3), - C(7bf9093215a4f483), C(cb557d6ed84285bd), C(daf58422f261fdb5), C(b4baa7a8)}, - {C(3b1fc6a3d279e67d), C(70ea1e49c226396), C(25505adcf104697c), - C(ba1ffba29f0367aa), C(a20bec1dd15a8b6c), C(e9bf61d2dab0f774), - C(f4f35bf5870a049c), C(ba1ffba29f0367aa), C(a20bec1dd15a8b6c), - C(e9bf61d2dab0f774), C(f4f35bf5870a049c), C(26787efa5b92385), - C(3d9533590ce30b59), C(a4da3e40530a01d4), C(6395deaefb70067c), - C(83e962fe)}, - {C(d97eacdf10f1c3c9), C(b54f4654043a36e0), C(b128f6eb09d1234), - C(d8ad7ec84a9c9aa2), C(e256cffed11f69e6), C(2cf65e4958ad5bda), - C(cfbf9b03245989a7), C(d8ad7ec84a9c9aa2), C(e256cffed11f69e6), - C(2cf65e4958ad5bda), C(cfbf9b03245989a7), C(9fa51e6686cf4444), - C(9425c117a34609d5), C(b25f7e2c6f30e96), C(ea5477c3f2b5afd1), C(aac3531c)}, + {C(3b1fc6a3d279e67d), C(70ea1e49c226396), C(25505adcf104697c), C(83e962fe)}, + {C(d97eacdf10f1c3c9), C(b54f4654043a36e0), C(b128f6eb09d1234), C(aac3531c)}, {C(293a5c1c4e203cd4), C(6b3329f1c130cefe), C(f2e32f8ec76aac91), - C(361e0a62c8187bff), C(6089971bb84d7133), C(93df7741588dd50b), - C(c2a9b6abcd1d80b1), C(361e0a62c8187bff), C(6089971bb84d7133), - C(93df7741588dd50b), C(c2a9b6abcd1d80b1), C(4d2f86869d79bc59), - C(85cd24d8aa570ff), C(b0dcf6ef0e94bbb5), C(2037c69aa7a78421), C(2b1db7cc)}, + C(2b1db7cc)}, {C(4290e018ffaedde7), C(a14948545418eb5e), C(72d851b202284636), - C(4ec02f3d2f2b23f2), C(ab3580708aa7c339), C(cdce066fbab3f65), - C(d8ed3ecf3c7647b9), C(4ec02f3d2f2b23f2), C(ab3580708aa7c339), - C(cdce066fbab3f65), C(d8ed3ecf3c7647b9), C(6d2204b3e31f344a), - C(61a4d87f80ee61d7), C(446c43dbed4b728f), C(73130ac94f58747e), C(cf00cd31)}, {C(f919a59cbde8bf2f), C(a56d04203b2dc5a5), C(38b06753ac871e48), - C(c2c9fc637dbdfcfa), C(292ab8306d149d75), C(7f436b874b9ffc07), - C(a5b56b0129218b80), C(c2c9fc637dbdfcfa), C(292ab8306d149d75), - C(7f436b874b9ffc07), C(a5b56b0129218b80), C(9188f7bdc47ec050), - C(cfe9345d03a15ade), C(40b520fb2750c49e), C(c2e83d343968af2e), C(7d3c43b8)}, {C(1d70a3f5521d7fa4), C(fb97b3fdc5891965), C(299d49bbbe3535af), - C(e1a8286a7d67946e), C(52bd956f047b298), C(cbd74332dd4204ac), - C(12b5be7752721976), C(e1a8286a7d67946e), C(52bd956f047b298), - C(cbd74332dd4204ac), C(12b5be7752721976), C(278426e27f6204b6), - C(932ca7a7cd610181), C(41647321f0a5914d), C(48f4aa61a0ae80db), C(cbd5fac6)}, {C(6af98d7b656d0d7c), C(d2e99ae96d6b5c0c), C(f63bd1603ef80627), - C(bde51033ac0413f8), C(bc0272f691aec629), C(6204332651bebc44), - C(1cbf00de026ea9bd), C(bde51033ac0413f8), C(bc0272f691aec629), - C(6204332651bebc44), C(1cbf00de026ea9bd), C(b9c7ed6a75f3ff1e), - C(7e310b76a5808e4f), C(acbbd1aad5531885), C(fc245f2473adeb9c), C(76d0fec4)}, - {C(395b7a8adb96ab75), C(582df7165b20f4a), C(e52bd30e9ff657f9), - C(6c71064996cbec8b), C(352c535edeefcb89), C(ac7f0aba15cd5ecd), - C(3aba1ca8353e5c60), C(6c71064996cbec8b), C(352c535edeefcb89), - C(ac7f0aba15cd5ecd), C(3aba1ca8353e5c60), C(5c30a288a80ce646), - C(c2940488b6617674), C(925f8cc66b370575), C(aa65d1283b9bb0ef), - C(405e3402)}, + {C(395b7a8adb96ab75), C(582df7165b20f4a), C(e52bd30e9ff657f9), C(405e3402)}, {C(3822dd82c7df012f), C(b9029b40bd9f122b), C(fd25b988468266c4), - C(43e47bd5bab1e0ef), C(4a71f363421f282f), C(880b2f32a2b4e289), - C(1299d4eda9d3eadf), C(43e47bd5bab1e0ef), C(4a71f363421f282f), - C(880b2f32a2b4e289), C(1299d4eda9d3eadf), C(d713a40226f5564), - C(4d8d34fedc769406), C(a85001b29cd9cac3), C(cae92352a41fd2b0), C(c732c481)}, {C(79f7efe4a80b951a), C(dd3a3fddfc6c9c41), C(ab4c812f9e27aa40), - C(832954ec9d0de333), C(94c390aa9bcb6b8a), C(f3b32afdc1f04f82), - C(d229c3b72e4b9a74), C(832954ec9d0de333), C(94c390aa9bcb6b8a), - C(f3b32afdc1f04f82), C(d229c3b72e4b9a74), C(1d11860d7ed624a6), - C(cadee20b3441b984), C(75307079bf306f7b), C(87902aa3b9753ba4), C(a8d123c9)}, - {C(ae6e59f5f055921a), C(e9d9b7bf68e82), C(5ce4e4a5b269cc59), - C(4960111789727567), C(149b8a37c7125ab6), C(78c7a13ab9749382), - C(1c61131260ca151a), C(4960111789727567), C(149b8a37c7125ab6), - C(78c7a13ab9749382), C(1c61131260ca151a), C(1e93276b35c309a0), - C(2618f56230acde58), C(af61130a18e4febf), C(7145deb18e89befe), - C(1e80ad7d)}, + {C(ae6e59f5f055921a), C(e9d9b7bf68e82), C(5ce4e4a5b269cc59), C(1e80ad7d)}, {C(8959dbbf07387d36), C(b4658afce48ea35d), C(8f3f82437d8cb8d6), - C(6566d74954986ba5), C(99d5235cc82519a7), C(257a23805c2d825), - C(ad75ccb968e93403), C(6566d74954986ba5), C(99d5235cc82519a7), - C(257a23805c2d825), C(ad75ccb968e93403), C(b45bd4cf78e11f7f), - C(80c5536bdc487983), C(a4fd76ecbf018c8a), C(3b9dac78a7a70d43), C(52aeb863)}, {C(4739613234278a49), C(99ea5bcd340bf663), C(258640912e712b12), - C(c8a2827404991402), C(7ee5e78550f02675), C(2ec53952db5ac662), - C(1526405a9df6794b), C(c8a2827404991402), C(7ee5e78550f02675), - C(2ec53952db5ac662), C(1526405a9df6794b), C(eddc6271170c5e1f), - C(f5a85f986001d9d6), C(95427c677bf58d58), C(53ed666dfa85cb29), C(ef7c0c18)}, {C(420e6c926bc54841), C(96dbbf6f4e7c75cd), C(d8d40fa70c3c67bb), - C(3edbc10e4bfee91b), C(f0d681304c28ef68), C(77ea602029aaaf9c), - C(90f070bd24c8483c), C(3edbc10e4bfee91b), C(f0d681304c28ef68), - C(77ea602029aaaf9c), C(90f070bd24c8483c), C(28bc8e41e08ceb86), - C(1eb56e48a65691ef), C(9fea5301c9202f0e), C(3fcb65091aa9f135), C(b6ad4b68)}, {C(c8601bab561bc1b7), C(72b26272a0ff869a), C(56fdfc986d6bc3c4), - C(83707730cad725d4), C(c9ca88c3a779674a), C(e1c696fbbd9aa933), - C(723f3baab1c17a45), C(83707730cad725d4), C(c9ca88c3a779674a), - C(e1c696fbbd9aa933), C(723f3baab1c17a45), C(f82abc7a1d851682), - C(30683836818e857d), C(78bfa3e89a5ab23f), C(6928234482b31817), C(c1e46b17)}, - {C(b2d294931a0e20eb), C(284ffd9a0815bc38), C(1f8a103aac9bbe6), - C(1ef8e98e1ea57269), C(5971116272f45a8b), C(187ad68ce95d8eac), - C(e94e93ee4e8ecaa6), C(1ef8e98e1ea57269), C(5971116272f45a8b), - C(187ad68ce95d8eac), C(e94e93ee4e8ecaa6), C(a0ff2a58611838b5), - C(b01e03849bfbae6f), C(d081e202e28ea3ab), C(51836bcee762bf13), - C(57b8df25)}, + {C(b2d294931a0e20eb), C(284ffd9a0815bc38), C(1f8a103aac9bbe6), C(57b8df25)}, {C(7966f53c37b6c6d7), C(8e6abcfb3aa2b88f), C(7f2e5e0724e5f345), - C(3eeb60c3f5f8143d), C(a25aec05c422a24f), C(b026b03ad3cca4db), - C(e6e030028cc02a02), C(3eeb60c3f5f8143d), C(a25aec05c422a24f), - C(b026b03ad3cca4db), C(e6e030028cc02a02), C(16fe679338b34bfc), - C(c1be385b5c8a9de4), C(65af5df6567530eb), C(ed3b303df4dc6335), C(e9fa36d6)}, {C(be9bb0abd03b7368), C(13bca93a3031be55), C(e864f4f52b55b472), - C(36a8d13a2cbb0939), C(254ac73907413230), C(73520d1522315a70), - C(8c9fdb5cf1e1a507), C(36a8d13a2cbb0939), C(254ac73907413230), - C(73520d1522315a70), C(8c9fdb5cf1e1a507), C(b3640570b926886), - C(fba2344ee87f7bab), C(de57341ab448df05), C(385612ee094fa977), C(8f8daefc)}, - {C(a08d128c5f1649be), C(a8166c3dbbe19aad), C(cb9f914f829ec62c), - C(5b2b7ca856fad1c3), C(8093022d682e375d), C(ea5d163ba7ea231f), - C(d6181d012c0de641), C(5b2b7ca856fad1c3), C(8093022d682e375d), - C(ea5d163ba7ea231f), C(d6181d012c0de641), C(e7d40d0ab8b08159), - C(2e82320f51b3a67e), C(27c2e356ea0b63a3), C(58842d01a2b1d077), C(6e1bb7e)}, + {C(a08d128c5f1649be), C(a8166c3dbbe19aad), C(cb9f914f829ec62c), C(6e1bb7e)}, {C(7c386f0ffe0465ac), C(530419c9d843dbf3), C(7450e3a4f72b8d8c), - C(48b218e3b721810d), C(d3757ac8609bc7fc), C(111ba02a88aefc8), - C(e86343137d3bfc2a), C(48b218e3b721810d), C(d3757ac8609bc7fc), - C(111ba02a88aefc8), C(e86343137d3bfc2a), C(44ad26b51661b507), - C(db1268670274f51e), C(62a5e75beae875f3), C(e266e7a44c5f28c6), C(fd0076f0)}, - {C(bb362094e7ef4f8), C(ff3c2a48966f9725), C(55152803acd4a7fe), - C(15747d8c505ffd00), C(438a15f391312cd6), C(e46ca62c26d821f5), - C(be78d74c9f79cb44), C(15747d8c505ffd00), C(438a15f391312cd6), - C(e46ca62c26d821f5), C(be78d74c9f79cb44), C(a8aa19f3aa59f09a), - C(effb3cddab2c9267), C(d78e41ad97cb16a5), C(ace6821513527d32), - C(899b17b6)}, + {C(bb362094e7ef4f8), C(ff3c2a48966f9725), C(55152803acd4a7fe), C(899b17b6)}, {C(cd80dea24321eea4), C(52b4fdc8130c2b15), C(f3ea100b154bfb82), - C(d9ccef1d4be46988), C(5ede0c4e383a5e66), C(da69683716a54d1e), - C(bfc3fdf02d242d24), C(d9ccef1d4be46988), C(5ede0c4e383a5e66), - C(da69683716a54d1e), C(bfc3fdf02d242d24), C(20ed30274651b3f5), - C(4c659824169e86c6), C(637226dae5b52a0e), C(7e050dbd1c71dc7f), C(e3e84e31)}, {C(d599a04125372c3a), C(313136c56a56f363), C(1e993c3677625832), - C(2870a99c76a587a4), C(99f74cc0b182dda4), C(8a5e895b2f0ca7b6), - C(3d78882d5e0bb1dc), C(2870a99c76a587a4), C(99f74cc0b182dda4), - C(8a5e895b2f0ca7b6), C(3d78882d5e0bb1dc), C(f466123732a3e25e), - C(aca5e59716a40e50), C(261d2e7383d0e686), C(ce9362d6a42c15a7), C(eef79b6b)}, - {C(dbbf541e9dfda0a), C(1479fceb6db4f844), C(31ab576b59062534), - C(a3335c417687cf3a), C(92ff114ac45cda75), C(c3b8a627384f13b5), - C(c4f25de33de8b3f7), C(a3335c417687cf3a), C(92ff114ac45cda75), - C(c3b8a627384f13b5), C(c4f25de33de8b3f7), C(eacbf520578c5964), - C(4cb19c5ab24f3215), C(e7d8a6f67f0c6e7), C(325c2413eb770ada), C(868e3315)}, - {C(c2ee3288be4fe2bf), C(c65d2f5ddf32b92), C(af6ecdf121ba5485), - C(c7cd48f7abf1fe59), C(ce600656ace6f53a), C(8a94a4381b108b34), - C(f9d1276c64bf59fb), C(c7cd48f7abf1fe59), C(ce600656ace6f53a), - C(8a94a4381b108b34), C(f9d1276c64bf59fb), C(219ce70ff5a112a5), - C(e6026c576e2d28d7), C(b8e467f25015e3a6), C(950cb904f37af710), - C(4639a426)}, + {C(dbbf541e9dfda0a), C(1479fceb6db4f844), C(31ab576b59062534), C(868e3315)}, + {C(c2ee3288be4fe2bf), C(c65d2f5ddf32b92), C(af6ecdf121ba5485), C(4639a426)}, {C(d86603ced1ed4730), C(f9de718aaada7709), C(db8b9755194c6535), - C(d803e1eead47604c), C(ad00f7611970a71b), C(bc50036b16ce71f5), - C(afba96210a2ca7d6), C(d803e1eead47604c), C(ad00f7611970a71b), - C(bc50036b16ce71f5), C(afba96210a2ca7d6), C(28f7a7be1d6765f0), - C(97bd888b93938c68), C(6ad41d1b407ded49), C(b9bfec098dc543e4), C(f3213646)}, {C(915263c671b28809), C(a815378e7ad762fd), C(abec6dc9b669f559), - C(d17c928c5342477f), C(745130b795254ad5), C(8c5db926fe88f8ba), - C(742a95c953e6d974), C(d17c928c5342477f), C(745130b795254ad5), - C(8c5db926fe88f8ba), C(742a95c953e6d974), C(279db8057b5d3e96), - C(98168411565b4ec4), C(50a72c54fa1125fa), C(27766a635db73638), C(17f148e9)}, - {C(2b67cdd38c307a5e), C(cb1d45bb5c9fe1c), C(800baf2a02ec18ad), - C(6531c1fe32bcb417), C(8c970d8df8cdbeb4), C(917ba5fc67e72b40), - C(4b65e4e263e0a426), C(6531c1fe32bcb417), C(8c970d8df8cdbeb4), - C(917ba5fc67e72b40), C(4b65e4e263e0a426), C(e0de33ce88a8b3a9), - C(f8ef98a437e16b08), C(a5162c0c7c5f7b62), C(dbdac43361b2b881), - C(bfd94880)}, + {C(2b67cdd38c307a5e), C(cb1d45bb5c9fe1c), C(800baf2a02ec18ad), C(bfd94880)}, {C(2d107419073b9cd0), C(a96db0740cef8f54), C(ec41ee91b3ecdc1b), - C(ffe319654c8e7ebc), C(6a67b8f13ead5a72), C(6dd10a34f80d532f), - C(6e9cfaece9fbca4), C(ffe319654c8e7ebc), C(6a67b8f13ead5a72), - C(6dd10a34f80d532f), C(6e9cfaece9fbca4), C(b4468eb6a30aa7e9), - C(e87995bee483222a), C(d036c2c90c609391), C(853306e82fa32247), C(bb1fa7f3)}, - {C(f3e9487ec0e26dfc), C(1ab1f63224e837fa), C(119983bb5a8125d8), - C(8950cfcf4bdf622c), C(8847dca82efeef2f), C(646b75b026708169), - C(21cab4b1687bd8b), C(8950cfcf4bdf622c), C(8847dca82efeef2f), - C(646b75b026708169), C(21cab4b1687bd8b), C(243b489a9eae6231), - C(5f3e634c4b779876), C(ff8abd1548eaf646), C(c7962f5f0151914b), C(88816b1)}, + {C(f3e9487ec0e26dfc), C(1ab1f63224e837fa), C(119983bb5a8125d8), C(88816b1)}, {C(1160987c8fe86f7d), C(879e6db1481eb91b), C(d7dcb802bfe6885d), - C(14453b5cc3d82396), C(4ef700c33ed278bc), C(1639c72ffc00d12e), - C(fb140ee6155f700d), C(14453b5cc3d82396), C(4ef700c33ed278bc), - C(1639c72ffc00d12e), C(fb140ee6155f700d), C(2e6b5c96a6620862), - C(a1f136998cbe19c), C(74e058a3b6c5a712), C(93dcf6bd33928b17), C(5c2faeb3)}, + C(5c2faeb3)}, {C(eab8112c560b967b), C(97f550b58e89dbae), C(846ed506d304051f), - C(276aa37744b5a028), C(8c10800ee90ea573), C(e6e57d2b33a1e0b7), - C(91f83563cd3b9dda), C(276aa37744b5a028), C(8c10800ee90ea573), - C(e6e57d2b33a1e0b7), C(91f83563cd3b9dda), C(afbb4739570738a1), - C(440ba98da5d8f69), C(fde4e9b0eda20350), C(e67dfa5a2138fa1), C(51b5fc6f)}, + C(51b5fc6f)}, {C(1addcf0386d35351), C(b5f436561f8f1484), C(85d38e22181c9bb1), - C(ff5c03f003c1fefe), C(e1098670afe7ff6), C(ea445030cf86de19), - C(f155c68b5c2967f8), C(ff5c03f003c1fefe), C(e1098670afe7ff6), - C(ea445030cf86de19), C(f155c68b5c2967f8), C(95d31b145dbb2e9e), - C(914fe1ca3deb3265), C(6066020b1358ccc1), C(c74bb7e2dee15036), C(33d94752)}, {C(d445ba84bf803e09), C(1216c2497038f804), C(2293216ea2237207), - C(e2164451c651adfb), C(b2534e65477f9823), C(4d70691a69671e34), - C(15be4963dbde8143), C(e2164451c651adfb), C(b2534e65477f9823), - C(4d70691a69671e34), C(15be4963dbde8143), C(762e75c406c5e9a3), - C(7b7579f7e0356841), C(480533eb066dfce5), C(90ae14ea6bfeb4ae), C(b0c92948)}, {C(37235a096a8be435), C(d9b73130493589c2), C(3b1024f59378d3be), - C(ad159f542d81f04e), C(49626a97a946096), C(d8d3998bf09fd304), - C(d127a411eae69459), C(ad159f542d81f04e), C(49626a97a946096), - C(d8d3998bf09fd304), C(d127a411eae69459), C(8f3253c4eb785a7b), - C(4049062f37e62397), C(b9fa04d3b670e5c1), C(1211a7967ac9350f), C(c7171590)}, {C(763ad6ea2fe1c99d), C(cf7af5368ac1e26b), C(4d5e451b3bb8d3d4), - C(3712eb913d04e2f2), C(2f9500d319c84d89), C(4ac6eb21a8cf06f9), - C(7d1917afcde42744), C(3712eb913d04e2f2), C(2f9500d319c84d89), - C(4ac6eb21a8cf06f9), C(7d1917afcde42744), C(6b58604b5dd10903), - C(c4288dfbc1e319fc), C(230f75ca96817c6e), C(8894cba3b763756c), C(240a67fb)}, {C(ea627fc84cd1b857), C(85e372494520071f), C(69ec61800845780b), - C(a3c1c5ca1b0367), C(eb6933997272bb3d), C(76a72cb62692a655), - C(140bb5531edf756e), C(a3c1c5ca1b0367), C(eb6933997272bb3d), - C(76a72cb62692a655), C(140bb5531edf756e), C(8d0d8067d1c925f4), - C(7b3fa56d8d77a10c), C(2bd00287b0946d88), C(f08c8e4bd65b8970), C(e1843cd5)}, {C(1f2ffd79f2cdc0c8), C(726a1bc31b337aaa), C(678b7f275ef96434), - C(5aa82bfaa99d3978), C(c18f96cade5ce18d), C(38404491f9e34c03), - C(891fb8926ba0418c), C(5aa82bfaa99d3978), C(c18f96cade5ce18d), - C(38404491f9e34c03), C(891fb8926ba0418c), C(e5f69a6398114c15), - C(7b8ded3623bc6b1d), C(2f3e5c5da5ff70e8), C(1ab142addea6a9ec), C(fda1452b)}, {C(39a9e146ec4b3210), C(f63f75802a78b1ac), C(e2e22539c94741c3), - C(8b305d532e61226e), C(caeae80da2ea2e), C(88a6289a76ac684e), - C(8ce5b5f9df1cbd85), C(8b305d532e61226e), C(caeae80da2ea2e), - C(88a6289a76ac684e), C(8ce5b5f9df1cbd85), C(8ae1fc4798e00d57), - C(e7164b8fb364fc46), C(6a978c9bd3a66943), C(ef10d5ae4dd08dc), C(a2cad330)}, + C(a2cad330)}, {C(74cba303e2dd9d6d), C(692699b83289fad1), C(dfb9aa7874678480), - C(751390a8a5c41bdc), C(6ee5fbf87605d34), C(6ca73f610f3a8f7c), - C(e898b3c996570ad), C(751390a8a5c41bdc), C(6ee5fbf87605d34), - C(6ca73f610f3a8f7c), C(e898b3c996570ad), C(98168a5858fc7110), - C(6f987fa27aa0daa2), C(f25e3e180d4b36a3), C(d0b03495aeb1be8a), C(53467e16)}, {C(4cbc2b73a43071e0), C(56c5db4c4ca4e0b7), C(1b275a162f46bd3d), - C(b87a326e413604bf), C(d8f9a5fa214b03ab), C(8a8bb8265771cf88), - C(a655319054f6e70f), C(b87a326e413604bf), C(d8f9a5fa214b03ab), - C(8a8bb8265771cf88), C(a655319054f6e70f), C(b499cb8e65a9af44), - C(bee7fafcc8307491), C(5d2e55fa9b27cda2), C(63b120f5fb2d6ee5), C(da14a8d0)}, {C(875638b9715d2221), C(d9ba0615c0c58740), C(616d4be2dfe825aa), - C(5df25f13ea7bc284), C(165edfaafd2598fb), C(af7215c5c718c696), - C(e9f2f9ca655e769), C(5df25f13ea7bc284), C(165edfaafd2598fb), - C(af7215c5c718c696), C(e9f2f9ca655e769), C(e459cfcb565d3d2d), - C(41d032631be2418a), C(c505db05fd946f60), C(54990394a714f5de), C(67333551)}, {C(fb686b2782994a8d), C(edee60693756bb48), C(e6bc3cae0ded2ef5), - C(58eb4d03b2c3ddf5), C(6d2542995f9189f1), C(c0beec58a5f5fea2), - C(ed67436f42e2a78b), C(58eb4d03b2c3ddf5), C(6d2542995f9189f1), - C(c0beec58a5f5fea2), C(ed67436f42e2a78b), C(dfec763cdb2b5193), - C(724a8d5345bd2d6), C(94d4fd1b81457c23), C(28e87c50cdede453), C(a0ebd66e)}, + C(a0ebd66e)}, {C(ab21d81a911e6723), C(4c31b07354852f59), C(835da384c9384744), - C(7f759dddc6e8549a), C(616dd0ca022c8735), C(94717ad4bc15ceb3), - C(f66c7be808ab36e), C(7f759dddc6e8549a), C(616dd0ca022c8735), - C(94717ad4bc15ceb3), C(f66c7be808ab36e), C(af8286b550b2f4b7), - C(745bd217d20a9f40), C(c73bfb9c5430f015), C(55e65922666e3fc2), C(4b769593)}, {C(33d013cc0cd46ecf), C(3de726423aea122c), C(116af51117fe21a9), - C(f271ba474edc562d), C(e6596e67f9dd3ebd), C(c0a288edf808f383), - C(b3def70681c6babc), C(f271ba474edc562d), C(e6596e67f9dd3ebd), - C(c0a288edf808f383), C(b3def70681c6babc), C(7da7864e9989b095), - C(bf2f8718693cd8a1), C(264a9144166da776), C(61ad90676870beb6), C(6aa75624)}, - {C(8ca92c7cd39fae5d), C(317e620e1bf20f1), C(4f0b33bf2194b97f), - C(45744afcf131dbee), C(97222392c2559350), C(498a19b280c6d6ed), - C(83ac2c36acdb8d49), C(45744afcf131dbee), C(97222392c2559350), - C(498a19b280c6d6ed), C(83ac2c36acdb8d49), C(7a69645c294daa62), - C(abe9d2be8275b3d2), C(39542019de371085), C(7f4efac8488cd6ad), - C(602a3f96)}, - {C(fdde3b03f018f43e), C(38f932946c78660), C(c84084ce946851ee), - C(b6dd09ba7851c7af), C(570de4e1bb13b133), C(c4e784eb97211642), - C(8285a7fcdcc7c58d), C(b6dd09ba7851c7af), C(570de4e1bb13b133), - C(c4e784eb97211642), C(8285a7fcdcc7c58d), C(d421f47990da899b), - C(8aed409c997eaa13), C(7a045929c2e29ccf), C(b373682a6202c86b), - C(cd183c4d)}, + {C(8ca92c7cd39fae5d), C(317e620e1bf20f1), C(4f0b33bf2194b97f), C(602a3f96)}, + {C(fdde3b03f018f43e), C(38f932946c78660), C(c84084ce946851ee), C(cd183c4d)}, {C(9c8502050e9c9458), C(d6d2a1a69964beb9), C(1675766f480229b5), - C(216e1d6c86cb524c), C(d01cf6fd4f4065c0), C(fffa4ec5b482ea0f), - C(a0e20ee6a5404ac1), C(216e1d6c86cb524c), C(d01cf6fd4f4065c0), - C(fffa4ec5b482ea0f), C(a0e20ee6a5404ac1), C(c1b037e4eebaf85e), - C(634e3d7c3ebf89eb), C(bcda972358c67d1), C(fd1352181e5b8578), C(960a4d07)}, + C(960a4d07)}, {C(348176ca2fa2fdd2), C(3a89c514cc360c2d), C(9f90b8afb318d6d0), - C(bceee07c11a9ac30), C(2e2d47dff8e77eb7), C(11a394cd7b6d614a), - C(1d7c41d54e15cb4a), C(bceee07c11a9ac30), C(2e2d47dff8e77eb7), - C(11a394cd7b6d614a), C(1d7c41d54e15cb4a), C(15baa5ae7312b0fc), - C(f398f596cc984635), C(8ab8fdf87a6788e8), C(b2b5c1234ab47e2), C(9ae998c4)}, + C(9ae998c4)}, {C(4a3d3dfbbaea130b), C(4e221c920f61ed01), C(553fd6cd1304531f), - C(bd2b31b5608143fe), C(ab717a10f2554853), C(293857f04d194d22), - C(d51be8fa86f254f0), C(bd2b31b5608143fe), C(ab717a10f2554853), - C(293857f04d194d22), C(d51be8fa86f254f0), C(1eee39e07686907e), - C(639039fe0e8d3052), C(d6ec1470cef97ff), C(370c82b860034f0f), C(74e2179d)}, + C(74e2179d)}, {C(b371f768cdf4edb9), C(bdef2ace6d2de0f0), C(e05b4100f7f1baec), - C(b9e0d415b4ebd534), C(c97c2a27efaa33d7), C(591cdb35f84ef9da), - C(a57d02d0e8e3756c), C(b9e0d415b4ebd534), C(c97c2a27efaa33d7), - C(591cdb35f84ef9da), C(a57d02d0e8e3756c), C(23f55f12d7c5c87b), - C(4c7ca0fe23221101), C(dbc3020480334564), C(d985992f32c236b1), C(ee9bae25)}, - {C(7a1d2e96934f61f), C(eb1760ae6af7d961), C(887eb0da063005df), - C(2228d6725e31b8ab), C(9b98f7e4d0142e70), C(b6a8c2115b8e0fe7), - C(b591e2f5ab9b94b1), C(2228d6725e31b8ab), C(9b98f7e4d0142e70), - C(b6a8c2115b8e0fe7), C(b591e2f5ab9b94b1), C(6c1feaa8065318e0), - C(4e7e2ca21c2e81fb), C(e9fe5d8ce7993c45), C(ee411fa2f12cf8df), - C(b66edf10)}, + {C(7a1d2e96934f61f), C(eb1760ae6af7d961), C(887eb0da063005df), C(b66edf10)}, {C(8be53d466d4728f2), C(86a5ac8e0d416640), C(984aa464cdb5c8bb), - C(87049e68f5d38e59), C(7d8ce44ec6bd7751), C(cc28d08ab414839c), - C(6c8f0bd34fe843e3), C(87049e68f5d38e59), C(7d8ce44ec6bd7751), - C(cc28d08ab414839c), C(6c8f0bd34fe843e3), C(b8496dcdc01f3e47), - C(2f03125c282ac26), C(82a8797ba3f5ef07), C(7c977a4d10bf52b8), C(d6209737)}, - {C(829677eb03abf042), C(43cad004b6bc2c0), C(f2f224756803971a), - C(98d0dbf796480187), C(fbcb5f3e1bef5742), C(5af2a0463bf6e921), - C(ad9555bf0120b3a3), C(98d0dbf796480187), C(fbcb5f3e1bef5742), - C(5af2a0463bf6e921), C(ad9555bf0120b3a3), C(283e39b3dc99f447), - C(bedaa1a4a0250c28), C(9d50546624ff9a57), C(4abaf523d1c090f6), C(b994a88)}, - {C(754435bae3496fc), C(5707fc006f094dcf), C(8951c86ab19d8e40), - C(57c5208e8f021a77), C(f7653fbb69cd9276), C(a484410af21d75cb), - C(f19b6844b3d627e8), C(57c5208e8f021a77), C(f7653fbb69cd9276), - C(a484410af21d75cb), C(f19b6844b3d627e8), C(f37400fc3ffd9514), - C(36ae0d821734edfd), C(5f37820af1f1f306), C(be637d40e6a5ad0), C(a05d43c0)}, + C(d6209737)}, + {C(829677eb03abf042), C(43cad004b6bc2c0), C(f2f224756803971a), C(b994a88)}, + {C(754435bae3496fc), C(5707fc006f094dcf), C(8951c86ab19d8e40), C(a05d43c0)}, {C(fda9877ea8e3805f), C(31e868b6ffd521b7), C(b08c90681fb6a0fd), - C(68110a7f83f5d3ff), C(6d77e045901b85a8), C(84ef681113036d8b), - C(3b9f8e3928f56160), C(68110a7f83f5d3ff), C(6d77e045901b85a8), - C(84ef681113036d8b), C(3b9f8e3928f56160), C(fc8b7f56c130835), - C(a11f3e800638e841), C(d9572267f5cf28c1), C(7897c8149803f2aa), C(c79f73a8)}, {C(2e36f523ca8f5eb5), C(8b22932f89b27513), C(331cd6ecbfadc1bb), - C(d1bfe4df12b04cbf), C(f58c17243fd63842), C(3a453cdba80a60af), - C(5737b2ca7470ea95), C(d1bfe4df12b04cbf), C(f58c17243fd63842), - C(3a453cdba80a60af), C(5737b2ca7470ea95), C(54d44a3f4477030c), - C(8168e02d4869aa7f), C(77f383a17778559d), C(95e1737d77a268fc), C(a490aff5)}, {C(21a378ef76828208), C(a5c13037fa841da2), C(506d22a53fbe9812), - C(61c9c95d91017da5), C(16f7c83ba68f5279), C(9c0619b0808d05f7), - C(83c117ce4e6b70a3), C(61c9c95d91017da5), C(16f7c83ba68f5279), - C(9c0619b0808d05f7), C(83c117ce4e6b70a3), C(cfb4c8af7fd01413), - C(fdef04e602e72296), C(ed6124d337889b1), C(4919c86707b830da), C(dfad65b4)}, - {C(ccdd5600054b16ca), C(f78846e84204cb7b), C(1f9faec82c24eac9), - C(58634004c7b2d19a), C(24bb5f51ed3b9073), C(46409de018033d00), - C(4a9805eed5ac802e), C(58634004c7b2d19a), C(24bb5f51ed3b9073), - C(46409de018033d00), C(4a9805eed5ac802e), C(e18de8db306baf82), - C(46bbf75f1fa025ff), C(5faf2fb09be09487), C(3fbc62bd4e558fb3), C(1d07dfb)}, + C(dfad65b4)}, + {C(ccdd5600054b16ca), C(f78846e84204cb7b), C(1f9faec82c24eac9), C(1d07dfb)}, {C(7854468f4e0cabd0), C(3a3f6b4f098d0692), C(ae2423ec7799d30d), - C(29c3529eb165eeba), C(443de3703b657c35), C(66acbce31ae1bc8d), - C(1acc99effe1d547e), C(29c3529eb165eeba), C(443de3703b657c35), - C(66acbce31ae1bc8d), C(1acc99effe1d547e), C(cf07f8a57906573d), - C(31bafb0bbb9a86e7), C(40c69492702a9346), C(7df61fdaa0b858af), C(416df9a0)}, {C(7f88db5346d8f997), C(88eac9aacc653798), C(68a4d0295f8eefa1), - C(ae59ca86f4c3323d), C(25906c09906d5c4c), C(8dd2aa0c0a6584ae), - C(232a7d96b38f40e9), C(ae59ca86f4c3323d), C(25906c09906d5c4c), - C(8dd2aa0c0a6584ae), C(232a7d96b38f40e9), C(8986ee00a2ed0042), - C(c49ae7e428c8a7d1), C(b7dd8280713ac9c2), C(e018720aed1ebc28), C(1f8fb9cc)}, {C(bb3fb5fb01d60fcf), C(1b7cc0847a215eb6), C(1246c994437990a1), - C(d4edc954c07cd8f3), C(224f47e7c00a30ab), C(d5ad7ad7f41ef0c6), - C(59e089281d869fd7), C(d4edc954c07cd8f3), C(224f47e7c00a30ab), - C(d5ad7ad7f41ef0c6), C(59e089281d869fd7), C(f29340d07a14b6f1), - C(c87c5ef76d9c4ef3), C(463118794193a9a), C(2922dcb0540f0dbc), C(7abf48e3)}, + C(7abf48e3)}, {C(2e783e1761acd84d), C(39158042bac975a0), C(1cd21c5a8071188d), - C(b1b7ec44f9302176), C(5cb476450dc0c297), C(dc5ef652521ef6a2), - C(3cc79a9e334e1f84), C(b1b7ec44f9302176), C(5cb476450dc0c297), - C(dc5ef652521ef6a2), C(3cc79a9e334e1f84), C(769e2a283dbcc651), - C(9f24b105c8511d3f), C(c31c15575de2f27e), C(ecfecf32c3ae2d66), C(dea4e3dd)}, {C(392058251cf22acc), C(944ec4475ead4620), C(b330a10b5cb94166), - C(54bc9bee7cbe1767), C(485820bdbe442431), C(54d6120ea2972e90), - C(f437a0341f29b72a), C(54bc9bee7cbe1767), C(485820bdbe442431), - C(54d6120ea2972e90), C(f437a0341f29b72a), C(8f30885c784d5704), - C(aa95376b16c7906a), C(e826928cfaf93dc3), C(20e8f54d1c16d7d8), C(c6064f22)}, - {C(adf5c1e5d6419947), C(2a9747bc659d28aa), C(95c5b8cb1f5d62c), - C(80973ea532b0f310), C(a471829aa9c17dd9), C(c2ff3479394804ab), - C(6bf44f8606753636), C(80973ea532b0f310), C(a471829aa9c17dd9), - C(c2ff3479394804ab), C(6bf44f8606753636), C(5184d2973e6dd827), - C(121b96369a332d9a), C(5c25d3475ab69e50), C(26d2961d62884168), - C(743bed9c)}, + {C(adf5c1e5d6419947), C(2a9747bc659d28aa), C(95c5b8cb1f5d62c), C(743bed9c)}, {C(6bc1db2c2bee5aba), C(e63b0ed635307398), C(7b2eca111f30dbbc), - C(230d2b3e47f09830), C(ec8624a821c1caf4), C(ea6ec411cdbf1cb1), - C(5f38ae82af364e27), C(230d2b3e47f09830), C(ec8624a821c1caf4), - C(ea6ec411cdbf1cb1), C(5f38ae82af364e27), C(a519ef515ea7187c), - C(6bad5efa7ebae05f), C(748abacb11a74a63), C(a28eef963d1396eb), C(fce254d5)}, {C(b00f898229efa508), C(83b7590ad7f6985c), C(2780e70a0592e41d), - C(7122413bdbc94035), C(e7f90fae33bf7763), C(4b6bd0fb30b12387), - C(557359c0c44f48ca), C(7122413bdbc94035), C(e7f90fae33bf7763), - C(4b6bd0fb30b12387), C(557359c0c44f48ca), C(d5656c3d6bc5f0d), - C(983ff8e5e784da99), C(628479671b445bf), C(e179a1e27ce68f5d), C(e47ec9d1)}, + C(e47ec9d1)}, {C(b56eb769ce0d9a8c), C(ce196117bfbcaf04), C(b26c3c3797d66165), - C(5ed12338f630ab76), C(fab19fcb319116d), C(167f5f42b521724b), - C(c4aa56c409568d74), C(5ed12338f630ab76), C(fab19fcb319116d), - C(167f5f42b521724b), C(c4aa56c409568d74), C(75fff4b42f8e9778), - C(94218f94710c1ea3), C(b7b05efb738b06a6), C(83fff2deabf9cd3), C(334a145c)}, + C(334a145c)}, {C(70c0637675b94150), C(259e1669305b0a15), C(46e1dd9fd387a58d), - C(fca4e5bc9292788e), C(cd509dc1facce41c), C(bbba575a59d82fe), - C(4e2e71c15b45d4d3), C(fca4e5bc9292788e), C(cd509dc1facce41c), - C(bbba575a59d82fe), C(4e2e71c15b45d4d3), C(5dc54582ead999c), - C(72612d1571963c6f), C(30318a9d2d3d1829), C(785dd00f4cc9c9a0), C(adec1e3c)}, {C(74c0b8a6821faafe), C(abac39d7491370e7), C(faf0b2a48a4e6aed), - C(967e970df9673d2a), C(d465247cffa415c0), C(33a1df0ca1107722), - C(49fc2a10adce4a32), C(967e970df9673d2a), C(d465247cffa415c0), - C(33a1df0ca1107722), C(49fc2a10adce4a32), C(c5707e079a284308), - C(573028266635dda6), C(f786f5eee6127fa0), C(b30d79cebfb51266), C(f6a9fbf8)}, {C(5fb5e48ac7b7fa4f), C(a96170f08f5acbc7), C(bbf5c63d4f52a1e5), - C(6cc09e60700563e9), C(d18f23221e964791), C(ffc23eeef7af26eb), - C(693a954a3622a315), C(815308a32a9b0daf), C(efb2ab27bf6fd0bd), - C(9f1ffc0986111118), C(f9a3aa1778ea3985), C(698fe54b2b93933b), - C(dacc2b28404d0f10), C(815308a32a9b0daf), C(efb2ab27bf6fd0bd), C(5398210c)}, }; void TestUnchanging(const uint64_t* expected, int offset, int len) { - const uint128 u = CityHash128(data + offset, len); - const uint128 v = CityHash128WithSeed(data + offset, len, kSeed128); EXPECT_EQ(expected[0], CityHash64(data + offset, len)); - EXPECT_EQ(expected[15], CityHash32(data + offset, len)); + EXPECT_EQ(expected[3], CityHash32(data + offset, len)); EXPECT_EQ(expected[1], CityHash64WithSeed(data + offset, len, kSeed0)); EXPECT_EQ(expected[2], CityHash64WithSeeds(data + offset, len, kSeed0, kSeed1)); - EXPECT_EQ(expected[3], Uint128Low64(u)); - EXPECT_EQ(expected[4], Uint128High64(u)); - EXPECT_EQ(expected[5], Uint128Low64(v)); - EXPECT_EQ(expected[6], Uint128High64(v)); -#ifdef __SSE4_2__ - const uint128 y = CityHashCrc128(data + offset, len); - const uint128 z = CityHashCrc128WithSeed(data + offset, len, kSeed128); - uint64_t crc256_results[4]; - CityHashCrc256(data + offset, len, crc256_results); - EXPECT_EQ(expected[7], Uint128Low64(y)); - EXPECT_EQ(expected[8], Uint128High64(y)); - EXPECT_EQ(expected[9], Uint128Low64(z)); - EXPECT_EQ(expected[10], Uint128High64(z)); - for (int i = 0; i < 4; i++) { - EXPECT_EQ(expected[11 + i], crc256_results[i]); - } -#endif } TEST(CityHashTest, Unchanging) {
diff --git a/absl/hash/internal/hash.cc b/absl/hash/internal/hash.cc index 4bf6409..4ab7a9f 100644 --- a/absl/hash/internal/hash.cc +++ b/absl/hash/internal/hash.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h index 4543d67..9ab9890 100644 --- a/absl/hash/internal/hash.h +++ b/absl/hash/internal/hash.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -221,7 +221,9 @@ } // AbslHashValue() for hashing floating-point values template <typename H, typename Float> -typename std::enable_if<std::is_floating_point<Float>::value, H>::type +typename std::enable_if<std::is_same<Float, float>::value || + std::is_same<Float, double>::value, + H>::type AbslHashValue(H hash_state, Float value) { return hash_internal::hash_bytes(std::move(hash_state), value == 0 ? 0 : value); @@ -231,8 +233,9 @@ // For example, in x86 sizeof(long double)==16 but it only really uses 80-bits // of it. This means we can't use hash_bytes on a long double and have to // convert it to something else first. -template <typename H> -H AbslHashValue(H hash_state, long double value) { +template <typename H, typename LongDouble> +typename std::enable_if<std::is_same<LongDouble, long double>::value, H>::type +AbslHashValue(H hash_state, LongDouble value) { const int category = std::fpclassify(value); switch (category) { case FP_INFINITE: @@ -264,7 +267,12 @@ // AbslHashValue() for hashing pointers template <typename H, typename T> H AbslHashValue(H hash_state, T* ptr) { - return hash_internal::hash_bytes(std::move(hash_state), ptr); + auto v = reinterpret_cast<uintptr_t>(ptr); + // Due to alignment, pointers tend to have low bits as zero, and the next few + // bits follow a pattern since they are also multiples of some base value. + // Mixing the pointer twice helps prevent stuck low bits for certain alignment + // values. + return H::combine(std::move(hash_state), v, v); } // AbslHashValue() for hashing nullptr_t @@ -303,13 +311,13 @@ // AbslHashValue for hashing tuples template <typename H, typename... Ts> -#if _MSC_VER +#if defined(_MSC_VER) // This SFINAE gets MSVC confused under some conditions. Let's just disable it // for now. H -#else +#else // _MSC_VER typename std::enable_if<absl::conjunction<is_hashable<Ts>...>::value, H>::type -#endif +#endif // _MSC_VER AbslHashValue(H hash_state, const std::tuple<Ts...>& t) { return hash_internal::hash_tuple(std::move(hash_state), t, absl::make_index_sequence<sizeof...(Ts)>()); @@ -494,6 +502,15 @@ } return H::combine(std::move(hash_state), v.index()); } + +// ----------------------------------------------------------------------------- +// AbslHashValue for Other Types +// ----------------------------------------------------------------------------- + +// AbslHashValue for hashing std::bitset is not defined, for the same reason as +// for vector<bool> (see std::vector above): It does not expose the raw bytes, +// and a fallback to std::hash<> is most likely faster. + // ----------------------------------------------------------------------------- // hash_range_or_bytes() @@ -518,51 +535,22 @@ return hash_state; } -// InvokeHashTag -// -// InvokeHash(H, const T&) invokes the appropriate hash implementation for a -// hasher of type `H` and a value of type `T`. If `T` is not hashable, there -// will be no matching overload of InvokeHash(). -// Note: Some platforms (eg MSVC) do not support the detect idiom on -// std::hash. In those platforms the last fallback will be std::hash and -// InvokeHash() will always have a valid overload even if std::hash<T> is not -// valid. -// -// We try the following options in order: -// * If is_uniquely_represented, hash bytes directly. -// * ADL AbslHashValue(H, const T&) call. -// * std::hash<T> - -// In MSVC we can't probe std::hash or stdext::hash because it triggers a -// static_assert instead of failing substitution. -#if defined(_MSC_VER) -#undef ABSL_HASH_INTERNAL_CAN_POISON_ -#else // _MSC_VER -#define ABSL_HASH_INTERNAL_CAN_POISON_ 1 -#endif // _MSC_VER - #if defined(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE) && \ - ABSL_HASH_INTERNAL_CAN_POISON_ + ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ #define ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 1 +#else +#define ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 0 #endif -enum class InvokeHashTag { - kUniquelyRepresented, - kHashValue, -#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ - kLegacyHash, -#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ - kStdHash, - kNone -}; - // HashSelect // // Type trait to select the appropriate hash implementation to use. -// HashSelect<T>::value is an instance of InvokeHashTag that indicates the best -// available hashing mechanism. -// See `Note` above about MSVC. -template <typename T> +// HashSelect::type<T> will give the proper hash implementation, to be invoked +// as: +// HashSelect::type<T>::Invoke(state, value) +// Also, HashSelect::type<T>::value is a boolean equal to `true` if there is a +// valid `Invoke` function. Types that are not hashable will have a ::value of +// `false`. struct HashSelect { private: struct State : HashStateBase<State> { @@ -571,95 +559,75 @@ using State::HashStateBase::combine_contiguous; }; - // `Probe<V, Tag>::value` evaluates to `V<T>::value` if it is a valid - // expression, and `false` otherwise. - // `Probe<V, Tag>::tag` always evaluates to `Tag`. - template <template <typename> class V, InvokeHashTag Tag> - struct Probe { + struct UniquelyRepresentedProbe { + template <typename H, typename T> + static auto Invoke(H state, const T& value) + -> absl::enable_if_t<is_uniquely_represented<T>::value, H> { + return hash_internal::hash_bytes(std::move(state), value); + } + }; + + struct HashValueProbe { + template <typename H, typename T> + static auto Invoke(H state, const T& value) -> absl::enable_if_t< + std::is_same<H, + decltype(AbslHashValue(std::move(state), value))>::value, + H> { + return AbslHashValue(std::move(state), value); + } + }; + + struct LegacyHashProbe { +#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ + template <typename H, typename T> + static auto Invoke(H state, const T& value) -> absl::enable_if_t< + std::is_convertible< + decltype(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<T>()(value)), + size_t>::value, + H> { + return hash_internal::hash_bytes( + std::move(state), + ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<T>{}(value)); + } +#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ + }; + + struct StdHashProbe { + template <typename H, typename T> + static auto Invoke(H state, const T& value) + -> absl::enable_if_t<type_traits_internal::IsHashable<T>::value, H> { + return hash_internal::hash_bytes(std::move(state), std::hash<T>{}(value)); + } + }; + + template <typename Hash, typename T> + struct Probe : Hash { private: - template <typename U, typename std::enable_if<V<U>::value, int>::type = 0> + template <typename H, typename = decltype(H::Invoke( + std::declval<State>(), std::declval<const T&>()))> static std::true_type Test(int); template <typename U> static std::false_type Test(char); public: - static constexpr InvokeHashTag kTag = Tag; - static constexpr bool value = decltype( - Test<absl::remove_const_t<absl::remove_reference_t<T>>>(0))::value; + static constexpr bool value = decltype(Test<Hash>(0))::value; }; - template <typename U> - using ProbeUniquelyRepresented = is_uniquely_represented<U>; - - template <typename U> - using ProbeHashValue = - std::is_same<State, decltype(AbslHashValue(std::declval<State>(), - std::declval<const U&>()))>; - -#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ - template <typename U> - using ProbeLegacyHash = - std::is_convertible<decltype(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash< - U>()(std::declval<const U&>())), - size_t>; -#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ - - template <typename U> - using ProbeStdHash = -#if ABSL_HASH_INTERNAL_CAN_POISON_ - std::is_convertible<decltype(std::hash<U>()(std::declval<const U&>())), - size_t>; -#else // ABSL_HASH_INTERNAL_CAN_POISON_ - std::true_type; -#endif // ABSL_HASH_INTERNAL_CAN_POISON_ - - template <typename U> - using ProbeNone = std::true_type; - public: // Probe each implementation in order. // disjunction provides short circuting wrt instantiation. - static constexpr InvokeHashTag value = absl::disjunction< - Probe<ProbeUniquelyRepresented, InvokeHashTag::kUniquelyRepresented>, - Probe<ProbeHashValue, InvokeHashTag::kHashValue>, -#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ - Probe<ProbeLegacyHash, InvokeHashTag::kLegacyHash>, -#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ - Probe<ProbeStdHash, InvokeHashTag::kStdHash>, - Probe<ProbeNone, InvokeHashTag::kNone>>::kTag; + template <typename T> + using Apply = absl::disjunction< // + Probe<UniquelyRepresentedProbe, T>, // + Probe<HashValueProbe, T>, // + Probe<LegacyHashProbe, T>, // + Probe<StdHashProbe, T>, // + std::false_type>; }; template <typename T> -struct is_hashable : std::integral_constant<bool, HashSelect<T>::value != - InvokeHashTag::kNone> {}; - -template <typename H, typename T> -absl::enable_if_t<HashSelect<T>::value == InvokeHashTag::kUniquelyRepresented, - H> -InvokeHash(H state, const T& value) { - return hash_internal::hash_bytes(std::move(state), value); -} - -template <typename H, typename T> -absl::enable_if_t<HashSelect<T>::value == InvokeHashTag::kHashValue, H> -InvokeHash(H state, const T& value) { - return AbslHashValue(std::move(state), value); -} - -#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ -template <typename H, typename T> -absl::enable_if_t<HashSelect<T>::value == InvokeHashTag::kLegacyHash, H> -InvokeHash(H state, const T& value) { - return hash_internal::hash_bytes( - std::move(state), ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<T>{}(value)); -} -#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ - -template <typename H, typename T> -absl::enable_if_t<HashSelect<T>::value == InvokeHashTag::kStdHash, H> -InvokeHash(H state, const T& value) { - return hash_internal::hash_bytes(std::move(state), std::hash<T>{}(value)); -} +struct is_hashable + : std::integral_constant<bool, HashSelect::template Apply<T>::value> {}; // CityHashState class CityHashState : public HashStateBase<CityHashState> { @@ -869,7 +837,8 @@ template <typename H> template <typename T, typename... Ts> H HashStateBase<H>::combine(H state, const T& value, const Ts&... values) { - return H::combine(hash_internal::InvokeHash(std::move(state), value), + return H::combine(hash_internal::HashSelect::template Apply<T>::Invoke( + std::move(state), value), values...); }
diff --git a/absl/hash/internal/print_hash_of.cc b/absl/hash/internal/print_hash_of.cc index b6df31c..c392125 100644 --- a/absl/hash/internal/print_hash_of.cc +++ b/absl/hash/internal/print_hash_of.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/hash/internal/spy_hash_state.h b/absl/hash/internal/spy_hash_state.h index 03d795b..c4cc8d0 100644 --- a/absl/hash/internal/spy_hash_state.h +++ b/absl/hash/internal/spy_hash_state.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -39,8 +39,7 @@ template <typename T> class SpyHashStateImpl : public HashStateBase<SpyHashStateImpl<T>> { public: - SpyHashStateImpl() - : error_(std::make_shared<absl::optional<std::string>>()) { + SpyHashStateImpl() : error_(std::make_shared<absl::optional<std::string>>()) { static_assert(std::is_void<T>::value, ""); } @@ -170,7 +169,6 @@ // AbslHashValue directly (because the hash state type does not match). static bool direct_absl_hash_value_error_; - std::vector<std::string> hash_representation_; // This is a shared_ptr because we want all instances of the particular // SpyHashState run to share the field. This way we can set the error for @@ -200,7 +198,7 @@ template < typename T, typename U, // Only trigger for when (T != U), - absl::enable_if_t<!std::is_same<T, U>::value, int> = 0, + typename = absl::enable_if_t<!std::is_same<T, U>::value>, // This statement works in two ways: // - First, it instantiates RunOnStartup and forces the initialization of // `run`, which set the global variable.
diff --git a/absl/memory/BUILD.bazel b/absl/memory/BUILD.bazel index 89a312e..7c6366f 100644 --- a/absl/memory/BUILD.bazel +++ b/absl/memory/BUILD.bazel
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -15,7 +15,7 @@ # load( - "//absl:copts.bzl", + "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_TEST_COPTS", "ABSL_EXCEPTIONS_FLAG",
diff --git a/absl/memory/CMakeLists.txt b/absl/memory/CMakeLists.txt index 5958f5c..0a81220 100644 --- a/absl/memory/CMakeLists.txt +++ b/absl/memory/CMakeLists.txt
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -14,58 +14,45 @@ # limitations under the License. # -list(APPEND MEMORY_PUBLIC_HEADERS - "memory.h" -) - - -absl_header_library( - TARGET - absl_memory - EXPORT_NAME +absl_cc_library( + NAME memory + HDRS + "memory.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::core_headers + absl::meta + PUBLIC ) -# -## TESTS -# - -# test memory_test -list(APPEND MEMORY_TEST_SRC - "memory_test.cc" - ${MEMORY_PUBLIC_HEADERS} -) -set(MEMORY_TEST_PUBLIC_LIBRARIES absl::base absl::memory) - - - -absl_test( - TARGET +absl_cc_test( + NAME memory_test - SOURCES - ${MEMORY_TEST_SRC} - PUBLIC_LIBRARIES - ${MEMORY_TEST_PUBLIC_LIBRARIES} + SRCS + "memory_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::memory + absl::base + absl::core_headers + gmock_main ) - -# test memory_exception_safety_test -set(MEMORY_EXCEPTION_SAFETY_TEST_SRC "memory_exception_safety_test.cc") -set(MEMORY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES - absl::memory - absl_base_internal_exception_safety_testing -) - -absl_test( - TARGET +absl_cc_test( + NAME memory_exception_safety_test - SOURCES - ${MEMORY_EXCEPTION_SAFETY_TEST_SRC} - PUBLIC_LIBRARIES - ${MEMORY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS + SRCS + "memory_exception_safety_test.cc" + COPTS + ${ABSL_TEST_COPTS} ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::memory + absl::exception_safety_testing + gmock_main ) - - -
diff --git a/absl/memory/memory.h b/absl/memory/memory.h index 1eaec0f..5a4a1a1 100644 --- a/absl/memory/memory.h +++ b/absl/memory/memory.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -47,19 +47,14 @@ // X* NewX(int, int); // auto x = WrapUnique(NewX(1, 2)); // 'x' is std::unique_ptr<X>. // -// The purpose of WrapUnique is to automatically deduce the pointer type. If you -// wish to make the type explicit, for readability reasons or because you prefer -// to use a base-class pointer rather than a derived one, just use +// Do not call WrapUnique with an explicit type, as in +// `WrapUnique<X>(NewX(1, 2))`. The purpose of WrapUnique is to automatically +// deduce the pointer type. If you wish to make the type explicit, just use // `std::unique_ptr` directly. // -// Example: -// X* Factory(int, int); -// auto x = std::unique_ptr<X>(Factory(1, 2)); +// auto x = std::unique_ptr<X>(NewX(1, 2)); // - or - -// std::unique_ptr<X> x(Factory(1, 2)); -// -// This has the added advantage of working whether Factory returns a raw -// pointer or a `std::unique_ptr`. +// std::unique_ptr<X> x(NewX(1, 2)); // // While `absl::WrapUnique` is useful for capturing the output of a raw // pointer factory, prefer 'absl::make_unique<T>(args...)' over @@ -120,7 +115,7 @@ // // For more background on why `std::unique_ptr<T>(new T(a,b))` is problematic, // see Herb Sutter's explanation on -// (Exception-Safe Function Calls)[http://herbsutter.com/gotw/_102/]. +// (Exception-Safe Function Calls)[https://herbsutter.com/gotw/_102/]. // (In general, reviewers should treat `new T(a,b)` with scrutiny.) // // Example usage: @@ -599,7 +594,7 @@ return a.max_size(); } static size_type max_size_impl(char, const Alloc&) { - return std::numeric_limits<size_type>::max() / sizeof(value_type); + return (std::numeric_limits<size_type>::max)() / sizeof(value_type); } template <typename A> @@ -646,7 +641,7 @@ : memory_internal::ExtractOrT<memory_internal::GetIsNothrow, Alloc, std::false_type> {}; -#if ABSL_ALLOCATOR_NOTHROW +#if defined(ABSL_ALLOCATOR_NOTHROW) && ABSL_ALLOCATOR_NOTHROW template <typename T> struct allocator_is_nothrow<std::allocator<T>> : std::true_type {}; struct default_allocator_is_nothrow : std::true_type {}; @@ -655,59 +650,42 @@ #endif namespace memory_internal { -#ifdef ABSL_HAVE_EXCEPTIONS // ConstructRange template <typename Allocator, typename Iterator, typename... Args> void ConstructRange(Allocator& alloc, Iterator first, Iterator last, const Args&... args) { for (Iterator cur = first; cur != last; ++cur) { - try { - std::allocator_traits<Allocator>::construct(alloc, cur, args...); - } catch (...) { + ABSL_INTERNAL_TRY { + std::allocator_traits<Allocator>::construct(alloc, std::addressof(*cur), + args...); + } + ABSL_INTERNAL_CATCH_ANY { while (cur != first) { --cur; - std::allocator_traits<Allocator>::destroy(alloc, cur); + std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur)); } - throw; + ABSL_INTERNAL_RETHROW; } } } -#else // ABSL_HAVE_EXCEPTIONS // ConstructRange -template <typename Allocator, typename Iterator, typename... Args> -void ConstructRange(Allocator& alloc, Iterator first, Iterator last, - const Args&... args) { - for (; first != last; ++first) { - std::allocator_traits<Allocator>::construct(alloc, first, args...); - } -} -#endif // ABSL_HAVE_EXCEPTIONS // ConstructRange -#ifdef ABSL_HAVE_EXCEPTIONS // CopyRange template <typename Allocator, typename Iterator, typename InputIterator> void CopyRange(Allocator& alloc, Iterator destination, InputIterator first, InputIterator last) { for (Iterator cur = destination; first != last; static_cast<void>(++cur), static_cast<void>(++first)) { - try { - std::allocator_traits<Allocator>::construct(alloc, cur, *first); - } catch (...) { + ABSL_INTERNAL_TRY { + std::allocator_traits<Allocator>::construct(alloc, std::addressof(*cur), + *first); + } + ABSL_INTERNAL_CATCH_ANY { while (cur != destination) { --cur; - std::allocator_traits<Allocator>::destroy(alloc, cur); + std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur)); } - throw; + ABSL_INTERNAL_RETHROW; } } } -#else // ABSL_HAVE_EXCEPTIONS // CopyRange -template <typename Allocator, typename Iterator, typename InputIterator> -void CopyRange(Allocator& alloc, Iterator destination, InputIterator first, - InputIterator last) { - for (; first != last; - static_cast<void>(++destination), static_cast<void>(++first)) { - std::allocator_traits<Allocator>::construct(alloc, destination, *first); - } -} -#endif // ABSL_HAVE_EXCEPTIONS // CopyRange } // namespace memory_internal } // namespace absl
diff --git a/absl/memory/memory_exception_safety_test.cc b/absl/memory/memory_exception_safety_test.cc index 00d2b19..a1c3970 100644 --- a/absl/memory/memory_exception_safety_test.cc +++ b/absl/memory/memory_exception_safety_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/memory/memory_test.cc b/absl/memory/memory_test.cc index 2e453e2..8905433 100644 --- a/absl/memory/memory_test.cc +++ b/absl/memory/memory_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -69,6 +69,45 @@ EXPECT_EQ("hi", *p); } +// InitializationVerifier fills in a pattern when allocated so we can +// distinguish between its default and value initialized states (without +// accessing truly uninitialized memory). +struct InitializationVerifier { + static constexpr int kDefaultScalar = 0x43; + static constexpr int kDefaultArray = 0x4B; + + static void* operator new(size_t n) { + void* ret = ::operator new(n); + memset(ret, kDefaultScalar, n); + return ret; + } + + static void* operator new[](size_t n) { + void* ret = ::operator new[](n); + memset(ret, kDefaultArray, n); + return ret; + } + + int a; + int b; +}; + +TEST(Initialization, MakeUnique) { + auto p = absl::make_unique<InitializationVerifier>(); + + EXPECT_EQ(0, p->a); + EXPECT_EQ(0, p->b); +} + +TEST(Initialization, MakeUniqueArray) { + auto p = absl::make_unique<InitializationVerifier[]>(2); + + EXPECT_EQ(0, p[0].a); + EXPECT_EQ(0, p[0].b); + EXPECT_EQ(0, p[1].a); + EXPECT_EQ(0, p[1].b); +} + struct MoveOnly { MoveOnly() = default; explicit MoveOnly(int i1) : ip1{new int{i1}} {} @@ -145,7 +184,7 @@ explicit TakesStdType(const std::vector<int> &vec) {} }; using absl::make_unique; - make_unique<TakesStdType>(std::vector<int>()); + (void)make_unique<TakesStdType>(std::vector<int>()); } #if 0
diff --git a/absl/meta/BUILD.bazel b/absl/meta/BUILD.bazel index dbc9717..1c39fa9 100644 --- a/absl/meta/BUILD.bazel +++ b/absl/meta/BUILD.bazel
@@ -1,5 +1,5 @@ load( - "//absl:copts.bzl", + "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_TEST_COPTS", )
diff --git a/absl/meta/CMakeLists.txt b/absl/meta/CMakeLists.txt index adb0ceb..74d4a54 100644 --- a/absl/meta/CMakeLists.txt +++ b/absl/meta/CMakeLists.txt
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -14,39 +14,37 @@ # limitations under the License. # -list(APPEND META_PUBLIC_HEADERS - "type_traits.h" +absl_cc_library( + NAME + type_traits + HDRS + "type_traits.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::config + PUBLIC ) - -# -## TESTS -# - -# test type_traits_test -list(APPEND TYPE_TRAITS_TEST_SRC - "type_traits_test.cc" - ${META_PUBLIC_HEADERS} -) - -absl_header_library( - TARGET - absl_meta - PUBLIC_LIBRARIES - absl::base - EXPORT_NAME - meta - ) - -absl_test( - TARGET +absl_cc_test( + NAME type_traits_test - SOURCES - ${TYPE_TRAITS_TEST_SRC} - PUBLIC_LIBRARIES + SRCS + "type_traits_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::type_traits absl::base - absl::meta + absl::core_headers + gmock_main ) - - +# component target +absl_cc_library( + NAME + meta + DEPS + absl::type_traits + PUBLIC +)
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index 23ebd6e..fbdc921 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -22,7 +22,7 @@ // support type inference, classification, and transformation, as well as // make it easier to write templates based on generic type behavior. // -// See http://en.cppreference.com/w/cpp/header/type_traits +// See https://en.cppreference.com/w/cpp/header/type_traits // // WARNING: use of many of the constructs in this header will count as "complex // template metaprogramming", so before proceeding, please carefully consider @@ -246,7 +246,7 @@ // For the purposes of this check, the call to std::declval is considered // trivial." // -// Notes from http://en.cppreference.com/w/cpp/types/is_constructible: +// Notes from https://en.cppreference.com/w/cpp/types/is_constructible: // In many implementations, is_nothrow_constructible also checks if the // destructor throws because it is effectively noexcept(T(arg)). Same // applies to is_trivially_constructible, which, in these implementations, also @@ -413,24 +413,139 @@ using result_of_t = typename std::result_of<T>::type; namespace type_traits_internal { +// In MSVC we can't probe std::hash or stdext::hash because it triggers a +// static_assert instead of failing substitution. Libc++ prior to 4.0 +// also used a static_assert. +// +#if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \ + _LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11) +#define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 0 +#else +#define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 1 +#endif + +#if !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ template <typename Key, typename = size_t> +struct IsHashable : std::true_type {}; +#else // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ +template <typename Key, typename = void> struct IsHashable : std::false_type {}; template <typename Key> -struct IsHashable<Key, - decltype(std::declval<std::hash<Key>>()(std::declval<Key>()))> - : std::true_type {}; +struct IsHashable< + Key, + absl::enable_if_t<std::is_convertible< + decltype(std::declval<std::hash<Key>&>()(std::declval<Key const&>())), + std::size_t>::value>> : std::true_type {}; +#endif // !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ -template <typename Key> -struct IsHashEnabled - : absl::conjunction<std::is_default_constructible<std::hash<Key>>, - std::is_copy_constructible<std::hash<Key>>, - std::is_destructible<std::hash<Key>>, - absl::is_copy_assignable<std::hash<Key>>, - IsHashable<Key>> {}; +struct AssertHashEnabledHelper { + private: + static void Sink(...) {} + struct NAT {}; + + template <class Key> + static auto GetReturnType(int) + -> decltype(std::declval<std::hash<Key>>()(std::declval<Key const&>())); + template <class Key> + static NAT GetReturnType(...); + + template <class Key> + static std::nullptr_t DoIt() { + static_assert(IsHashable<Key>::value, + "std::hash<Key> does not provide a call operator"); + static_assert( + std::is_default_constructible<std::hash<Key>>::value, + "std::hash<Key> must be default constructible when it is enabled"); + static_assert( + std::is_copy_constructible<std::hash<Key>>::value, + "std::hash<Key> must be copy constructible when it is enabled"); + static_assert(absl::is_copy_assignable<std::hash<Key>>::value, + "std::hash<Key> must be copy assignable when it is enabled"); + // is_destructible is unchecked as it's implied by each of the + // is_constructible checks. + using ReturnType = decltype(GetReturnType<Key>(0)); + static_assert(std::is_same<ReturnType, NAT>::value || + std::is_same<ReturnType, size_t>::value, + "std::hash<Key> must return size_t"); + return nullptr; + } + + template <class... Ts> + friend void AssertHashEnabled(); +}; + +template <class... Ts> +inline void AssertHashEnabled() { + using Helper = AssertHashEnabledHelper; + Helper::Sink(Helper::DoIt<Ts>()...); +} } // namespace type_traits_internal +// An internal namespace that is required to implement the C++17 swap traits. +// It is not further nested in type_traits_internal to avoid long symbol names. +namespace swap_internal { + +// Necessary for the traits. +using std::swap; + +// This declaration prevents global `swap` and `absl::swap` overloads from being +// considered unless ADL picks them up. +void swap(); + +template <class T> +using IsSwappableImpl = decltype(swap(std::declval<T&>(), std::declval<T&>())); + +// NOTE: This dance with the default template parameter is for MSVC. +template <class T, + class IsNoexcept = std::integral_constant< + bool, noexcept(swap(std::declval<T&>(), std::declval<T&>()))>> +using IsNothrowSwappableImpl = typename std::enable_if<IsNoexcept::value>::type; + +// IsSwappable +// +// Determines whether the standard swap idiom is a valid expression for +// arguments of type `T`. +template <class T> +struct IsSwappable + : absl::type_traits_internal::is_detected<IsSwappableImpl, T> {}; + +// IsNothrowSwappable +// +// Determines whether the standard swap idiom is a valid expression for +// arguments of type `T` and is noexcept. +template <class T> +struct IsNothrowSwappable + : absl::type_traits_internal::is_detected<IsNothrowSwappableImpl, T> {}; + +// Swap() +// +// Performs the swap idiom from a namespace where valid candidates may only be +// found in `std` or via ADL. +template <class T, absl::enable_if_t<IsSwappable<T>::value, int> = 0> +void Swap(T& lhs, T& rhs) noexcept(IsNothrowSwappable<T>::value) { + swap(lhs, rhs); +} + +// StdSwapIsUnconstrained +// +// Some standard library implementations are broken in that they do not +// constrain `std::swap`. This will effectively tell us if we are dealing with +// one of those implementations. +using StdSwapIsUnconstrained = IsSwappable<void()>; + +} // namespace swap_internal + +namespace type_traits_internal { + +// Make the swap-related traits/function accessible from this namespace. +using swap_internal::IsNothrowSwappable; +using swap_internal::IsSwappable; +using swap_internal::Swap; +using swap_internal::StdSwapIsUnconstrained; + +} // namespace type_traits_internal } // namespace absl #endif // ABSL_META_TYPE_TRAITS_H_
diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc index f51f5de..912336e 100644 --- a/absl/meta/type_traits_test.cc +++ b/absl/meta/type_traits_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -953,4 +953,85 @@ #endif // _LIBCPP_VERSION } +namespace adl_namespace { + +struct DeletedSwap { +}; + +void swap(DeletedSwap&, DeletedSwap&) = delete; + +struct SpecialNoexceptSwap { + SpecialNoexceptSwap(SpecialNoexceptSwap&&) {} + SpecialNoexceptSwap& operator=(SpecialNoexceptSwap&&) { return *this; } + ~SpecialNoexceptSwap() = default; +}; + +void swap(SpecialNoexceptSwap&, SpecialNoexceptSwap&) noexcept {} + +} // namespace adl_namespace + +TEST(TypeTraitsTest, IsSwappable) { + using absl::type_traits_internal::IsSwappable; + using absl::type_traits_internal::StdSwapIsUnconstrained; + + EXPECT_TRUE(IsSwappable<int>::value); + + struct S {}; + EXPECT_TRUE(IsSwappable<S>::value); + + struct NoConstruct { + NoConstruct(NoConstruct&&) = delete; + NoConstruct& operator=(NoConstruct&&) { return *this; } + ~NoConstruct() = default; + }; + + EXPECT_EQ(IsSwappable<NoConstruct>::value, StdSwapIsUnconstrained::value); + struct NoAssign { + NoAssign(NoAssign&&) {} + NoAssign& operator=(NoAssign&&) = delete; + ~NoAssign() = default; + }; + + EXPECT_EQ(IsSwappable<NoAssign>::value, StdSwapIsUnconstrained::value); + + EXPECT_FALSE(IsSwappable<adl_namespace::DeletedSwap>::value); + + EXPECT_TRUE(IsSwappable<adl_namespace::SpecialNoexceptSwap>::value); +} + +TEST(TypeTraitsTest, IsNothrowSwappable) { + using absl::type_traits_internal::IsNothrowSwappable; + using absl::type_traits_internal::StdSwapIsUnconstrained; + + EXPECT_TRUE(IsNothrowSwappable<int>::value); + + struct NonNoexceptMoves { + NonNoexceptMoves(NonNoexceptMoves&&) {} + NonNoexceptMoves& operator=(NonNoexceptMoves&&) { return *this; } + ~NonNoexceptMoves() = default; + }; + + EXPECT_FALSE(IsNothrowSwappable<NonNoexceptMoves>::value); + + struct NoConstruct { + NoConstruct(NoConstruct&&) = delete; + NoConstruct& operator=(NoConstruct&&) { return *this; } + ~NoConstruct() = default; + }; + + EXPECT_FALSE(IsNothrowSwappable<NoConstruct>::value); + + struct NoAssign { + NoAssign(NoAssign&&) {} + NoAssign& operator=(NoAssign&&) = delete; + ~NoAssign() = default; + }; + + EXPECT_FALSE(IsNothrowSwappable<NoAssign>::value); + + EXPECT_FALSE(IsNothrowSwappable<adl_namespace::DeletedSwap>::value); + + EXPECT_TRUE(IsNothrowSwappable<adl_namespace::SpecialNoexceptSwap>::value); +} + } // namespace
diff --git a/absl/numeric/BUILD.bazel b/absl/numeric/BUILD.bazel index 324ce66..7cd7ee1 100644 --- a/absl/numeric/BUILD.bazel +++ b/absl/numeric/BUILD.bazel
@@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -13,7 +13,7 @@ # limitations under the License. load( - "//absl:copts.bzl", + "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_TEST_COPTS", )
diff --git a/absl/numeric/CMakeLists.txt b/absl/numeric/CMakeLists.txt index 3360b2e..d26141c 100644 --- a/absl/numeric/CMakeLists.txt +++ b/absl/numeric/CMakeLists.txt
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -14,49 +14,45 @@ # limitations under the License. # -list(APPEND NUMERIC_PUBLIC_HEADERS - "int128.h" -) - - -# library 128 -list(APPEND INT128_SRC - "int128.cc" - ${NUMERIC_PUBLIC_HEADERS} -) -absl_library( - TARGET - absl_int128 - SOURCES - ${INT128_SRC} - PUBLIC_LIBRARIES - ${INT128_PUBLIC_LIBRARIES} - EXPORT_NAME +absl_cc_library( + NAME int128 + HDRS + "int128.h" + SRCS + "int128.cc" + "int128_have_intrinsic.inc" + "int128_no_intrinsic.inc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::config + absl::core_headers + PUBLIC ) - -absl_header_library( - TARGET - absl_numeric - PUBLIC_LIBRARIES - absl::int128 - EXPORT_NAME - numeric -) - -# test int128_test -set(INT128_TEST_SRC "int128_test.cc") -set(INT128_TEST_PUBLIC_LIBRARIES absl::numeric absl::base) - -absl_test( - TARGET +absl_cc_test( + NAME int128_test - SOURCES - ${INT128_TEST_SRC} - PUBLIC_LIBRARIES - ${INT128_TEST_PUBLIC_LIBRARIES} + SRCS + "int128_stream_test.cc" + "int128_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::int128 + absl::base + absl::core_headers + absl::hash_testing + absl::type_traits + gmock_main ) - - +# component target +absl_cc_library( + NAME + numeric + DEPS + absl::int128 + PUBLIC +)
diff --git a/absl/numeric/int128.cc b/absl/numeric/int128.cc index cd79534..93b62c5 100644 --- a/absl/numeric/int128.cc +++ b/absl/numeric/int128.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -17,7 +17,7 @@ #include <stddef.h> #include <cassert> #include <iomanip> -#include <iostream> // NOLINT(readability/streams) +#include <ostream> // NOLINT(readability/streams) #include <sstream> #include <string> #include <type_traits> @@ -65,7 +65,7 @@ // Long division/modulo for uint128 implemented using the shift-subtract // division algorithm adapted from: -// http://stackoverflow.com/questions/5386377/division-without-using +// https://stackoverflow.com/questions/5386377/division-without-using void DivModImpl(uint128 dividend, uint128 divisor, uint128* quotient_ret, uint128* remainder_ret) { assert(divisor != 0); @@ -123,6 +123,28 @@ return MakeUint128(0, static_cast<uint64_t>(v)); } + +#if defined(__clang__) && !defined(__SSE3__) +// Workaround for clang bug: https://bugs.llvm.org/show_bug.cgi?id=38289 +// Casting from long double to uint64_t is miscompiled and drops bits. +// It is more work, so only use when we need the workaround. +uint128 MakeUint128FromFloat(long double v) { + // Go 50 bits at a time, that fits in a double + static_assert(std::numeric_limits<double>::digits >= 50, ""); + static_assert(std::numeric_limits<long double>::digits <= 150, ""); + // Undefined behavior if v is not finite or cannot fit into uint128. + assert(std::isfinite(v) && v > -1 && v < std::ldexp(1.0L, 128)); + + v = std::ldexp(v, -100); + uint64_t w0 = static_cast<uint64_t>(static_cast<double>(std::trunc(v))); + v = std::ldexp(v - static_cast<double>(w0), 50); + uint64_t w1 = static_cast<uint64_t>(static_cast<double>(std::trunc(v))); + v = std::ldexp(v - static_cast<double>(w1), 50); + uint64_t w2 = static_cast<uint64_t>(static_cast<double>(std::trunc(v))); + return (static_cast<uint128>(w0) << 100) | (static_cast<uint128>(w1) << 50) | + static_cast<uint128>(w2); +} +#endif // __clang__ && !__SSE3__ } // namespace uint128::uint128(float v) : uint128(MakeUint128FromFloat(v)) {}
diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h index 79b62a7..2f5b8ad 100644 --- a/absl/numeric/int128.h +++ b/absl/numeric/int128.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -37,8 +37,21 @@ #include "absl/base/macros.h" #include "absl/base/port.h" -namespace absl { +#if defined(_MSC_VER) +// In very old versions of MSVC and when the /Zc:wchar_t flag is off, wchar_t is +// a typedef for unsigned short. Otherwise wchar_t is mapped to the __wchar_t +// builtin type. We need to make sure not to define operator wchar_t() +// alongside operator unsigned short() in these instances. +#define ABSL_INTERNAL_WCHAR_T __wchar_t +#if defined(_M_X64) +#include <intrin.h> +#pragma intrinsic(_umul128) +#endif // defined(_M_X64) +#else // defined(_MSC_VER) +#define ABSL_INTERNAL_WCHAR_T wchar_t +#endif // defined(_MSC_VER) +namespace absl { // uint128 // @@ -126,7 +139,7 @@ constexpr explicit operator unsigned char() const; constexpr explicit operator char16_t() const; constexpr explicit operator char32_t() const; - constexpr explicit operator wchar_t() const; + constexpr explicit operator ABSL_INTERNAL_WCHAR_T() const; constexpr explicit operator short() const; // NOLINT(runtime/int) // NOLINTNEXTLINE(runtime/int) constexpr explicit operator unsigned short() const; @@ -227,8 +240,8 @@ // TODO(strel) add operator>>(std::istream&, uint128) constexpr uint128 Uint128Max() { - return uint128(std::numeric_limits<uint64_t>::max(), - std::numeric_limits<uint64_t>::max()); + return uint128((std::numeric_limits<uint64_t>::max)(), + (std::numeric_limits<uint64_t>::max)()); } } // namespace absl @@ -266,9 +279,9 @@ #endif // ABSL_HAVE_INTRINSIC_INT128 static constexpr bool tinyness_before = false; - static constexpr absl::uint128 min() { return 0; } + static constexpr absl::uint128 (min)() { return 0; } static constexpr absl::uint128 lowest() { return 0; } - static constexpr absl::uint128 max() { return absl::Uint128Max(); } + static constexpr absl::uint128 (max)() { return absl::Uint128Max(); } static constexpr absl::uint128 epsilon() { return 0; } static constexpr absl::uint128 round_error() { return 0; } static constexpr absl::uint128 infinity() { return 0; } @@ -384,13 +397,13 @@ constexpr uint128::uint128(int v) : lo_{static_cast<uint64_t>(v)}, - hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0} {} + hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0} {} constexpr uint128::uint128(long v) // NOLINT(runtime/int) : lo_{static_cast<uint64_t>(v)}, - hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0} {} + hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0} {} constexpr uint128::uint128(long long v) // NOLINT(runtime/int) : lo_{static_cast<uint64_t>(v)}, - hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0} {} + hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0} {} constexpr uint128::uint128(unsigned int v) : lo_{v}, hi_{0} {} // NOLINTNEXTLINE(runtime/int) @@ -413,13 +426,13 @@ : hi_{high}, lo_{low} {} constexpr uint128::uint128(int v) - : hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0}, + : hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0}, lo_{static_cast<uint64_t>(v)} {} constexpr uint128::uint128(long v) // NOLINT(runtime/int) - : hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0}, + : hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0}, lo_{static_cast<uint64_t>(v)} {} constexpr uint128::uint128(long long v) // NOLINT(runtime/int) - : hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0}, + : hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0}, lo_{static_cast<uint64_t>(v)} {} constexpr uint128::uint128(unsigned int v) : hi_{0}, lo_{v} {} @@ -463,8 +476,8 @@ return static_cast<char32_t>(lo_); } -constexpr uint128::operator wchar_t() const { - return static_cast<wchar_t>(lo_); +constexpr uint128::operator ABSL_INTERNAL_WCHAR_T() const { + return static_cast<ABSL_INTERNAL_WCHAR_T>(lo_); } // NOLINTNEXTLINE(runtime/int) @@ -661,6 +674,12 @@ // can be used for uint128 storage. return static_cast<unsigned __int128>(lhs) * static_cast<unsigned __int128>(rhs); +#elif defined(_MSC_VER) && defined(_M_X64) + uint64_t carry; + uint64_t low = _umul128(Uint128Low64(lhs), Uint128Low64(rhs), &carry); + return MakeUint128(Uint128Low64(lhs) * Uint128High64(rhs) + + Uint128High64(lhs) * Uint128Low64(rhs) + carry, + low); #else // ABSL_HAVE_INTRINSIC128 uint64_t a32 = Uint128Low64(lhs) >> 32; uint64_t a00 = Uint128Low64(lhs) & 0xffffffff; @@ -708,4 +727,6 @@ } // namespace absl +#undef ABSL_INTERNAL_WCHAR_T + #endif // ABSL_NUMERIC_INT128_H_
diff --git a/absl/numeric/int128_benchmark.cc b/absl/numeric/int128_benchmark.cc index 1cb7d0e..a5502d9 100644 --- a/absl/numeric/int128_benchmark.cc +++ b/absl/numeric/int128_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/numeric/int128_have_intrinsic.inc b/absl/numeric/int128_have_intrinsic.inc index ee2a093..c7ea683 100644 --- a/absl/numeric/int128_have_intrinsic.inc +++ b/absl/numeric/int128_have_intrinsic.inc
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -15,4 +15,4 @@ // 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. +// included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined.
diff --git a/absl/numeric/int128_no_intrinsic.inc b/absl/numeric/int128_no_intrinsic.inc index 0d0b3cf..046cb9b 100644 --- a/absl/numeric/int128_no_intrinsic.inc +++ b/absl/numeric/int128_no_intrinsic.inc
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -15,4 +15,4 @@ // 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. +// is included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined.
diff --git a/absl/numeric/int128_stream_test.cc b/absl/numeric/int128_stream_test.cc index 09efaad..3cfa9dc 100644 --- a/absl/numeric/int128_stream_test.cc +++ b/absl/numeric/int128_stream_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/numeric/int128_test.cc b/absl/numeric/int128_test.cc index dfe3475..5e1b5ec 100644 --- a/absl/numeric/int128_test.cc +++ b/absl/numeric/int128_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -51,7 +51,7 @@ class Uint128FloatTraitsTest : public ::testing::Test {}; typedef ::testing::Types<float, double, long double> FloatingPointTypes; -TYPED_TEST_CASE(Uint128IntegerTraitsTest, IntegerTypes); +TYPED_TEST_SUITE(Uint128IntegerTraitsTest, IntegerTypes); TYPED_TEST(Uint128IntegerTraitsTest, ConstructAssignTest) { static_assert(std::is_constructible<absl::uint128, TypeParam>::value, @@ -62,7 +62,7 @@ "TypeParam must not be assignable from absl::uint128"); } -TYPED_TEST_CASE(Uint128FloatTraitsTest, FloatingPointTypes); +TYPED_TEST_SUITE(Uint128FloatTraitsTest, FloatingPointTypes); TYPED_TEST(Uint128FloatTraitsTest, ConstructAssignTest) { static_assert(std::is_constructible<absl::uint128, TypeParam>::value, @@ -271,6 +271,20 @@ EXPECT_EQ(static_cast<absl::uint128>(round_to_zero), 0); EXPECT_EQ(static_cast<absl::uint128>(round_to_five), 5); EXPECT_EQ(static_cast<absl::uint128>(round_to_nine), 9); + + absl::uint128 highest_precision_in_long_double = + ~absl::uint128{} >> (128 - std::numeric_limits<long double>::digits); + EXPECT_EQ(highest_precision_in_long_double, + static_cast<absl::uint128>( + static_cast<long double>(highest_precision_in_long_double))); + // Apply a mask just to make sure all the bits are the right place. + const absl::uint128 arbitrary_mask = + absl::MakeUint128(0xa29f622677ded751, 0xf8ca66add076f468); + EXPECT_EQ(highest_precision_in_long_double & arbitrary_mask, + static_cast<absl::uint128>(static_cast<long double>( + highest_precision_in_long_double & arbitrary_mask))); + + EXPECT_EQ(static_cast<absl::uint128>(-0.1L), 0); } TEST(Uint128, OperatorAssignReturnRef) { @@ -440,4 +454,29 @@ EXPECT_EQ(absl::Uint128Max(), std::numeric_limits<absl::uint128>::max()); } +TEST(Uint128, Hash) { + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({ + // Some simple values + absl::uint128{0}, + absl::uint128{1}, + ~absl::uint128{}, + // 64 bit limits + absl::uint128{std::numeric_limits<int64_t>::max()}, + absl::uint128{std::numeric_limits<uint64_t>::max()} + 0, + absl::uint128{std::numeric_limits<uint64_t>::max()} + 1, + absl::uint128{std::numeric_limits<uint64_t>::max()} + 2, + // Keeping high same + absl::uint128{1} << 62, + absl::uint128{1} << 63, + // Keeping low same + absl::uint128{1} << 64, + absl::uint128{1} << 65, + // 128 bit limits + std::numeric_limits<absl::uint128>::max(), + std::numeric_limits<absl::uint128>::max() - 1, + std::numeric_limits<absl::uint128>::min() + 1, + std::numeric_limits<absl::uint128>::min(), + })); +} + } // namespace
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 6d7c261..9640ff4 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel
@@ -5,17 +5,16 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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( - "//absl:copts.bzl", + "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_TEST_COPTS", "ABSL_EXCEPTIONS_FLAG", @@ -413,6 +412,7 @@ copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ + ":pow10_helper", ":strings", "//absl/base", "//absl/base:core_headers", @@ -471,6 +471,8 @@ srcs = ["charconv_test.cc"], copts = ABSL_TEST_COPTS, deps = [ + ":pow10_helper", + ":str_format", ":strings", "//absl/base", "@com_google_googletest//:gtest_main", @@ -659,3 +661,23 @@ "@com_google_googletest//:gtest_main", ], ) + +cc_library( + name = "pow10_helper", + testonly = True, + srcs = ["internal/pow10_helper.cc"], + hdrs = ["internal/pow10_helper.h"], + visibility = ["//visibility:private"], +) + +cc_test( + name = "pow10_helper_test", + srcs = ["internal/pow10_helper_test.cc"], + copts = ABSL_TEST_COPTS, + visibility = ["//visibility:private"], + deps = [ + ":pow10_helper", + ":str_format", + "@com_google_googletest//:gtest_main", + ], +)
diff --git a/absl/strings/BUILD.gn b/absl/strings/BUILD.gn index 20af83c..6f5cef6 100644 --- a/absl/strings/BUILD.gn +++ b/absl/strings/BUILD.gn
@@ -144,3 +144,21 @@ "../types:span", ] } + +source_set("pow10_helper") { + testonly = true + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ + "//build/config/compiler:no_chromium_code", + "//third_party/abseil-cpp:absl_default_cflags_cc", + ] + public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] + sources = [ + "internal/pow10_helper.cc", + ] + public = [ + "internal/pow10_helper.h", + ] + visibility = [] + visibility += [ ":*" ] +}
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index f3e4162..d3393a3 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -14,93 +14,359 @@ # limitations under the License. # - -list(APPEND STRINGS_PUBLIC_HEADERS - "ascii.h" - "charconv.h" - "escaping.h" - "match.h" - "numbers.h" - "str_cat.h" - "string_view.h" - "strip.h" - "str_join.h" - "str_replace.h" - "str_split.h" - "substitute.h" -) - - -list(APPEND STRINGS_INTERNAL_HEADERS - "internal/char_map.h" - "internal/charconv_bigint.h" - "internal/charconv_parse.h" - "internal/memutil.h" - "internal/ostringstream.h" - "internal/resize_uninitialized.h" - "internal/stl_type_traits.h" - "internal/str_join_internal.h" - "internal/str_split_internal.h" - "internal/utf8.h" -) - - - -# add string library -list(APPEND STRINGS_SRC - "ascii.cc" - "charconv.cc" - "escaping.cc" - "internal/charconv_bigint.cc" - "internal/charconv_parse.cc" - "internal/memutil.cc" - "internal/memutil.h" - "internal/utf8.cc" - "internal/ostringstream.cc" - "match.cc" - "numbers.cc" - "str_cat.cc" - "str_replace.cc" - "str_split.cc" - "string_view.cc" - "substitute.cc" - ${STRINGS_PUBLIC_HEADERS} - ${STRINGS_INTERNAL_HEADERS} -) -set(STRINGS_PUBLIC_LIBRARIES absl::base absl_throw_delegate) - -absl_library( - TARGET - absl_strings - SOURCES - ${STRINGS_SRC} - PUBLIC_LIBRARIES - ${STRINGS_PUBLIC_LIBRARIES} - EXPORT_NAME +absl_cc_library( + NAME strings + HDRS + "ascii.h" + "charconv.h" + "escaping.h" + "match.h" + "numbers.h" + "str_cat.h" + "str_join.h" + "str_replace.h" + "str_split.h" + "string_view.h" + "strip.h" + "substitute.h" + SRCS + "ascii.cc" + "charconv.cc" + "escaping.cc" + "internal/charconv_bigint.cc" + "internal/charconv_bigint.h" + "internal/charconv_parse.cc" + "internal/charconv_parse.h" + "internal/memutil.cc" + "internal/memutil.h" + "internal/stl_type_traits.h" + "internal/str_join_internal.h" + "internal/str_split_internal.h" + "match.cc" + "numbers.cc" + "str_cat.cc" + "str_replace.cc" + "str_split.cc" + "string_view.cc" + "substitute.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::strings_internal + absl::base + absl::bits + absl::config + absl::core_headers + absl::endian + absl::throw_delegate + absl::memory + absl::type_traits + absl::int128 + PUBLIC ) -# add str_format library -absl_header_library( - TARGET - absl_str_format - PUBLIC_LIBRARIES - str_format_internal - EXPORT_NAME +absl_cc_library( + NAME + strings_internal + HDRS + "internal/char_map.h" + "internal/ostringstream.h" + "internal/resize_uninitialized.h" + "internal/utf8.h" + SRCS + "internal/ostringstream.cc" + "internal/utf8.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::core_headers + absl::endian + absl::type_traits +) + +absl_cc_test( + NAME + match_test + SRCS + "match_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::base + gmock_main +) + +absl_cc_test( + NAME + escaping_test + SRCS + "escaping_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::core_headers + absl::fixed_array + gmock_main +) + +absl_cc_test( + NAME + ascii_test + SRCS + "ascii_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::core_headers + gmock_main +) + +absl_cc_test( + NAME + memutil_test + SRCS + "internal/memutil.h" + "internal/memutil_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::core_headers + gmock_main +) + +absl_cc_test( + NAME + utf8_test + SRCS + "internal/utf8_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings_internal + absl::base + absl::core_headers + gmock_main +) + +absl_cc_test( + NAME + string_view_test + SRCS + "string_view_test.cc" + COPTS + ${ABSL_TEST_COPTS} + ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::strings + absl::config + absl::core_headers + absl::dynamic_annotations + gmock_main +) + +absl_cc_test( + NAME + substitute_test + SRCS + "substitute_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::core_headers + gmock_main +) + +absl_cc_test( + NAME + str_replace_test + SRCS + "str_replace_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + gmock_main +) + +absl_cc_test( + NAME + str_split_test + SRCS + "str_split_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::base + absl::core_headers + absl::dynamic_annotations + gmock_main +) + +absl_cc_test( + NAME + ostringstream_test + SRCS + "internal/ostringstream_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings_internal + gmock_main +) + +absl_cc_test( + NAME + resize_uninitialized_test + SRCS + "internal/resize_uninitialized.h" + "internal/resize_uninitialized_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::base + absl::core_headers + absl::type_traits + gmock_main +) + +absl_cc_test( + NAME + str_join_test + SRCS + "str_join_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::base + absl::core_headers + absl::memory + gmock_main +) + +absl_cc_test( + NAME + str_cat_test + SRCS + "str_cat_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::core_headers + gmock_main +) + +absl_cc_test( + NAME + numbers_test + SRCS + "internal/numbers_test_common.h" + "numbers_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::base + absl::core_headers + absl::pow10_helper + gmock_main +) + +absl_cc_test( + NAME + strip_test + SRCS + "strip_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::base + gmock_main +) + +absl_cc_test( + NAME + char_map_test + SRCS + "internal/char_map_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings_internal + gmock_main +) + +absl_cc_test( + NAME + charconv_test + SRCS + "charconv_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::str_format + absl::base + absl::pow10_helper + gmock_main +) + +absl_cc_test( + NAME + charconv_parse_test + SRCS + "internal/charconv_parse.h" + "internal/charconv_parse_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::base + gmock_main +) + +absl_cc_test( + NAME + charconv_bigint_test + SRCS + "internal/charconv_bigint.h" + "internal/charconv_bigint_test.cc" + "internal/charconv_parse.h" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + absl::base + gmock_main +) + +absl_cc_library( + NAME str_format + HDRS + "str_format.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::str_format_internal + PUBLIC ) -# str_format_internal -absl_library( - TARGET +absl_cc_library( + NAME str_format_internal - SOURCES - "internal/str_format/arg.cc" - "internal/str_format/bind.cc" - "internal/str_format/extension.cc" - "internal/str_format/float_conversion.cc" - "internal/str_format/output.cc" - "internal/str_format/parser.cc" + HDRS "internal/str_format/arg.h" "internal/str_format/bind.h" "internal/str_format/checker.h" @@ -108,356 +374,145 @@ "internal/str_format/float_conversion.h" "internal/str_format/output.h" "internal/str_format/parser.h" - PUBLIC_LIBRARIES - str_format_extension_internal + SRCS + "internal/str_format/arg.cc" + "internal/str_format/bind.cc" + "internal/str_format/extension.cc" + "internal/str_format/float_conversion.cc" + "internal/str_format/output.cc" + "internal/str_format/parser.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS absl::strings - absl::base - absl::numeric - absl::container + absl::core_headers + absl::inlined_vector + absl::type_traits + absl::int128 absl::span ) -# str_format_extension_internal -absl_library( - TARGET - str_format_extension_internal - SOURCES - "internal/str_format/extension.cc" - "internal/str_format/extension.h" - "internal/str_format/output.cc" - "internal/str_format/output.h" - PUBLIC_LIBRARIES - absl::base - absl::strings -) - -# -## TESTS -# - -# test match_test -set(MATCH_TEST_SRC "match_test.cc") -set(MATCH_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET - match_test - SOURCES - ${MATCH_TEST_SRC} - PUBLIC_LIBRARIES - ${MATCH_TEST_PUBLIC_LIBRARIES} -) - - -# test escaping_test -set(ESCAPING_TEST_SRC "escaping_test.cc") -set(ESCAPING_TEST_PUBLIC_LIBRARIES absl::strings absl::base) - -absl_test( - TARGET - escaping_test - SOURCES - ${ESCAPING_TEST_SRC} - PUBLIC_LIBRARIES - ${ESCAPING_TEST_PUBLIC_LIBRARIES} -) - - -# test ascii_test -set(ASCII_TEST_SRC "ascii_test.cc") -set(ASCII_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET - ascii_test - SOURCES - ${ASCII_TEST_SRC} - PUBLIC_LIBRARIES - ${ASCII_TEST_PUBLIC_LIBRARIES} -) - - -# test memutil_test -set(MEMUTIL_TEST_SRC "internal/memutil_test.cc") -set(MEMUTIL_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET - memutil_test - SOURCES - ${MEMUTIL_TEST_SRC} - PUBLIC_LIBRARIES - ${MEMUTIL_TEST_PUBLIC_LIBRARIES} -) - - -# test utf8_test -set(UTF8_TEST_SRC "internal/utf8_test.cc") -set(UTF8_TEST_PUBLIC_LIBRARIES absl::strings absl::base) - -absl_test( - TARGET - utf8_test - SOURCES - ${UTF8_TEST_SRC} - PUBLIC_LIBRARIES - ${UTF8_TEST_PUBLIC_LIBRARIES} -) - - -# test string_view_test -set(STRING_VIEW_TEST_SRC "string_view_test.cc") -set(STRING_VIEW_TEST_PUBLIC_LIBRARIES absl::strings absl_throw_delegate absl::base) - -absl_test( - TARGET - string_view_test - SOURCES - ${STRING_VIEW_TEST_SRC} - PUBLIC_LIBRARIES - ${STRING_VIEW_TEST_PUBLIC_LIBRARIES} -) - - -# test substitute_test -set(SUBSTITUTE_TEST_SRC "substitute_test.cc") -set(SUBSTITUTE_TEST_PUBLIC_LIBRARIES absl::strings absl::base) - -absl_test( - TARGET - substitute_test - SOURCES - ${SUBSTITUTE_TEST_SRC} - PUBLIC_LIBRARIES - ${SUBSTITUTE_TEST_PUBLIC_LIBRARIES} -) - - -# test str_replace_test -set(STR_REPLACE_TEST_SRC "str_replace_test.cc") -set(STR_REPLACE_TEST_PUBLIC_LIBRARIES absl::strings absl::base absl_throw_delegate) - -absl_test( - TARGET - str_replace_test - SOURCES - ${STR_REPLACE_TEST_SRC} - PUBLIC_LIBRARIES - ${STR_REPLACE_TEST_PUBLIC_LIBRARIES} -) - - -# test str_split_test -set(STR_SPLIT_TEST_SRC "str_split_test.cc") -set(STR_SPLIT_TEST_PUBLIC_LIBRARIES absl::strings absl::base absl_throw_delegate) - -absl_test( - TARGET - str_split_test - SOURCES - ${STR_SPLIT_TEST_SRC} - PUBLIC_LIBRARIES - ${STR_SPLIT_TEST_PUBLIC_LIBRARIES} -) - - -# test ostringstream_test -set(OSTRINGSTREAM_TEST_SRC "internal/ostringstream_test.cc") -set(OSTRINGSTREAM_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET - ostringstream_test - SOURCES - ${OSTRINGSTREAM_TEST_SRC} - PUBLIC_LIBRARIES - ${OSTRINGSTREAM_TEST_PUBLIC_LIBRARIES} -) - - -# test resize_uninitialized_test -set(RESIZE_UNINITIALIZED_TEST_SRC "internal/resize_uninitialized_test.cc") - -absl_test( - TARGET - resize_uninitialized_test - SOURCES - ${RESIZE_UNINITIALIZED_TEST_SRC} -) - - -# test str_join_test -set(STR_JOIN_TEST_SRC "str_join_test.cc") -set(STR_JOIN_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET - str_join_test - SOURCES - ${STR_JOIN_TEST_SRC} - PUBLIC_LIBRARIES - ${STR_JOIN_TEST_PUBLIC_LIBRARIES} -) - - -# test str_cat_test -set(STR_CAT_TEST_SRC "str_cat_test.cc") -set(STR_CAT_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET - str_cat_test - SOURCES - ${STR_CAT_TEST_SRC} - PUBLIC_LIBRARIES - ${STR_CAT_TEST_PUBLIC_LIBRARIES} -) - - -# test numbers_test -set(NUMBERS_TEST_SRC "numbers_test.cc") -set(NUMBERS_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET - numbers_test - SOURCES - ${NUMBERS_TEST_SRC} - PUBLIC_LIBRARIES - ${NUMBERS_TEST_PUBLIC_LIBRARIES} -) - - -# test strip_test -set(STRIP_TEST_SRC "strip_test.cc") -set(STRIP_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET - strip_test - SOURCES - ${STRIP_TEST_SRC} - PUBLIC_LIBRARIES - ${STRIP_TEST_PUBLIC_LIBRARIES} -) - - -# test char_map_test -set(CHAR_MAP_TEST_SRC "internal/char_map_test.cc") -set(CHAR_MAP_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET - char_map_test - SOURCES - ${CHAR_MAP_TEST_SRC} - PUBLIC_LIBRARIES - ${CHAR_MAP_TEST_PUBLIC_LIBRARIES} -) - - -# test charconv_test -set(CHARCONV_TEST_SRC "charconv_test.cc") -set(CHARCONV_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET - charconv_test - SOURCES - ${CHARCONV_TEST_SRC} - PUBLIC_LIBRARIES - ${CHARCONV_TEST_PUBLIC_LIBRARIES} -) - - -# test charconv_parse_test -set(CHARCONV_PARSE_TEST_SRC "internal/charconv_parse_test.cc") -set(CHARCONV_PARSE_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET - charconv_parse_test - SOURCES - ${CHARCONV_PARSE_TEST_SRC} - PUBLIC_LIBRARIES - ${CHARCONV_PARSE_TEST_PUBLIC_LIBRARIES} -) - - -# test charconv_bigint_test -set(CHARCONV_BIGINT_TEST_SRC "internal/charconv_bigint_test.cc") -set(CHARCONV_BIGINT_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET - charconv_bigint_test - SOURCES - ${CHARCONV_BIGINT_TEST_SRC} - PUBLIC_LIBRARIES - ${CHARCONV_BIGINT_TEST_PUBLIC_LIBRARIES} -) -# test str_format_test -absl_test( - TARGET +absl_cc_test( + NAME str_format_test - SOURCES + SRCS "str_format_test.cc" - PUBLIC_LIBRARIES - absl::base + COPTS + ${ABSL_TEST_COPTS} + DEPS absl::str_format absl::strings + absl::core_headers + gmock_main ) -# test str_format_bind_test -absl_test( - TARGET - str_format_bind_test - SOURCES - "internal/str_format/bind_test.cc" - PUBLIC_LIBRARIES - str_format_internal -) - -# test str_format_checker_test -absl_test( - TARGET - str_format_checker_test - SOURCES - "internal/str_format/checker_test.cc" - PUBLIC_LIBRARIES +absl_cc_test( + NAME + str_format_extension_test + SRCS + "internal/str_format/extension_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS absl::str_format + absl::str_format_internal + gmock_main ) -# test str_format_convert_test -absl_test( - TARGET +absl_cc_test( + NAME + str_format_arg_test + SRCS + "internal/str_format/arg_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::str_format + absl::str_format_internal + gmock_main +) + +absl_cc_test( + NAME + str_format_bind_test + SRCS + "internal/str_format/bind_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::str_format_internal + gmock_main +) + +absl_cc_test( + NAME + str_format_checker_test + SRCS + "internal/str_format/checker_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::str_format + gmock_main +) + +absl_cc_test( + NAME str_format_convert_test - SOURCES + SRCS "internal/str_format/convert_test.cc" - PUBLIC_LIBRARIES - str_format_internal - absl::numeric + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::str_format_internal + absl::int128 + gmock_main ) -# test str_format_output_test -absl_test( - TARGET +absl_cc_test( + NAME str_format_output_test - SOURCES + SRCS "internal/str_format/output_test.cc" - PUBLIC_LIBRARIES - str_format_extension_internal + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::str_format_internal + gmock_main ) -# test str_format_parser_test -absl_test( - TARGET +absl_cc_test( + NAME str_format_parser_test - SOURCES + SRCS "internal/str_format/parser_test.cc" - PUBLIC_LIBRARIES - str_format_internal - absl::base + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::str_format_internal + absl::core_headers + gmock_main ) +absl_cc_library( + NAME + pow10_helper + HDRS + "internal/pow10_helper.h" + SRCS + "internal/pow10_helper.cc" + TESTONLY +) +absl_cc_test( + NAME + pow10_helper_test + SRCS + "internal/pow10_helper_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::pow10_helper + absl::str_format + gmock_main +)
diff --git a/absl/strings/ascii.cc b/absl/strings/ascii.cc index c9481e8..3f7c581 100644 --- a/absl/strings/ascii.cc +++ b/absl/strings/ascii.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/ascii.h b/absl/strings/ascii.h index 48a9da2..f9e4fd1 100644 --- a/absl/strings/ascii.h +++ b/absl/strings/ascii.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/ascii_benchmark.cc b/absl/strings/ascii_benchmark.cc index 8dea4b8..aca458c 100644 --- a/absl/strings/ascii_benchmark.cc +++ b/absl/strings/ascii_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/ascii_test.cc b/absl/strings/ascii_test.cc index 9903b04..5ecd23f 100644 --- a/absl/strings/ascii_test.cc +++ b/absl/strings/ascii_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/charconv.cc b/absl/strings/charconv.cc index c7b8c98..bc07e7a 100644 --- a/absl/strings/charconv.cc +++ b/absl/strings/charconv.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -551,9 +551,10 @@ int binary_exponent = Power10Exponent(parsed_decimal.exponent); // Discard bits that are inaccurate due to truncation error. The magic - // `mantissa_width` constants below are justified in charconv_algorithm.md. - // They represent the number of bits in `wide_binary_mantissa` that are - // guaranteed to be unaffected by error propagation. + // `mantissa_width` constants below are justified in + // https://abseil.io/about/design/charconv. They represent the number of bits + // in `wide_binary_mantissa` that are guaranteed to be unaffected by error + // propagation. bool mantissa_exact; int mantissa_width; if (parsed_decimal.subrange_begin) {
diff --git a/absl/strings/charconv.h b/absl/strings/charconv.h index 0735382..59f74bf 100644 --- a/absl/strings/charconv.h +++ b/absl/strings/charconv.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/charconv_benchmark.cc b/absl/strings/charconv_benchmark.cc index fd83f44..644b2ab 100644 --- a/absl/strings/charconv_benchmark.cc +++ b/absl/strings/charconv_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/charconv_test.cc b/absl/strings/charconv_test.cc index 89418fe..b58fad2 100644 --- a/absl/strings/charconv_test.cc +++ b/absl/strings/charconv_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -19,7 +19,9 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/strings/internal/pow10_helper.h" #include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" #ifdef _MSC_FULL_VER #define ABSL_COMPILER_DOES_EXACT_ROUNDING 0 @@ -31,6 +33,8 @@ namespace { +using absl::strings_internal::Pow10; + #if ABSL_COMPILER_DOES_EXACT_ROUNDING // Tests that the given string is accepted by absl::from_chars, and that it @@ -275,7 +279,8 @@ absl::from_chars(low_rep.data(), low_rep.data() + low_rep.size(), actual_low); EXPECT_EQ(expected_low, actual_low); - std::string high_rep = absl::StrCat(mantissa, std::string(1000, '0'), "1e", exponent); + std::string high_rep = + absl::StrCat(mantissa, std::string(1000, '0'), "1e", exponent); FloatType actual_high = 0; absl::from_chars(high_rep.data(), high_rep.data() + high_rep.size(), actual_high); @@ -678,7 +683,8 @@ auto result = absl::from_chars(input.data(), input.data() + input.size(), actual); EXPECT_EQ(result.ec, std::errc()); - EXPECT_EQ(expected, actual); + EXPECT_EQ(expected, actual) + << absl::StrFormat("%a vs %a", expected, actual); } // test legal values near upper_bound for (index = upper_bound, step = 1; index > lower_bound; @@ -690,7 +696,8 @@ auto result = absl::from_chars(input.data(), input.data() + input.size(), actual); EXPECT_EQ(result.ec, std::errc()); - EXPECT_EQ(expected, actual); + EXPECT_EQ(expected, actual) + << absl::StrFormat("%a vs %a", expected, actual); } // Test underflow values below lower_bound for (index = lower_bound - 1, step = 1; index > -1000000; @@ -747,7 +754,7 @@ // acceptable exponents in this test. TEST(FromChars, DecimalDoubleLimits) { auto input_gen = [](int index) { return absl::StrCat("1.0e", index); }; - auto expected_gen = [](int index) { return std::pow(10.0, index); }; + auto expected_gen = [](int index) { return Pow10(index); }; TestOverflowAndUnderflow<double>(input_gen, expected_gen, -323, 308); } @@ -759,7 +766,7 @@ // acceptable exponents in this test. TEST(FromChars, DecimalFloatLimits) { auto input_gen = [](int index) { return absl::StrCat("1.0e", index); }; - auto expected_gen = [](int index) { return std::pow(10.0, index); }; + auto expected_gen = [](int index) { return Pow10(index); }; TestOverflowAndUnderflow<float>(input_gen, expected_gen, -45, 38); }
diff --git a/absl/strings/escaping.cc b/absl/strings/escaping.cc index 8d8b00b..bc8307e 100644 --- a/absl/strings/escaping.cc +++ b/absl/strings/escaping.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -179,7 +179,8 @@ ch = (ch << 4) + hex_digit_to_int(*++p); if (ch > 0xFF) { if (error) { - *error = "Value of \\" + std::string(hex_start, p + 1 - hex_start) + + *error = "Value of \\" + + std::string(hex_start, p + 1 - hex_start) + " exceeds 0xff"; } return false; @@ -294,7 +295,7 @@ // ---------------------------------------------------------------------- // CUnescapeInternal() // -// Same as above but uses a C++ string for output. 'source' and 'dest' +// Same as above but uses a std::string for output. 'source' and 'dest' // may be the same. // ---------------------------------------------------------------------- bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped, @@ -324,7 +325,8 @@ // // Escaped chars: \n, \r, \t, ", ', \, and !absl::ascii_isprint(). // ---------------------------------------------------------------------- -std::string CEscapeInternal(absl::string_view src, bool use_hex, bool utf8_safe) { +std::string CEscapeInternal(absl::string_view src, bool use_hex, + bool utf8_safe) { std::string dest; bool last_hex_escape = false; // true if last output char was \xNN. @@ -786,7 +788,7 @@ // Base64 encodes three bytes of input at a time. If the input is not // divisible by three, we pad as appropriate. // - // (from http://tools.ietf.org/html/rfc3548) + // (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 @@ -800,12 +802,12 @@ size_t len = (input_len / 3) * 4; if (input_len % 3 == 0) { - // (from http://tools.ietf.org/html/rfc3548) + // (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 http://tools.ietf.org/html/rfc3548) + // (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 @@ -814,7 +816,7 @@ len += 2; } } else { // (input_len % 3 == 2) - // (from http://tools.ietf.org/html/rfc3548) + // (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. @@ -843,8 +845,8 @@ // Three bytes of data encodes to four characters of cyphertext. // So we can pump through three-byte chunks atomically. - if (szsrc >= 3) { // "limit_src - 3" is UB if szsrc < 3 - while (cur_src < limit_src - 3) { // as long as we have >= 32 bits + 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]; @@ -1011,7 +1013,8 @@ } } -// This is a templated function so that T can be either a char* or a string. +// This is a templated function so that T can be either a char* or a +// std::string. template <typename T> void BytesToHexStringInternal(const unsigned char* src, T dest, ptrdiff_t num) { auto dest_ptr = &dest[0]; @@ -1028,7 +1031,8 @@ // // See CUnescapeInternal() for implementation details. // ---------------------------------------------------------------------- -bool CUnescape(absl::string_view source, std::string* dest, std::string* error) { +bool CUnescape(absl::string_view source, std::string* dest, + std::string* error) { return CUnescapeInternal(source, kUnescapeNulls, dest, error); }
diff --git a/absl/strings/escaping.h b/absl/strings/escaping.h index 2965973..fd9be78 100644 --- a/absl/strings/escaping.h +++ b/absl/strings/escaping.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -19,7 +19,6 @@ // // This header file contains string utilities involved in escaping and // unescaping strings in various ways. -// #ifndef ABSL_STRINGS_ESCAPING_H_ #define ABSL_STRINGS_ESCAPING_H_ @@ -38,7 +37,7 @@ // CUnescape() // // Unescapes a `source` string and copies it into `dest`, rewriting C-style -// escape sequences (http://en.cppreference.com/w/cpp/language/escape) into +// escape sequences (https://en.cppreference.com/w/cpp/language/escape) into // their proper code point equivalents, returning `true` if successful. // // The following unescape sequences can be handled: @@ -56,7 +55,6 @@ // UTF-8. (E.g., `\u2019` unescapes to the three bytes 0xE2, 0x80, and // 0x99). // -// // If any errors are encountered, this function returns `false`, leaving the // `dest` output parameter in an unspecified state, and stores the first // encountered error in `error`. To disable error reporting, set `error` to @@ -80,7 +78,7 @@ // CEscape() // // Escapes a 'src' string using C-style escapes sequences -// (http://en.cppreference.com/w/cpp/language/escape), escaping other +// (https://en.cppreference.com/w/cpp/language/escape), escaping other // non-printable/non-whitespace bytes as octal sequences (e.g. "\377"). // // Example:
diff --git a/absl/strings/escaping_benchmark.cc b/absl/strings/escaping_benchmark.cc index 0f791f4..10d5b03 100644 --- a/absl/strings/escaping_benchmark.cc +++ b/absl/strings/escaping_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/escaping_test.cc b/absl/strings/escaping_test.cc index 9dc27f3..d433b4c 100644 --- a/absl/strings/escaping_test.cc +++ b/absl/strings/escaping_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -36,18 +36,19 @@ TEST(CEscape, EscapeAndUnescape) { const std::string inputs[] = { - std::string("foo\nxx\r\b\0023"), - std::string(""), - std::string("abc"), - std::string("\1chad_rules"), - std::string("\1arnar_drools"), - std::string("xxxx\r\t'\"\\"), - std::string("\0xx\0", 4), - std::string("\x01\x31"), - std::string("abc\xb\x42\141bc"), - std::string("123\1\x31\x32\x33"), - std::string("\xc1\xca\x1b\x62\x19o\xcc\x04"), - std::string("\\\"\xe8\xb0\xb7\xe6\xad\x8c\\\" is Google\\\'s Chinese name"), + std::string("foo\nxx\r\b\0023"), + std::string(""), + std::string("abc"), + std::string("\1chad_rules"), + std::string("\1arnar_drools"), + std::string("xxxx\r\t'\"\\"), + std::string("\0xx\0", 4), + std::string("\x01\x31"), + std::string("abc\xb\x42\141bc"), + std::string("123\1\x31\x32\x33"), + std::string("\xc1\xca\x1b\x62\x19o\xcc\x04"), + std::string( + "\\\"\xe8\xb0\xb7\xe6\xad\x8c\\\" is Google\\\'s Chinese name"), }; // Do this twice, once for octal escapes and once for hex escapes. for (int kind = 0; kind < 4; kind++) { @@ -159,15 +160,14 @@ EXPECT_TRUE(absl::CUnescape(val.escaped, &out)); EXPECT_EQ(out, val.unescaped); } - std::string bad[] = - {"\\u1", // too short - "\\U1", // too short - "\\Uffffff", // exceeds 0x10ffff (largest Unicode) - "\\U00110000", // exceeds 0x10ffff (largest Unicode) - "\\uD835", // surrogate character (D800-DFFF) - "\\U0000DD04", // surrogate character (D800-DFFF) - "\\777", // exceeds 0xff - "\\xABCD"}; // exceeds 0xff + std::string bad[] = {"\\u1", // too short + "\\U1", // too short + "\\Uffffff", // exceeds 0x10ffff (largest Unicode) + "\\U00110000", // exceeds 0x10ffff (largest Unicode) + "\\uD835", // surrogate character (D800-DFFF) + "\\U0000DD04", // surrogate character (D800-DFFF) + "\\777", // exceeds 0xff + "\\xABCD"}; // exceeds 0xff for (const std::string& e : bad) { std::string error; std::string out; @@ -258,9 +258,11 @@ // All escapes, including newlines and null escapes, should have been // converted to the equivalent characters. EXPECT_EQ(std::string("\0\n" - "0\n" - "\0\n" - "\0", 7), result_string_); + "0\n" + "\0\n" + "\0", + 7), + result_string_); } @@ -268,17 +270,21 @@ std::string original_string(kStringWithMultipleHexNulls); EXPECT_TRUE(absl::CUnescape(original_string, &result_string_)); EXPECT_EQ(std::string("\0\n" - "0\n" - "\0\n" - "\0", 7), result_string_); + "0\n" + "\0\n" + "\0", + 7), + result_string_); } TEST_F(CUnescapeTest, UnescapesMultipleUnicodeNulls) { std::string original_string(kStringWithMultipleUnicodeNulls); EXPECT_TRUE(absl::CUnescape(original_string, &result_string_)); EXPECT_EQ(std::string("\0\n" - "0\n" - "\0", 5), result_string_); + "0\n" + "\0", + 5), + result_string_); } static struct {
diff --git a/absl/strings/internal/char_map.h b/absl/strings/internal/char_map.h index 8d92963..b9108b8 100644 --- a/absl/strings/internal/char_map.h +++ b/absl/strings/internal/char_map.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/char_map_benchmark.cc b/absl/strings/internal/char_map_benchmark.cc index c45f315..5cef967 100644 --- a/absl/strings/internal/char_map_benchmark.cc +++ b/absl/strings/internal/char_map_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/char_map_test.cc b/absl/strings/internal/char_map_test.cc index c3601e1..d330624 100644 --- a/absl/strings/internal/char_map_test.cc +++ b/absl/strings/internal/char_map_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/charconv_bigint.cc b/absl/strings/internal/charconv_bigint.cc index 3e7296e..95d471d 100644 --- a/absl/strings/internal/charconv_bigint.cc +++ b/absl/strings/internal/charconv_bigint.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/charconv_bigint.h b/absl/strings/internal/charconv_bigint.h index aa70af2..7da9a7e 100644 --- a/absl/strings/internal/charconv_bigint.h +++ b/absl/strings/internal/charconv_bigint.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -57,17 +57,10 @@ "unsupported max_words value"); BigUnsigned() : size_(0), words_{} {} - explicit BigUnsigned(uint32_t v) : size_(v > 0 ? 1 : 0), words_{v} {} - explicit BigUnsigned(uint64_t v) - : size_(0), - words_{static_cast<uint32_t>(v & 0xffffffff), - static_cast<uint32_t>(v >> 32)} { - if (words_[1]) { - size_ = 2; - } else if (words_[0]) { - size_ = 1; - } - } + explicit constexpr BigUnsigned(uint64_t v) + : size_((v >> 32) ? 2 : v ? 1 : 0), + words_{static_cast<uint32_t>(v & 0xffffffffu), + 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 @@ -110,12 +103,12 @@ SetToZero(); return; } - size_ = std::min(size_ + word_shift, max_words); + size_ = (std::min)(size_ + word_shift, max_words); count %= 32; if (count == 0) { std::copy_backward(words_, words_ + size_ - word_shift, words_ + size_); } else { - for (int i = std::min(size_, max_words - 1); i > word_shift; --i) { + for (int i = (std::min)(size_, max_words - 1); i > word_shift; --i) { words_[i] = (words_[i - word_shift] << count) | (words_[i - word_shift - 1] >> (32 - count)); } @@ -274,7 +267,7 @@ void MultiplyBy(int other_size, const uint32_t* other_words) { const int original_size = size_; const int first_step = - std::min(original_size + other_size - 2, max_words - 1); + (std::min)(original_size + other_size - 2, max_words - 1); for (int step = first_step; step >= 0; --step) { MultiplyStep(original_size, other_words, other_size, step); } @@ -293,7 +286,7 @@ value = 0; } } - size_ = std::min(max_words, std::max(index + 1, size_)); + size_ = (std::min)(max_words, (std::max)(index + 1, size_)); } } @@ -316,7 +309,7 @@ } else { // Normally 32-bit AddWithCarry() sets size_, but since we don't call // it when `high` is 0, do it ourselves here. - size_ = std::min(max_words, std::max(index + 1, size_)); + size_ = (std::min)(max_words, (std::max)(index + 1, size_)); } } } @@ -355,7 +348,7 @@ // Returns -1 if lhs < rhs, 0 if lhs == rhs, and 1 if lhs > rhs. template <int N, int M> int Compare(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { - int limit = std::max(lhs.size(), rhs.size()); + int limit = (std::max)(lhs.size(), rhs.size()); for (int i = limit - 1; i >= 0; --i) { const uint32_t lhs_word = lhs.GetWord(i); const uint32_t rhs_word = rhs.GetWord(i); @@ -370,7 +363,7 @@ template <int N, int M> bool operator==(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { - int limit = std::max(lhs.size(), rhs.size()); + int limit = (std::max)(lhs.size(), rhs.size()); for (int i = 0; i < limit; ++i) { if (lhs.GetWord(i) != rhs.GetWord(i)) { return false;
diff --git a/absl/strings/internal/charconv_bigint_test.cc b/absl/strings/internal/charconv_bigint_test.cc index 9b63578..745714a 100644 --- a/absl/strings/internal/charconv_bigint_test.cc +++ b/absl/strings/internal/charconv_bigint_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/charconv_parse.cc b/absl/strings/internal/charconv_parse.cc index 7e4dabc..f3c7232 100644 --- a/absl/strings/internal/charconv_parse.cc +++ b/absl/strings/internal/charconv_parse.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/charconv_parse.h b/absl/strings/internal/charconv_parse.h index 7a5c087..44d06b2 100644 --- a/absl/strings/internal/charconv_parse.h +++ b/absl/strings/internal/charconv_parse.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/charconv_parse_test.cc b/absl/strings/internal/charconv_parse_test.cc index f48b9ae..9511c98 100644 --- a/absl/strings/internal/charconv_parse_test.cc +++ b/absl/strings/internal/charconv_parse_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/escaping_test_common.h b/absl/strings/internal/escaping_test_common.h index cc41f43..bd80303 100644 --- a/absl/strings/internal/escaping_test_common.h +++ b/absl/strings/internal/escaping_test_common.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/memutil.cc b/absl/strings/internal/memutil.cc index a0de70d..77aa63c 100644 --- a/absl/strings/internal/memutil.cc +++ b/absl/strings/internal/memutil.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/memutil.h b/absl/strings/internal/memutil.h index 7de383b..7c071a8 100644 --- a/absl/strings/internal/memutil.h +++ b/absl/strings/internal/memutil.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/memutil_benchmark.cc b/absl/strings/internal/memutil_benchmark.cc index 77915ad..dc95c3e 100644 --- a/absl/strings/internal/memutil_benchmark.cc +++ b/absl/strings/internal/memutil_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/memutil_test.cc b/absl/strings/internal/memutil_test.cc index 09424de..d8681dd 100644 --- a/absl/strings/internal/memutil_test.cc +++ b/absl/strings/internal/memutil_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/numbers_test_common.h b/absl/strings/internal/numbers_test_common.h index 20e3af5..2824720 100644 --- a/absl/strings/internal/numbers_test_common.h +++ b/absl/strings/internal/numbers_test_common.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -64,11 +64,11 @@ inline const std::array<uint32_test_case, 27>& strtouint32_test_cases() { static const std::array<uint32_test_case, 27> test_cases{{ - {"0xffffffff", true, 16, std::numeric_limits<uint32_t>::max()}, + {"0xffffffff", true, 16, (std::numeric_limits<uint32_t>::max)()}, {"0x34234324", true, 16, 0x34234324}, {"34234324", true, 16, 0x34234324}, {"0", true, 16, 0}, - {" \t\n 0xffffffff", true, 16, std::numeric_limits<uint32_t>::max()}, + {" \t\n 0xffffffff", true, 16, (std::numeric_limits<uint32_t>::max)()}, {" \f\v 46", true, 10, 46}, // must accept weird whitespace {" \t\n 72717222", true, 8, 072717222}, {" \t\n 072717222", true, 8, 072717222}, @@ -77,7 +77,7 @@ // Base-10 version. {"34234324", true, 0, 34234324}, - {"4294967295", true, 0, std::numeric_limits<uint32_t>::max()}, + {"4294967295", true, 0, (std::numeric_limits<uint32_t>::max)()}, {"34234324 \n\t", true, 10, 34234324}, // Unusual base @@ -96,8 +96,8 @@ {" \t\n -123", false, 0, 0}, // Out of bounds. - {"4294967296", false, 0, std::numeric_limits<uint32_t>::max()}, - {"0x100000000", false, 0, std::numeric_limits<uint32_t>::max()}, + {"4294967296", false, 0, (std::numeric_limits<uint32_t>::max)()}, + {"0x100000000", false, 0, (std::numeric_limits<uint32_t>::max)()}, {nullptr, false, 0, 0}, }}; return test_cases; @@ -119,7 +119,7 @@ {"000", true, 0, 0}, {"0", true, 0, 0}, {" \t\n 0xffffffffffffffff", true, 16, - std::numeric_limits<uint64_t>::max()}, + (std::numeric_limits<uint64_t>::max)()}, {"012345670123456701234", true, 8, int64_t{012345670123456701234}}, {"12345670123456701234", true, 8, int64_t{012345670123456701234}}, @@ -130,7 +130,7 @@ {"34234324487834466", true, 0, int64_t{34234324487834466}}, {" \t\n 18446744073709551615", true, 0, - std::numeric_limits<uint64_t>::max()}, + (std::numeric_limits<uint64_t>::max)()}, {"34234324487834466 \n\t ", true, 0, int64_t{34234324487834466}}, @@ -156,12 +156,13 @@ // Out of bounds. {"18446744073709551616", false, 10, 0}, {"18446744073709551616", false, 0, 0}, - {"0x10000000000000000", false, 16, std::numeric_limits<uint64_t>::max()}, + {"0x10000000000000000", false, 16, + (std::numeric_limits<uint64_t>::max)()}, {"0X10000000000000000", false, 16, - std::numeric_limits<uint64_t>::max()}, // 0X versus 0x. - {"0x10000000000000000", false, 0, std::numeric_limits<uint64_t>::max()}, + (std::numeric_limits<uint64_t>::max)()}, // 0X versus 0x. + {"0x10000000000000000", false, 0, (std::numeric_limits<uint64_t>::max)()}, {"0X10000000000000000", false, 0, - std::numeric_limits<uint64_t>::max()}, // 0X versus 0x. + (std::numeric_limits<uint64_t>::max)()}, // 0X versus 0x. {"0x1234", true, 16, 0x1234},
diff --git a/absl/strings/internal/ostringstream.cc b/absl/strings/internal/ostringstream.cc index 6ee2b10..d0f0f84 100644 --- a/absl/strings/internal/ostringstream.cc +++ b/absl/strings/internal/ostringstream.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/ostringstream.h b/absl/strings/internal/ostringstream.h index e81a89a..2079201 100644 --- a/absl/strings/internal/ostringstream.h +++ b/absl/strings/internal/ostringstream.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -25,18 +25,18 @@ namespace absl { namespace strings_internal { -// The same as std::ostringstream but appends to a user-specified string, +// The same as std::ostringstream but appends to a user-specified std::string, // and is faster. It is ~70% faster to create, ~50% faster to write to, and -// completely free to extract the result string. +// completely free to extract the result std::string. // -// string s; +// std::string s; // OStringStream strm(&s); // strm << 42 << ' ' << 3.14; // appends to `s` // // The stream object doesn't have to be named. Starting from C++11 operator<< // works with rvalues of std::ostream. // -// string s; +// std::string s; // OStringStream(&s) << 42 << ' ' << 3.14; // appends to `s` // // OStringStream is faster to create than std::ostringstream but it's still @@ -45,14 +45,14 @@ // // Creates unnecessary instances of OStringStream: slow. // -// string s; +// std::string s; // OStringStream(&s) << 42; // OStringStream(&s) << ' '; // OStringStream(&s) << 3.14; // // Creates a single instance of OStringStream and reuses it: fast. // -// string s; +// std::string s; // OStringStream strm(&s); // strm << 42; // strm << ' '; @@ -64,8 +64,8 @@ // The argument can be null, in which case you'll need to call str(p) with a // non-null argument before you can write to the stream. // - // The destructor of OStringStream doesn't use the std::string. It's OK to destroy - // the std::string before the stream. + // The destructor of OStringStream doesn't use the std::string. It's OK to + // destroy the std::string before the stream. explicit OStringStream(std::string* s) : std::ostream(this), s_(s) {} std::string* str() { return s_; }
diff --git a/absl/strings/internal/ostringstream_benchmark.cc b/absl/strings/internal/ostringstream_benchmark.cc index c93f969..5979f18 100644 --- a/absl/strings/internal/ostringstream_benchmark.cc +++ b/absl/strings/internal/ostringstream_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/ostringstream_test.cc b/absl/strings/internal/ostringstream_test.cc index 069a0e1..2879e50 100644 --- a/absl/strings/internal/ostringstream_test.cc +++ b/absl/strings/internal/ostringstream_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/pow10_helper.cc b/absl/strings/internal/pow10_helper.cc new file mode 100644 index 0000000..03ed8d0 --- /dev/null +++ b/absl/strings/internal/pow10_helper.cc
@@ -0,0 +1,120 @@ +// 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/strings/internal/pow10_helper.h" + +#include <cmath> + +namespace absl { +namespace strings_internal { + +namespace { + +// The exact value of 1e23 falls precisely halfway between two representable +// doubles. Furthermore, the rounding rules we prefer (break ties by rounding +// to the nearest even) dictate in this case that the number should be rounded +// down, but this is not completely specified for floating-point literals in +// C++. (It just says to use the default rounding mode of the standard +// library.) We ensure the result we want by using a number that has an +// unambiguous correctly rounded answer. +constexpr double k1e23 = 9999999999999999e7; + +constexpr double kPowersOfTen[] = { + 0.0, 1e-323, 1e-322, 1e-321, 1e-320, 1e-319, 1e-318, 1e-317, 1e-316, + 1e-315, 1e-314, 1e-313, 1e-312, 1e-311, 1e-310, 1e-309, 1e-308, 1e-307, + 1e-306, 1e-305, 1e-304, 1e-303, 1e-302, 1e-301, 1e-300, 1e-299, 1e-298, + 1e-297, 1e-296, 1e-295, 1e-294, 1e-293, 1e-292, 1e-291, 1e-290, 1e-289, + 1e-288, 1e-287, 1e-286, 1e-285, 1e-284, 1e-283, 1e-282, 1e-281, 1e-280, + 1e-279, 1e-278, 1e-277, 1e-276, 1e-275, 1e-274, 1e-273, 1e-272, 1e-271, + 1e-270, 1e-269, 1e-268, 1e-267, 1e-266, 1e-265, 1e-264, 1e-263, 1e-262, + 1e-261, 1e-260, 1e-259, 1e-258, 1e-257, 1e-256, 1e-255, 1e-254, 1e-253, + 1e-252, 1e-251, 1e-250, 1e-249, 1e-248, 1e-247, 1e-246, 1e-245, 1e-244, + 1e-243, 1e-242, 1e-241, 1e-240, 1e-239, 1e-238, 1e-237, 1e-236, 1e-235, + 1e-234, 1e-233, 1e-232, 1e-231, 1e-230, 1e-229, 1e-228, 1e-227, 1e-226, + 1e-225, 1e-224, 1e-223, 1e-222, 1e-221, 1e-220, 1e-219, 1e-218, 1e-217, + 1e-216, 1e-215, 1e-214, 1e-213, 1e-212, 1e-211, 1e-210, 1e-209, 1e-208, + 1e-207, 1e-206, 1e-205, 1e-204, 1e-203, 1e-202, 1e-201, 1e-200, 1e-199, + 1e-198, 1e-197, 1e-196, 1e-195, 1e-194, 1e-193, 1e-192, 1e-191, 1e-190, + 1e-189, 1e-188, 1e-187, 1e-186, 1e-185, 1e-184, 1e-183, 1e-182, 1e-181, + 1e-180, 1e-179, 1e-178, 1e-177, 1e-176, 1e-175, 1e-174, 1e-173, 1e-172, + 1e-171, 1e-170, 1e-169, 1e-168, 1e-167, 1e-166, 1e-165, 1e-164, 1e-163, + 1e-162, 1e-161, 1e-160, 1e-159, 1e-158, 1e-157, 1e-156, 1e-155, 1e-154, + 1e-153, 1e-152, 1e-151, 1e-150, 1e-149, 1e-148, 1e-147, 1e-146, 1e-145, + 1e-144, 1e-143, 1e-142, 1e-141, 1e-140, 1e-139, 1e-138, 1e-137, 1e-136, + 1e-135, 1e-134, 1e-133, 1e-132, 1e-131, 1e-130, 1e-129, 1e-128, 1e-127, + 1e-126, 1e-125, 1e-124, 1e-123, 1e-122, 1e-121, 1e-120, 1e-119, 1e-118, + 1e-117, 1e-116, 1e-115, 1e-114, 1e-113, 1e-112, 1e-111, 1e-110, 1e-109, + 1e-108, 1e-107, 1e-106, 1e-105, 1e-104, 1e-103, 1e-102, 1e-101, 1e-100, + 1e-99, 1e-98, 1e-97, 1e-96, 1e-95, 1e-94, 1e-93, 1e-92, 1e-91, + 1e-90, 1e-89, 1e-88, 1e-87, 1e-86, 1e-85, 1e-84, 1e-83, 1e-82, + 1e-81, 1e-80, 1e-79, 1e-78, 1e-77, 1e-76, 1e-75, 1e-74, 1e-73, + 1e-72, 1e-71, 1e-70, 1e-69, 1e-68, 1e-67, 1e-66, 1e-65, 1e-64, + 1e-63, 1e-62, 1e-61, 1e-60, 1e-59, 1e-58, 1e-57, 1e-56, 1e-55, + 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49, 1e-48, 1e-47, 1e-46, + 1e-45, 1e-44, 1e-43, 1e-42, 1e-41, 1e-40, 1e-39, 1e-38, 1e-37, + 1e-36, 1e-35, 1e-34, 1e-33, 1e-32, 1e-31, 1e-30, 1e-29, 1e-28, + 1e-27, 1e-26, 1e-25, 1e-24, 1e-23, 1e-22, 1e-21, 1e-20, 1e-19, + 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, + 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, + 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, + 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, + 1e+18, 1e+19, 1e+20, 1e+21, 1e+22, k1e23, 1e+24, 1e+25, 1e+26, + 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, + 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 1e+41, 1e+42, 1e+43, 1e+44, + 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, + 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 1e+61, 1e+62, + 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, + 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, + 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, + 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, + 1e+99, 1e+100, 1e+101, 1e+102, 1e+103, 1e+104, 1e+105, 1e+106, 1e+107, + 1e+108, 1e+109, 1e+110, 1e+111, 1e+112, 1e+113, 1e+114, 1e+115, 1e+116, + 1e+117, 1e+118, 1e+119, 1e+120, 1e+121, 1e+122, 1e+123, 1e+124, 1e+125, + 1e+126, 1e+127, 1e+128, 1e+129, 1e+130, 1e+131, 1e+132, 1e+133, 1e+134, + 1e+135, 1e+136, 1e+137, 1e+138, 1e+139, 1e+140, 1e+141, 1e+142, 1e+143, + 1e+144, 1e+145, 1e+146, 1e+147, 1e+148, 1e+149, 1e+150, 1e+151, 1e+152, + 1e+153, 1e+154, 1e+155, 1e+156, 1e+157, 1e+158, 1e+159, 1e+160, 1e+161, + 1e+162, 1e+163, 1e+164, 1e+165, 1e+166, 1e+167, 1e+168, 1e+169, 1e+170, + 1e+171, 1e+172, 1e+173, 1e+174, 1e+175, 1e+176, 1e+177, 1e+178, 1e+179, + 1e+180, 1e+181, 1e+182, 1e+183, 1e+184, 1e+185, 1e+186, 1e+187, 1e+188, + 1e+189, 1e+190, 1e+191, 1e+192, 1e+193, 1e+194, 1e+195, 1e+196, 1e+197, + 1e+198, 1e+199, 1e+200, 1e+201, 1e+202, 1e+203, 1e+204, 1e+205, 1e+206, + 1e+207, 1e+208, 1e+209, 1e+210, 1e+211, 1e+212, 1e+213, 1e+214, 1e+215, + 1e+216, 1e+217, 1e+218, 1e+219, 1e+220, 1e+221, 1e+222, 1e+223, 1e+224, + 1e+225, 1e+226, 1e+227, 1e+228, 1e+229, 1e+230, 1e+231, 1e+232, 1e+233, + 1e+234, 1e+235, 1e+236, 1e+237, 1e+238, 1e+239, 1e+240, 1e+241, 1e+242, + 1e+243, 1e+244, 1e+245, 1e+246, 1e+247, 1e+248, 1e+249, 1e+250, 1e+251, + 1e+252, 1e+253, 1e+254, 1e+255, 1e+256, 1e+257, 1e+258, 1e+259, 1e+260, + 1e+261, 1e+262, 1e+263, 1e+264, 1e+265, 1e+266, 1e+267, 1e+268, 1e+269, + 1e+270, 1e+271, 1e+272, 1e+273, 1e+274, 1e+275, 1e+276, 1e+277, 1e+278, + 1e+279, 1e+280, 1e+281, 1e+282, 1e+283, 1e+284, 1e+285, 1e+286, 1e+287, + 1e+288, 1e+289, 1e+290, 1e+291, 1e+292, 1e+293, 1e+294, 1e+295, 1e+296, + 1e+297, 1e+298, 1e+299, 1e+300, 1e+301, 1e+302, 1e+303, 1e+304, 1e+305, + 1e+306, 1e+307, 1e+308, +}; + +} // namespace + +double Pow10(int exp) { + if (exp < -324) { + return 0.0; + } else if (exp > 308) { + return INFINITY; + } else { + return kPowersOfTen[exp + 324]; + } +} + +} // namespace strings_internal +} // namespace absl
diff --git a/absl/strings/internal/pow10_helper.h b/absl/strings/internal/pow10_helper.h new file mode 100644 index 0000000..9d1aa71 --- /dev/null +++ b/absl/strings/internal/pow10_helper.h
@@ -0,0 +1,36 @@ +// +// 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. +// +// This test helper library contains a table of powers of 10, to guarantee +// precise values are computed across the full range of doubles. We can't rely +// on the pow() function, because not all standard libraries ship a version +// that is precise. +#ifndef ABSL_STRINGS_INTERNAL_POW10_HELPER_H_ +#define ABSL_STRINGS_INTERNAL_POW10_HELPER_H_ + +#include <vector> + +namespace absl { +namespace strings_internal { + +// Computes the precise value of 10^exp. (I.e. the nearest representable +// double to the exact value, rounding to nearest-even in the (single) case of +// being exactly halfway between.) +double Pow10(int exp); + +} // namespace strings_internal +} // namespace absl + +#endif // ABSL_STRINGS_INTERNAL_POW10_HELPER_H_
diff --git a/absl/strings/internal/pow10_helper_test.cc b/absl/strings/internal/pow10_helper_test.cc new file mode 100644 index 0000000..a4a68b5 --- /dev/null +++ b/absl/strings/internal/pow10_helper_test.cc
@@ -0,0 +1,120 @@ +// 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/strings/internal/pow10_helper.h" + +#include <cmath> + +#include "gtest/gtest.h" +#include "absl/strings/str_format.h" + +namespace absl { +namespace strings_internal { + +namespace { + +struct TestCase { + int power; // Testing Pow10(power) + uint64_t significand; // Raw bits of the expected value + int radix; // significand is adjusted by 2^radix +}; + +TEST(Pow10HelperTest, Works) { + // The logic in pow10_helper.cc is so simple that theoretically we don't even + // need a test. However, we're paranoid and believe that there may be + // compilers that don't round floating-point literals correctly, even though + // it is specified by the standard. We check various edge cases, just to be + // sure. + constexpr TestCase kTestCases[] = { + // Subnormals + {-323, 0x2, -1074}, + {-322, 0x14, -1074}, + {-321, 0xca, -1074}, + {-320, 0x7e8, -1074}, + {-319, 0x4f10, -1074}, + {-318, 0x316a2, -1074}, + {-317, 0x1ee257, -1074}, + {-316, 0x134d761, -1074}, + {-315, 0xc1069cd, -1074}, + {-314, 0x78a42205, -1074}, + {-313, 0x4b6695433, -1074}, + {-312, 0x2f201d49fb, -1074}, + {-311, 0x1d74124e3d1, -1074}, + {-310, 0x12688b70e62b, -1074}, + {-309, 0xb8157268fdaf, -1074}, + {-308, 0x730d67819e8d2, -1074}, + // Values that are very close to rounding the other way. + // Comment shows difference of significand from the true value. + {-307, 0x11fa182c40c60d, -1072}, // -.4588 + {-290, 0x18f2b061aea072, -1016}, // .4854 + {-276, 0x11BA03F5B21000, -969}, // .4709 + {-259, 0x1899C2F6732210, -913}, // .4830 + {-252, 0x1D53844EE47DD1, -890}, // -.4743 + {-227, 0x1E5297287C2F45, -807}, // -.4708 + {-198, 0x1322E220A5B17E, -710}, // -.4714 + {-195, 0x12B010D3E1CF56, -700}, // .4928 + {-192, 0x123FF06EEA847A, -690}, // .4968 + {-163, 0x1708D0F84D3DE7, -594}, // -.4977 + {-145, 0x13FAAC3E3FA1F3, -534}, // -.4785 + {-111, 0x133D4032C2C7F5, -421}, // .4774 + {-106, 0x1D5B561574765B, -405}, // -.4869 + {-104, 0x16EF5B40C2FC77, -398}, // -.4741 + {-88, 0x197683DF2F268D, -345}, // -.4738 + {-86, 0x13E497065CD61F, -338}, // .4736 + {-76, 0x17288E1271F513, -305}, // -.4761 + {-63, 0x1A53FC9631D10D, -262}, // .4929 + {-30, 0x14484BFEEBC2A0, -152}, // .4758 + {-21, 0x12E3B40A0E9B4F, -122}, // -.4916 + {-5, 0x14F8B588E368F1, -69}, // .4829 + {23, 0x152D02C7E14AF6, 24}, // -.5000 (exactly, round-to-even) + {29, 0x1431E0FAE6D721, 44}, // -.4870 + {34, 0x1ED09BEAD87C03, 60}, // -.4721 + {70, 0x172EBAD6DDC73D, 180}, // .4733 + {105, 0x1BE7ABD3781ECA, 296}, // -.4850 + {126, 0x17A2ECC414A03F, 366}, // -.4999 + {130, 0x1CDA62055B2D9E, 379}, // .4855 + {165, 0x115D847AD00087, 496}, // -.4913 + {172, 0x14B378469B6732, 519}, // .4818 + {187, 0x1262DFEEBBB0F9, 569}, // -.4805 + {210, 0x18557F31326BBB, 645}, // -.4992 + {212, 0x1302CB5E6F642A, 652}, // -.4838 + {215, 0x1290BA9A38C7D1, 662}, // -.4881 + {236, 0x1F736F9B3494E9, 731}, // .4707 + {244, 0x176EC98994F489, 758}, // .4924 + {250, 0x1658E3AB795204, 778}, // -.4963 + {252, 0x117571DDF6C814, 785}, // .4873 + {254, 0x1B4781EAD1989E, 791}, // -.4887 + {260, 0x1A03FDE214CAF1, 811}, // .4784 + {284, 0x1585041B2C477F, 891}, // .4798 + {304, 0x1D2A1BE4048F90, 957}, // -.4987 + // Out-of-range values + {-324, 0x0, 0}, + {-325, 0x0, 0}, + {-326, 0x0, 0}, + {309, 1, 2000}, + {310, 1, 2000}, + {311, 1, 2000}, + }; + for (const TestCase& test_case : kTestCases) { + EXPECT_EQ(Pow10(test_case.power), + std::ldexp(test_case.significand, test_case.radix)) + << absl::StrFormat("Failure for Pow10(%d): %a vs %a", test_case.power, + Pow10(test_case.power), + std::ldexp(test_case.significand, test_case.radix)); + } +} + +} // namespace +} // namespace strings_internal +} // namespace absl
diff --git a/absl/strings/internal/resize_uninitialized.h b/absl/strings/internal/resize_uninitialized.h index a94e054..469962b 100644 --- a/absl/strings/internal/resize_uninitialized.h +++ b/absl/strings/internal/resize_uninitialized.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -18,6 +18,7 @@ #define ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ #include <string> +#include <type_traits> #include <utility> #include "absl/base/port.h" @@ -27,40 +28,42 @@ namespace strings_internal { // Is a subclass of true_type or false_type, depending on whether or not -// T has a resize_uninitialized member. -template <typename T, typename = void> -struct HasResizeUninitialized : std::false_type {}; -template <typename T> -struct HasResizeUninitialized< - T, absl::void_t<decltype(std::declval<T>().resize_uninitialized(237))>> - : std::true_type {}; +// T has a __resize_default_init member. +template <typename string_type, typename = void> +struct ResizeUninitializedTraits { + using HasMember = std::false_type; + 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. template <typename string_type> -void ResizeUninit(string_type* s, size_t new_size, std::true_type) { - s->resize_uninitialized(new_size); -} -template <typename string_type> -void ResizeUninit(string_type* s, size_t new_size, std::false_type) { - s->resize(new_size); -} +struct ResizeUninitializedTraits< + string_type, absl::void_t<decltype(std::declval<string_type&>() + .__resize_default_init(237))> > { + using HasMember = std::true_type; + static void Resize(string_type* s, size_t new_size) { + s->__resize_default_init(new_size); + } +}; -// Returns true if the string implementation supports a resize where -// the new characters added to the string are left untouched. +// Returns true if the std::string implementation supports a resize where +// the new characters added to the std::string are left untouched. // // (A better name might be "STLStringSupportsUninitializedResize", alluding to // the previous function.) template <typename string_type> inline constexpr bool STLStringSupportsNontrashingResize(string_type*) { - return HasResizeUninitialized<string_type>(); + return ResizeUninitializedTraits<string_type>::HasMember::value; } // Like str->resize(new_size), except any new characters added to "*str" as a // result of resizing may be left uninitialized, rather than being filled with // '0' bytes. Typically used when code is then going to overwrite the backing -// store of the string with known data. Uses a Google extension to ::string. +// store of the std::string with known data. template <typename string_type, typename = void> inline void STLStringResizeUninitialized(string_type* s, size_t new_size) { - ResizeUninit(s, new_size, HasResizeUninitialized<string_type>()); + ResizeUninitializedTraits<string_type>::Resize(s, new_size); } } // namespace strings_internal
diff --git a/absl/strings/internal/resize_uninitialized_test.cc b/absl/strings/internal/resize_uninitialized_test.cc index ad282ef..c5be0b1 100644 --- a/absl/strings/internal/resize_uninitialized_test.cc +++ b/absl/strings/internal/resize_uninitialized_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -24,44 +24,44 @@ void resize(size_t) { resize_call_count += 1; } }; -int resize_uninitialized_call_count = 0; +int resize_default_init_call_count = 0; -struct resize_uninitializable_string { +struct resize_default_init_string { void resize(size_t) { resize_call_count += 1; } - void resize_uninitialized(size_t) { resize_uninitialized_call_count += 1; } + void __resize_default_init(size_t) { resize_default_init_call_count += 1; } }; TEST(ResizeUninit, WithAndWithout) { resize_call_count = 0; - resize_uninitialized_call_count = 0; + resize_default_init_call_count = 0; { resizable_string rs; EXPECT_EQ(resize_call_count, 0); - EXPECT_EQ(resize_uninitialized_call_count, 0); + EXPECT_EQ(resize_default_init_call_count, 0); EXPECT_FALSE( absl::strings_internal::STLStringSupportsNontrashingResize(&rs)); EXPECT_EQ(resize_call_count, 0); - EXPECT_EQ(resize_uninitialized_call_count, 0); + EXPECT_EQ(resize_default_init_call_count, 0); absl::strings_internal::STLStringResizeUninitialized(&rs, 237); EXPECT_EQ(resize_call_count, 1); - EXPECT_EQ(resize_uninitialized_call_count, 0); + EXPECT_EQ(resize_default_init_call_count, 0); } resize_call_count = 0; - resize_uninitialized_call_count = 0; + resize_default_init_call_count = 0; { - resize_uninitializable_string rus; + resize_default_init_string rus; EXPECT_EQ(resize_call_count, 0); - EXPECT_EQ(resize_uninitialized_call_count, 0); + EXPECT_EQ(resize_default_init_call_count, 0); EXPECT_TRUE( absl::strings_internal::STLStringSupportsNontrashingResize(&rus)); EXPECT_EQ(resize_call_count, 0); - EXPECT_EQ(resize_uninitialized_call_count, 0); + EXPECT_EQ(resize_default_init_call_count, 0); absl::strings_internal::STLStringResizeUninitialized(&rus, 237); EXPECT_EQ(resize_call_count, 0); - EXPECT_EQ(resize_uninitialized_call_count, 1); + EXPECT_EQ(resize_default_init_call_count, 1); } }
diff --git a/absl/strings/internal/stl_type_traits.h b/absl/strings/internal/stl_type_traits.h index 04c4a53..202ab37 100644 --- a/absl/strings/internal/stl_type_traits.h +++ b/absl/strings/internal/stl_type_traits.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h index 3376d48..4d48af0 100644 --- a/absl/strings/internal/str_format/arg.h +++ b/absl/strings/internal/str_format/arg.h
@@ -35,12 +35,14 @@ T, void_t<decltype(AbslFormatConvert( std::declval<const T&>(), std::declval<ConversionSpec>(), std::declval<FormatSink*>()))>> : std::true_type {}; + template <typename T> class StreamedWrapper; // If 'v' can be converted (in the printf sense) according to 'conv', // then convert it, appending to `sink` and return `true`. // Otherwise fail and return `false`. + // Raw pointers. struct VoidPtr { VoidPtr() = default; @@ -54,7 +56,8 @@ FormatSinkImpl* sink); // Strings. -ConvertResult<Conv::s> FormatConvertImpl(const std::string& v, ConversionSpec conv, +ConvertResult<Conv::s> FormatConvertImpl(const std::string& v, + ConversionSpec conv, FormatSinkImpl* sink); ConvertResult<Conv::s> FormatConvertImpl(string_view v, ConversionSpec conv, FormatSinkImpl* sink); @@ -80,7 +83,7 @@ int precision = conv.precision(); if (precision >= 0) - to_write = std::min(to_write, static_cast<size_t>(precision)); + to_write = (std::min)(to_write, static_cast<size_t>(precision)); space_remaining = Excess(to_write, space_remaining); @@ -335,12 +338,12 @@ using CommonType = typename std::conditional<std::is_signed<T>::value, int64_t, uint64_t>::type; if (static_cast<CommonType>(val) > - static_cast<CommonType>(std::numeric_limits<int>::max())) { - return std::numeric_limits<int>::max(); + static_cast<CommonType>((std::numeric_limits<int>::max)())) { + return (std::numeric_limits<int>::max)(); } else if (std::is_signed<T>::value && static_cast<CommonType>(val) < - static_cast<CommonType>(std::numeric_limits<int>::min())) { - return std::numeric_limits<int>::min(); + static_cast<CommonType>((std::numeric_limits<int>::min)())) { + return (std::numeric_limits<int>::min)(); } return static_cast<int>(val); } @@ -409,7 +412,7 @@ ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(double, __VA_ARGS__); \ ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long double, __VA_ARGS__); \ ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(const char*, __VA_ARGS__); \ - ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::string, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::string, __VA_ARGS__); \ ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(string_view, __VA_ARGS__) ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern);
diff --git a/absl/strings/internal/str_format/arg_test.cc b/absl/strings/internal/str_format/arg_test.cc index 83d5904..3421fac 100644 --- a/absl/strings/internal/str_format/arg_test.cc +++ b/absl/strings/internal/str_format/arg_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// https://www.apache.org/licenses/LICENSE-2.0 // #include "absl/strings/internal/str_format/arg.h"
diff --git a/absl/strings/internal/str_format/bind.cc b/absl/strings/internal/str_format/bind.cc index c4eddd1..a31859e 100644 --- a/absl/strings/internal/str_format/bind.cc +++ b/absl/strings/internal/str_format/bind.cc
@@ -25,12 +25,12 @@ explicit ArgContext(absl::Span<const FormatArgImpl> pack) : pack_(pack) {} // Fill 'bound' with the results of applying the context's argument pack - // to the specified 'props'. We synthesize a BoundConversion by + // to the specified 'unbound'. We synthesize a BoundConversion by // lining up a UnboundConversion with a user argument. We also // resolve any '*' specifiers for width and precision, so after // this call, 'bound' has all the information it needs to be formatted. // Returns false on failure. - bool Bind(const UnboundConversion *props, BoundConversion *bound); + bool Bind(const UnboundConversion* unbound, BoundConversion* bound); private: absl::Span<const FormatArgImpl> pack_; @@ -53,7 +53,8 @@ // "A negative field width is taken as a '-' flag followed by a // positive field width." force_left = true; - width = -width; + // Make sure we don't overflow the width when negating it. + width = -std::max(width, -std::numeric_limits<int>::max()); } } @@ -159,7 +160,7 @@ } std::string Summarize(const UntypedFormatSpecImpl format, - absl::Span<const FormatArgImpl> args) { + absl::Span<const FormatArgImpl> args) { typedef SummarizingConverter Converter; std::string out; { @@ -187,7 +188,7 @@ } std::string& AppendPack(std::string* out, const UntypedFormatSpecImpl format, - absl::Span<const FormatArgImpl> args) { + absl::Span<const FormatArgImpl> args) { size_t orig = out->size(); if (ABSL_PREDICT_FALSE(!FormatUntyped(out, format, args))) { out->erase(orig);
diff --git a/absl/strings/internal/str_format/bind.h b/absl/strings/internal/str_format/bind.h index 1b52df9..4f78295 100644 --- a/absl/strings/internal/str_format/bind.h +++ b/absl/strings/internal/str_format/bind.h
@@ -153,7 +153,7 @@ // for testing std::string Summarize(UntypedFormatSpecImpl format, - absl::Span<const FormatArgImpl> args); + absl::Span<const FormatArgImpl> args); bool BindWithPack(const UnboundConversion* props, absl::Span<const FormatArgImpl> pack, BoundConversion* bound); @@ -162,10 +162,10 @@ absl::Span<const FormatArgImpl> args); std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format, - absl::Span<const FormatArgImpl> args); + absl::Span<const FormatArgImpl> args); inline std::string FormatPack(const UntypedFormatSpecImpl format, - absl::Span<const FormatArgImpl> args) { + absl::Span<const FormatArgImpl> args) { std::string out; AppendPack(&out, format, args); return out; @@ -176,7 +176,7 @@ int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format, absl::Span<const FormatArgImpl> args); -// Returned by Streamed(v). Converts via '%s' to the string created +// Returned by Streamed(v). Converts via '%s' to the std::string created // by std::ostream << v. template <typename T> class StreamedWrapper {
diff --git a/absl/strings/internal/str_format/bind_test.cc b/absl/strings/internal/str_format/bind_test.cc index 4757573..ba6470e 100644 --- a/absl/strings/internal/str_format/bind_test.cc +++ b/absl/strings/internal/str_format/bind_test.cc
@@ -1,6 +1,7 @@ #include "absl/strings/internal/str_format/bind.h" #include <string.h> +#include <limits> #include "gtest/gtest.h" @@ -91,6 +92,20 @@ } } +TEST_F(FormatBindTest, WidthUnderflowRegression) { + UnboundConversion props; + BoundConversion bound; + int next = 0; + const int args_i[] = {std::numeric_limits<int>::min(), 17}; + const FormatArgImpl args[] = {FormatArgImpl(args_i[0]), + FormatArgImpl(args_i[1])}; + ASSERT_TRUE(Extract("*d", &props, &next)); + ASSERT_TRUE(BindWithPack(&props, args, &bound)); + + EXPECT_EQ(bound.width(), std::numeric_limits<int>::max()); + EXPECT_EQ(bound.arg(), args + 1); +} + TEST_F(FormatBindTest, FormatPack) { struct Expectation { int line;
diff --git a/absl/strings/internal/str_format/checker_test.cc b/absl/strings/internal/str_format/checker_test.cc index 14d11ea..c1d8c76 100644 --- a/absl/strings/internal/str_format/checker_test.cc +++ b/absl/strings/internal/str_format/checker_test.cc
@@ -62,32 +62,32 @@ ValidFormat<int>("%% %d"), // ValidFormat<int>("%ld"), // ValidFormat<int>("%lld"), // - ValidFormat<std::string>("%s"), // - ValidFormat<std::string>("%10s"), // + ValidFormat<std::string>("%s"), // + ValidFormat<std::string>("%10s"), // ValidFormat<int>("%.10x"), // ValidFormat<int, int>("%*.3x"), // ValidFormat<int>("%1.d"), // ValidFormat<int>("%.d"), // ValidFormat<int, double>("%d %g"), // - ValidFormat<int, std::string>("%*s"), // + ValidFormat<int, std::string>("%*s"), // ValidFormat<int, double>("%.*f"), // ValidFormat<void (*)(), volatile int*>("%p %p"), // ValidFormat<string_view, const char*, double, void*>( "string_view=%s const char*=%s double=%f void*=%p)"), - ValidFormat<int>("%% %1$d"), // - ValidFormat<int>("%1$ld"), // - ValidFormat<int>("%1$lld"), // - ValidFormat<std::string>("%1$s"), // - ValidFormat<std::string>("%1$10s"), // - ValidFormat<int>("%1$.10x"), // - ValidFormat<int>("%1$*1$.*1$d"), // - ValidFormat<int, int>("%1$*2$.3x"), // - ValidFormat<int>("%1$1.d"), // - ValidFormat<int>("%1$.d"), // - ValidFormat<double, int>("%2$d %1$g"), // - ValidFormat<int, std::string>("%2$*1$s"), // - ValidFormat<int, double>("%2$.*1$f"), // + ValidFormat<int>("%% %1$d"), // + ValidFormat<int>("%1$ld"), // + ValidFormat<int>("%1$lld"), // + ValidFormat<std::string>("%1$s"), // + ValidFormat<std::string>("%1$10s"), // + ValidFormat<int>("%1$.10x"), // + ValidFormat<int>("%1$*1$.*1$d"), // + ValidFormat<int, int>("%1$*2$.3x"), // + ValidFormat<int>("%1$1.d"), // + ValidFormat<int>("%1$.d"), // + ValidFormat<double, int>("%2$d %1$g"), // + ValidFormat<int, std::string>("%2$*1$s"), // + ValidFormat<int, double>("%2$.*1$f"), // ValidFormat<void*, string_view, const char*, double>( "string_view=%2$s const char*=%3$s double=%4$f void*=%1$p " "repeat=%3$s)")}; @@ -99,25 +99,25 @@ constexpr Case falses[] = { ValidFormat<int>(""), // - ValidFormat<e>("%s"), // - ValidFormat<e2>("%s"), // - ValidFormat<>("%s"), // - ValidFormat<>("%r"), // - ValidFormat<int>("%s"), // - ValidFormat<int>("%.1.d"), // - ValidFormat<int>("%*1d"), // - ValidFormat<int>("%1-d"), // + ValidFormat<e>("%s"), // + ValidFormat<e2>("%s"), // + ValidFormat<>("%s"), // + ValidFormat<>("%r"), // + ValidFormat<int>("%s"), // + ValidFormat<int>("%.1.d"), // + ValidFormat<int>("%*1d"), // + ValidFormat<int>("%1-d"), // ValidFormat<std::string, int>("%*s"), // - ValidFormat<int>("%*d"), // + ValidFormat<int>("%*d"), // ValidFormat<std::string>("%p"), // - ValidFormat<int (*)(int)>("%d"), // + ValidFormat<int (*)(int)>("%d"), // - ValidFormat<>("%3$d"), // - ValidFormat<>("%1$r"), // - ValidFormat<int>("%1$s"), // - ValidFormat<int>("%1$.1.d"), // - ValidFormat<int>("%1$*2$1d"), // - ValidFormat<int>("%1$1-d"), // + ValidFormat<>("%3$d"), // + ValidFormat<>("%1$r"), // + ValidFormat<int>("%1$s"), // + ValidFormat<int>("%1$.1.d"), // + ValidFormat<int>("%1$*2$1d"), // + ValidFormat<int>("%1$1-d"), // ValidFormat<std::string, int>("%2$*1$s"), // ValidFormat<std::string>("%1$p"),
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc index 32f8a0f..99cc0af 100644 --- a/absl/strings/internal/str_format/convert_test.cc +++ b/absl/strings/internal/str_format/convert_test.cc
@@ -232,7 +232,7 @@ template <typename T> class TypedFormatConvertTest : public FormatConvertTest { }; -TYPED_TEST_CASE_P(TypedFormatConvertTest); +TYPED_TEST_SUITE_P(TypedFormatConvertTest); std::vector<std::string> AllFlagCombinations() { const char kFlags[] = {'-', '#', '0', '+', ' '}; @@ -363,6 +363,7 @@ AllIntTypes; INSTANTIATE_TYPED_TEST_CASE_P(TypedFormatConvertTestWithAllIntTypes, TypedFormatConvertTest, AllIntTypes); + TEST_F(FormatConvertTest, Uint128) { absl::uint128 v = static_cast<absl::uint128>(0x1234567890abcdef) * 1979; absl::uint128 max = absl::Uint128Max();
diff --git a/absl/strings/internal/str_format/extension.cc b/absl/strings/internal/str_format/extension.cc index c217470..d7f5815 100644 --- a/absl/strings/internal/str_format/extension.cc +++ b/absl/strings/internal/str_format/extension.cc
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/str_format/extension.h b/absl/strings/internal/str_format/extension.h index 11b996a..eb81f8a 100644 --- a/absl/strings/internal/str_format/extension.h +++ b/absl/strings/internal/str_format/extension.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -13,7 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ @@ -360,7 +359,7 @@ integral = d | i | u | o | x | X, floating = a | e | f | g | A | E | F | G, numeric = integral | floating, - string = s, // absl:ignore(std::string) + string = s, pointer = p }; @@ -409,4 +408,4 @@ } // namespace absl -#endif // ABSL_STRINGS_STR_FORMAT_EXTENSION_H_ +#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
diff --git a/absl/strings/internal/str_format/extension_test.cc b/absl/strings/internal/str_format/extension_test.cc index 224fc92..4e23fef 100644 --- a/absl/strings/internal/str_format/extension_test.cc +++ b/absl/strings/internal/str_format/extension_test.cc
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -18,6 +18,7 @@ #include <random> #include <string> + #include "absl/strings/str_format.h" #include "gtest/gtest.h"
diff --git a/absl/strings/internal/str_format/output.cc b/absl/strings/internal/str_format/output.cc index 5c3795b..38987b6 100644 --- a/absl/strings/internal/str_format/output.cc +++ b/absl/strings/internal/str_format/output.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -20,6 +20,16 @@ namespace absl { namespace str_format_internal { +namespace { +struct ClearErrnoGuard { + ClearErrnoGuard() : old_value(errno) { errno = 0; } + ~ClearErrnoGuard() { + if (!errno) errno = old_value; + } + int old_value; +}; +} // namespace + void BufferRawSink::Write(string_view v) { size_t to_write = std::min(v.size(), size_); std::memcpy(buffer_, v.data(), to_write); @@ -30,14 +40,27 @@ void FILERawSink::Write(string_view v) { while (!v.empty() && !error_) { + // Reset errno to zero in case the libc implementation doesn't set errno + // when a failure occurs. + ClearErrnoGuard guard; + if (size_t result = std::fwrite(v.data(), 1, v.size(), output_)) { // Some progress was made. count_ += result; v.remove_prefix(result); } else { - // Some error occurred. - if (errno != EINTR) { + if (errno == EINTR) { + continue; + } else if (errno) { error_ = errno; + } else if (std::ferror(output_)) { + // Non-POSIX compliant libc implementations may not set errno, so we + // have check the streams error indicator. + error_ = EBADF; + } else { + // We're likely on a non-POSIX system that encountered EINTR but had no + // way of reporting it. + continue; } } }
diff --git a/absl/strings/internal/str_format/output.h b/absl/strings/internal/str_format/output.h index 12ecd99..42da641 100644 --- a/absl/strings/internal/str_format/output.h +++ b/absl/strings/internal/str_format/output.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/str_format/output_test.cc b/absl/strings/internal/str_format/output_test.cc index cc3c615..6e04abe 100644 --- a/absl/strings/internal/str_format/output_test.cc +++ b/absl/strings/internal/str_format/output_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -17,7 +17,6 @@ #include <sstream> #include <string> - #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -28,12 +27,6 @@ std::string str = "ABC"; str_format_internal::InvokeFlush(&str, "DEF"); EXPECT_EQ(str, "ABCDEF"); - -#if UTIL_FORMAT_HAS_GLOBAL_STRING - std::string str2 = "ABC"; - str_format_internal::InvokeFlush(&str2, "DEF"); - EXPECT_EQ(str2, "ABCDEF"); -#endif // UTIL_FORMAT_HAS_GLOBAL_STRING } TEST(InvokeFlush, Stream) {
diff --git a/absl/strings/internal/str_format/parser.cc b/absl/strings/internal/str_format/parser.cc index 5e3d0d0..10487f2 100644 --- a/absl/strings/internal/str_format/parser.cc +++ b/absl/strings/internal/str_format/parser.cc
@@ -99,10 +99,11 @@ // digit doesn't match the expected characters. int num_digits = std::numeric_limits<int>::digits10; for (;;) { - if (ABSL_PREDICT_FALSE(pos == end || !num_digits)) break; + if (ABSL_PREDICT_FALSE(pos == end)) break; c = *pos++; if (!std::isdigit(c)) break; --num_digits; + if (ABSL_PREDICT_FALSE(!num_digits)) break; digits = 10 * digits + c - '0'; } return digits;
diff --git a/absl/strings/internal/str_format/parser_test.cc b/absl/strings/internal/str_format/parser_test.cc index ae40203..ff70575 100644 --- a/absl/strings/internal/str_format/parser_test.cc +++ b/absl/strings/internal/str_format/parser_test.cc
@@ -246,6 +246,8 @@ EXPECT_FALSE(Run("1000000000.999999999d")); EXPECT_FALSE(Run("999999999.1000000000d")); + EXPECT_FALSE(Run("9999999999d")); + EXPECT_FALSE(Run(".9999999999d")); } TEST_F(ConsumeUnboundConversionTest, Flags) {
diff --git a/absl/strings/internal/str_join_internal.h b/absl/strings/internal/str_join_internal.h index 0058fc8..7c35f4d 100644 --- a/absl/strings/internal/str_join_internal.h +++ b/absl/strings/internal/str_join_internal.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -193,7 +193,7 @@ // and formats each element using the provided Formatter object. template <typename Iterator, typename Formatter> std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s, - Formatter&& f) { + Formatter&& f) { std::string result; absl::string_view sep(""); for (Iterator it = start; it != end; ++it) { @@ -212,7 +212,7 @@ // This is an overload of the previous JoinAlgorithm() function. Here the // Formatter argument is of type NoFormatter. Since NoFormatter is an internal // type, this overload is only invoked when strings::Join() is called with a -// range of string-like objects (e.g., string, absl::string_view), and an +// range of string-like objects (e.g., std::string, absl::string_view), and an // explicit Formatter argument was NOT specified. // // The optimization is that the needed space will be reserved in the output @@ -224,7 +224,7 @@ typename std::iterator_traits<Iterator>::iterator_category, std::forward_iterator_tag>::value>::type> std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s, - NoFormatter) { + NoFormatter) { std::string result; if (start != end) { // Sums size @@ -276,14 +276,15 @@ template <typename... T, typename Formatter> std::string JoinAlgorithm(const std::tuple<T...>& tup, absl::string_view sep, - Formatter&& fmt) { + Formatter&& fmt) { std::string result; JoinTupleLoop<0, sizeof...(T)>()(&result, tup, sep, fmt); return result; } template <typename Iterator> -std::string JoinRange(Iterator first, Iterator last, absl::string_view separator) { +std::string JoinRange(Iterator first, Iterator last, + absl::string_view separator) { // No formatter was explicitly given, so a default must be chosen. typedef typename std::iterator_traits<Iterator>::value_type ValueType; typedef typename DefaultFormatter<ValueType>::Type Formatter; @@ -292,7 +293,7 @@ template <typename Range, typename Formatter> std::string JoinRange(const Range& range, absl::string_view separator, - Formatter&& fmt) { + Formatter&& fmt) { using std::begin; using std::end; return JoinAlgorithm(begin(range), end(range), separator, fmt);
diff --git a/absl/strings/internal/str_split_internal.h b/absl/strings/internal/str_split_internal.h index 81e8d55..52f6222 100644 --- a/absl/strings/internal/str_split_internal.h +++ b/absl/strings/internal/str_split_internal.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -96,8 +96,8 @@ } } - // Holds the data moved from temporary std::string arguments. Declared first so - // that 'value' can refer to 'copy_'. + // 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_; }; @@ -376,10 +376,10 @@ // Partial specialization for a std::vector<std::string>. // - // Optimized for the common case of splitting to a std::vector<std::string>. In - // this case we first split the results to a std::vector<absl::string_view> so - // the returned std::vector<std::string> can have space reserved to avoid std::string - // moves. + // Optimized for the common case of splitting to a std::vector<std::string>. + // In this case we first split the results to a std::vector<absl::string_view> + // so the returned std::vector<std::string> can have space reserved to avoid + // std::string moves. template <typename A> struct ConvertToContainer<std::vector<std::string, A>, std::string, false> { std::vector<std::string, A> operator()(const Splitter& splitter) const {
diff --git a/absl/strings/internal/utf8.cc b/absl/strings/internal/utf8.cc index 2415c2c..82d36c2 100644 --- a/absl/strings/internal/utf8.cc +++ b/absl/strings/internal/utf8.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/internal/utf8.h b/absl/strings/internal/utf8.h index d2c3c0b..0423630 100644 --- a/absl/strings/internal/utf8.h +++ b/absl/strings/internal/utf8.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -13,7 +13,6 @@ // limitations under the License. // // UTF8 utilities, implemented to reduce dependencies. -// #ifndef ABSL_STRINGS_INTERNAL_UTF8_H_ #define ABSL_STRINGS_INTERNAL_UTF8_H_
diff --git a/absl/strings/internal/utf8_test.cc b/absl/strings/internal/utf8_test.cc index 64cec70..88dd503 100644 --- a/absl/strings/internal/utf8_test.cc +++ b/absl/strings/internal/utf8_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -22,12 +22,17 @@ namespace { +#if !defined(__cpp_char8_t) +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++2a-compat" +#endif TEST(EncodeUTF8Char, BasicFunction) { std::pair<char32_t, std::string> tests[] = {{0x0030, u8"\u0030"}, - {0x00A3, u8"\u00A3"}, - {0x00010000, u8"\U00010000"}, - {0x0000FFFF, u8"\U0000FFFF"}, - {0x0010FFFD, u8"\U0010FFFD"}}; + {0x00A3, u8"\u00A3"}, + {0x00010000, u8"\U00010000"}, + {0x0000FFFF, u8"\U0000FFFF"}, + {0x0010FFFD, u8"\U0010FFFD"}}; for (auto &test : tests) { char buf0[7] = {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}; char buf1[7] = {'\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF'}; @@ -53,5 +58,9 @@ EXPECT_LE(absl::strings_internal::EncodeUTF8Char(buf2, -1), absl::strings_internal::kMaxEncodedUTF8Size); } +#if defined(__clang__) +#pragma clang diagnostic pop +#endif +#endif // !defined(__cpp_char8_t) } // namespace
diff --git a/absl/strings/match.cc b/absl/strings/match.cc index 3d10c57..7b24241 100644 --- a/absl/strings/match.cc +++ b/absl/strings/match.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -18,15 +18,6 @@ namespace absl { -namespace { -bool CaseEqual(absl::string_view piece1, absl::string_view piece2) { - return (piece1.size() == piece2.size() && - 0 == strings_internal::memcasecmp(piece1.data(), piece2.data(), - piece1.size())); - // memcasecmp uses ascii_tolower(). -} -} // namespace - bool EqualsIgnoreCase(absl::string_view piece1, absl::string_view piece2) { return (piece1.size() == piece2.size() && 0 == absl::strings_internal::memcasecmp(piece1.data(), piece2.data(), @@ -36,12 +27,12 @@ bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix) { return (text.size() >= prefix.size()) && - CaseEqual(text.substr(0, prefix.size()), prefix); + EqualsIgnoreCase(text.substr(0, prefix.size()), prefix); } bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix) { return (text.size() >= suffix.size()) && - CaseEqual(text.substr(text.size() - suffix.size()), suffix); + EqualsIgnoreCase(text.substr(text.size() - suffix.size()), suffix); } } // namespace absl
diff --git a/absl/strings/match.h b/absl/strings/match.h index 6e8ed10..5251b7f 100644 --- a/absl/strings/match.h +++ b/absl/strings/match.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -74,13 +74,13 @@ // StartsWithIgnoreCase() // -// Returns whether a given ASCII string `text` starts with `starts_with`, +// 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); // EndsWithIgnoreCase() // -// Returns whether a given ASCII string `text` ends with `ends_with`, ignoring +// 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);
diff --git a/absl/strings/match_test.cc b/absl/strings/match_test.cc index c21e00b..4c313dd 100644 --- a/absl/strings/match_test.cc +++ b/absl/strings/match_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -19,7 +19,7 @@ namespace { TEST(MatchTest, StartsWith) { - const std::string s1("123" "\0" "456", 7); + const std::string s1("123\0abc", 7); const absl::string_view a("foobar"); const absl::string_view b(s1); const absl::string_view e; @@ -36,7 +36,7 @@ } TEST(MatchTest, EndsWith) { - const std::string s1("123" "\0" "456", 7); + const std::string s1("123\0abc", 7); const absl::string_view a("foobar"); const absl::string_view b(s1); const absl::string_view e;
diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc index 9309f9d..558c339 100644 --- a/absl/strings/numbers.cc +++ b/absl/strings/numbers.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -35,17 +35,18 @@ #include "absl/strings/ascii.h" #include "absl/strings/charconv.h" #include "absl/strings/internal/memutil.h" +#include "absl/strings/match.h" #include "absl/strings/str_cat.h" namespace absl { -bool SimpleAtof(absl::string_view str, float* value) { - *value = 0.0; +bool SimpleAtof(absl::string_view str, float* out) { + *out = 0.0; str = StripAsciiWhitespace(str); if (!str.empty() && str[0] == '+') { str.remove_prefix(1); } - auto result = absl::from_chars(str.data(), str.data() + str.size(), *value); + auto result = absl::from_chars(str.data(), str.data() + str.size(), *out); if (result.ec == std::errc::invalid_argument) { return false; } @@ -56,22 +57,22 @@ // from_chars() with DR 3801's current wording will return max() on // overflow. SimpleAtof returns infinity instead. if (result.ec == std::errc::result_out_of_range) { - if (*value > 1.0) { - *value = std::numeric_limits<float>::infinity(); - } else if (*value < -1.0) { - *value = -std::numeric_limits<float>::infinity(); + if (*out > 1.0) { + *out = std::numeric_limits<float>::infinity(); + } else if (*out < -1.0) { + *out = -std::numeric_limits<float>::infinity(); } } return true; } -bool SimpleAtod(absl::string_view str, double* value) { - *value = 0.0; +bool SimpleAtod(absl::string_view str, double* out) { + *out = 0.0; str = StripAsciiWhitespace(str); if (!str.empty() && str[0] == '+') { str.remove_prefix(1); } - auto result = absl::from_chars(str.data(), str.data() + str.size(), *value); + auto result = absl::from_chars(str.data(), str.data() + str.size(), *out); if (result.ec == std::errc::invalid_argument) { return false; } @@ -82,10 +83,10 @@ // from_chars() with DR 3801's current wording will return max() on // overflow. SimpleAtod returns infinity instead. if (result.ec == std::errc::result_out_of_range) { - if (*value > 1.0) { - *value = std::numeric_limits<double>::infinity(); - } else if (*value < -1.0) { - *value = -std::numeric_limits<double>::infinity(); + if (*out > 1.0) { + *out = std::numeric_limits<double>::infinity(); + } else if (*out < -1.0) { + *out = -std::numeric_limits<double>::infinity(); } } return true; @@ -93,14 +94,6 @@ namespace { -// TODO(rogeeff): replace with the real released thing once we figure out what -// it is. -inline bool CaseEqual(absl::string_view piece1, absl::string_view piece2) { - return (piece1.size() == piece2.size() && - 0 == strings_internal::memcasecmp(piece1.data(), piece2.data(), - piece1.size())); -} - // Writes a two-character representation of 'i' to 'buf'. 'i' must be in the // range 0 <= i < 100, and buf must have space for two characters. Example: // char buf[2]; @@ -136,18 +129,18 @@ } // namespace -bool SimpleAtob(absl::string_view str, bool* value) { - ABSL_RAW_CHECK(value != nullptr, "Output pointer must not be nullptr."); - if (CaseEqual(str, "true") || CaseEqual(str, "t") || - CaseEqual(str, "yes") || CaseEqual(str, "y") || - CaseEqual(str, "1")) { - *value = true; +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") || + EqualsIgnoreCase(str, "yes") || EqualsIgnoreCase(str, "y") || + EqualsIgnoreCase(str, "1")) { + *out = true; return true; } - if (CaseEqual(str, "false") || CaseEqual(str, "f") || - CaseEqual(str, "no") || CaseEqual(str, "n") || - CaseEqual(str, "0")) { - *value = false; + if (EqualsIgnoreCase(str, "false") || EqualsIgnoreCase(str, "f") || + EqualsIgnoreCase(str, "no") || EqualsIgnoreCase(str, "n") || + EqualsIgnoreCase(str, "0")) { + *out = false; return true; } return false;
diff --git a/absl/strings/numbers.h b/absl/strings/numbers.h index f9b2cce..e0f96df 100644 --- a/absl/strings/numbers.h +++ b/absl/strings/numbers.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -44,7 +44,8 @@ // 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. +// integer type. 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 s, int_type* out); @@ -52,25 +53,29 @@ // // Converts the given string (optionally followed or preceded by ASCII // whitespace) into a float, which may be rounded on overflow or underflow. -// See http://en.cppreference.com/w/c/string/byte/strtof for details about the -// allowed formats for `str`. -ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* value); +// 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 +// 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. -// See http://en.cppreference.com/w/c/string/byte/strtof for details about the -// allowed formats for `str`. -ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str, double* value); +// 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 +// returns `false`, leaving `out` in an unspecified state. +ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str, double* out); // SimpleAtob() // // Converts the given string into a boolean, returning `true` if successful. // The following case-insensitive strings are interpreted as boolean `true`: // "true", "t", "yes", "y", "1". The following case-insensitive strings -// are interpreted as boolean `false`: "false", "f", "no", "n", "0". -ABSL_MUST_USE_RESULT bool SimpleAtob(absl::string_view str, bool* value); +// are interpreted as boolean `false`: "false", "f", "no", "n", "0". If any +// errors are encountered, this function returns `false`, leaving `out` in an +// unspecified state. +ABSL_MUST_USE_RESULT bool SimpleAtob(absl::string_view str, bool* out); } // namespace absl
diff --git a/absl/strings/numbers_benchmark.cc b/absl/strings/numbers_benchmark.cc index 0570b75..54dbedd 100644 --- a/absl/strings/numbers_benchmark.cc +++ b/absl/strings/numbers_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc index 36fc0d6..ca2ee48 100644 --- a/absl/strings/numbers_test.cc +++ b/absl/strings/numbers_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -39,6 +39,7 @@ #include "absl/strings/str_cat.h" #include "absl/strings/internal/numbers_test_common.h" +#include "absl/strings/internal/pow10_helper.h" namespace { @@ -190,7 +191,8 @@ EXPECT_EQ(expected, std::string(&buffer[1], actual)) << " Input " << x; char* generic_actual = absl::numbers_internal::FastIntToBuffer(x, &buffer[1]); - EXPECT_EQ(expected, std::string(&buffer[1], generic_actual)) << " Input " << x; + EXPECT_EQ(expected, std::string(&buffer[1], generic_actual)) + << " Input " << x; char* my_actual = absl::numbers_internal::FastIntToBuffer(MyUInt64(x), &buffer[1]); @@ -783,7 +785,7 @@ if (iters_per_float == 0) iters_per_float = 1; for (float f : floats) { if (f == last) continue; - float testf = nextafter(last, std::numeric_limits<float>::max()); + float testf = std::nextafter(last, std::numeric_limits<float>::max()); runnable(testf); runnable(-testf); last = testf; @@ -797,7 +799,7 @@ last = testf; } } - testf = nextafter(f, 0.0f); + testf = std::nextafter(f, 0.0f); if (testf > last) { runnable(testf); runnable(-testf); @@ -871,15 +873,15 @@ } for (int exponent = -324; exponent <= 308; ++exponent) { - double powten = pow(10.0, exponent); + double powten = absl::strings_internal::Pow10(exponent); if (powten == 0) powten = 5e-324; if (kFloatNumCases >= 1e9) { // The exhaustive test takes a very long time, so log progress. char buf[kSixDigitsToBufferSize]; ABSL_RAW_LOG( INFO, "%s", - absl::StrCat("Exp ", exponent, " powten=", powten, "(", - powten, ") (", + absl::StrCat("Exp ", exponent, " powten=", powten, "(", powten, + ") (", std::string(buf, SixDigitsToBuffer(powten, buf)), ")") .c_str()); }
diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc index efa4fd7..2667976 100644 --- a/absl/strings/str_cat.cc +++ b/absl/strings/str_cat.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -78,9 +78,9 @@ // ---------------------------------------------------------------------- // StrCat() -// This merges the given strings or integers, with no delimiter. This +// This merges the given strings or integers, with no delimiter. This // is designed to be the fastest possible way to construct a string out -// of a mix of raw C strings, StringPieces, strings, and integer values. +// of a mix of raw C strings, string_views, strings, and integer values. // ---------------------------------------------------------------------- // Append is merely a version of memcpy that returns the address of the byte @@ -119,7 +119,7 @@ } std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, - const AlphaNum& d) { + const AlphaNum& d) { std::string result; strings_internal::STLStringResizeUninitialized( &result, a.size() + b.size() + c.size() + d.size());
diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h index da9ed9a..cba8ceb 100644 --- a/absl/strings/str_cat.h +++ b/absl/strings/str_cat.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -42,7 +42,6 @@ // Floating point numbers are formatted with six-digit precision, which is // the default for "std::cout <<" or printf "%g" (the same as "%.6g"). // -// // You can convert to hexadecimal output rather than decimal output using the // `Hex` type contained here. To do so, pass `Hex(my_int)` as a parameter to // `StrCat()` or `StrAppend()`. You may specify a minimum hex field width using @@ -78,8 +77,8 @@ // Enum that specifies the number of significant digits to return in a `Hex` or // `Dec` conversion and fill character to use. A `kZeroPad2` value, for example, -// would produce hexadecimal strings such as "0A","0F" and a 'kSpacePad5' value -// would produce hexadecimal strings such as " A"," F". +// would produce hexadecimal strings such as "0a","0f" and a 'kSpacePad5' value +// would produce hexadecimal strings such as " a"," f". enum PadSpec : uint8_t { kNoPad = 1, kZeroPad2, @@ -97,6 +96,10 @@ kZeroPad14, kZeroPad15, kZeroPad16, + kZeroPad17, + kZeroPad18, + kZeroPad19, + kZeroPad20, kSpacePad2 = kZeroPad2 + 64, kSpacePad3, @@ -113,6 +116,10 @@ kSpacePad14, kSpacePad15, kSpacePad16, + kSpacePad17, + kSpacePad18, + kSpacePad19, + kSpacePad20, }; // ----------------------------------------------------------------------------- @@ -237,6 +244,7 @@ AlphaNum(const char* c_str) : piece_(c_str) {} // NOLINT(runtime/explicit) AlphaNum(absl::string_view pc) : piece_(pc) {} // NOLINT(runtime/explicit) + template <typename Allocator> AlphaNum( // NOLINT(runtime/explicit) const std::basic_string<char, std::char_traits<char>, Allocator>& str) @@ -309,16 +317,15 @@ ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b); ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c); + const AlphaNum& c); ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c, const AlphaNum& d); + const AlphaNum& c, const AlphaNum& d); // Support 5 or more arguments template <typename... AV> -ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c, const AlphaNum& d, - const AlphaNum& e, - const AV&... args) { +ABSL_MUST_USE_RESULT inline std::string StrCat( + const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d, + const AlphaNum& e, const AV&... args) { return strings_internal::CatPieces( {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), static_cast<const AlphaNum&>(args).Piece()...}); @@ -336,18 +343,18 @@ // not try to check each of its input arguments to be sure that they are not // a subset of the string being appended to. That is, while this will work: // -// string s = "foo"; +// std::string s = "foo"; // s += s; // // This output is undefined: // -// string s = "foo"; +// std::string s = "foo"; // StrAppend(&s, s); // // This output is undefined as well, since `absl::string_view` does not own its // data: // -// string s = "foobar"; +// std::string s = "foobar"; // absl::string_view p = s; // StrAppend(&s, p);
diff --git a/absl/strings/str_cat_benchmark.cc b/absl/strings/str_cat_benchmark.cc index b6df9e3..14c63b3 100644 --- a/absl/strings/str_cat_benchmark.cc +++ b/absl/strings/str_cat_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/str_cat_test.cc b/absl/strings/str_cat_test.cc index 555d8db..beb15fa 100644 --- a/absl/strings/str_cat_test.cc +++ b/absl/strings/str_cat_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -106,11 +106,7 @@ TEST(StrCat, Basics) { std::string result; - std::string strs[] = { - "Hello", - "Cruel", - "World" - }; + std::string strs[] = {"Hello", "Cruel", "World"}; std::string stdstrs[] = { "std::Hello", @@ -164,9 +160,10 @@ result = absl::StrCat(ui64s[0], ", ", ui64s[1], "!"); EXPECT_EQ(result, "12345678910, 10987654321!"); - std::string one = "1"; // Actually, it's the size of this std::string that we want; a - // 64-bit build distinguishes between size_t and uint64_t, - // even though they're both unsigned 64-bit values. + std::string one = + "1"; // Actually, it's the size of this std::string that we want; a + // 64-bit build distinguishes between size_t and uint64_t, + // even though they're both unsigned 64-bit values. result = absl::StrCat("And a ", one.size(), " and a ", &result[2] - &result[0], " and a ", one, " 2 3 4", "!"); EXPECT_EQ(result, "And a 1 and a 2 and a 1 2 3 4!"); @@ -306,11 +303,7 @@ TEST(StrAppend, Basics) { std::string result = "existing text"; - std::string strs[] = { - "Hello", - "Cruel", - "World" - }; + std::string strs[] = {"Hello", "Cruel", "World"}; std::string stdstrs[] = { "std::Hello", @@ -365,9 +358,10 @@ absl::StrAppend(&result, ui64s[0], ", ", ui64s[1], "!"); EXPECT_EQ(result.substr(old_size), "12345678910, 10987654321!"); - std::string one = "1"; // Actually, it's the size of this std::string that we want; a - // 64-bit build distinguishes between size_t and uint64_t, - // even though they're both unsigned 64-bit values. + std::string one = + "1"; // Actually, it's the size of this std::string that we want; a + // 64-bit build distinguishes between size_t and uint64_t, + // even though they're both unsigned 64-bit values. old_size = result.size(); absl::StrAppend(&result, "And a ", one.size(), " and a ", &result[2] - &result[0], " and a ", one, " 2 3 4", "!"); @@ -427,7 +421,7 @@ snprintf(expected, sizeof(expected), nopad_format, v); EXPECT_EQ(expected, actual) << " decimal value " << v; - for (int spec = absl::kZeroPad2; spec <= absl::kZeroPad16; ++spec) { + for (int spec = absl::kZeroPad2; spec <= absl::kZeroPad20; ++spec) { std::string actual = absl::StrCat(absl::Hex(v, static_cast<absl::PadSpec>(spec))); snprintf(expected, sizeof(expected), zeropad_format, @@ -435,7 +429,7 @@ EXPECT_EQ(expected, actual) << " decimal value " << v; } - for (int spec = absl::kSpacePad2; spec <= absl::kSpacePad16; ++spec) { + for (int spec = absl::kSpacePad2; spec <= absl::kSpacePad20; ++spec) { std::string actual = absl::StrCat(absl::Hex(v, static_cast<absl::PadSpec>(spec))); snprintf(expected, sizeof(expected), spacepad_format, @@ -453,7 +447,7 @@ snprintf(expected, sizeof(expected), nopad_format, v); EXPECT_EQ(expected, actual) << " decimal value " << v; - for (int spec = absl::kZeroPad2; spec <= absl::kZeroPad16; ++spec) { + for (int spec = absl::kZeroPad2; spec <= absl::kZeroPad20; ++spec) { std::string actual = absl::StrCat(absl::Dec(v, static_cast<absl::PadSpec>(spec))); snprintf(expected, sizeof(expected), zeropad_format, @@ -463,7 +457,7 @@ << "' digits " << (spec - absl::kZeroPad2 + 2); } - for (int spec = absl::kSpacePad2; spec <= absl::kSpacePad16; ++spec) { + for (int spec = absl::kSpacePad2; spec <= absl::kSpacePad20; ++spec) { std::string actual = absl::StrCat(absl::Dec(v, static_cast<absl::PadSpec>(spec))); snprintf(expected, sizeof(expected), spacepad_format,
diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h index 2d07725..539d951 100644 --- a/absl/strings/str_format.h +++ b/absl/strings/str_format.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -24,7 +24,8 @@ // // Example: // -// string s = absl::StrFormat("%s %s You have $%d!", "Hello", name, dollars); +// std::string s = absl::StrFormat( +// "%s %s You have $%d!", "Hello", name, dollars); // // The library consists of the following basic utilities: // @@ -89,7 +90,7 @@ // Example: // // absl::UntypedFormatSpec format("%d"); -// string out; +// std::string out; // CHECK(absl::FormatUntyped(&out, format, {absl::FormatArg(1)})); class UntypedFormatSpec { public: @@ -135,8 +136,8 @@ // Example: // // int n = 0; -// string s = absl::StrFormat("%s%d%n", "hello", 123, -// absl::FormatCountCapture(&n)); +// std::string s = absl::StrFormat("%s%d%n", "hello", 123, +// absl::FormatCountCapture(&n)); // EXPECT_EQ(8, n); class FormatCountCapture { public: @@ -186,7 +187,7 @@ // A format string generally follows the POSIX syntax as used within the POSIX // `printf` specification. // -// (See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html.) +// (See http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html.) // // In specific, the `FormatSpec` supports the following type specifiers: // * `c` for characters @@ -223,7 +224,7 @@ // "%p", *int -> "0x7ffdeb6ad2a4" // // int n = 0; -// string s = absl::StrFormat( +// std::string s = absl::StrFormat( // "%s%d%n", "hello", 123, absl::FormatCountCapture(&n)); // EXPECT_EQ(8, n); // @@ -290,14 +291,14 @@ // // Example: // -// string s = absl::StrFormat( +// std::string s = absl::StrFormat( // "Welcome to %s, Number %d!", "The Village", 6); // EXPECT_EQ("Welcome to The Village, Number 6!", s); // // Returns an empty string in case of error. template <typename... Args> ABSL_MUST_USE_RESULT std::string StrFormat(const FormatSpec<Args...>& format, - const Args&... args) { + const Args&... args) { return str_format_internal::FormatPack( str_format_internal::UntypedFormatSpecImpl::Extract(format), {str_format_internal::FormatArgImpl(args)...}); @@ -311,11 +312,12 @@ // // Example: // -// string orig("For example PI is approximately "); +// std::string orig("For example PI is approximately "); // std::cout << StrAppendFormat(&orig, "%12.6f", 3.14); template <typename... Args> -std::string& StrAppendFormat(std::string* dst, const FormatSpec<Args...>& format, - const Args&... args) { +std::string& StrAppendFormat(std::string* dst, + const FormatSpec<Args...>& format, + const Args&... args) { return str_format_internal::AppendPack( dst, str_format_internal::UntypedFormatSpecImpl::Extract(format), {str_format_internal::FormatArgImpl(args)...}); @@ -434,7 +436,8 @@ // `absl::FormatRawSink` interface), using a format string and zero or more // additional arguments. // -// By default, `string` and `std::ostream` are supported as destination objects. +// By default, `std::string` and `std::ostream` are supported as destination +// objects. // // `absl::Format()` is a generic version of `absl::StrFormat(), for custom // sinks. The format string, like format strings for `StrFormat()`, is checked @@ -483,9 +486,10 @@ // // Example: // -// std::optional<string> FormatDynamic(const string& in_format, -// const vector<string>& in_args) { -// string out; +// std::optional<std::string> FormatDynamic( +// const std::string& in_format, +// const vector<std::string>& in_args) { +// std::string out; // std::vector<absl::FormatArg> args; // for (const auto& v : in_args) { // // It is important that 'v' is a reference to the objects in in_args. @@ -509,4 +513,5 @@ } } // namespace absl + #endif // ABSL_STRINGS_STR_FORMAT_H_
diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc index aa14e21..d4cffa0 100644 --- a/absl/strings/str_format_test.cc +++ b/absl/strings/str_format_test.cc
@@ -242,6 +242,7 @@ std::string ReadFile() { std::fseek(file_, 0, SEEK_END); int size = std::ftell(file_); + EXPECT_GT(size, 0); std::rewind(file_); std::string str(2 * size, ' '); int read_bytes = std::fread(&str[0], 1, str.size(), file_); @@ -270,7 +271,7 @@ EXPECT_EQ(errno, EBADF); } -#if __GNUC__ +#if __GLIBC__ TEST_F(FormatEntryPointTest, FprintfTooLarge) { std::FILE* f = std::fopen("/dev/null", "w"); int width = 2000000000; @@ -297,7 +298,7 @@ EXPECT_EQ(result, 30); EXPECT_EQ(tmp.ReadFile(), "STRING: ABC NUMBER: -000000019"); } -#endif // __GNUC__ +#endif // __GLIBC__ TEST_F(FormatEntryPointTest, SNPrintF) { char buffer[16]; @@ -340,7 +341,7 @@ 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" - std::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++"); @@ -605,35 +606,21 @@ // Some codegen thunks that we can use to easily dump the generated assembly for // different StrFormat calls. -inline std::string CodegenAbslStrFormatInt(int i) { +std::string CodegenAbslStrFormatInt(int i) { // NOLINT return absl::StrFormat("%d", i); } -inline std::string CodegenAbslStrFormatIntStringInt64(int i, const std::string& s, - int64_t i64) { +std::string CodegenAbslStrFormatIntStringInt64(int i, const std::string& s, + int64_t i64) { // NOLINT return absl::StrFormat("%d %s %d", i, s, i64); } -inline void CodegenAbslStrAppendFormatInt(std::string* out, int i) { +void CodegenAbslStrAppendFormatInt(std::string* out, int i) { // NOLINT absl::StrAppendFormat(out, "%d", i); } -inline void CodegenAbslStrAppendFormatIntStringInt64(std::string* out, int i, - const std::string& s, - int64_t i64) { +void CodegenAbslStrAppendFormatIntStringInt64(std::string* out, int i, + const std::string& s, + int64_t i64) { // NOLINT absl::StrAppendFormat(out, "%d %s %d", i, s, i64); } - -auto absl_internal_str_format_force_codegen_funcs = std::make_tuple( - CodegenAbslStrFormatInt, CodegenAbslStrFormatIntStringInt64, - CodegenAbslStrAppendFormatInt, CodegenAbslStrAppendFormatIntStringInt64); - -bool absl_internal_str_format_force_codegen_always_false; -// Force the compiler to generate the functions by making it look like we -// escape the function pointers. -// It can't statically know that -// absl_internal_str_format_force_codegen_always_false is not changed by someone -// else. -bool absl_internal_str_format_force_codegen = - absl_internal_str_format_force_codegen_always_false && - printf("%p", &absl_internal_str_format_force_codegen_funcs) == 0;
diff --git a/absl/strings/str_join.h b/absl/strings/str_join.h index f9611ad..7345b96 100644 --- a/absl/strings/str_join.h +++ b/absl/strings/str_join.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -18,13 +18,13 @@ // ----------------------------------------------------------------------------- // // This header file contains functions for joining a range of elements and -// returning the result as a string. StrJoin operations are specified by passing -// a range, a separator string to use between the elements joined, and an -// optional Formatter responsible for converting each argument in the range to a -// string. If omitted, a default `AlphaNumFormatter()` is called on the elements -// to be joined, using the same formatting that `absl::StrCat()` uses. This -// package defines a number of default formatters, and you can define your own -// implementations. +// returning the result as a std::string. StrJoin operations are specified by +// passing a range, a separator string to use between the elements joined, and +// an optional Formatter responsible for converting each argument in the range +// to a string. If omitted, a default `AlphaNumFormatter()` is called on the +// elements to be joined, using the same formatting that `absl::StrCat()` uses. +// This package defines a number of default formatters, and you can define your +// own implementations. // // Ranges are specified by passing a container with `std::begin()` and // `std::end()` iterators, container-specific `begin()` and `end()` iterators, a @@ -37,8 +37,8 @@ // // Example: // -// std::vector<string> v = {"foo", "bar", "baz"}; -// string s = absl::StrJoin(v, "-"); +// std::vector<std::string> v = {"foo", "bar", "baz"}; +// std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ("foo-bar-baz", s); // // See comments on the `absl::StrJoin()` function for more examples. @@ -66,16 +66,16 @@ // ----------------------------------------------------------------------------- // // A Formatter is a function object that is responsible for formatting its -// argument as a string and appending it to a given output string. Formatters -// may be implemented as function objects, lambdas, or normal functions. You may -// provide your own Formatter to enable `absl::StrJoin()` to work with arbitrary -// types. +// argument as a string and appending it to a given output std::string. +// Formatters may be implemented as function objects, lambdas, or normal +// functions. You may provide your own Formatter to enable `absl::StrJoin()` to +// work with arbitrary types. // // The following is an example of a custom Formatter that simply uses -// `std::to_string()` to format an integer as a string. +// `std::to_string()` to format an integer as a std::string. // // struct MyFormatter { -// void operator()(string* out, int i) const { +// void operator()(std::string* out, int i) const { // out->append(std::to_string(i)); // } // }; @@ -84,7 +84,7 @@ // argument to `absl::StrJoin()`: // // std::vector<int> v = {1, 2, 3, 4}; -// string s = absl::StrJoin(v, "-", MyFormatter()); +// std::string s = absl::StrJoin(v, "-", MyFormatter()); // EXPECT_EQ("1-2-3-4", s); // // The following standard formatters are provided within this file: @@ -156,7 +156,7 @@ // StrJoin() // ----------------------------------------------------------------------------- // -// Joins a range of elements and returns the result as a string. +// Joins a range of elements and returns the result as a std::string. // `absl::StrJoin()` takes a range, a separator string to use between the // elements joined, and an optional Formatter responsible for converting each // argument in the range to a string. @@ -167,22 +167,22 @@ // Example 1: // // Joins a collection of strings. This pattern also works with a collection // // of `absl::string_view` or even `const char*`. -// std::vector<string> v = {"foo", "bar", "baz"}; -// string s = absl::StrJoin(v, "-"); +// std::vector<std::string> v = {"foo", "bar", "baz"}; +// std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ("foo-bar-baz", s); // // Example 2: // // Joins the values in the given `std::initializer_list<>` specified using // // brace initialization. This pattern also works with an initializer_list // // of ints or `absl::string_view` -- any `AlphaNum`-compatible type. -// string s = absl::StrJoin({"foo", "bar", "baz"}, "-"); +// std::string s = absl::StrJoin({"foo", "bar", "baz"}, "-"); // EXPECT_EQ("foo-bar-baz", s); // // Example 3: // // Joins a collection of ints. This pattern also works with floats, // // doubles, int64s -- any `StrCat()`-compatible type. // std::vector<int> v = {1, 2, 3, -4}; -// string s = absl::StrJoin(v, "-"); +// std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ("1-2-3--4", s); // // Example 4: @@ -193,7 +193,7 @@ // // `std::vector<int*>`. // int x = 1, y = 2, z = 3; // std::vector<int*> v = {&x, &y, &z}; -// string s = absl::StrJoin(v, "-"); +// std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ("1-2-3", s); // // Example 5: @@ -202,53 +202,53 @@ // v.emplace_back(new int(1)); // v.emplace_back(new int(2)); // v.emplace_back(new int(3)); -// string s = absl::StrJoin(v, "-"); +// std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ("1-2-3", s); // // Example 6: // // Joins a `std::map`, with each key-value pair separated by an equals // // sign. This pattern would also work with, say, a // // `std::vector<std::pair<>>`. -// std::map<string, int> m = { +// std::map<std::string, int> m = { // std::make_pair("a", 1), // std::make_pair("b", 2), // std::make_pair("c", 3)}; -// string s = absl::StrJoin(m, ",", absl::PairFormatter("=")); +// std::string s = absl::StrJoin(m, ",", absl::PairFormatter("=")); // EXPECT_EQ("a=1,b=2,c=3", s); // // Example 7: // // These examples show how `absl::StrJoin()` handles a few common edge // // cases: -// std::vector<string> v_empty; +// std::vector<std::string> v_empty; // EXPECT_EQ("", absl::StrJoin(v_empty, "-")); // -// std::vector<string> v_one_item = {"foo"}; +// std::vector<std::string> v_one_item = {"foo"}; // EXPECT_EQ("foo", absl::StrJoin(v_one_item, "-")); // -// std::vector<string> v_empty_string = {""}; +// std::vector<std::string> v_empty_string = {""}; // EXPECT_EQ("", absl::StrJoin(v_empty_string, "-")); // -// std::vector<string> v_one_item_empty_string = {"a", ""}; +// std::vector<std::string> v_one_item_empty_string = {"a", ""}; // EXPECT_EQ("a-", absl::StrJoin(v_one_item_empty_string, "-")); // -// std::vector<string> v_two_empty_string = {"", ""}; +// std::vector<std::string> v_two_empty_string = {"", ""}; // EXPECT_EQ("-", absl::StrJoin(v_two_empty_string, "-")); // // Example 8: // // Joins a `std::tuple<T...>` of heterogeneous types, converting each to -// // a string using the `absl::AlphaNum` class. -// string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-"); +// // a std::string using the `absl::AlphaNum` class. +// std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-"); // EXPECT_EQ("123-abc-0.456", s); template <typename Iterator, typename Formatter> std::string StrJoin(Iterator start, Iterator end, absl::string_view sep, - Formatter&& fmt) { + Formatter&& fmt) { return strings_internal::JoinAlgorithm(start, end, sep, fmt); } template <typename Range, typename Formatter> std::string StrJoin(const Range& range, absl::string_view separator, - Formatter&& fmt) { + Formatter&& fmt) { return strings_internal::JoinRange(range, separator, fmt); } @@ -260,7 +260,7 @@ template <typename... T, typename Formatter> std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator, - Formatter&& fmt) { + Formatter&& fmt) { return strings_internal::JoinAlgorithm(value, separator, fmt); } @@ -280,7 +280,8 @@ } template <typename... T> -std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator) { +std::string StrJoin(const std::tuple<T...>& value, + absl::string_view separator) { return strings_internal::JoinAlgorithm(value, separator, AlphaNumFormatter()); }
diff --git a/absl/strings/str_join_benchmark.cc b/absl/strings/str_join_benchmark.cc index 7fb0e49..d6f689f 100644 --- a/absl/strings/str_join_benchmark.cc +++ b/absl/strings/str_join_benchmark.cc
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -58,7 +58,8 @@ const int string_len = state.range(0); const int num_pairs = state.range(1); const std::string s(string_len, 'x'); - const std::vector<std::pair<std::string, int>> v(num_pairs, std::make_pair(s, 42)); + const std::vector<std::pair<std::string, int>> v(num_pairs, + std::make_pair(s, 42)); for (auto _ : state) { std::string s = absl::StrJoin(v, ",", absl::PairFormatter("=")); benchmark::DoNotOptimize(s);
diff --git a/absl/strings/str_join_test.cc b/absl/strings/str_join_test.cc index c941f9c..921d9c2 100644 --- a/absl/strings/str_join_test.cc +++ b/absl/strings/str_join_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -118,7 +118,7 @@ { // A std::map, which is a collection of std::pair<>s. - std::map<std::string, int> m = { {"a", 1}, {"b", 2}, {"c", 3} }; + std::map<std::string, int> m = {{"a", 1}, {"b", 2}, {"c", 3}}; EXPECT_EQ("a=1,b=2,c=3", absl::StrJoin(m, ",", absl::PairFormatter("="))); } @@ -140,7 +140,8 @@ } { - // A range of 1 element gives a std::string with that element but no separator. + // A range of 1 element gives a std::string with that element but no + // separator. std::vector<std::string> v = {"foo"}; EXPECT_EQ("foo", absl::StrJoin(v, "-")); } @@ -173,9 +174,10 @@ TEST(StrJoin, CustomFormatter) { std::vector<std::string> v{"One", "Two", "Three"}; { - std::string joined = absl::StrJoin(v, "", [](std::string* out, const std::string& in) { - absl::StrAppend(out, "(", in, ")"); - }); + std::string joined = + absl::StrJoin(v, "", [](std::string* out, const std::string& in) { + absl::StrAppend(out, "(", in, ")"); + }); EXPECT_EQ("(One)(Two)(Three)", joined); } {
diff --git a/absl/strings/str_replace.cc b/absl/strings/str_replace.cc index 69efa35..280f63d 100644 --- a/absl/strings/str_replace.cc +++ b/absl/strings/str_replace.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -68,11 +68,12 @@ // aren't inlined. std::string StrReplaceAll(absl::string_view s, - strings_internal::FixedMapping replacements) { + strings_internal::FixedMapping replacements) { return StrReplaceAll<strings_internal::FixedMapping>(s, replacements); } -int StrReplaceAll(strings_internal::FixedMapping replacements, std::string* target) { +int StrReplaceAll(strings_internal::FixedMapping replacements, + std::string* target) { return StrReplaceAll<strings_internal::FixedMapping>(replacements, target); }
diff --git a/absl/strings/str_replace.h b/absl/strings/str_replace.h index 3bfe4c6..30540d0 100644 --- a/absl/strings/str_replace.h +++ b/absl/strings/str_replace.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -29,12 +29,12 @@ // // Example: // -// string html_escaped = absl::StrReplaceAll(user_input, { -// {"&", "&"}, -// {"<", "<"}, -// {">", ">"}, -// {"\"", """}, -// {"'", "'"}}); +// std::string html_escaped = absl::StrReplaceAll(user_input, { +// {"&", "&"}, +// {"<", "<"}, +// {">", ">"}, +// {"\"", """}, +// {"'", "'"}}); #ifndef ABSL_STRINGS_STR_REPLACE_H_ #define ABSL_STRINGS_STR_REPLACE_H_ @@ -58,10 +58,11 @@ // // Example: // -// string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!", -// {{"$count", absl::StrCat(5)}, -// {"$who", "Bob"}, -// {"#Noun", "Apples"}}); +// std::string s = absl::StrReplaceAll( +// "$who bought $count #Noun. Thanks $who!", +// {{"$count", absl::StrCat(5)}, +// {"$who", "Bob"}, +// {"#Noun", "Apples"}}); // EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); ABSL_MUST_USE_RESULT std::string StrReplaceAll( absl::string_view s, @@ -78,20 +79,22 @@ // replacements["$who"] = "Bob"; // replacements["$count"] = "5"; // replacements["#Noun"] = "Apples"; -// string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!", -// replacements); +// std::string s = absl::StrReplaceAll( +// "$who bought $count #Noun. Thanks $who!", +// replacements); // EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); // // // A std::vector of std::pair elements can be more efficient. -// std::vector<std::pair<const absl::string_view, string>> replacements; +// std::vector<std::pair<const absl::string_view, std::string>> replacements; // replacements.push_back({"&", "&"}); // replacements.push_back({"<", "<"}); // replacements.push_back({">", ">"}); -// string s = absl::StrReplaceAll("if (ptr < &foo)", +// std::string s = absl::StrReplaceAll("if (ptr < &foo)", // replacements); // EXPECT_EQ("if (ptr < &foo)", s); template <typename StrToStrMapping> -std::string StrReplaceAll(absl::string_view s, const StrToStrMapping& replacements); +std::string StrReplaceAll(absl::string_view s, + const StrToStrMapping& replacements); // Overload of `StrReplaceAll()` to replace character sequences within a given // output string *in place* with replacements provided within an initializer @@ -99,7 +102,7 @@ // // Example: // -// string s = std::string("$who bought $count #Noun. Thanks $who!"); +// std::string s = std::string("$who bought $count #Noun. Thanks $who!"); // int count; // count = absl::StrReplaceAll({{"$count", absl::StrCat(5)}, // {"$who", "Bob"}, @@ -117,7 +120,7 @@ // // Example: // -// string s = std::string("if (ptr < &foo)"); +// std::string s = std::string("if (ptr < &foo)"); // int count = absl::StrReplaceAll({{"&", "&"}, // {"<", "<"}, // {">", ">"}}, &s); @@ -187,7 +190,8 @@ } // namespace strings_internal template <typename StrToStrMapping> -std::string StrReplaceAll(absl::string_view s, const StrToStrMapping& replacements) { +std::string StrReplaceAll(absl::string_view s, + const StrToStrMapping& replacements) { auto subs = strings_internal::FindSubstitutions(s, replacements); std::string result; result.reserve(s.size());
diff --git a/absl/strings/str_replace_benchmark.cc b/absl/strings/str_replace_benchmark.cc index 8386f2e..95b2dc1 100644 --- a/absl/strings/str_replace_benchmark.cc +++ b/absl/strings/str_replace_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -54,7 +54,7 @@ size_t r = 0; big_string = new std::string(1000 * 1000, ' '); for (std::string phrase : {"the quick brown fox jumped over the lazy dogs", - "pack my box with the five dozen liquor jugs"}) { + "pack my box with the five dozen liquor jugs"}) { for (int i = 0; i < 10 * 1000; ++i) { r = r * 237 + 41; // not very random. memcpy(&(*big_string)[r % (big_string->size() - phrase.size())], @@ -108,11 +108,11 @@ std::string src = *big_string; for (auto _ : state) { std::string dest = absl::StrReplaceAll(src, {{"the", "box"}, - {"brown", "quick"}, - {"jumped", "liquored"}, - {"dozen", "brown"}, - {"lazy", "pack"}, - {"liquor", "shakes"}}); + {"brown", "quick"}, + {"jumped", "liquored"}, + {"dozen", "brown"}, + {"lazy", "pack"}, + {"liquor", "shakes"}}); ABSL_RAW_CHECK(dest == *after_replacing_many, "not benchmarking intended behavior"); }
diff --git a/absl/strings/str_replace_test.cc b/absl/strings/str_replace_test.cc index 5d003a2..1ca23af 100644 --- a/absl/strings/str_replace_test.cc +++ b/absl/strings/str_replace_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -148,7 +148,7 @@ replacements["$count"] = "5"; replacements["#Noun"] = "Apples"; std::string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!", - replacements); + replacements); EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); }
diff --git a/absl/strings/str_split.cc b/absl/strings/str_split.cc index 0a68c52..2593130 100644 --- a/absl/strings/str_split.cc +++ b/absl/strings/str_split.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/str_split.h b/absl/strings/str_split.h index c7eb280..7333078 100644 --- a/absl/strings/str_split.h +++ b/absl/strings/str_split.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -71,23 +71,23 @@ // - `ByLength` // - `MaxSplits` // +// A Delimiter's `Find()` member function will be passed an input `text` that is +// to be split and a position (`pos`) to begin searching for the next delimiter +// in `text`. The returned absl::string_view should refer to the next occurrence +// (after `pos`) of the represented delimiter; this returned absl::string_view +// represents the next location where the input `text` should be broken. // -// A Delimiter's Find() member function will be passed the input text that is to -// be split and the position to begin searching for the next delimiter in the -// input text. The returned absl::string_view should refer to the next -// occurrence (after pos) of the represented delimiter; this returned -// absl::string_view represents the next location where the input string should -// be broken. The returned absl::string_view may be zero-length if the Delimiter -// does not represent a part of the string (e.g., a fixed-length delimiter). If -// no delimiter is found in the given text, a zero-length absl::string_view -// referring to text.end() should be returned (e.g., -// absl::string_view(text.end(), 0)). It is important that the returned -// absl::string_view always be within the bounds of input text given as an +// The returned absl::string_view may be zero-length if the Delimiter does not +// represent a part of the string (e.g., a fixed-length delimiter). If no +// delimiter is found in the input `text`, a zero-length absl::string_view +// referring to `text.end()` should be returned (e.g., +// `text.substr(text.size())`). It is important that the returned +// absl::string_view always be within the bounds of the input `text` given as an // argument--it must not refer to a string that is physically located outside of // the given string. // // The following example is a simple Delimiter object that is created with a -// single char and will look for that char in the text passed to the Find() +// single char and will look for that char in the text passed to the `Find()` // function: // // struct SimpleDelimiter { @@ -96,9 +96,9 @@ // absl::string_view Find(absl::string_view text, size_t pos) { // auto found = text.find(c_, pos); // if (found == absl::string_view::npos) -// return absl::string_view(text.end(), 0); +// return text.substr(text.size()); // -// return absl::string_view(text, found, 1); +// return text.substr(found, 1); // } // }; @@ -131,8 +131,7 @@ // ByChar // // A single character delimiter. `ByChar` is functionally equivalent to a -// 1-char string within a `ByString` delimiter, but slightly more -// efficient. +// 1-char string within a `ByString` delimiter, but slightly more efficient. // // Example: // @@ -413,10 +412,10 @@ // // The `StrSplit()` function adapts the returned collection to the collection // specified by the caller (e.g. `std::vector` above). The returned collections -// may contain `string`, `absl::string_view` (in which case the original string -// being split must ensure that it outlives the collection), or any object that -// can be explicitly created from an `absl::string_view`. This behavior works -// for: +// may contain `std::string`, `absl::string_view` (in which case the original +// string being split must ensure that it outlives the collection), or any +// object that can be explicitly created from an `absl::string_view`. This +// behavior works for: // // 1) All standard STL containers including `std::vector`, `std::list`, // `std::deque`, `std::set`,`std::multiset`, 'std::map`, and `std::multimap` @@ -460,7 +459,7 @@ // Example: // // // Stores first two split strings as the members in a std::pair. -// std::pair<string, string> p = absl::StrSplit("a,b,c", ','); +// std::pair<std::string, std::string> p = absl::StrSplit("a,b,c", ','); // // p.first == "a", p.second == "b" // "c" is omitted. // // The `StrSplit()` function can be used multiple times to perform more @@ -470,7 +469,7 @@ // // // The input string "a=b=c,d=e,f=,g" becomes // // { "a" => "b=c", "d" => "e", "f" => "", "g" => "" } -// std::map<string, string> m; +// std::map<std::string, std::string> m; // for (absl::string_view sp : absl::StrSplit("a=b=c,d=e,f=,g", ',')) { // m.insert(absl::StrSplit(sp, absl::MaxSplits('=', 1))); // }
diff --git a/absl/strings/str_split_benchmark.cc b/absl/strings/str_split_benchmark.cc index 326ff74..28c25e8 100644 --- a/absl/strings/str_split_benchmark.cc +++ b/absl/strings/str_split_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -35,16 +35,16 @@ return test; } -void BM_Split2StringPiece(benchmark::State& state) { +void BM_Split2StringView(benchmark::State& state) { std::string test = MakeTestString(state.range(0)); for (auto _ : state) { std::vector<absl::string_view> result = absl::StrSplit(test, ';'); benchmark::DoNotOptimize(result); } } -BENCHMARK_RANGE(BM_Split2StringPiece, 0, 1 << 20); +BENCHMARK_RANGE(BM_Split2StringView, 0, 1 << 20); -void BM_Split2StringPieceLifted(benchmark::State& state) { +void BM_Split2StringViewLifted(benchmark::State& state) { std::string test = MakeTestString(state.range(0)); std::vector<absl::string_view> result; for (auto _ : state) { @@ -52,7 +52,7 @@ } benchmark::DoNotOptimize(result); } -BENCHMARK_RANGE(BM_Split2StringPieceLifted, 0, 1 << 20); +BENCHMARK_RANGE(BM_Split2StringViewLifted, 0, 1 << 20); void BM_Split2String(benchmark::State& state) { std::string test = MakeTestString(state.range(0)); @@ -69,7 +69,8 @@ void BM_Split2SplitStringUsing(benchmark::State& state) { std::string test = MakeTestString(state.range(0)); for (auto _ : state) { - std::vector<std::string> result = absl::StrSplit(test, ';', absl::SkipEmpty()); + std::vector<std::string> result = + absl::StrSplit(test, ';', absl::SkipEmpty()); benchmark::DoNotOptimize(result); } }
diff --git a/absl/strings/str_split_test.cc b/absl/strings/str_split_test.cc index 413ad31..ef6400e 100644 --- a/absl/strings/str_split_test.cc +++ b/absl/strings/str_split_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -40,8 +40,8 @@ TEST(Split, TraitsTest) { static_assert(!absl::strings_internal::SplitterIsConvertibleTo<int>::value, ""); - static_assert(!absl::strings_internal::SplitterIsConvertibleTo<std::string>::value, - ""); + static_assert( + !absl::strings_internal::SplitterIsConvertibleTo<std::string>::value, ""); static_assert(absl::strings_internal::SplitterIsConvertibleTo< std::vector<std::string>>::value, ""); @@ -182,7 +182,8 @@ { // Uses the SkipWhitespace predicate. using absl::SkipWhitespace; - std::vector<std::string> v = absl::StrSplit(" a , ,,b,", ',', SkipWhitespace()); + std::vector<std::string> v = + absl::StrSplit(" a , ,,b,", ',', SkipWhitespace()); EXPECT_THAT(v, ElementsAre(" a ", "b")); } @@ -215,7 +216,8 @@ { // Results stored in a std::multimap. - std::multimap<std::string, std::string> m = absl::StrSplit("a,1,b,2,a,3", ','); + std::multimap<std::string, std::string> m = + absl::StrSplit("a,1,b,2,a,3", ','); EXPECT_EQ(3, m.size()); auto it = m.find("a"); EXPECT_EQ("1", it->second); @@ -271,7 +273,8 @@ EXPECT_EQ("a", *it); // tests dereference ++it; // tests preincrement EXPECT_NE(it, end); - EXPECT_EQ("b", std::string(it->data(), it->size())); // tests dereference as ptr + EXPECT_EQ("b", + std::string(it->data(), it->size())); // tests dereference as ptr it++; // tests postincrement EXPECT_EQ(it, end); } @@ -295,7 +298,8 @@ EXPECT_EQ("a", *it); // tests dereference ++it; // tests preincrement -- "b" should be skipped here. EXPECT_NE(it, end); - EXPECT_EQ("c", std::string(it->data(), it->size())); // tests dereference as ptr + EXPECT_EQ("c", + std::string(it->data(), it->size())); // tests dereference as ptr it++; // tests postincrement EXPECT_EQ(it, end); } @@ -421,10 +425,13 @@ TestMapConversionOperator<std::map<std::string, std::string>>(splitter); TestMapConversionOperator< std::multimap<absl::string_view, absl::string_view>>(splitter); - TestMapConversionOperator<std::multimap<absl::string_view, std::string>>(splitter); - TestMapConversionOperator<std::multimap<std::string, absl::string_view>>(splitter); + TestMapConversionOperator<std::multimap<absl::string_view, std::string>>( + splitter); + TestMapConversionOperator<std::multimap<std::string, absl::string_view>>( + splitter); TestMapConversionOperator<std::multimap<std::string, std::string>>(splitter); - TestMapConversionOperator<std::unordered_map<std::string, std::string>>(splitter); + TestMapConversionOperator<std::unordered_map<std::string, std::string>>( + splitter); // Tests conversion to std::pair @@ -568,10 +575,9 @@ } TEST(Split, Temporary) { - // Use a std::string longer than the small-std::string-optimization length, so that when - // the temporary is destroyed, if the splitter keeps a reference to the - // std::string's contents, it'll reference freed memory instead of just dead - // on-stack memory. + // 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, + // it'll reference freed memory instead of just dead on-stack memory. const char input[] = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u"; EXPECT_LT(sizeof(std::string), ABSL_ARRAYSIZE(input)) << "Input should be larger than fits on the stack."; @@ -647,6 +653,11 @@ } } +#if !defined(__cpp_char8_t) +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++2a-compat" +#endif TEST(Split, UTF8) { // Tests splitting utf8 strings and utf8 delimiters. std::string utf8_string = u8"\u03BA\u1F79\u03C3\u03BC\u03B5"; @@ -673,6 +684,10 @@ EXPECT_THAT(v, ElementsAre("Foo", u8"h\u00E4llo", u8"th\u4E1Ere")); } } +#if defined(__clang__) +#pragma clang diagnostic pop +#endif +#endif // !defined(__cpp_char8_t) TEST(Split, EmptyStringDelimiter) { {
diff --git a/absl/strings/string_view.cc b/absl/strings/string_view.cc index 4ceeb6b..cb79d5d 100644 --- a/absl/strings/string_view.cc +++ b/absl/strings/string_view.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -228,7 +228,7 @@ // member definitions that are required by the C++ standard, resulting in // LNK1169 "multiply defined" errors at link time. __declspec(selectany) asks // MSVC to choose only one definition for the symbol it decorates. See details -// at http://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx +// at https://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx #ifdef _MSC_VER #define ABSL_STRING_VIEW_SELECTANY __declspec(selectany) #else
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h index 6bcd3c4..f8b2001 100644 --- a/absl/strings/string_view.h +++ b/absl/strings/string_view.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -32,7 +32,7 @@ #ifdef ABSL_HAVE_STD_STRING_VIEW -#include <string_view> +#include <string_view> // IWYU pragma: export namespace absl { using std::string_view; @@ -101,7 +101,6 @@ // 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 @@ -277,7 +276,7 @@ // Checks if the `string_view` is empty (refers to no characters). constexpr bool empty() const noexcept { return length_ == 0; } - // std::string:view::operator[] + // string_view::operator[] // // Returns the ith element of an `string_view` using the array operator. // Note that this operator does not perform any bounds checking. @@ -355,7 +354,7 @@ 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); + n = (std::min)(n, length_ - pos); return string_view(ptr_ + pos, n); } @@ -368,7 +367,7 @@ // 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_); + 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; @@ -490,7 +489,7 @@ private: static constexpr size_type kMaxSize = - std::numeric_limits<difference_type>::max(); + (std::numeric_limits<difference_type>::max)(); static constexpr size_type CheckLengthInternal(size_type len) { return ABSL_ASSERT(len <= kMaxSize), len; @@ -508,6 +507,7 @@ if (len != y.size()) { return false; } + return x.data() == y.data() || len <= 0 || memcmp(x.data(), y.data(), len) == 0; } @@ -517,7 +517,7 @@ } inline bool operator<(string_view x, string_view y) noexcept { - auto min_size = std::min(x.size(), y.size()); + 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()); } @@ -547,7 +547,7 @@ // Provided because std::string_view::substr throws if `pos > size()` inline string_view ClippedSubstr(string_view s, size_t pos, size_t n = string_view::npos) { - pos = std::min(pos, static_cast<size_t>(s.size())); + pos = (std::min)(pos, static_cast<size_t>(s.size())); return s.substr(pos, n); }
diff --git a/absl/strings/string_view_benchmark.cc b/absl/strings/string_view_benchmark.cc index fb46db1..46909cb 100644 --- a/absl/strings/string_view_benchmark.cc +++ b/absl/strings/string_view_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -151,7 +151,7 @@ std::string haystack(state.range(0), '0'); absl::string_view s(haystack); for (auto _ : state) { - s.find("x"); // not present; length 1 + benchmark::DoNotOptimize(s.find("x")); // not present; length 1 } } BENCHMARK(BM_find_string_view_len_one)->Range(1, 1 << 20); @@ -160,7 +160,7 @@ std::string haystack(state.range(0), '0'); absl::string_view s(haystack); for (auto _ : state) { - s.find("xx"); // not present; length 2 + benchmark::DoNotOptimize(s.find("xx")); // not present; length 2 } } BENCHMARK(BM_find_string_view_len_two)->Range(1, 1 << 20); @@ -169,7 +169,7 @@ std::string haystack(state.range(0), '0'); absl::string_view s(haystack); for (auto _ : state) { - s.find('x'); // not present + benchmark::DoNotOptimize(s.find('x')); // not present } } BENCHMARK(BM_find_one_char)->Range(1, 1 << 20); @@ -178,7 +178,7 @@ std::string haystack(state.range(0), '0'); absl::string_view s(haystack); for (auto _ : state) { - s.rfind('x'); // not present + benchmark::DoNotOptimize(s.rfind('x')); // not present } } BENCHMARK(BM_rfind_one_char)->Range(1, 1 << 20); @@ -193,7 +193,7 @@ absl::string_view s(haystack); for (auto _ : state) { - s.find_first_of(needle); + benchmark::DoNotOptimize(s.find_first_of(needle)); } }
diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc index a94e822..f5acf1d 100644 --- a/absl/strings/string_view_test.cc +++ b/absl/strings/string_view_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -284,9 +284,10 @@ } #undef COMPARE -// Sadly, our users often confuse string::npos with absl::string_view::npos; -// So much so that we test here that they are the same. They need to -// both be unsigned, and both be the maximum-valued integer of their type. +// Sadly, our users often confuse std::string::npos with +// absl::string_view::npos; So much so that we test here that they are the same. +// They need to both be unsigned, and both be the maximum-valued integer of +// their type. template <typename T> struct is_type { @@ -678,9 +679,9 @@ EXPECT_EQ(a.substr(23, absl::string_view::npos), c); // throw exception #ifdef ABSL_HAVE_EXCEPTIONS - EXPECT_THROW(a.substr(99, 2), std::out_of_range); + EXPECT_THROW((void)a.substr(99, 2), std::out_of_range); #else - EXPECT_DEATH(a.substr(99, 2), "absl::string_view::substr"); + EXPECT_DEATH((void)a.substr(99, 2), "absl::string_view::substr"); #endif } @@ -755,7 +756,6 @@ std::string s1("123"); s1 += '\0'; s1 += "456"; - absl::string_view b(s1); absl::string_view e; std::string s2; @@ -995,8 +995,8 @@ TEST(StringViewTest, Noexcept) { EXPECT_TRUE((std::is_nothrow_constructible<absl::string_view, const std::string&>::value)); - EXPECT_TRUE( - (std::is_nothrow_constructible<absl::string_view, const std::string&>::value)); + EXPECT_TRUE((std::is_nothrow_constructible<absl::string_view, + const std::string&>::value)); EXPECT_TRUE(std::is_nothrow_constructible<absl::string_view>::value); constexpr absl::string_view sp; EXPECT_TRUE(noexcept(sp.begin()));
diff --git a/absl/strings/strip.h b/absl/strings/strip.h index 8d0d7c6..e1341e0 100644 --- a/absl/strings/strip.h +++ b/absl/strings/strip.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/strip_test.cc b/absl/strings/strip_test.cc index 40c4c60..e4e00cb 100644 --- a/absl/strings/strip_test.cc +++ b/absl/strings/strip_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -27,9 +27,6 @@ namespace { -using testing::ElementsAre; -using testing::IsEmpty; - TEST(Strip, ConsumePrefixOneChar) { absl::string_view input("abc"); EXPECT_TRUE(absl::ConsumePrefix(&input, "a"));
diff --git a/absl/strings/substitute.cc b/absl/strings/substitute.cc index 3b20059..bc17695 100644 --- a/absl/strings/substitute.cc +++ b/absl/strings/substitute.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h index 4de7b4e..507bc4f 100644 --- a/absl/strings/substitute.h +++ b/absl/strings/substitute.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -36,18 +36,17 @@ // use at that location within the format string. // // Example 1: -// string s = Substitute("$1 purchased $0 $2. Thanks $1!", -// 5, "Bob", "Apples"); +// std::string s = Substitute("$1 purchased $0 $2. Thanks $1!", +// 5, "Bob", "Apples"); // EXPECT_EQ("Bob purchased 5 Apples. Thanks Bob!", s); // // Example 2: -// string s = "Hi. "; +// std::string s = "Hi. "; // SubstituteAndAppend(&s, "My name is $0 and I am $1 years old.", "Bob", 5); // EXPECT_EQ("Hi. My name is Bob and I am 5 years old.", s); // -// // Supported types: -// * absl::string_view, string, const char* (null is equivalent to "") +// * absl::string_view, std::string, const char* (null is equivalent to "") // * int32_t, int64_t, uint32_t, uint64 // * float, double // * bool (Printed as "true" or "false") @@ -456,7 +455,7 @@ // Example: // template <typename... Args> // void VarMsg(absl::string_view format, const Args&... args) { -// string s = absl::Substitute(format, args...); +// std::string s = absl::Substitute(format, args...); ABSL_MUST_USE_RESULT inline std::string Substitute(absl::string_view format) { std::string result; @@ -574,70 +573,70 @@ "contains one of $1-$9"); std::string Substitute(const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1) + const substitute_internal::Arg& a1) ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 3, "There were 2 substitution arguments given, but " "this format std::string is either missing its $0/$1, or " "contains one of $2-$9"); std::string Substitute(const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2) + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2) ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 7, "There were 3 substitution arguments given, but " "this format std::string is either missing its $0/$1/$2, or " "contains one of $3-$9"); std::string Substitute(const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3) + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3) ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 15, "There were 4 substitution arguments given, but " "this format std::string is either missing its $0-$3, or " "contains one of $4-$9"); std::string Substitute(const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4) + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4) ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 31, "There were 5 substitution arguments given, but " "this format std::string is either missing its $0-$4, or " "contains one of $5-$9"); std::string Substitute(const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5) + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5) ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 63, "There were 6 substitution arguments given, but " "this format std::string is either missing its $0-$5, or " "contains one of $6-$9"); std::string Substitute(const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, - const substitute_internal::Arg& a6) + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5, + const substitute_internal::Arg& a6) ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 127, "There were 7 substitution arguments given, but " "this format std::string is either missing its $0-$6, or " "contains one of $7-$9"); std::string Substitute(const char* format, const substitute_internal::Arg& a0, - const substitute_internal::Arg& a1, - const substitute_internal::Arg& a2, - const substitute_internal::Arg& a3, - const substitute_internal::Arg& a4, - const substitute_internal::Arg& a5, - const substitute_internal::Arg& a6, - const substitute_internal::Arg& a7) + const substitute_internal::Arg& a1, + const substitute_internal::Arg& a2, + const substitute_internal::Arg& a3, + const substitute_internal::Arg& a4, + const substitute_internal::Arg& a5, + const substitute_internal::Arg& a6, + const substitute_internal::Arg& a7) ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 255, "There were 8 substitution arguments given, but " "this format std::string is either missing its $0-$7, or "
diff --git a/absl/strings/substitute_test.cc b/absl/strings/substitute_test.cc index 144df01..f656890 100644 --- a/absl/strings/substitute_test.cc +++ b/absl/strings/substitute_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel index f52e9d4..5e69847 100644 --- a/absl/synchronization/BUILD.bazel +++ b/absl/synchronization/BUILD.bazel
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -15,7 +15,7 @@ # load( - "//absl:copts.bzl", + "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_TEST_COPTS", ) @@ -69,6 +69,10 @@ "notification.h", ], copts = ABSL_DEFAULT_COPTS, + linkopts = select({ + "//absl:windows": [], + "//conditions:default": ["-pthread"], + }), deps = [ ":graphcycles_internal", "//absl/base", @@ -170,18 +174,31 @@ ], ) -cc_test( - name = "mutex_benchmark", +cc_library( + name = "mutex_benchmark_common", + testonly = 1, srcs = ["mutex_benchmark.cc"], copts = ABSL_TEST_COPTS, - tags = ["benchmark"], - visibility = ["//visibility:private"], + visibility = [ + "//absl/synchronization:__pkg__", + ], deps = [ ":synchronization", ":thread_pool", "//absl/base", "@com_github_google_benchmark//:benchmark_main", ], + alwayslink = 1, +) + +cc_binary( + name = "mutex_benchmark", + testonly = 1, + copts = ABSL_DEFAULT_COPTS, + visibility = ["//visibility:private"], + deps = [ + ":mutex_benchmark_common", + ], ) cc_test( @@ -232,10 +249,6 @@ "lifetime_test.cc", ], copts = ABSL_TEST_COPTS, - linkopts = select({ - "//absl:windows": [], - "//conditions:default": ["-pthread"], - }), tags = ["no_test_ios_x86_64"], deps = [ ":synchronization",
diff --git a/absl/synchronization/CMakeLists.txt b/absl/synchronization/CMakeLists.txt index de0d7b7..68473b7 100644 --- a/absl/synchronization/CMakeLists.txt +++ b/absl/synchronization/CMakeLists.txt
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -14,142 +14,182 @@ # limitations under the License. # -list(APPEND SYNCHRONIZATION_PUBLIC_HEADERS - "barrier.h" - "blocking_counter.h" - "mutex.h" - "notification.h" +absl_cc_library( + NAME + graphcycles_internal + HDRS + "internal/graphcycles.h" + SRCS + "internal/graphcycles.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::base + absl::base_internal + absl::core_headers + absl::malloc_internal ) - -list(APPEND SYNCHRONIZATION_INTERNAL_HEADERS - "internal/create_thread_identity.h" - "internal/graphcycles.h" - "internal/kernel_timeout.h" - "internal/per_thread_sem.h" - "internal/thread_pool.h" - "internal/waiter.h" -) - - - -# synchronization library -list(APPEND SYNCHRONIZATION_SRC - "barrier.cc" - "blocking_counter.cc" - "internal/create_thread_identity.cc" - "internal/per_thread_sem.cc" - "internal/waiter.cc" - "internal/graphcycles.cc" - "notification.cc" - "mutex.cc" -) - -set(SYNCHRONIZATION_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::symbolize absl::time) - -absl_library( - TARGET - absl_synchronization - SOURCES - ${SYNCHRONIZATION_SRC} - PUBLIC_LIBRARIES - ${SYNCHRONIZATION_PUBLIC_LIBRARIES} - EXPORT_NAME +absl_cc_library( + NAME synchronization + HDRS + "barrier.h" + "blocking_counter.h" + "internal/create_thread_identity.h" + "internal/kernel_timeout.h" + "internal/mutex_nonprod.inc" + "internal/per_thread_sem.h" + "internal/waiter.h" + "mutex.h" + "notification.h" + SRCS + "barrier.cc" + "blocking_counter.cc" + "internal/create_thread_identity.cc" + "internal/per_thread_sem.cc" + "internal/waiter.cc" + "notification.cc" + "mutex.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::graphcycles_internal + absl::base + absl::base_internal + absl::config + absl::core_headers + absl::dynamic_annotations + absl::malloc_internal + absl::stacktrace + absl::symbolize + absl::time + PUBLIC ) - -# -## TESTS -# - - -# test barrier_test -set(BARRIER_TEST_SRC "barrier_test.cc") -set(BARRIER_TEST_PUBLIC_LIBRARIES absl::synchronization) - -absl_test( - TARGET +absl_cc_test( + NAME barrier_test - SOURCES - ${BARRIER_TEST_SRC} - PUBLIC_LIBRARIES - ${BARRIER_TEST_PUBLIC_LIBRARIES} + SRCS + "barrier_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::synchronization + absl::time + gmock_main ) - -# test blocking_counter_test -set(BLOCKING_COUNTER_TEST_SRC "blocking_counter_test.cc") -set(BLOCKING_COUNTER_TEST_PUBLIC_LIBRARIES absl::synchronization) - -absl_test( - TARGET +absl_cc_test( + NAME blocking_counter_test - SOURCES - ${BLOCKING_COUNTER_TEST_SRC} - PUBLIC_LIBRARIES - ${BLOCKING_COUNTER_TEST_PUBLIC_LIBRARIES} + SRCS + "blocking_counter_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::synchronization + absl::time + gmock_main ) - -# test graphcycles_test -set(GRAPHCYCLES_TEST_SRC "internal/graphcycles_test.cc") -set(GRAPHCYCLES_TEST_PUBLIC_LIBRARIES absl::synchronization) - -absl_test( - TARGET +absl_cc_test( + NAME graphcycles_test - SOURCES - ${GRAPHCYCLES_TEST_SRC} - PUBLIC_LIBRARIES - ${GRAPHCYCLES_TEST_PUBLIC_LIBRARIES} + SRCS + "internal/graphcycles_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::graphcycles_internal + absl::base + absl::core_headers + gmock_main ) +absl_cc_library( + NAME + thread_pool + HDRS + "internal/thread_pool.h" + DEPS + absl::synchronization + absl::core_headers + TESTONLY +) -# test mutex_test -set(MUTEX_TEST_SRC "mutex_test.cc") -set(MUTEX_TEST_PUBLIC_LIBRARIES absl::synchronization) - -absl_test( - TARGET +absl_cc_test( + NAME mutex_test - SOURCES - ${MUTEX_TEST_SRC} - PUBLIC_LIBRARIES - ${MUTEX_TEST_PUBLIC_LIBRARIES} + SRCS + "mutex_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::synchronization + absl::thread_pool + absl::base + absl::core_headers + absl::memory + absl::time + gmock_main ) - -# test notification_test -set(NOTIFICATION_TEST_SRC "notification_test.cc") -set(NOTIFICATION_TEST_PUBLIC_LIBRARIES absl::synchronization) - -absl_test( - TARGET +absl_cc_test( + NAME notification_test - SOURCES - ${NOTIFICATION_TEST_SRC} - PUBLIC_LIBRARIES - ${NOTIFICATION_TEST_PUBLIC_LIBRARIES} + SRCS + "notification_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::synchronization + absl::time + gmock_main ) - -# test per_thread_sem_test_common -set(PER_THREAD_SEM_TEST_COMMON_SRC "internal/per_thread_sem_test.cc") -set(PER_THREAD_SEM_TEST_COMMON_PUBLIC_LIBRARIES absl::synchronization absl::strings) - -absl_test( - TARGET +absl_cc_library( + NAME per_thread_sem_test_common - SOURCES - ${PER_THREAD_SEM_TEST_COMMON_SRC} - PUBLIC_LIBRARIES - ${PER_THREAD_SEM_TEST_COMMON_PUBLIC_LIBRARIES} + SRCS + "internal/per_thread_sem_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::synchronization + absl::base + absl::strings + absl::time + gmock + TESTONLY ) +absl_cc_test( + NAME + per_thread_sem_test + SRCS + "internal/per_thread_sem_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::per_thread_sem_test_common + absl::synchronization + absl::base + absl::strings + absl::time + gmock_main +) - - - - - +absl_cc_test( + NAME + lifetime_test + SRCS + "lifetime_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::synchronization + absl::base + absl::core_headers + Threads::Threads +)
diff --git a/absl/synchronization/barrier.cc b/absl/synchronization/barrier.cc index a1b3ad5..c2c539a 100644 --- a/absl/synchronization/barrier.cc +++ b/absl/synchronization/barrier.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/synchronization/barrier.h b/absl/synchronization/barrier.h index f834fee..23bb2f5 100644 --- a/absl/synchronization/barrier.h +++ b/absl/synchronization/barrier.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/synchronization/barrier_test.cc b/absl/synchronization/barrier_test.cc index d6cabab..bfc6cb1 100644 --- a/absl/synchronization/barrier_test.cc +++ b/absl/synchronization/barrier_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/synchronization/blocking_counter.cc b/absl/synchronization/blocking_counter.cc index 7e68e96..481a06b 100644 --- a/absl/synchronization/blocking_counter.cc +++ b/absl/synchronization/blocking_counter.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/synchronization/blocking_counter.h b/absl/synchronization/blocking_counter.h index 557ed02..4c66e0a 100644 --- a/absl/synchronization/blocking_counter.h +++ b/absl/synchronization/blocking_counter.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/synchronization/blocking_counter_test.cc b/absl/synchronization/blocking_counter_test.cc index e8223f8..c63e339 100644 --- a/absl/synchronization/blocking_counter_test.cc +++ b/absl/synchronization/blocking_counter_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/synchronization/internal/create_thread_identity.cc b/absl/synchronization/internal/create_thread_identity.cc index e7a65cd..6e93605 100644 --- a/absl/synchronization/internal/create_thread_identity.cc +++ b/absl/synchronization/internal/create_thread_identity.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -67,6 +67,30 @@ return (addr + align - 1) & ~(align - 1); } +static void ResetThreadIdentity(base_internal::ThreadIdentity* identity) { + base_internal::PerThreadSynch* pts = &identity->per_thread_synch; + pts->next = nullptr; + pts->skip = nullptr; + pts->may_skip = false; + pts->waitp = nullptr; + pts->suppress_fatal_errors = false; + pts->readers = 0; + pts->priority = 0; + pts->next_priority_read_cycles = 0; + pts->state.store(base_internal::PerThreadSynch::State::kAvailable, + std::memory_order_relaxed); + pts->maybe_unlocking = false; + 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); + identity->is_idle.store(false, std::memory_order_relaxed); + identity->next = nullptr; +} + static base_internal::ThreadIdentity* NewThreadIdentity() { base_internal::ThreadIdentity* identity = nullptr; @@ -90,7 +114,7 @@ RoundUp(reinterpret_cast<intptr_t>(allocation), base_internal::PerThreadSynch::kAlignment)); } - memset(identity, 0, sizeof(*identity)); + ResetThreadIdentity(identity); return identity; }
diff --git a/absl/synchronization/internal/create_thread_identity.h b/absl/synchronization/internal/create_thread_identity.h index 1bb87de..ebb16c5 100644 --- a/absl/synchronization/internal/create_thread_identity.h +++ b/absl/synchronization/internal/create_thread_identity.h
@@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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, @@ -50,4 +50,5 @@ } // namespace synchronization_internal } // namespace absl + #endif // ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_
diff --git a/absl/synchronization/internal/graphcycles.cc b/absl/synchronization/internal/graphcycles.cc index d3878de..0c8c756 100644 --- a/absl/synchronization/internal/graphcycles.cc +++ b/absl/synchronization/internal/graphcycles.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/synchronization/internal/graphcycles.h b/absl/synchronization/internal/graphcycles.h index 2e6686a..e5bde00 100644 --- a/absl/synchronization/internal/graphcycles.h +++ b/absl/synchronization/internal/graphcycles.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/synchronization/internal/graphcycles_benchmark.cc b/absl/synchronization/internal/graphcycles_benchmark.cc index a239c25..54823e0 100644 --- a/absl/synchronization/internal/graphcycles_benchmark.cc +++ b/absl/synchronization/internal/graphcycles_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/synchronization/internal/graphcycles_test.cc b/absl/synchronization/internal/graphcycles_test.cc index 9a85b39..58e8477 100644 --- a/absl/synchronization/internal/graphcycles_test.cc +++ b/absl/synchronization/internal/graphcycles_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/synchronization/internal/kernel_timeout.h b/absl/synchronization/internal/kernel_timeout.h index bb70800..61c72e7 100644 --- a/absl/synchronization/internal/kernel_timeout.h +++ b/absl/synchronization/internal/kernel_timeout.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -53,6 +53,7 @@ // We explicitly do not support other custom formats: timespec, int64_t nanos. // Unify on this and absl::Time, please. + bool has_timeout() const { return ns_ != 0; } private: @@ -76,7 +77,7 @@ if (x <= 0) x = 1; // A time larger than what can be represented to the kernel is treated // as no timeout. - if (x == std::numeric_limits<int64_t>::max()) x = 0; + if (x == (std::numeric_limits<int64_t>::max)()) x = 0; return x; } @@ -90,7 +91,7 @@ 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(); + n = (std::numeric_limits<int64_t>::max)(); } // Kernel APIs validate timespecs as being at or after the epoch, @@ -100,8 +101,8 @@ if (n < 0) n = 0; struct timespec abstime; - int64_t seconds = std::min(n / kNanosPerSecond, - int64_t{std::numeric_limits<time_t>::max()}); + 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); @@ -119,7 +120,7 @@ // <intsafe.h> and <WinBase.h>. typedef unsigned long DWord; // NOLINT DWord InMillisecondsFromNow() const { - constexpr DWord kInfinite = std::numeric_limits<DWord>::max(); + constexpr DWord kInfinite = (std::numeric_limits<DWord>::max)(); if (!has_timeout()) { return kInfinite; } @@ -130,7 +131,7 @@ if (ns_ >= now) { // Round up so that Now() + ms_from_now >= ns_. constexpr uint64_t max_nanos = - std::numeric_limits<int64_t>::max() - 999999u; + (std::numeric_limits<int64_t>::max)() - 999999u; uint64_t ms_from_now = (std::min<uint64_t>(max_nanos, ns_ - now) + 999999u) / 1000000u; if (ms_from_now > kInfinite) { @@ -148,4 +149,5 @@ } // namespace synchronization_internal } // namespace absl + #endif // ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
diff --git a/absl/synchronization/internal/mutex_nonprod.cc b/absl/synchronization/internal/mutex_nonprod.cc index 45c6032..267deaf 100644 --- a/absl/synchronization/internal/mutex_nonprod.cc +++ b/absl/synchronization/internal/mutex_nonprod.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/synchronization/internal/mutex_nonprod.inc b/absl/synchronization/internal/mutex_nonprod.inc index 0aab3d1..b8d5af7 100644 --- a/absl/synchronization/internal/mutex_nonprod.inc +++ b/absl/synchronization/internal/mutex_nonprod.inc
@@ -214,6 +214,9 @@ // 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;
diff --git a/absl/synchronization/internal/per_thread_sem.cc b/absl/synchronization/internal/per_thread_sem.cc index caa2baf..b7014fb 100644 --- a/absl/synchronization/internal/per_thread_sem.cc +++ b/absl/synchronization/internal/per_thread_sem.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -89,6 +89,7 @@ if (identity->blocked_count_ptr != nullptr) { identity->blocked_count_ptr->fetch_sub(1, std::memory_order_relaxed); } + identity->is_idle.store(false, std::memory_order_relaxed); identity->wait_start.store(0, std::memory_order_relaxed); return !timeout;
diff --git a/absl/synchronization/internal/per_thread_sem.h b/absl/synchronization/internal/per_thread_sem.h index 678b69e..e7da070 100644 --- a/absl/synchronization/internal/per_thread_sem.h +++ b/absl/synchronization/internal/per_thread_sem.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -104,4 +104,5 @@ absl::synchronization_internal::KernelTimeout t) { return AbslInternalPerThreadSemWait(t); } + #endif // ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
diff --git a/absl/synchronization/internal/per_thread_sem_test.cc b/absl/synchronization/internal/per_thread_sem_test.cc index c29d840..dba7239 100644 --- a/absl/synchronization/internal/per_thread_sem_test.cc +++ b/absl/synchronization/internal/per_thread_sem_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -114,10 +114,9 @@ min_cycles = std::min(min_cycles, cycles); total_cycles += cycles; } - std::string out = - StrCat(msg, "min cycle count=", min_cycles, " avg cycle count=", - absl::SixDigits(static_cast<double>(total_cycles) / - kNumIterations)); + std::string out = StrCat( + msg, "min cycle count=", min_cycles, " avg cycle count=", + absl::SixDigits(static_cast<double>(total_cycles) / kNumIterations)); printf("%s\n", out.c_str()); partner_thread.join(); @@ -152,12 +151,16 @@ } TEST_F(PerThreadSemTest, Timeouts) { - absl::Time timeout = absl::Now() + absl::Milliseconds(50); + const absl::Duration delay = absl::Milliseconds(50); + const absl::Time start = absl::Now(); + EXPECT_FALSE(Wait(start + delay)); + const absl::Duration elapsed = absl::Now() - start; // Allow for a slight early return, to account for quality of implementation // issues on various platforms. const absl::Duration slop = absl::Microseconds(200); - EXPECT_FALSE(Wait(timeout)); - EXPECT_LE(timeout, absl::Now() + slop); + EXPECT_LE(delay - slop, elapsed) + << "Wait returned " << delay - elapsed + << " early (with " << slop << " slop), start time was " << start; absl::Time negative_timeout = absl::UnixEpoch() - absl::Milliseconds(100); EXPECT_FALSE(Wait(negative_timeout));
diff --git a/absl/synchronization/internal/thread_pool.h b/absl/synchronization/internal/thread_pool.h index 8464042..7f458f5 100644 --- a/absl/synchronization/internal/thread_pool.h +++ b/absl/synchronization/internal/thread_pool.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -16,6 +16,7 @@ #define ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_ #include <cassert> +#include <cstddef> #include <functional> #include <queue> #include <thread> // NOLINT(build/c++11) @@ -42,7 +43,7 @@ ~ThreadPool() { { absl::MutexLock l(&mu_); - for (int i = 0; i < threads_.size(); ++i) { + for (size_t i = 0; i < threads_.size(); i++) { queue_.push(nullptr); // Shutdown signal. } }
diff --git a/absl/synchronization/internal/waiter.cc b/absl/synchronization/internal/waiter.cc index 768c520..74b0965 100644 --- a/absl/synchronization/internal/waiter.cc +++ b/absl/synchronization/internal/waiter.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -40,6 +40,7 @@ #include <atomic> #include <cassert> #include <cstdint> + #include "absl/base/internal/raw_logging.h" #include "absl/base/internal/thread_identity.h" #include "absl/base/optimization.h" @@ -81,6 +82,7 @@ #define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF #endif #endif + class Futex { public: static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
diff --git a/absl/synchronization/internal/waiter.h b/absl/synchronization/internal/waiter.h index 23166f4..66b4beb 100644 --- a/absl/synchronization/internal/waiter.h +++ b/absl/synchronization/internal/waiter.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/synchronization/lifetime_test.cc b/absl/synchronization/lifetime_test.cc index 90c9009..0279c8f 100644 --- a/absl/synchronization/lifetime_test.cc +++ b/absl/synchronization/lifetime_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -17,6 +17,7 @@ #include <type_traits> #include "absl/base/attributes.h" +#include "absl/base/const_init.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/thread_annotations.h" #include "absl/synchronization/mutex.h" @@ -72,23 +73,19 @@ // Launch thread 1 and thread 2, and block on their completion. // If any of 'mutex', 'condvar', or 'notification' is nullptr, use a locally // constructed instance instead. -void RunTests(absl::Mutex* mutex, absl::CondVar* condvar, - absl::Notification* notification) { +void RunTests(absl::Mutex* mutex, absl::CondVar* condvar) { absl::Mutex default_mutex; absl::CondVar default_condvar; - absl::Notification default_notification; + absl::Notification notification; if (!mutex) { mutex = &default_mutex; } if (!condvar) { condvar = &default_condvar; } - if (!notification) { - notification = &default_notification; - } bool state = false; - std::thread thread_one(ThreadOne, mutex, condvar, notification, &state); - std::thread thread_two(ThreadTwo, mutex, condvar, notification, &state); + std::thread thread_one(ThreadOne, mutex, condvar, ¬ification, &state); + std::thread thread_two(ThreadTwo, mutex, condvar, ¬ification, &state); thread_one.join(); thread_two.join(); } @@ -96,10 +93,13 @@ void TestLocals() { absl::Mutex mutex; absl::CondVar condvar; - absl::Notification notification; - RunTests(&mutex, &condvar, ¬ification); + RunTests(&mutex, &condvar); } +// Normal kConstInit usage +ABSL_CONST_INIT absl::Mutex const_init_mutex(absl::kConstInit); +void TestConstInitGlobal() { RunTests(&const_init_mutex, nullptr); } + // Global variables during start and termination // // In a translation unit, static storage duration variables are initialized in @@ -122,10 +122,53 @@ Function fn_; }; +// kConstInit +// Test early usage. (Declaration comes first; definitions must appear after +// the test runner.) +extern absl::Mutex early_const_init_mutex; +// (Normally I'd write this +[], to make the cast-to-function-pointer explicit, +// but in some MSVC setups we support, lambdas provide conversion operators to +// different flavors of function pointers, making this trick ambiguous.) +OnConstruction test_early_const_init([] { + RunTests(&early_const_init_mutex, nullptr); +}); +// This definition appears before test_early_const_init, but it should be +// initialized first (due to constant initialization). Test that the object +// actually works when constructed this way. +ABSL_CONST_INIT absl::Mutex early_const_init_mutex(absl::kConstInit); + +// Furthermore, test that the const-init c'tor doesn't stomp over the state of +// a Mutex. Really, this is a test that the platform under test correctly +// supports C++11 constant initialization. (The constant-initialization +// constructors of globals "happen at link time"; memory is pre-initialized, +// before the constructors of either grab_lock or check_still_locked are run.) +extern absl::Mutex const_init_sanity_mutex; +OnConstruction grab_lock([]() NO_THREAD_SAFETY_ANALYSIS { + const_init_sanity_mutex.Lock(); +}); +ABSL_CONST_INIT absl::Mutex const_init_sanity_mutex(absl::kConstInit); +OnConstruction check_still_locked([]() NO_THREAD_SAFETY_ANALYSIS { + const_init_sanity_mutex.AssertHeld(); + const_init_sanity_mutex.Unlock(); +}); + +// Test shutdown usage. (Declarations come first; definitions must appear after +// the test runner.) +extern absl::Mutex late_const_init_mutex; +// OnDestruction is being used here as a global variable, even though it has a +// non-trivial destructor. This is against the style guide. We're violating +// that rule here to check that the exception we allow for kConstInit is safe. +// NOLINTNEXTLINE +OnDestruction test_late_const_init([] { + RunTests(&late_const_init_mutex, nullptr); +}); +ABSL_CONST_INIT absl::Mutex late_const_init_mutex(absl::kConstInit); + } // namespace int main() { TestLocals(); + TestConstInitGlobal(); // Explicitly call exit(0) here, to make it clear that we intend for the // above global object destructors to run. std::exit(0);
diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc index 9d59a79..97c5919 100644 --- a/absl/synchronization/mutex.cc +++ b/absl/synchronization/mutex.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -118,6 +118,10 @@ } // namespace +static inline bool EvalConditionAnnotated(const Condition *cond, Mutex *mu, + bool locking, bool trylock, + bool read_lock); + void RegisterMutexProfiler(void (*fn)(int64_t wait_timestamp)) { submit_profile_data.Store(fn); } @@ -233,15 +237,14 @@ SYNCH_EV_SIGNALALL, }; -enum { // Event flags - SYNCH_F_R = 0x01, // reader event - SYNCH_F_LCK = 0x02, // PostSynchEvent called with mutex held - SYNCH_F_ACQ = 0x04, // event is an acquire +enum { // Event flags + SYNCH_F_R = 0x01, // reader event + SYNCH_F_LCK = 0x02, // PostSynchEvent called with mutex held + SYNCH_F_TRY = 0x04, // TryLock or ReaderTryLock + SYNCH_F_UNLOCK = 0x08, // Unlock or ReaderUnlock SYNCH_F_LCK_W = SYNCH_F_LCK, SYNCH_F_LCK_R = SYNCH_F_LCK | SYNCH_F_R, - SYNCH_F_ACQ_W = SYNCH_F_ACQ, - SYNCH_F_ACQ_R = SYNCH_F_ACQ | SYNCH_F_R, }; } // anonymous namespace @@ -250,21 +253,22 @@ int flags; const char *msg; } event_properties[] = { - { SYNCH_F_LCK_W|SYNCH_F_ACQ_W, "TryLock succeeded " }, - { 0, "TryLock failed " }, - { SYNCH_F_LCK_R|SYNCH_F_ACQ_R, "ReaderTryLock succeeded " }, - { 0, "ReaderTryLock failed " }, - { SYNCH_F_ACQ_W, "Lock blocking " }, - { SYNCH_F_LCK_W, "Lock returning " }, - { SYNCH_F_ACQ_R, "ReaderLock blocking " }, - { SYNCH_F_LCK_R, "ReaderLock returning " }, - { SYNCH_F_LCK_W, "Unlock " }, - { SYNCH_F_LCK_R, "ReaderUnlock " }, - { 0, "Wait on " }, - { 0, "Wait unblocked " }, - { 0, "Signal on " }, - { 0, "SignalAll on " }, + {SYNCH_F_LCK_W | SYNCH_F_TRY, "TryLock succeeded "}, + {0, "TryLock failed "}, + {SYNCH_F_LCK_R | SYNCH_F_TRY, "ReaderTryLock succeeded "}, + {0, "ReaderTryLock failed "}, + {0, "Lock blocking "}, + {SYNCH_F_LCK_W, "Lock returning "}, + {0, "ReaderLock blocking "}, + {SYNCH_F_LCK_R, "ReaderLock returning "}, + {SYNCH_F_LCK_W | SYNCH_F_UNLOCK, "Unlock "}, + {SYNCH_F_LCK_R | SYNCH_F_UNLOCK, "ReaderUnlock "}, + {0, "Wait on "}, + {0, "Wait unblocked "}, + {0, "Signal on "}, + {0, "SignalAll on "}, }; + static absl::base_internal::SpinLock synch_event_mu( absl::base_internal::kLinkerInitialized); // protects synch_event @@ -414,9 +418,26 @@ ABSL_RAW_LOG(INFO, "%s%p %s %s", event_properties[ev].msg, obj, (e == nullptr ? "" : e->name), buffer); } - if ((event_properties[ev].flags & SYNCH_F_LCK) != 0 && e != nullptr && - e->invariant != nullptr) { - (*e->invariant)(e->arg); + const int flags = event_properties[ev].flags; + if ((flags & SYNCH_F_LCK) != 0 && e != nullptr && e->invariant != nullptr) { + // Calling the invariant as is causes problems under ThreadSanitizer. + // We are currently inside of Mutex Lock/Unlock and are ignoring all + // memory accesses and synchronization. If the invariant transitively + // synchronizes something else and we ignore the synchronization, we will + // get false positive race reports later. + // Reuse EvalConditionAnnotated to properly call into user code. + struct local { + static bool pred(SynchEvent *ev) { + (*ev->invariant)(ev->arg); + return false; + } + }; + Condition cond(&local::pred, e); + Mutex *mu = static_cast<Mutex *>(obj); + const bool locking = (flags & SYNCH_F_UNLOCK) == 0; + const bool trylock = (flags & SYNCH_F_TRY) != 0; + const bool read_lock = (flags & SYNCH_F_R) != 0; + EvalConditionAnnotated(&cond, mu, locking, trylock, read_lock); } UnrefSynchEvent(e); } @@ -1079,7 +1100,7 @@ // if the wait extends past the absolute time specified, even if "s" is still // on the mutex queue. In this case, remove "s" from the queue and return // true, otherwise return false. -void Mutex::Block(PerThreadSynch *s) { +ABSL_XRAY_LOG_ARGS(1) void Mutex::Block(PerThreadSynch *s) { while (s->state.load(std::memory_order_acquire) == PerThreadSynch::kQueued) { if (!DecrementSynchSem(this, s, s->waitp->timeout)) { // After a timeout, we go into a spin loop until we remove ourselves @@ -1552,7 +1573,7 @@ ABSL_TSAN_MUTEX_PRE_LOCK(this, TsanFlags(how)); this->LockSlowLoop(&waitp, flags); bool res = waitp.cond != nullptr || // => cond known true from LockSlowLoop - cond.Eval(); + EvalConditionAnnotated(&cond, this, true, false, how == kShared); ABSL_TSAN_MUTEX_POST_LOCK(this, TsanFlags(how), 0); return res; } @@ -1730,12 +1751,17 @@ // Compute cond->Eval() and tell race detectors that we do it under mutex mu. static inline bool EvalConditionAnnotated(const Condition *cond, Mutex *mu, - bool locking, Mutex::MuHow how) { + bool locking, bool trylock, + bool read_lock) { // Delicate annotation dance. // We are currently inside of read/write lock/unlock operation. // All memory accesses are ignored inside of mutex operations + for unlock // operation tsan considers that we've already released the mutex. bool res = false; +#ifdef THREAD_SANITIZER + const int flags = read_lock ? __tsan_mutex_read_lock : 0; + const int tryflags = flags | (trylock ? __tsan_mutex_try_lock : 0); +#endif if (locking) { // For lock we pretend that we have finished the operation, // evaluate the predicate, then unlock the mutex and start locking it again @@ -1743,24 +1769,26 @@ // Note: we can't simply do POST_LOCK, Eval, PRE_LOCK, because then tsan // will think the lock acquisition is recursive which will trigger // deadlock detector. - ABSL_TSAN_MUTEX_POST_LOCK(mu, TsanFlags(how), 0); + ABSL_TSAN_MUTEX_POST_LOCK(mu, tryflags, 0); res = cond->Eval(); - ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, TsanFlags(how)); - ABSL_TSAN_MUTEX_POST_UNLOCK(mu, TsanFlags(how)); - ABSL_TSAN_MUTEX_PRE_LOCK(mu, TsanFlags(how)); + // There is no "try" version of Unlock, so use flags instead of tryflags. + ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, flags); + ABSL_TSAN_MUTEX_POST_UNLOCK(mu, flags); + ABSL_TSAN_MUTEX_PRE_LOCK(mu, tryflags); } else { // Similarly, for unlock we pretend that we have unlocked the mutex, // lock the mutex, evaluate the predicate, and start unlocking it again // to match the annotation at the end of outer unlock operation. - ABSL_TSAN_MUTEX_POST_UNLOCK(mu, TsanFlags(how)); - ABSL_TSAN_MUTEX_PRE_LOCK(mu, TsanFlags(how)); - ABSL_TSAN_MUTEX_POST_LOCK(mu, TsanFlags(how), 0); + ABSL_TSAN_MUTEX_POST_UNLOCK(mu, flags); + ABSL_TSAN_MUTEX_PRE_LOCK(mu, flags); + ABSL_TSAN_MUTEX_POST_LOCK(mu, flags, 0); res = cond->Eval(); - ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, TsanFlags(how)); + ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, flags); } // Prevent unused param warnings in non-TSAN builds. static_cast<void>(mu); - static_cast<void>(how); + static_cast<void>(trylock); + static_cast<void>(read_lock); return res; } @@ -1806,7 +1834,8 @@ v, (how->fast_or | (v & zap_desig_waker[flags & kMuHasBlocked])) + how->fast_add, std::memory_order_acquire, std::memory_order_relaxed)) { - if (cond == nullptr || EvalConditionAnnotated(cond, this, true, how)) { + if (cond == nullptr || + EvalConditionAnnotated(cond, this, true, false, how == kShared)) { return true; } unlock = true; @@ -1824,7 +1853,8 @@ } this->LockSlowLoop(&waitp, flags); return waitp.cond != nullptr || // => cond known true from LockSlowLoop - cond == nullptr || EvalConditionAnnotated(cond, this, true, how); + cond == nullptr || + EvalConditionAnnotated(cond, this, true, false, how == kShared); } // RAW_CHECK_FMT() takes a condition, a printf-style format string, and @@ -1841,7 +1871,7 @@ // Test for either of two situations that should not occur in v: // kMuWriter and kMuReader // kMuWrWait and !kMuWait - const intptr_t w = v ^ kMuWait; + const uintptr_t w = v ^ kMuWait; // By flipping that bit, we can now test for: // kMuWriter and kMuReader in w // kMuWrWait and kMuWait in w @@ -1880,7 +1910,8 @@ waitp->how->fast_add, std::memory_order_acquire, std::memory_order_relaxed)) { if (waitp->cond == nullptr || - EvalConditionAnnotated(waitp->cond, this, true, waitp->how)) { + EvalConditionAnnotated(waitp->cond, this, true, false, + waitp->how == kShared)) { break; // we timed out, or condition true, so return } this->UnlockSlow(waitp); // got lock but condition false @@ -1923,7 +1954,8 @@ std::memory_order_release, std::memory_order_relaxed)); if (waitp->cond == nullptr || - EvalConditionAnnotated(waitp->cond, this, true, waitp->how)) { + EvalConditionAnnotated(waitp->cond, this, true, false, + waitp->how == kShared)) { break; // we timed out, or condition true, so return } this->UnlockSlow(waitp); // got lock but condition false
diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h index a378190..c38e356 100644 --- a/absl/synchronization/mutex.h +++ b/absl/synchronization/mutex.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -61,6 +61,7 @@ #include <cstdint> #include <string> +#include "absl/base/const_init.h" #include "absl/base/internal/identity.h" #include "absl/base/internal/low_level_alloc.h" #include "absl/base/internal/thread_identity.h" @@ -136,7 +137,27 @@ class LOCKABLE Mutex { public: + // Creates a `Mutex` that is not held by anyone. This constructor is + // typically used for Mutexes allocated on the heap or the stack. + // + // To create `Mutex` instances with static storage duration + // (e.g. a namespace-scoped or global variable), see + // `Mutex::Mutex(absl::kConstInit)` below instead. Mutex(); + + // Creates a mutex with static storage duration. A global variable + // constructed this way avoids the lifetime issues that can occur on program + // startup and shutdown. (See absl/base/const_init.h.) + // + // For Mutexes allocated on the heap and stack, instead use the default + // constructor, which can interact more fully with the thread sanitizer. + // + // Example usage: + // namespace foo { + // ABSL_CONST_INIT Mutex mu(absl::kConstInit); + // } + explicit constexpr Mutex(absl::ConstInitType); + ~Mutex(); // Mutex::Lock() @@ -584,7 +605,7 @@ // ----------------------------------------------------------------------------- // // As noted above, `Mutex` contains a number of member functions which take a -// `Condition` as a argument; clients can wait for conditions to become `true` +// `Condition` as an argument; clients can wait for conditions to become `true` // before attempting to acquire the mutex. These sections are known as // "condition critical" sections. To use a `Condition`, you simply need to // construct it, and use within an appropriate `Mutex` member function; @@ -879,11 +900,15 @@ }; #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); } +inline constexpr Mutex::Mutex(absl::ConstInitType) : mu_(0) {} + inline CondVar::CondVar() : cv_(0) {} #endif @@ -1025,4 +1050,5 @@ extern "C" { void AbslInternalMutexYield(); } // extern "C" + #endif // ABSL_SYNCHRONIZATION_MUTEX_H_
diff --git a/absl/synchronization/mutex_benchmark.cc b/absl/synchronization/mutex_benchmark.cc index 1e019e0..ab18800 100644 --- a/absl/synchronization/mutex_benchmark.cc +++ b/absl/synchronization/mutex_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -12,16 +12,154 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include <cstdint> +#include <mutex> // NOLINT(build/c++11) #include <vector> -#include "benchmark/benchmark.h" -#include "absl/base/internal/sysinfo.h" +#include "absl/base/internal/cycleclock.h" +#include "absl/base/internal/spinlock.h" #include "absl/synchronization/blocking_counter.h" #include "absl/synchronization/internal/thread_pool.h" #include "absl/synchronization/mutex.h" +#include "benchmark/benchmark.h" namespace { +void BM_Mutex(benchmark::State& state) { + static absl::Mutex* mu = new absl::Mutex; + for (auto _ : state) { + absl::MutexLock lock(mu); + } +} +BENCHMARK(BM_Mutex)->UseRealTime()->Threads(1)->ThreadPerCpu(); + +static void DelayNs(int64_t ns, int* data) { + int64_t end = absl::base_internal::CycleClock::Now() + + ns * absl::base_internal::CycleClock::Frequency() / 1e9; + while (absl::base_internal::CycleClock::Now() < end) { + ++(*data); + benchmark::DoNotOptimize(*data); + } +} + +template <typename MutexType> +class RaiiLocker { + public: + explicit RaiiLocker(MutexType* mu) : mu_(mu) { mu_->Lock(); } + ~RaiiLocker() { mu_->Unlock(); } + private: + MutexType* mu_; +}; + +template <> +class RaiiLocker<std::mutex> { + public: + explicit RaiiLocker(std::mutex* mu) : mu_(mu) { mu_->lock(); } + ~RaiiLocker() { mu_->unlock(); } + private: + std::mutex* mu_; +}; + +template <typename MutexType> +void BM_Contended(benchmark::State& state) { + struct Shared { + MutexType mu; + int data = 0; + }; + static auto* shared = new Shared; + int local = 0; + for (auto _ : state) { + // Here we model both local work outside of the critical section as well as + // some work inside of the critical section. The idea is to capture some + // more or less realisitic contention levels. + // If contention is too low, the benchmark won't measure anything useful. + // If contention is unrealistically high, the benchmark will favor + // bad mutex implementations that block and otherwise distract threads + // from the mutex and shared state for as much as possible. + // To achieve this amount of local work is multiplied by number of threads + // to keep ratio between local work and critical section approximately + // equal regardless of number of threads. + DelayNs(100 * state.threads, &local); + RaiiLocker<MutexType> locker(&shared->mu); + DelayNs(state.range(0), &shared->data); + } +} + +BENCHMARK_TEMPLATE(BM_Contended, absl::Mutex) + ->UseRealTime() + // ThreadPerCpu poorly handles non-power-of-two CPU counts. + ->Threads(1) + ->Threads(2) + ->Threads(4) + ->Threads(6) + ->Threads(8) + ->Threads(12) + ->Threads(16) + ->Threads(24) + ->Threads(32) + ->Threads(48) + ->Threads(64) + ->Threads(96) + ->Threads(128) + ->Threads(192) + ->Threads(256) + // Some empirically chosen amounts of work in critical section. + // 1 is low contention, 200 is high contention and few values in between. + ->Arg(1) + ->Arg(20) + ->Arg(50) + ->Arg(200); + +BENCHMARK_TEMPLATE(BM_Contended, absl::base_internal::SpinLock) + ->UseRealTime() + // ThreadPerCpu poorly handles non-power-of-two CPU counts. + ->Threads(1) + ->Threads(2) + ->Threads(4) + ->Threads(6) + ->Threads(8) + ->Threads(12) + ->Threads(16) + ->Threads(24) + ->Threads(32) + ->Threads(48) + ->Threads(64) + ->Threads(96) + ->Threads(128) + ->Threads(192) + ->Threads(256) + // Some empirically chosen amounts of work in critical section. + // 1 is low contention, 200 is high contention and few values in between. + ->Arg(1) + ->Arg(20) + ->Arg(50) + ->Arg(200); + +BENCHMARK_TEMPLATE(BM_Contended, std::mutex) + ->UseRealTime() + // ThreadPerCpu poorly handles non-power-of-two CPU counts. + ->Threads(1) + ->Threads(2) + ->Threads(4) + ->Threads(6) + ->Threads(8) + ->Threads(12) + ->Threads(16) + ->Threads(24) + ->Threads(32) + ->Threads(48) + ->Threads(64) + ->Threads(96) + ->Threads(128) + ->Threads(192) + ->Threads(256) + // Some empirically chosen amounts of work in critical section. + // 1 is low contention, 200 is high contention and few values in between. + ->Arg(1) + ->Arg(20) + ->Arg(50) + ->Arg(200); + // Measure the overhead of conditions on mutex release (when they must be // evaluated). Mutex has (some) support for equivalence classes allowing // Conditions with the same function/argument to potentially not be multiply @@ -82,13 +220,4 @@ #endif BENCHMARK(BM_ConditionWaiters)->RangePair(0, 2, 1, kMaxConditionWaiters); -void BM_ContendedMutex(benchmark::State& state) { - static absl::Mutex* mu = new absl::Mutex; - for (auto _ : state) { - absl::MutexLock lock(mu); - } -} -BENCHMARK(BM_ContendedMutex)->Threads(1); -BENCHMARK(BM_ContendedMutex)->ThreadPerCpu(); - } // namespace
diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc index b2820e2..1021122 100644 --- a/absl/synchronization/mutex_test.cc +++ b/absl/synchronization/mutex_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -610,9 +610,9 @@ waiter2.reset(); // "join" waiter2 } -INSTANTIATE_TEST_CASE_P(CondVarWaitDeadlockTest, CondVarWaitDeadlock, - ::testing::Range(0, 8), - ::testing::PrintToStringParamName()); +INSTANTIATE_TEST_SUITE_P(CondVarWaitDeadlockTest, CondVarWaitDeadlock, + ::testing::Range(0, 8), + ::testing::PrintToStringParamName()); // -------------------------------------------------------- // Test for fix of bug in DequeueAllWakeable() @@ -1032,9 +1032,9 @@ ScopedDisableBazelTestWarnings() { #ifdef WIN32 char file[MAX_PATH]; - if (GetEnvironmentVariable(kVarName, file, sizeof(file)) < sizeof(file)) { + if (GetEnvironmentVariableA(kVarName, file, sizeof(file)) < sizeof(file)) { warnings_output_file_ = file; - SetEnvironmentVariable(kVarName, nullptr); + SetEnvironmentVariableA(kVarName, nullptr); } #else const char *file = getenv(kVarName); @@ -1048,7 +1048,7 @@ ~ScopedDisableBazelTestWarnings() { if (!warnings_output_file_.empty()) { #ifdef WIN32 - SetEnvironmentVariable(kVarName, warnings_output_file_.c_str()); + SetEnvironmentVariableA(kVarName, warnings_output_file_.c_str()); #else setenv(kVarName, warnings_output_file_.c_str(), 0); #endif @@ -1367,8 +1367,8 @@ } // Instantiate `TimeoutTest` with `MakeTimeoutTestParamValues()`. -INSTANTIATE_TEST_CASE_P(All, TimeoutTest, - testing::ValuesIn(MakeTimeoutTestParamValues())); +INSTANTIATE_TEST_SUITE_P(All, TimeoutTest, + testing::ValuesIn(MakeTimeoutTestParamValues())); TEST_P(TimeoutTest, Await) { const TimeoutTestParam params = GetParam(); @@ -1548,9 +1548,9 @@ class MutexVariableThreadCountTest : public ::testing::TestWithParam<int> {}; // Instantiate the above with AllThreadCountOptions(). -INSTANTIATE_TEST_CASE_P(ThreadCounts, MutexVariableThreadCountTest, - ::testing::ValuesIn(AllThreadCountValues()), - ::testing::PrintToStringParamName()); +INSTANTIATE_TEST_SUITE_P(ThreadCounts, MutexVariableThreadCountTest, + ::testing::ValuesIn(AllThreadCountValues()), + ::testing::PrintToStringParamName()); // Reduces iterations by some factor for slow platforms // (determined empirically).
diff --git a/absl/synchronization/notification.cc b/absl/synchronization/notification.cc index ed8cc90..53ace00 100644 --- a/absl/synchronization/notification.cc +++ b/absl/synchronization/notification.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -22,6 +22,7 @@ #include "absl/time/time.h" namespace absl { + void Notification::Notify() { MutexLock l(&this->mutex_);
diff --git a/absl/synchronization/notification.h b/absl/synchronization/notification.h index 107932f..82d111a 100644 --- a/absl/synchronization/notification.h +++ b/absl/synchronization/notification.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -52,6 +52,7 @@ #include <atomic> +#include "absl/base/macros.h" #include "absl/synchronization/mutex.h" #include "absl/time/time.h" @@ -109,4 +110,5 @@ }; } // namespace absl + #endif // ABSL_SYNCHRONIZATION_NOTIFICATION_H_
diff --git a/absl/synchronization/notification_test.cc b/absl/synchronization/notification_test.cc index d8708d5..059d4cd 100644 --- a/absl/synchronization/notification_test.cc +++ b/absl/synchronization/notification_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -72,12 +72,16 @@ EXPECT_FALSE(notification->WaitForNotificationWithDeadline(absl::Now())); const absl::Duration delay = absl::Milliseconds(50); + const absl::Time start = absl::Now(); + EXPECT_FALSE(notification->WaitForNotificationWithTimeout(delay)); + const absl::Duration elapsed = absl::Now() - start; + // Allow for a slight early return, to account for quality of implementation // issues on various platforms. const absl::Duration slop = absl::Microseconds(200); - absl::Time start = absl::Now(); - EXPECT_FALSE(notification->WaitForNotificationWithTimeout(delay)); - EXPECT_LE(start + delay, absl::Now() + slop); + EXPECT_LE(delay - slop, elapsed) + << "WaitForNotificationWithTimeout returned " << delay - elapsed + << " early (with " << slop << " slop), start time was " << start; ThreadSafeCounter ready_counter; ThreadSafeCounter done_counter;
diff --git a/absl/time/BUILD.bazel b/absl/time/BUILD.bazel index c7c16d4..a94be65 100644 --- a/absl/time/BUILD.bazel +++ b/absl/time/BUILD.bazel
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -15,7 +15,7 @@ # load( - "//absl:copts.bzl", + "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_TEST_COPTS", ) @@ -27,6 +27,7 @@ cc_library( name = "time", srcs = [ + "civil_time.cc", "clock.cc", "duration.cc", "format.cc", @@ -35,6 +36,7 @@ "time.cc", ], hdrs = [ + "civil_time.h", "clock.h", "time.h", ], @@ -72,10 +74,10 @@ cc_test( name = "time_test", srcs = [ + "civil_time_test.cc", "clock_test.cc", "duration_test.cc", "format_test.cc", - "time_norm_test.cc", "time_test.cc", "time_zone_test.cc", ], @@ -94,6 +96,7 @@ cc_test( name = "time_benchmark", srcs = [ + "civil_time_benchmark.cc", "clock_benchmark.cc", "duration_benchmark.cc", "format_benchmark.cc", @@ -107,6 +110,8 @@ ":test_util", ":time", "//absl/base", + "//absl/base:core_headers", + "//absl/hash", "@com_github_google_benchmark//:benchmark_main", ], )
diff --git a/absl/time/BUILD.gn b/absl/time/BUILD.gn index 5758e9d..e3f9e1a 100644 --- a/absl/time/BUILD.gn +++ b/absl/time/BUILD.gn
@@ -22,6 +22,7 @@ ] public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] sources = [ + "civil_time.cc", "clock.cc", "duration.cc", "format.cc", @@ -30,6 +31,7 @@ "time.cc", ] public = [ + "civil_time.h", "clock.h", "time.h", ]
diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt index 0627236..5909832 100644 --- a/absl/time/CMakeLists.txt +++ b/absl/time/CMakeLists.txt
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -14,83 +14,114 @@ # limitations under the License. # -list(APPEND TIME_PUBLIC_HEADERS - "clock.h" - "time.h" -) - - -list(APPEND TIME_INTERNAL_HEADERS - "internal/test_util.h" - "internal/cctz/include/cctz/civil_time.h" - "internal/cctz/include/cctz/civil_time_detail.h" - "internal/cctz/include/cctz/time_zone.h" - "internal/cctz/include/cctz/zone_info_source.h" -) - -list(APPEND TIME_SRC - "time.cc" +absl_cc_library( + NAME + time + HDRS + "civil_time.h" + "clock.h" + "time.h" + SRCS + "civil_time.cc" "clock.cc" "duration.cc" "format.cc" + "internal/get_current_time_chrono.inc" + "internal/get_current_time_posix.inc" + "time.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::base + absl::core_headers + absl::int128 + absl::strings + absl::civil_time + absl::time_zone + PUBLIC +) + +absl_cc_library( + NAME + civil_time + HDRS + "internal/cctz/include/cctz/civil_time.h" + "internal/cctz/include/cctz/civil_time_detail.h" + SRCS "internal/cctz/src/civil_time_detail.cc" - "internal/cctz/src/time_zone_fixed.cc" - "internal/cctz/src/time_zone_fixed.h" - "internal/cctz/src/time_zone_format.cc" - "internal/cctz/src/time_zone_if.cc" - "internal/cctz/src/time_zone_if.h" - "internal/cctz/src/time_zone_impl.cc" - "internal/cctz/src/time_zone_impl.h" - "internal/cctz/src/time_zone_info.cc" - "internal/cctz/src/time_zone_info.h" - "internal/cctz/src/time_zone_libc.cc" - "internal/cctz/src/time_zone_libc.h" - "internal/cctz/src/time_zone_lookup.cc" - "internal/cctz/src/time_zone_posix.cc" - "internal/cctz/src/time_zone_posix.h" - "internal/cctz/src/tzfile.h" - "internal/cctz/src/zone_info_source.cc" - ${TIME_PUBLIC_HEADERS} - ${TIME_INTERNAL_HEADERS} -) -set(TIME_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::int128 absl::strings) - -absl_library( - TARGET - absl_time - SOURCES - ${TIME_SRC} - PUBLIC_LIBRARIES - ${TIME_PUBLIC_LIBRARIES} - EXPORT_NAME - time + COPTS + ${ABSL_DEFAULT_COPTS} ) +if(APPLE) + find_library(CoreFoundation CoreFoundation) +endif() - -# -## TESTS -# - -# test time_test -list(APPEND TIME_TEST_SRC - "time_test.cc" - "clock_test.cc" - "duration_test.cc" - "format_test.cc" - "time_norm_test.cc" - "time_test.cc" - "time_zone_test.cc" - "internal/test_util.cc" +absl_cc_library( + NAME + time_zone + HDRS + "internal/cctz/include/cctz/time_zone.h" + "internal/cctz/include/cctz/zone_info_source.h" + SRCS + "internal/cctz/src/time_zone_fixed.cc" + "internal/cctz/src/time_zone_fixed.h" + "internal/cctz/src/time_zone_format.cc" + "internal/cctz/src/time_zone_if.cc" + "internal/cctz/src/time_zone_if.h" + "internal/cctz/src/time_zone_impl.cc" + "internal/cctz/src/time_zone_impl.h" + "internal/cctz/src/time_zone_info.cc" + "internal/cctz/src/time_zone_info.h" + "internal/cctz/src/time_zone_libc.cc" + "internal/cctz/src/time_zone_libc.h" + "internal/cctz/src/time_zone_lookup.cc" + "internal/cctz/src/time_zone_posix.cc" + "internal/cctz/src/time_zone_posix.h" + "internal/cctz/src/tzfile.h" + "internal/cctz/src/zone_info_source.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + $<$<PLATFORM_ID:Darwin>:${CoreFoundation}> ) -set(TIME_TEST_PUBLIC_LIBRARIES absl::time) -absl_test( - TARGET +absl_cc_library( + NAME + test_util + HDRS + "internal/test_util.h" + SRCS + "internal/test_util.cc" + "internal/zoneinfo.inc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::time + absl::base + absl::time_zone + gmock + TESTONLY +) + +absl_cc_test( + NAME time_test - SOURCES - ${TIME_TEST_SRC} - PUBLIC_LIBRARIES - ${TIME_TEST_PUBLIC_LIBRARIES} + SRCS + "civil_time_test.cc" + "clock_test.cc" + "duration_test.cc" + "format_test.cc" + "time_test.cc" + "time_zone_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::test_util + absl::time + absl::base + absl::config + absl::core_headers + absl::time_zone + gmock_main ) -
diff --git a/absl/time/civil_time.cc b/absl/time/civil_time.cc new file mode 100644 index 0000000..7527fc1 --- /dev/null +++ b/absl/time/civil_time.cc
@@ -0,0 +1,83 @@ +// 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/time/civil_time.h" + +#include <cstdlib> +#include <string> + +#include "absl/strings/str_cat.h" +#include "absl/time/time.h" + +namespace absl { + +namespace { + +// Since a civil time has a larger year range than absl::Time (64-bit years vs +// 64-bit seconds, respectively) we normalize years to roughly +/- 400 years +// around the year 2400, which will produce an equivalent year in a range that +// absl::Time can handle. +inline civil_year_t NormalizeYear(civil_year_t year) { + return 2400 + year % 400; +} + +// Formats the given CivilSecond according to the given format. +std::string FormatYearAnd(string_view fmt, CivilSecond cs) { + 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. + return StrCat(cs.year(), + FormatTime(std::string(fmt), FromCivil(ncs, utc), utc)); +} + +} // namespace + +std::string FormatCivilTime(CivilSecond c) { + return FormatYearAnd("-%m-%dT%H:%M:%S", c); +} +std::string FormatCivilTime(CivilMinute c) { + return FormatYearAnd("-%m-%dT%H:%M", c); +} +std::string FormatCivilTime(CivilHour c) { + return FormatYearAnd("-%m-%dT%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); } + +namespace time_internal { + +std::ostream& operator<<(std::ostream& os, CivilYear y) { + return os << FormatCivilTime(y); +} +std::ostream& operator<<(std::ostream& os, CivilMonth m) { + return os << FormatCivilTime(m); +} +std::ostream& operator<<(std::ostream& os, CivilDay d) { + return os << FormatCivilTime(d); +} +std::ostream& operator<<(std::ostream& os, CivilHour h) { + return os << FormatCivilTime(h); +} +std::ostream& operator<<(std::ostream& os, CivilMinute m) { + return os << FormatCivilTime(m); +} +std::ostream& operator<<(std::ostream& os, CivilSecond s) { + return os << FormatCivilTime(s); +} + +} // namespace time_internal + +} // namespace absl
diff --git a/absl/time/civil_time.h b/absl/time/civil_time.h new file mode 100644 index 0000000..2dfcbd2 --- /dev/null +++ b/absl/time/civil_time.h
@@ -0,0 +1,485 @@ +// 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: civil_time.h +// ----------------------------------------------------------------------------- +// +// This header file defines abstractions for computing with "civil time". +// The term "civil time" refers to the legally recognized human-scale time +// that is represented by the six fields `YYYY-MM-DD hh:mm:ss`. A "date" +// is perhaps the most common example of a civil time (represented here as +// an `absl::CivilDay`). +// +// Modern-day civil time follows the Gregorian Calendar and is a +// time-zone-independent concept: a civil time of "2015-06-01 12:00:00", for +// example, is not tied to a time zone. Put another way, a civil time does not +// map to a unique point in time; a civil time must be mapped to an absolute +// time *through* a time zone. +// +// Because a civil time is what most people think of as "time," it is common to +// map absolute times to civil times to present to users. +// +// Time zones define the relationship between absolute and civil times. Given an +// absolute or civil time and a time zone, you can compute the other time: +// +// Civil Time = F(Absolute Time, Time Zone) +// Absolute Time = G(Civil Time, Time Zone) +// +// The Abseil time library allows you to construct such civil times from +// absolute times; consult time.h for such functionality. +// +// This library provides six classes for constructing civil-time objects, and +// provides several helper functions for rounding, iterating, and performing +// arithmetic on civil-time objects, while avoiding complications like +// daylight-saving time (DST): +// +// * `absl::CivilSecond` +// * `absl::CivilMinute` +// * `absl::CivilHour` +// * `absl::CivilDay` +// * `absl::CivilMonth` +// * `absl::CivilYear` +// +// Example: +// +// // Construct a civil-time object for a specific day +// const absl::CivilDay cd(1969, 07, 20); +// +// // Construct a civil-time object for a specific second +// const absl::CivilSecond cd(2018, 8, 1, 12, 0, 1); +// +// Note: In C++14 and later, this library is usable in a constexpr context. +// +// Example: +// +// // Valid in C++14 +// constexpr absl::CivilDay cd(1969, 07, 20); + +#ifndef ABSL_TIME_CIVIL_TIME_H_ +#define ABSL_TIME_CIVIL_TIME_H_ + +#include <string> + +#include "absl/strings/string_view.h" +#include "absl/time/internal/cctz/include/cctz/civil_time.h" + +namespace absl { + +namespace time_internal { +struct second_tag : cctz::detail::second_tag {}; +struct minute_tag : second_tag, cctz::detail::minute_tag {}; +struct hour_tag : minute_tag, cctz::detail::hour_tag {}; +struct day_tag : hour_tag, cctz::detail::day_tag {}; +struct month_tag : day_tag, cctz::detail::month_tag {}; +struct year_tag : month_tag, cctz::detail::year_tag {}; +} // namespace time_internal + +// ----------------------------------------------------------------------------- +// CivilSecond, CivilMinute, CivilHour, CivilDay, CivilMonth, CivilYear +// ----------------------------------------------------------------------------- +// +// Each of these civil-time types is a simple value type with the same +// interface for construction and the same six accessors for each of the civil +// time fields (year, month, day, hour, minute, and second, aka YMDHMS). These +// classes differ only in their alignment, which is indicated by the type name +// and specifies the field on which arithmetic operates. +// +// CONSTRUCTION +// +// Each of the civil-time types can be constructed in two ways: by directly +// passing to the constructor up to six integers representing the YMDHMS fields, +// or by copying the YMDHMS fields from a differently aligned civil-time type. +// Omitted fields are assigned their minimum valid value. Hours, minutes, and +// seconds will be set to 0, month and day will be set to 1. Since there is no +// minimum year, the default is 1970. +// +// Examples: +// +// absl::CivilDay default_value; // 1970-01-01 00:00:00 +// +// absl::CivilDay a(2015, 2, 3); // 2015-02-03 00:00:00 +// absl::CivilDay b(2015, 2, 3, 4, 5, 6); // 2015-02-03 00:00:00 +// absl::CivilDay c(2015); // 2015-01-01 00:00:00 +// +// absl::CivilSecond ss(2015, 2, 3, 4, 5, 6); // 2015-02-03 04:05:06 +// absl::CivilMinute mm(ss); // 2015-02-03 04:05:00 +// absl::CivilHour hh(mm); // 2015-02-03 04:00:00 +// absl::CivilDay d(hh); // 2015-02-03 00:00:00 +// absl::CivilMonth m(d); // 2015-02-01 00:00:00 +// absl::CivilYear y(m); // 2015-01-01 00:00:00 +// +// m = absl::CivilMonth(y); // 2015-01-01 00:00:00 +// d = absl::CivilDay(m); // 2015-01-01 00:00:00 +// hh = absl::CivilHour(d); // 2015-01-01 00:00:00 +// mm = absl::CivilMinute(hh); // 2015-01-01 00:00:00 +// ss = absl::CivilSecond(mm); // 2015-01-01 00:00:00 +// +// Each civil-time class is aligned to the civil-time field indicated in the +// class's name after normalization. Alignment is performed by setting all the +// inferior fields to their minimum valid value (as described above). The +// following are examples of how each of the six types would align the fields +// representing November 22, 2015 at 12:34:56 in the afternoon. (Note: the +// string format used here is not important; it's just a shorthand way of +// showing the six YMDHMS fields.) +// +// absl::CivilSecond : 2015-11-22 12:34:56 +// absl::CivilMinute : 2015-11-22 12:34:00 +// absl::CivilHour : 2015-11-22 12:00:00 +// absl::CivilDay : 2015-11-22 00:00:00 +// absl::CivilMonth : 2015-11-01 00:00:00 +// absl::CivilYear : 2015-01-01 00:00:00 +// +// Each civil-time type performs arithmetic on the field to which it is +// aligned. This means that adding 1 to an absl::CivilDay increments the day +// field (normalizing as necessary), and subtracting 7 from an absl::CivilMonth +// operates on the month field (normalizing as necessary). All arithmetic +// produces a valid civil time. Difference requires two similarly aligned +// civil-time objects and returns the scalar answer in units of the objects' +// alignment. For example, the difference between two absl::CivilHour objects +// will give an answer in units of civil hours. +// +// ALIGNMENT CONVERSION +// +// The alignment of a civil-time object cannot change, but the object may be +// used to construct a new object with a different alignment. This is referred +// to as "realigning". When realigning to a type with the same or more +// precision (e.g., absl::CivilDay -> absl::CivilSecond), the conversion may be +// performed implicitly since no information is lost. However, if information +// could be discarded (e.g., CivilSecond -> CivilDay), the conversion must +// be explicit at the call site. +// +// Examples: +// +// void UseDay(absl::CivilDay day); +// +// absl::CivilSecond cs; +// UseDay(cs); // Won't compile because data may be discarded +// UseDay(absl::CivilDay(cs)); // OK: explicit conversion +// +// absl::CivilDay cd; +// UseDay(cd); // OK: no conversion needed +// +// absl::CivilMonth cm; +// UseDay(cm); // OK: implicit conversion to absl::CivilDay +// +// NORMALIZATION +// +// Normalization takes invalid values and adjusts them to produce valid values. +// Within the civil-time library, integer arguments passed to the Civil* +// constructors may be out-of-range, in which case they are normalized by +// carrying overflow into a field of courser granularity to produce valid +// civil-time objects. This normalization enables natural arithmetic on +// constructor arguments without worrying about the field's range. +// +// Examples: +// +// // Out-of-range; normalized to 2016-11-01 +// absl::CivilDay d(2016, 10, 32); +// // Out-of-range, negative: normalized to 2016-10-30T23 +// absl::CivilHour h1(2016, 10, 31, -1); +// // Normalization is cumulative: normalized to 2016-10-30T23 +// absl::CivilHour h2(2016, 10, 32, -25); +// +// Note: If normalization is undesired, you can signal an error by comparing +// the constructor arguments to the normalized values returned by the YMDHMS +// properties. +// +// COMPARISON +// +// Comparison between civil-time objects considers all six YMDHMS fields, +// regardless of the type's alignment. Comparison between differently aligned +// civil-time types is allowed. +// +// Examples: +// +// absl::CivilDay feb_3(2015, 2, 3); // 2015-02-03 00:00:00 +// absl::CivilDay mar_4(2015, 3, 4); // 2015-03-04 00:00:00 +// // feb_3 < mar_4 +// // absl::CivilYear(feb_3) == absl::CivilYear(mar_4) +// +// absl::CivilSecond feb_3_noon(2015, 2, 3, 12, 0, 0); // 2015-02-03 12:00:00 +// // feb_3 < feb_3_noon +// // feb_3 == absl::CivilDay(feb_3_noon) +// +// // Iterates all the days of February 2015. +// for (absl::CivilDay d(2015, 2, 1); d < absl::CivilMonth(2015, 3); ++d) { +// // ... +// } +// +// ARITHMETIC +// +// Civil-time types support natural arithmetic operators such as addition, +// subtraction, and difference. Arithmetic operates on the civil-time field +// indicated in the type's name. Difference operators require arguments with +// the same alignment and return the answer in units of the alignment. +// +// Example: +// +// absl::CivilDay a(2015, 2, 3); +// ++a; // 2015-02-04 00:00:00 +// --a; // 2015-02-03 00:00:00 +// absl::CivilDay b = a + 1; // 2015-02-04 00:00:00 +// absl::CivilDay c = 1 + b; // 2015-02-05 00:00:00 +// int n = c - a; // n = 2 (civil days) +// int m = c - absl::CivilMonth(c); // Won't compile: different types. +// +// ACCESSORS +// +// Each civil-time type has accessors for all six of the civil-time fields: +// year, month, day, hour, minute, and second. +// +// civil_year_t year() +// int month() +// int day() +// int hour() +// int minute() +// int second() +// +// Recall that fields inferior to the type's aligment will be set to their +// minimum valid value. +// +// Example: +// +// absl::CivilDay d(2015, 6, 28); +// // d.year() == 2015 +// // d.month() == 6 +// // d.day() == 28 +// // d.hour() == 0 +// // d.minute() == 0 +// // d.second() == 0 +// +// CASE STUDY: Adding a month to January 31. +// +// One of the classic questions that arises when considering a civil time +// library (or a date library or a date/time library) is this: +// "What is the result of adding a month to January 31?" +// This is an interesting question because it is unclear what is meant by a +// "month", and several different answers are possible, depending on context: +// +// 1. March 3 (or 2 if a leap year), if "add a month" means to add a month to +// the current month, and adjust the date to overflow the extra days into +// March. In this case the result of "February 31" would be normalized as +// within the civil-time library. +// 2. February 28 (or 29 if a leap year), if "add a month" means to add a +// month, and adjust the date while holding the resulting month constant. +// In this case, the result of "February 31" would be truncated to the last +// day in February. +// 3. An error. The caller may get some error, an exception, an invalid date +// object, or perhaps return `false`. This may make sense because there is +// no single unambiguously correct answer to the question. +// +// Practically speaking, any answer that is not what the programmer intended +// is the wrong answer. +// +// The Abseil time library avoids this problem by making it impossible to +// ask ambiguous questions. All civil-time objects are aligned to a particular +// civil-field boundary (such as aligned to a year, month, day, hour, minute, +// or second), and arithmetic operates on the field to which the object is +// aligned. This means that in order to "add a month" the object must first be +// aligned to a month boundary, which is equivalent to the first day of that +// month. +// +// Of course, there are ways to compute an answer the question at hand using +// this Abseil time library, but they require the programmer to be explicit +// about the answer they expect. To illustrate, let's see how to compute all +// three of the above possible answers to the question of "Jan 31 plus 1 +// month": +// +// Example: +// +// const absl::CivilDay d(2015, 1, 31); +// +// // Answer 1: +// // Add 1 to the month field in the constructor, and rely on normalization. +// const auto normalized = absl::CivilDay(d.year(), d.month() + 1, d.day()); +// // normalized == 2015-03-03 (aka Feb 31) +// +// // Answer 2: +// // Add 1 to month field, capping to the end of next month. +// const auto next_month = absl::CivilMonth(d) + 1; +// const auto last_day_of_next_month = absl::CivilDay(next_month + 1) - 1; +// const auto capped = std::min(normalized, last_day_of_next_month); +// // capped == 2015-02-28 +// +// // Answer 3: +// // Signal an error if the normalized answer is not in next month. +// if (absl::CivilMonth(normalized) != next_month) { +// // error, month overflow +// } +// +using CivilSecond = + time_internal::cctz::detail::civil_time<time_internal::second_tag>; +using CivilMinute = + time_internal::cctz::detail::civil_time<time_internal::minute_tag>; +using CivilHour = + time_internal::cctz::detail::civil_time<time_internal::hour_tag>; +using CivilDay = + time_internal::cctz::detail::civil_time<time_internal::day_tag>; +using CivilMonth = + time_internal::cctz::detail::civil_time<time_internal::month_tag>; +using CivilYear = + time_internal::cctz::detail::civil_time<time_internal::year_tag>; + +// civil_year_t +// +// Type alias of a civil-time year value. This type is guaranteed to (at least) +// support any year value supported by `time_t`. +// +// Example: +// +// absl::CivilSecond cs = ...; +// absl::civil_year_t y = cs.year(); +// cs = absl::CivilSecond(y, 1, 1, 0, 0, 0); // CivilSecond(CivilYear(cs)) +// +using civil_year_t = time_internal::cctz::year_t; + +// civil_diff_t +// +// Type alias of the difference between two civil-time values. +// This type is used to indicate arguments that are not +// normalized (such as parameters to the civil-time constructors), the results +// of civil-time subtraction, or the operand to civil-time addition. +// +// Example: +// +// absl::civil_diff_t n_sec = cs1 - cs2; // cs1 == cs2 + n_sec; +// +using civil_diff_t = time_internal::cctz::diff_t; + +// Weekday::monday, Weekday::tuesday, Weekday::wednesday, Weekday::thursday, +// Weekday::friday, Weekday::saturday, Weekday::sunday +// +// The Weekday enum class represents the civil-time concept of a "weekday" with +// members for all days of the week. +// +// absl::Weekday wd = absl::Weekday::thursday; +// +using Weekday = time_internal::cctz::weekday; + +// GetWeekday() +// +// Returns the absl::Weekday for the given absl::CivilDay. +// +// Example: +// +// absl::CivilDay a(2015, 8, 13); +// absl::Weekday wd = absl::GetWeekday(a); // wd == absl::Weekday::thursday +// +inline Weekday GetWeekday(CivilDay cd) { + return time_internal::cctz::get_weekday(cd); +} + +// NextWeekday() +// PrevWeekday() +// +// Returns the absl::CivilDay that strictly follows or precedes a given +// absl::CivilDay, and that falls on the given absl::Weekday. +// +// Example, given the following month: +// +// August 2015 +// Su Mo Tu We Th Fr Sa +// 1 +// 2 3 4 5 6 7 8 +// 9 10 11 12 13 14 15 +// 16 17 18 19 20 21 22 +// 23 24 25 26 27 28 29 +// 30 31 +// +// absl::CivilDay a(2015, 8, 13); +// // absl::GetWeekday(a) == absl::Weekday::thursday +// absl::CivilDay b = absl::NextWeekday(a, absl::Weekday::thursday); +// // b = 2015-08-20 +// absl::CivilDay c = absl::PrevWeekday(a, absl::Weekday::thursday); +// // c = 2015-08-06 +// +// absl::CivilDay d = ... +// // Gets the following Thursday if d is not already Thursday +// absl::CivilDay thurs1 = absl::PrevWeekday(d, absl::Weekday::thursday) + 7; +// // Gets the previous Thursday if d is not already Thursday +// absl::CivilDay thurs2 = absl::NextWeekday(d, absl::Weekday::thursday) - 7; +// +inline CivilDay NextWeekday(CivilDay cd, Weekday wd) { + return CivilDay(time_internal::cctz::next_weekday(cd, wd)); +} +inline CivilDay PrevWeekday(CivilDay cd, Weekday wd) { + return CivilDay(time_internal::cctz::prev_weekday(cd, wd)); +} + +// GetYearDay() +// +// Returns the day-of-year for the given absl::CivilDay. +// +// Example: +// +// absl::CivilDay a(2015, 1, 1); +// int yd_jan_1 = absl::GetYearDay(a); // yd_jan_1 = 1 +// absl::CivilDay b(2015, 12, 31); +// int yd_dec_31 = absl::GetYearDay(b); // yd_dec_31 = 365 +// +inline int GetYearDay(CivilDay cd) { + return time_internal::cctz::get_yearday(cd); +} + +// FormatCivilTime() +// +// Formats the given civil-time value into a string value of the following +// format: +// +// 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 = absl::CivilDay(1969, 7, 20); +// std::string day_string = absl::FormatCivilTime(d); // "1969-07-20" +// +std::string FormatCivilTime(CivilSecond c); +std::string FormatCivilTime(CivilMinute c); +std::string FormatCivilTime(CivilHour c); +std::string FormatCivilTime(CivilDay c); +std::string FormatCivilTime(CivilMonth c); +std::string FormatCivilTime(CivilYear c); + +namespace time_internal { // For functions found via ADL on civil-time tags. + +// Streaming Operators +// +// Each civil-time type may be sent to an output stream using operator<<(). +// The result matches the string produced by `FormatCivilTime()`. +// +// Example: +// +// absl::CivilDay d = absl::CivilDay("1969-07-20"); +// std::cout << "Date is: " << d << "\n"; +// +std::ostream& operator<<(std::ostream& os, CivilYear y); +std::ostream& operator<<(std::ostream& os, CivilMonth m); +std::ostream& operator<<(std::ostream& os, CivilDay d); +std::ostream& operator<<(std::ostream& os, CivilHour h); +std::ostream& operator<<(std::ostream& os, CivilMinute m); +std::ostream& operator<<(std::ostream& os, CivilSecond s); + +} // namespace time_internal + +} // namespace absl + +#endif // ABSL_TIME_CIVIL_TIME_H_
diff --git a/absl/time/civil_time_benchmark.cc b/absl/time/civil_time_benchmark.cc new file mode 100644 index 0000000..4086983 --- /dev/null +++ b/absl/time/civil_time_benchmark.cc
@@ -0,0 +1,107 @@ +// 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/time/civil_time.h" + +#include <numeric> +#include <vector> + +#include "absl/hash/hash.h" +#include "benchmark/benchmark.h" + +namespace { + +// Run on (12 X 3492 MHz CPUs); 2018-11-05T13:44:29.814239103-08:00 +// CPU: Intel Haswell with HyperThreading (6 cores) dL1:32KB dL2:256KB dL3:15MB +// Benchmark Time(ns) CPU(ns) Iterations +// ---------------------------------------------------------------- +// BM_Difference_Days 14.5 14.5 48531105 +// BM_Step_Days 12.6 12.6 54876006 +// BM_Format 587 587 1000000 +// BM_Parse 692 692 1000000 +// BM_RoundTripFormatParse 1309 1309 532075 +// BM_CivilYearAbslHash 0.710 0.710 976400000 +// BM_CivilMonthAbslHash 1.13 1.13 619500000 +// BM_CivilDayAbslHash 1.70 1.70 426000000 +// BM_CivilHourAbslHash 2.45 2.45 287600000 +// BM_CivilMinuteAbslHash 3.21 3.21 226200000 +// BM_CivilSecondAbslHash 4.10 4.10 171800000 + +void BM_Difference_Days(benchmark::State& state) { + const absl::CivilDay c(2014, 8, 22); + const absl::CivilDay epoch(1970, 1, 1); + while (state.KeepRunning()) { + const absl::civil_diff_t n = c - epoch; + benchmark::DoNotOptimize(n); + } +} +BENCHMARK(BM_Difference_Days); + +void BM_Step_Days(benchmark::State& state) { + const absl::CivilDay kStart(2014, 8, 22); + absl::CivilDay c = kStart; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(++c); + } +} +BENCHMARK(BM_Step_Days); + +void BM_Format(benchmark::State& state) { + const absl::CivilSecond c(2014, 1, 2, 3, 4, 5); + while (state.KeepRunning()) { + const std::string s = absl::FormatCivilTime(c); + benchmark::DoNotOptimize(s); + } +} +BENCHMARK(BM_Format); + +template <typename T> +void BM_CivilTimeAbslHash(benchmark::State& state) { + const int kSize = 100000; + std::vector<T> civil_times(kSize); + std::iota(civil_times.begin(), civil_times.end(), T(2018)); + + absl::Hash<T> absl_hasher; + while (state.KeepRunningBatch(kSize)) { + for (const T civil_time : civil_times) { + benchmark::DoNotOptimize(absl_hasher(civil_time)); + } + } +} +void BM_CivilYearAbslHash(benchmark::State& state) { + BM_CivilTimeAbslHash<absl::CivilYear>(state); +} +void BM_CivilMonthAbslHash(benchmark::State& state) { + BM_CivilTimeAbslHash<absl::CivilMonth>(state); +} +void BM_CivilDayAbslHash(benchmark::State& state) { + BM_CivilTimeAbslHash<absl::CivilDay>(state); +} +void BM_CivilHourAbslHash(benchmark::State& state) { + BM_CivilTimeAbslHash<absl::CivilHour>(state); +} +void BM_CivilMinuteAbslHash(benchmark::State& state) { + BM_CivilTimeAbslHash<absl::CivilMinute>(state); +} +void BM_CivilSecondAbslHash(benchmark::State& state) { + BM_CivilTimeAbslHash<absl::CivilSecond>(state); +} +BENCHMARK(BM_CivilYearAbslHash); +BENCHMARK(BM_CivilMonthAbslHash); +BENCHMARK(BM_CivilDayAbslHash); +BENCHMARK(BM_CivilHourAbslHash); +BENCHMARK(BM_CivilMinuteAbslHash); +BENCHMARK(BM_CivilSecondAbslHash); + +} // namespace
diff --git a/absl/time/civil_time_test.cc b/absl/time/civil_time_test.cc new file mode 100644 index 0000000..b8d5713 --- /dev/null +++ b/absl/time/civil_time_test.cc
@@ -0,0 +1,1073 @@ +// 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/time/civil_time.h" + +#include <limits> +#include <sstream> +#include <type_traits> + +#include "absl/base/macros.h" +#include "gtest/gtest.h" + +namespace { + +TEST(CivilTime, DefaultConstruction) { + absl::CivilSecond ss; + EXPECT_EQ("1970-01-01T00:00:00", absl::FormatCivilTime(ss)); + + absl::CivilMinute mm; + EXPECT_EQ("1970-01-01T00:00", absl::FormatCivilTime(mm)); + + absl::CivilHour hh; + EXPECT_EQ("1970-01-01T00", absl::FormatCivilTime(hh)); + + absl::CivilDay d; + EXPECT_EQ("1970-01-01", absl::FormatCivilTime(d)); + + absl::CivilMonth m; + EXPECT_EQ("1970-01", absl::FormatCivilTime(m)); + + absl::CivilYear y; + EXPECT_EQ("1970", absl::FormatCivilTime(y)); +} + +TEST(CivilTime, StructMember) { + struct S { + absl::CivilDay day; + }; + S s = {}; + EXPECT_EQ(absl::CivilDay{}, s.day); +} + +TEST(CivilTime, FieldsConstruction) { + EXPECT_EQ("2015-01-02T03:04:05", + absl::FormatCivilTime(absl::CivilSecond(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015-01-02T03:04:00", + absl::FormatCivilTime(absl::CivilSecond(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015-01-02T03:00:00", + absl::FormatCivilTime(absl::CivilSecond(2015, 1, 2, 3))); + EXPECT_EQ("2015-01-02T00:00:00", + absl::FormatCivilTime(absl::CivilSecond(2015, 1, 2))); + EXPECT_EQ("2015-01-01T00:00:00", + absl::FormatCivilTime(absl::CivilSecond(2015, 1))); + EXPECT_EQ("2015-01-01T00:00:00", + absl::FormatCivilTime(absl::CivilSecond(2015))); + + EXPECT_EQ("2015-01-02T03:04", + absl::FormatCivilTime(absl::CivilMinute(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015-01-02T03:04", + absl::FormatCivilTime(absl::CivilMinute(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015-01-02T03:00", + absl::FormatCivilTime(absl::CivilMinute(2015, 1, 2, 3))); + EXPECT_EQ("2015-01-02T00:00", + absl::FormatCivilTime(absl::CivilMinute(2015, 1, 2))); + EXPECT_EQ("2015-01-01T00:00", + absl::FormatCivilTime(absl::CivilMinute(2015, 1))); + EXPECT_EQ("2015-01-01T00:00", + absl::FormatCivilTime(absl::CivilMinute(2015))); + + EXPECT_EQ("2015-01-02T03", + absl::FormatCivilTime(absl::CivilHour(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015-01-02T03", + absl::FormatCivilTime(absl::CivilHour(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015-01-02T03", + absl::FormatCivilTime(absl::CivilHour(2015, 1, 2, 3))); + EXPECT_EQ("2015-01-02T00", + absl::FormatCivilTime(absl::CivilHour(2015, 1, 2))); + EXPECT_EQ("2015-01-01T00", + absl::FormatCivilTime(absl::CivilHour(2015, 1))); + EXPECT_EQ("2015-01-01T00", + absl::FormatCivilTime(absl::CivilHour(2015))); + + EXPECT_EQ("2015-01-02", + absl::FormatCivilTime(absl::CivilDay(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015-01-02", + absl::FormatCivilTime(absl::CivilDay(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015-01-02", + absl::FormatCivilTime(absl::CivilDay(2015, 1, 2, 3))); + EXPECT_EQ("2015-01-02", + absl::FormatCivilTime(absl::CivilDay(2015, 1, 2))); + EXPECT_EQ("2015-01-01", + absl::FormatCivilTime(absl::CivilDay(2015, 1))); + EXPECT_EQ("2015-01-01", + absl::FormatCivilTime(absl::CivilDay(2015))); + + EXPECT_EQ("2015-01", + absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015-01", + absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015-01", + absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2, 3))); + EXPECT_EQ("2015-01", + absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2))); + EXPECT_EQ("2015-01", + absl::FormatCivilTime(absl::CivilMonth(2015, 1))); + EXPECT_EQ("2015-01", + absl::FormatCivilTime(absl::CivilMonth(2015))); + + EXPECT_EQ("2015", + absl::FormatCivilTime(absl::CivilYear(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015", + absl::FormatCivilTime(absl::CivilYear(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015", + absl::FormatCivilTime(absl::CivilYear(2015, 1, 2, 3))); + EXPECT_EQ("2015", + absl::FormatCivilTime(absl::CivilYear(2015, 1, 2))); + EXPECT_EQ("2015", + absl::FormatCivilTime(absl::CivilYear(2015, 1))); + EXPECT_EQ("2015", + absl::FormatCivilTime(absl::CivilYear(2015))); +} + +TEST(CivilTime, FieldsConstructionLimits) { + const int kIntMax = std::numeric_limits<int>::max(); + EXPECT_EQ("2038-01-19T03:14:07", + absl::FormatCivilTime(absl::CivilSecond( + 1970, 1, 1, 0, 0, kIntMax))); + EXPECT_EQ("6121-02-11T05:21:07", + absl::FormatCivilTime(absl::CivilSecond( + 1970, 1, 1, 0, kIntMax, kIntMax))); + EXPECT_EQ("251104-11-20T12:21:07", + absl::FormatCivilTime(absl::CivilSecond( + 1970, 1, 1, kIntMax, kIntMax, kIntMax))); + EXPECT_EQ("6130715-05-30T12:21:07", + absl::FormatCivilTime(absl::CivilSecond( + 1970, 1, kIntMax, kIntMax, kIntMax, kIntMax))); + EXPECT_EQ("185087685-11-26T12:21:07", + absl::FormatCivilTime(absl::CivilSecond( + 1970, kIntMax, kIntMax, kIntMax, kIntMax, kIntMax))); + + const int kIntMin = std::numeric_limits<int>::min(); + EXPECT_EQ("1901-12-13T20:45:52", + absl::FormatCivilTime(absl::CivilSecond( + 1970, 1, 1, 0, 0, kIntMin))); + EXPECT_EQ("-2182-11-20T18:37:52", + absl::FormatCivilTime(absl::CivilSecond( + 1970, 1, 1, 0, kIntMin, kIntMin))); + EXPECT_EQ("-247165-02-11T10:37:52", + absl::FormatCivilTime(absl::CivilSecond( + 1970, 1, 1, kIntMin, kIntMin, kIntMin))); + EXPECT_EQ("-6126776-08-01T10:37:52", + absl::FormatCivilTime(absl::CivilSecond( + 1970, 1, kIntMin, kIntMin, kIntMin, kIntMin))); + EXPECT_EQ("-185083747-10-31T10:37:52", + absl::FormatCivilTime(absl::CivilSecond( + 1970, kIntMin, kIntMin, kIntMin, kIntMin, kIntMin))); +} + +TEST(CivilTime, RangeLimits) { + const absl::civil_year_t kYearMax = + std::numeric_limits<absl::civil_year_t>::max(); + EXPECT_EQ(absl::CivilYear(kYearMax), + absl::CivilYear::max()); + EXPECT_EQ(absl::CivilMonth(kYearMax, 12), + absl::CivilMonth::max()); + EXPECT_EQ(absl::CivilDay(kYearMax, 12, 31), + absl::CivilDay::max()); + EXPECT_EQ(absl::CivilHour(kYearMax, 12, 31, 23), + absl::CivilHour::max()); + EXPECT_EQ(absl::CivilMinute(kYearMax, 12, 31, 23, 59), + absl::CivilMinute::max()); + EXPECT_EQ(absl::CivilSecond(kYearMax, 12, 31, 23, 59, 59), + absl::CivilSecond::max()); + + const absl::civil_year_t kYearMin = + std::numeric_limits<absl::civil_year_t>::min(); + EXPECT_EQ(absl::CivilYear(kYearMin), + absl::CivilYear::min()); + EXPECT_EQ(absl::CivilMonth(kYearMin, 1), + absl::CivilMonth::min()); + EXPECT_EQ(absl::CivilDay(kYearMin, 1, 1), + absl::CivilDay::min()); + EXPECT_EQ(absl::CivilHour(kYearMin, 1, 1, 0), + absl::CivilHour::min()); + EXPECT_EQ(absl::CivilMinute(kYearMin, 1, 1, 0, 0), + absl::CivilMinute::min()); + EXPECT_EQ(absl::CivilSecond(kYearMin, 1, 1, 0, 0, 0), + absl::CivilSecond::min()); +} + +TEST(CivilTime, ImplicitCrossAlignment) { + absl::CivilYear year(2015); + absl::CivilMonth month = year; + absl::CivilDay day = month; + absl::CivilHour hour = day; + absl::CivilMinute minute = hour; + absl::CivilSecond second = minute; + + second = year; + EXPECT_EQ(second, year); + second = month; + EXPECT_EQ(second, month); + second = day; + EXPECT_EQ(second, day); + second = hour; + EXPECT_EQ(second, hour); + second = minute; + EXPECT_EQ(second, minute); + + minute = year; + EXPECT_EQ(minute, year); + minute = month; + EXPECT_EQ(minute, month); + minute = day; + EXPECT_EQ(minute, day); + minute = hour; + EXPECT_EQ(minute, hour); + + hour = year; + EXPECT_EQ(hour, year); + hour = month; + EXPECT_EQ(hour, month); + hour = day; + EXPECT_EQ(hour, day); + + day = year; + EXPECT_EQ(day, year); + day = month; + EXPECT_EQ(day, month); + + month = year; + EXPECT_EQ(month, year); + + // Ensures unsafe conversions are not allowed. + EXPECT_FALSE( + (std::is_convertible<absl::CivilSecond, absl::CivilMinute>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilSecond, absl::CivilHour>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilSecond, absl::CivilDay>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilSecond, absl::CivilMonth>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilSecond, absl::CivilYear>::value)); + + EXPECT_FALSE( + (std::is_convertible<absl::CivilMinute, absl::CivilHour>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilMinute, absl::CivilDay>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilMinute, absl::CivilMonth>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilMinute, absl::CivilYear>::value)); + + EXPECT_FALSE( + (std::is_convertible<absl::CivilHour, absl::CivilDay>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilHour, absl::CivilMonth>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilHour, absl::CivilYear>::value)); + + EXPECT_FALSE( + (std::is_convertible<absl::CivilDay, absl::CivilMonth>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilDay, absl::CivilYear>::value)); + + EXPECT_FALSE( + (std::is_convertible<absl::CivilMonth, absl::CivilYear>::value)); +} + +TEST(CivilTime, ExplicitCrossAlignment) { + // + // Assign from smaller units -> larger units + // + + absl::CivilSecond second(2015, 1, 2, 3, 4, 5); + EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(second)); + + absl::CivilMinute minute(second); + EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(minute)); + + absl::CivilHour hour(minute); + EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(hour)); + + absl::CivilDay day(hour); + EXPECT_EQ("2015-01-02", absl::FormatCivilTime(day)); + + absl::CivilMonth month(day); + EXPECT_EQ("2015-01", absl::FormatCivilTime(month)); + + absl::CivilYear year(month); + EXPECT_EQ("2015", absl::FormatCivilTime(year)); + + // + // Now assign from larger units -> smaller units + // + + month = absl::CivilMonth(year); + EXPECT_EQ("2015-01", absl::FormatCivilTime(month)); + + day = absl::CivilDay(month); + EXPECT_EQ("2015-01-01", absl::FormatCivilTime(day)); + + hour = absl::CivilHour(day); + EXPECT_EQ("2015-01-01T00", absl::FormatCivilTime(hour)); + + minute = absl::CivilMinute(hour); + EXPECT_EQ("2015-01-01T00:00", absl::FormatCivilTime(minute)); + + second = absl::CivilSecond(minute); + EXPECT_EQ("2015-01-01T00:00:00", absl::FormatCivilTime(second)); +} + +// Metafunction to test whether difference is allowed between two types. +template <typename T1, typename T2> +struct HasDiff { + template <typename U1, typename U2> + static std::false_type test(...); + template <typename U1, typename U2> + static std::true_type test(decltype(std::declval<U1>() - std::declval<U2>())); + static constexpr bool value = decltype(test<T1, T2>(0))::value; +}; + +TEST(CivilTime, DisallowCrossAlignedDifference) { + // Difference is allowed between types with the same alignment. + static_assert(HasDiff<absl::CivilSecond, absl::CivilSecond>::value, ""); + static_assert(HasDiff<absl::CivilMinute, absl::CivilMinute>::value, ""); + static_assert(HasDiff<absl::CivilHour, absl::CivilHour>::value, ""); + static_assert(HasDiff<absl::CivilDay, absl::CivilDay>::value, ""); + static_assert(HasDiff<absl::CivilMonth, absl::CivilMonth>::value, ""); + static_assert(HasDiff<absl::CivilYear, absl::CivilYear>::value, ""); + + // Difference is disallowed between types with different alignments. + static_assert(!HasDiff<absl::CivilSecond, absl::CivilMinute>::value, ""); + static_assert(!HasDiff<absl::CivilSecond, absl::CivilHour>::value, ""); + static_assert(!HasDiff<absl::CivilSecond, absl::CivilDay>::value, ""); + static_assert(!HasDiff<absl::CivilSecond, absl::CivilMonth>::value, ""); + static_assert(!HasDiff<absl::CivilSecond, absl::CivilYear>::value, ""); + + static_assert(!HasDiff<absl::CivilMinute, absl::CivilHour>::value, ""); + static_assert(!HasDiff<absl::CivilMinute, absl::CivilDay>::value, ""); + static_assert(!HasDiff<absl::CivilMinute, absl::CivilMonth>::value, ""); + static_assert(!HasDiff<absl::CivilMinute, absl::CivilYear>::value, ""); + + static_assert(!HasDiff<absl::CivilHour, absl::CivilDay>::value, ""); + static_assert(!HasDiff<absl::CivilHour, absl::CivilMonth>::value, ""); + static_assert(!HasDiff<absl::CivilHour, absl::CivilYear>::value, ""); + + static_assert(!HasDiff<absl::CivilDay, absl::CivilMonth>::value, ""); + static_assert(!HasDiff<absl::CivilDay, absl::CivilYear>::value, ""); + + static_assert(!HasDiff<absl::CivilMonth, absl::CivilYear>::value, ""); +} + +TEST(CivilTime, ValueSemantics) { + const absl::CivilHour a(2015, 1, 2, 3); + const absl::CivilHour b = a; + const absl::CivilHour c(b); + absl::CivilHour d; + d = c; + EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(d)); +} + +TEST(CivilTime, Relational) { + // Tests that the alignment unit is ignored in comparison. + const absl::CivilYear year(2014); + const absl::CivilMonth month(year); + EXPECT_EQ(year, month); + +#define TEST_RELATIONAL(OLDER, YOUNGER) \ + do { \ + EXPECT_FALSE(OLDER < OLDER); \ + EXPECT_FALSE(OLDER > OLDER); \ + EXPECT_TRUE(OLDER >= OLDER); \ + EXPECT_TRUE(OLDER <= OLDER); \ + EXPECT_FALSE(YOUNGER < YOUNGER); \ + EXPECT_FALSE(YOUNGER > YOUNGER); \ + EXPECT_TRUE(YOUNGER >= YOUNGER); \ + EXPECT_TRUE(YOUNGER <= YOUNGER); \ + EXPECT_EQ(OLDER, OLDER); \ + EXPECT_NE(OLDER, YOUNGER); \ + EXPECT_LT(OLDER, YOUNGER); \ + EXPECT_LE(OLDER, YOUNGER); \ + EXPECT_GT(YOUNGER, OLDER); \ + EXPECT_GE(YOUNGER, OLDER); \ + } while (0) + + // Alignment is ignored in comparison (verified above), so CivilSecond is + // used to test comparison in all field positions. + TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 0, 0, 0), + absl::CivilSecond(2015, 1, 1, 0, 0, 0)); + TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 0, 0, 0), + absl::CivilSecond(2014, 2, 1, 0, 0, 0)); + TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 0, 0, 0), + absl::CivilSecond(2014, 1, 2, 0, 0, 0)); + TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 0, 0, 0), + absl::CivilSecond(2014, 1, 1, 1, 0, 0)); + TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 1, 0, 0), + absl::CivilSecond(2014, 1, 1, 1, 1, 0)); + TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 1, 1, 0), + absl::CivilSecond(2014, 1, 1, 1, 1, 1)); + + // Tests the relational operators of two different civil-time types. + TEST_RELATIONAL(absl::CivilDay(2014, 1, 1), + absl::CivilMinute(2014, 1, 1, 1, 1)); + TEST_RELATIONAL(absl::CivilDay(2014, 1, 1), + absl::CivilMonth(2014, 2)); + +#undef TEST_RELATIONAL +} + +TEST(CivilTime, Arithmetic) { + absl::CivilSecond second(2015, 1, 2, 3, 4, 5); + EXPECT_EQ("2015-01-02T03:04:06", absl::FormatCivilTime(second += 1)); + EXPECT_EQ("2015-01-02T03:04:07", absl::FormatCivilTime(second + 1)); + EXPECT_EQ("2015-01-02T03:04:08", absl::FormatCivilTime(2 + second)); + EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(second - 1)); + EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(second -= 1)); + EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(second++)); + EXPECT_EQ("2015-01-02T03:04:07", absl::FormatCivilTime(++second)); + EXPECT_EQ("2015-01-02T03:04:07", absl::FormatCivilTime(second--)); + EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(--second)); + + absl::CivilMinute minute(2015, 1, 2, 3, 4); + EXPECT_EQ("2015-01-02T03:05", absl::FormatCivilTime(minute += 1)); + EXPECT_EQ("2015-01-02T03:06", absl::FormatCivilTime(minute + 1)); + EXPECT_EQ("2015-01-02T03:07", absl::FormatCivilTime(2 + minute)); + EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(minute - 1)); + EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(minute -= 1)); + EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(minute++)); + EXPECT_EQ("2015-01-02T03:06", absl::FormatCivilTime(++minute)); + EXPECT_EQ("2015-01-02T03:06", absl::FormatCivilTime(minute--)); + EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(--minute)); + + absl::CivilHour hour(2015, 1, 2, 3); + EXPECT_EQ("2015-01-02T04", absl::FormatCivilTime(hour += 1)); + EXPECT_EQ("2015-01-02T05", absl::FormatCivilTime(hour + 1)); + EXPECT_EQ("2015-01-02T06", absl::FormatCivilTime(2 + hour)); + EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(hour - 1)); + EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(hour -= 1)); + EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(hour++)); + EXPECT_EQ("2015-01-02T05", absl::FormatCivilTime(++hour)); + EXPECT_EQ("2015-01-02T05", absl::FormatCivilTime(hour--)); + EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(--hour)); + + absl::CivilDay day(2015, 1, 2); + EXPECT_EQ("2015-01-03", absl::FormatCivilTime(day += 1)); + EXPECT_EQ("2015-01-04", absl::FormatCivilTime(day + 1)); + EXPECT_EQ("2015-01-05", absl::FormatCivilTime(2 + day)); + EXPECT_EQ("2015-01-02", absl::FormatCivilTime(day - 1)); + EXPECT_EQ("2015-01-02", absl::FormatCivilTime(day -= 1)); + EXPECT_EQ("2015-01-02", absl::FormatCivilTime(day++)); + EXPECT_EQ("2015-01-04", absl::FormatCivilTime(++day)); + EXPECT_EQ("2015-01-04", absl::FormatCivilTime(day--)); + EXPECT_EQ("2015-01-02", absl::FormatCivilTime(--day)); + + absl::CivilMonth month(2015, 1); + EXPECT_EQ("2015-02", absl::FormatCivilTime(month += 1)); + EXPECT_EQ("2015-03", absl::FormatCivilTime(month + 1)); + EXPECT_EQ("2015-04", absl::FormatCivilTime(2 + month)); + EXPECT_EQ("2015-01", absl::FormatCivilTime(month - 1)); + EXPECT_EQ("2015-01", absl::FormatCivilTime(month -= 1)); + EXPECT_EQ("2015-01", absl::FormatCivilTime(month++)); + EXPECT_EQ("2015-03", absl::FormatCivilTime(++month)); + EXPECT_EQ("2015-03", absl::FormatCivilTime(month--)); + EXPECT_EQ("2015-01", absl::FormatCivilTime(--month)); + + absl::CivilYear year(2015); + EXPECT_EQ("2016", absl::FormatCivilTime(year += 1)); + EXPECT_EQ("2017", absl::FormatCivilTime(year + 1)); + EXPECT_EQ("2018", absl::FormatCivilTime(2 + year)); + EXPECT_EQ("2015", absl::FormatCivilTime(year - 1)); + EXPECT_EQ("2015", absl::FormatCivilTime(year -= 1)); + EXPECT_EQ("2015", absl::FormatCivilTime(year++)); + EXPECT_EQ("2017", absl::FormatCivilTime(++year)); + EXPECT_EQ("2017", absl::FormatCivilTime(year--)); + EXPECT_EQ("2015", absl::FormatCivilTime(--year)); +} + +TEST(CivilTime, ArithmeticLimits) { + const int kIntMax = std::numeric_limits<int>::max(); + const int kIntMin = std::numeric_limits<int>::min(); + + absl::CivilSecond second(1970, 1, 1, 0, 0, 0); + second += kIntMax; + EXPECT_EQ("2038-01-19T03:14:07", absl::FormatCivilTime(second)); + second -= kIntMax; + EXPECT_EQ("1970-01-01T00:00:00", absl::FormatCivilTime(second)); + second += kIntMin; + EXPECT_EQ("1901-12-13T20:45:52", absl::FormatCivilTime(second)); + second -= kIntMin; + EXPECT_EQ("1970-01-01T00:00:00", absl::FormatCivilTime(second)); + + absl::CivilMinute minute(1970, 1, 1, 0, 0); + minute += kIntMax; + EXPECT_EQ("6053-01-23T02:07", absl::FormatCivilTime(minute)); + minute -= kIntMax; + EXPECT_EQ("1970-01-01T00:00", absl::FormatCivilTime(minute)); + minute += kIntMin; + EXPECT_EQ("-2114-12-08T21:52", absl::FormatCivilTime(minute)); + minute -= kIntMin; + EXPECT_EQ("1970-01-01T00:00", absl::FormatCivilTime(minute)); + + absl::CivilHour hour(1970, 1, 1, 0); + hour += kIntMax; + EXPECT_EQ("246953-10-09T07", absl::FormatCivilTime(hour)); + hour -= kIntMax; + EXPECT_EQ("1970-01-01T00", absl::FormatCivilTime(hour)); + hour += kIntMin; + EXPECT_EQ("-243014-03-24T16", absl::FormatCivilTime(hour)); + hour -= kIntMin; + EXPECT_EQ("1970-01-01T00", absl::FormatCivilTime(hour)); + + absl::CivilDay day(1970, 1, 1); + day += kIntMax; + EXPECT_EQ("5881580-07-11", absl::FormatCivilTime(day)); + day -= kIntMax; + EXPECT_EQ("1970-01-01", absl::FormatCivilTime(day)); + day += kIntMin; + EXPECT_EQ("-5877641-06-23", absl::FormatCivilTime(day)); + day -= kIntMin; + EXPECT_EQ("1970-01-01", absl::FormatCivilTime(day)); + + absl::CivilMonth month(1970, 1); + month += kIntMax; + EXPECT_EQ("178958940-08", absl::FormatCivilTime(month)); + month -= kIntMax; + EXPECT_EQ("1970-01", absl::FormatCivilTime(month)); + month += kIntMin; + EXPECT_EQ("-178955001-05", absl::FormatCivilTime(month)); + month -= kIntMin; + EXPECT_EQ("1970-01", absl::FormatCivilTime(month)); + + absl::CivilYear year(0); + year += kIntMax; + EXPECT_EQ("2147483647", absl::FormatCivilTime(year)); + year -= kIntMax; + EXPECT_EQ("0", absl::FormatCivilTime(year)); + year += kIntMin; + EXPECT_EQ("-2147483648", absl::FormatCivilTime(year)); + year -= kIntMin; + EXPECT_EQ("0", absl::FormatCivilTime(year)); +} + +TEST(CivilTime, Difference) { + absl::CivilSecond second(2015, 1, 2, 3, 4, 5); + EXPECT_EQ(0, second - second); + EXPECT_EQ(10, (second + 10) - second); + EXPECT_EQ(-10, (second - 10) - second); + + absl::CivilMinute minute(2015, 1, 2, 3, 4); + EXPECT_EQ(0, minute - minute); + EXPECT_EQ(10, (minute + 10) - minute); + EXPECT_EQ(-10, (minute - 10) - minute); + + absl::CivilHour hour(2015, 1, 2, 3); + EXPECT_EQ(0, hour - hour); + EXPECT_EQ(10, (hour + 10) - hour); + EXPECT_EQ(-10, (hour - 10) - hour); + + absl::CivilDay day(2015, 1, 2); + EXPECT_EQ(0, day - day); + EXPECT_EQ(10, (day + 10) - day); + EXPECT_EQ(-10, (day - 10) - day); + + absl::CivilMonth month(2015, 1); + EXPECT_EQ(0, month - month); + EXPECT_EQ(10, (month + 10) - month); + EXPECT_EQ(-10, (month - 10) - month); + + absl::CivilYear year(2015); + EXPECT_EQ(0, year - year); + EXPECT_EQ(10, (year + 10) - year); + EXPECT_EQ(-10, (year - 10) - year); +} + +TEST(CivilTime, DifferenceLimits) { + const absl::civil_diff_t kDiffMax = + std::numeric_limits<absl::civil_diff_t>::max(); + const absl::civil_diff_t kDiffMin = + std::numeric_limits<absl::civil_diff_t>::min(); + + // Check day arithmetic at the end of the year range. + const absl::CivilDay max_day(kDiffMax, 12, 31); + EXPECT_EQ(1, max_day - (max_day - 1)); + EXPECT_EQ(-1, (max_day - 1) - max_day); + + // Check day arithmetic at the start of the year range. + const absl::CivilDay min_day(kDiffMin, 1, 1); + EXPECT_EQ(1, (min_day + 1) - min_day); + EXPECT_EQ(-1, min_day - (min_day + 1)); + + // Check the limits of the return value. + const absl::CivilDay d1(1970, 1, 1); + const absl::CivilDay d2(25252734927768524, 7, 27); + EXPECT_EQ(kDiffMax, d2 - d1); + EXPECT_EQ(kDiffMin, d1 - (d2 + 1)); +} + +TEST(CivilTime, Properties) { + absl::CivilSecond ss(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, ss.year()); + EXPECT_EQ(2, ss.month()); + EXPECT_EQ(3, ss.day()); + EXPECT_EQ(4, ss.hour()); + EXPECT_EQ(5, ss.minute()); + EXPECT_EQ(6, ss.second()); + + absl::CivilMinute mm(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, mm.year()); + EXPECT_EQ(2, mm.month()); + EXPECT_EQ(3, mm.day()); + EXPECT_EQ(4, mm.hour()); + EXPECT_EQ(5, mm.minute()); + EXPECT_EQ(0, mm.second()); + + absl::CivilHour hh(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, hh.year()); + EXPECT_EQ(2, hh.month()); + EXPECT_EQ(3, hh.day()); + EXPECT_EQ(4, hh.hour()); + EXPECT_EQ(0, hh.minute()); + EXPECT_EQ(0, hh.second()); + + absl::CivilDay d(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, d.year()); + EXPECT_EQ(2, d.month()); + EXPECT_EQ(3, d.day()); + EXPECT_EQ(0, d.hour()); + EXPECT_EQ(0, d.minute()); + EXPECT_EQ(0, d.second()); + + absl::CivilMonth m(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, m.year()); + EXPECT_EQ(2, m.month()); + EXPECT_EQ(1, m.day()); + EXPECT_EQ(0, m.hour()); + EXPECT_EQ(0, m.minute()); + EXPECT_EQ(0, m.second()); + + absl::CivilYear y(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, y.year()); + EXPECT_EQ(1, y.month()); + EXPECT_EQ(1, y.day()); + EXPECT_EQ(0, y.hour()); + EXPECT_EQ(0, y.minute()); + EXPECT_EQ(0, y.second()); +} + +TEST(CivilTime, Format) { + absl::CivilSecond ss; + EXPECT_EQ("1970-01-01T00:00:00", absl::FormatCivilTime(ss)); + + absl::CivilMinute mm; + EXPECT_EQ("1970-01-01T00:00", absl::FormatCivilTime(mm)); + + absl::CivilHour hh; + EXPECT_EQ("1970-01-01T00", absl::FormatCivilTime(hh)); + + absl::CivilDay d; + EXPECT_EQ("1970-01-01", absl::FormatCivilTime(d)); + + absl::CivilMonth m; + EXPECT_EQ("1970-01", absl::FormatCivilTime(m)); + + absl::CivilYear y; + EXPECT_EQ("1970", absl::FormatCivilTime(y)); +} + +TEST(CivilTime, FormatAndParseLenient) { + absl::CivilSecond ss; + EXPECT_EQ("1970-01-01T00:00:00", absl::FormatCivilTime(ss)); + + absl::CivilMinute mm; + EXPECT_EQ("1970-01-01T00:00", absl::FormatCivilTime(mm)); + + absl::CivilHour hh; + EXPECT_EQ("1970-01-01T00", absl::FormatCivilTime(hh)); + + absl::CivilDay d; + EXPECT_EQ("1970-01-01", absl::FormatCivilTime(d)); + + absl::CivilMonth m; + EXPECT_EQ("1970-01", absl::FormatCivilTime(m)); + + absl::CivilYear y; + EXPECT_EQ("1970", absl::FormatCivilTime(y)); +} + +TEST(CivilTime, OutputStream) { + absl::CivilSecond cs(2016, 2, 3, 4, 5, 6); + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << absl::CivilYear(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016.................X..", ss.str()); + } + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << absl::CivilMonth(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016-02..............X..", ss.str()); + } + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << absl::CivilDay(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016-02-03...........X..", ss.str()); + } + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << absl::CivilHour(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016-02-03T04........X..", ss.str()); + } + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << absl::CivilMinute(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016-02-03T04:05.....X..", ss.str()); + } + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << absl::CivilSecond(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016-02-03T04:05:06..X..", ss.str()); + } + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << absl::Weekday::wednesday; + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..Wednesday............X..", ss.str()); + } +} + +TEST(CivilTime, Weekday) { + absl::CivilDay d(1970, 1, 1); + EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(d)) << d; + + // We used to get this wrong for years < -30. + d = absl::CivilDay(-31, 12, 24); + EXPECT_EQ(absl::Weekday::wednesday, absl::GetWeekday(d)) << d; +} + +TEST(CivilTime, NextPrevWeekday) { + // Jan 1, 1970 was a Thursday. + const absl::CivilDay thursday(1970, 1, 1); + + // Thursday -> Thursday + absl::CivilDay d = absl::NextWeekday(thursday, absl::Weekday::thursday); + EXPECT_EQ(7, d - thursday) << d; + EXPECT_EQ(d - 14, absl::PrevWeekday(thursday, absl::Weekday::thursday)); + + // Thursday -> Friday + d = absl::NextWeekday(thursday, absl::Weekday::friday); + EXPECT_EQ(1, d - thursday) << d; + EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::friday)); + + // Thursday -> Saturday + d = absl::NextWeekday(thursday, absl::Weekday::saturday); + EXPECT_EQ(2, d - thursday) << d; + EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::saturday)); + + // Thursday -> Sunday + d = absl::NextWeekday(thursday, absl::Weekday::sunday); + EXPECT_EQ(3, d - thursday) << d; + EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::sunday)); + + // Thursday -> Monday + d = absl::NextWeekday(thursday, absl::Weekday::monday); + EXPECT_EQ(4, d - thursday) << d; + EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::monday)); + + // Thursday -> Tuesday + d = absl::NextWeekday(thursday, absl::Weekday::tuesday); + EXPECT_EQ(5, d - thursday) << d; + EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::tuesday)); + + // Thursday -> Wednesday + d = absl::NextWeekday(thursday, absl::Weekday::wednesday); + EXPECT_EQ(6, d - thursday) << d; + EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::wednesday)); +} + +// NOTE: Run this with --copt=-ftrapv to detect overflow problems. +TEST(CivilTime, DifferenceWithHugeYear) { + absl::CivilDay d1(9223372036854775807, 1, 1); + absl::CivilDay d2(9223372036854775807, 12, 31); + EXPECT_EQ(364, d2 - d1); + + d1 = absl::CivilDay(-9223372036854775807 - 1, 1, 1); + d2 = absl::CivilDay(-9223372036854775807 - 1, 12, 31); + EXPECT_EQ(365, d2 - d1); + + // Check the limits of the return value at the end of the year range. + d1 = absl::CivilDay(9223372036854775807, 1, 1); + d2 = absl::CivilDay(9198119301927009252, 6, 6); + EXPECT_EQ(9223372036854775807, d1 - d2); + d2 = d2 - 1; + EXPECT_EQ(-9223372036854775807 - 1, d2 - d1); + + // Check the limits of the return value at the start of the year range. + d1 = absl::CivilDay(-9223372036854775807 - 1, 1, 1); + d2 = absl::CivilDay(-9198119301927009254, 7, 28); + EXPECT_EQ(9223372036854775807, d2 - d1); + d2 = d2 + 1; + EXPECT_EQ(-9223372036854775807 - 1, d1 - d2); + + // Check the limits of the return value from either side of year 0. + d1 = absl::CivilDay(-12626367463883278, 9, 3); + d2 = absl::CivilDay(12626367463883277, 3, 28); + EXPECT_EQ(9223372036854775807, d2 - d1); + d2 = d2 + 1; + EXPECT_EQ(-9223372036854775807 - 1, d1 - d2); +} + +// NOTE: Run this with --copt=-ftrapv to detect overflow problems. +TEST(CivilTime, DifferenceNoIntermediateOverflow) { + // The difference up to the minute field would be below the minimum + // int64_t, but the 52 extra seconds brings us back to the minimum. + absl::CivilSecond s1(-292277022657, 1, 27, 8, 29 - 1, 52); + absl::CivilSecond s2(1970, 1, 1, 0, 0 - 1, 0); + EXPECT_EQ(-9223372036854775807 - 1, s1 - s2); + + // The difference up to the minute field would be above the maximum + // int64_t, but the -53 extra seconds brings us back to the maximum. + s1 = absl::CivilSecond(292277026596, 12, 4, 15, 30, 7 - 7); + s2 = absl::CivilSecond(1970, 1, 1, 0, 0, 0 - 7); + EXPECT_EQ(9223372036854775807, s1 - s2); +} + +TEST(CivilTime, NormalizeSimpleOverflow) { + absl::CivilSecond cs; + cs = absl::CivilSecond(2013, 11, 15, 16, 32, 59 + 1); + EXPECT_EQ("2013-11-15T16:33:00", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 16, 59 + 1, 14); + EXPECT_EQ("2013-11-15T17:00:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 23 + 1, 32, 14); + EXPECT_EQ("2013-11-16T00:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 30 + 1, 16, 32, 14); + EXPECT_EQ("2013-12-01T16:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 12 + 1, 15, 16, 32, 14); + EXPECT_EQ("2014-01-15T16:32:14", absl::FormatCivilTime(cs)); +} + +TEST(CivilTime, NormalizeSimpleUnderflow) { + absl::CivilSecond cs; + cs = absl::CivilSecond(2013, 11, 15, 16, 32, 0 - 1); + EXPECT_EQ("2013-11-15T16:31:59", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 16, 0 - 1, 14); + EXPECT_EQ("2013-11-15T15:59:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 0 - 1, 32, 14); + EXPECT_EQ("2013-11-14T23:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 1 - 1, 16, 32, 14); + EXPECT_EQ("2013-10-31T16:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 1 - 1, 15, 16, 32, 14); + EXPECT_EQ("2012-12-15T16:32:14", absl::FormatCivilTime(cs)); +} + +TEST(CivilTime, NormalizeMultipleOverflow) { + absl::CivilSecond cs(2013, 12, 31, 23, 59, 59 + 1); + EXPECT_EQ("2014-01-01T00:00:00", absl::FormatCivilTime(cs)); +} + +TEST(CivilTime, NormalizeMultipleUnderflow) { + absl::CivilSecond cs(2014, 1, 1, 0, 0, 0 - 1); + EXPECT_EQ("2013-12-31T23:59:59", absl::FormatCivilTime(cs)); +} + +TEST(CivilTime, NormalizeOverflowLimits) { + absl::CivilSecond cs; + + const int kintmax = std::numeric_limits<int>::max(); + cs = absl::CivilSecond(0, kintmax, kintmax, kintmax, kintmax, kintmax); + EXPECT_EQ("185085715-11-27T12:21:07", absl::FormatCivilTime(cs)); + + const int kintmin = std::numeric_limits<int>::min(); + cs = absl::CivilSecond(0, kintmin, kintmin, kintmin, kintmin, kintmin); + EXPECT_EQ("-185085717-10-31T10:37:52", absl::FormatCivilTime(cs)); +} + +TEST(CivilTime, NormalizeComplexOverflow) { + absl::CivilSecond cs; + cs = absl::CivilSecond(2013, 11, 15, 16, 32, 14 + 123456789); + EXPECT_EQ("2017-10-14T14:05:23", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 16, 32 + 1234567, 14); + EXPECT_EQ("2016-03-22T00:39:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 16 + 123456, 32, 14); + EXPECT_EQ("2027-12-16T16:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15 + 1234, 16, 32, 14); + EXPECT_EQ("2017-04-02T16:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11 + 123, 15, 16, 32, 14); + EXPECT_EQ("2024-02-15T16:32:14", absl::FormatCivilTime(cs)); +} + +TEST(CivilTime, NormalizeComplexUnderflow) { + absl::CivilSecond cs; + cs = absl::CivilSecond(1999, 3, 0, 0, 0, 0); // year 400 + EXPECT_EQ("1999-02-28T00:00:00", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 16, 32, 14 - 123456789); + EXPECT_EQ("2009-12-17T18:59:05", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 16, 32 - 1234567, 14); + EXPECT_EQ("2011-07-12T08:25:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 16 - 123456, 32, 14); + EXPECT_EQ("1999-10-16T16:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15 - 1234, 16, 32, 14); + EXPECT_EQ("2010-06-30T16:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11 - 123, 15, 16, 32, 14); + EXPECT_EQ("2003-08-15T16:32:14", absl::FormatCivilTime(cs)); +} + +TEST(CivilTime, NormalizeMishmash) { + absl::CivilSecond cs; + cs = absl::CivilSecond(2013, 11 - 123, 15 + 1234, 16 - 123456, 32 + 1234567, + 14 - 123456789); + EXPECT_EQ("1991-05-09T03:06:05", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11 + 123, 15 - 1234, 16 + 123456, 32 - 1234567, + 14 + 123456789); + EXPECT_EQ("2036-05-24T05:58:23", absl::FormatCivilTime(cs)); + + cs = absl::CivilSecond(2013, 11, -146097 + 1, 16, 32, 14); + EXPECT_EQ("1613-11-01T16:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11 + 400 * 12, -146097 + 1, 16, 32, 14); + EXPECT_EQ("2013-11-01T16:32:14", absl::FormatCivilTime(cs)); +} + +// Convert all the days from 1970-1-1 to 1970-1-146097 (aka 2369-12-31) +// and check that they normalize to the expected time. 146097 days span +// the 400-year Gregorian cycle used during normalization. +TEST(CivilTime, NormalizeAllTheDays) { + absl::CivilDay expected(1970, 1, 1); + for (int day = 1; day <= 146097; ++day) { + absl::CivilSecond cs(1970, 1, day, 0, 0, 0); + EXPECT_EQ(expected, cs); + ++expected; + } +} + +TEST(CivilTime, NormalizeWithHugeYear) { + absl::CivilMonth c(9223372036854775807, 1); + EXPECT_EQ("9223372036854775807-01", absl::FormatCivilTime(c)); + c = c - 1; // Causes normalization + EXPECT_EQ("9223372036854775806-12", absl::FormatCivilTime(c)); + + c = absl::CivilMonth(-9223372036854775807 - 1, 1); + EXPECT_EQ("-9223372036854775808-01", absl::FormatCivilTime(c)); + c = c + 12; // Causes normalization + EXPECT_EQ("-9223372036854775807-01", absl::FormatCivilTime(c)); +} + +TEST(CivilTime, LeapYears) { + const absl::CivilSecond s1(2013, 2, 28 + 1, 0, 0, 0); + EXPECT_EQ("2013-03-01T00:00:00", absl::FormatCivilTime(s1)); + + const absl::CivilSecond s2(2012, 2, 28 + 1, 0, 0, 0); + EXPECT_EQ("2012-02-29T00:00:00", absl::FormatCivilTime(s2)); + + const absl::CivilSecond s3(1900, 2, 28 + 1, 0, 0, 0); + EXPECT_EQ("1900-03-01T00:00:00", absl::FormatCivilTime(s3)); + + const struct { + int year; + int days; + struct { + int month; + int day; + } leap_day; // The date of the day after Feb 28. + } kLeapYearTable[]{ + {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}}, + }; + + for (int i = 0; i < ABSL_ARRAYSIZE(kLeapYearTable); ++i) { + const int y = kLeapYearTable[i].year; + const int m = kLeapYearTable[i].leap_day.month; + const int d = kLeapYearTable[i].leap_day.day; + const int n = kLeapYearTable[i].days; + + // Tests incrementing through the leap day. + const absl::CivilDay feb28(y, 2, 28); + const absl::CivilDay next_day = feb28 + 1; + EXPECT_EQ(m, next_day.month()); + EXPECT_EQ(d, next_day.day()); + + // Tests difference in days of leap years. + const absl::CivilYear year(feb28); + const absl::CivilYear next_year = year + 1; + EXPECT_EQ(n, absl::CivilDay(next_year) - absl::CivilDay(year)); + } +} + +TEST(CivilTime, FirstThursdayInMonth) { + const absl::CivilDay nov1(2014, 11, 1); + const absl::CivilDay thursday = + absl::PrevWeekday(nov1, absl::Weekday::thursday) + 7; + EXPECT_EQ("2014-11-06", absl::FormatCivilTime(thursday)); + + // Bonus: Date of Thanksgiving in the United States + // Rule: Fourth Thursday of November + const absl::CivilDay thanksgiving = thursday + 7 * 3; + EXPECT_EQ("2014-11-27", absl::FormatCivilTime(thanksgiving)); +} + +TEST(CivilTime, DocumentationExample) { + absl::CivilSecond second(2015, 6, 28, 1, 2, 3); // 2015-06-28 01:02:03 + absl::CivilMinute minute(second); // 2015-06-28 01:02:00 + absl::CivilDay day(minute); // 2015-06-28 00:00:00 + + second -= 1; // 2015-06-28 01:02:02 + --second; // 2015-06-28 01:02:01 + EXPECT_EQ(minute, second - 1); // Comparison between types + EXPECT_LT(minute, second); + + // int diff = second - minute; // ERROR: Mixed types, won't compile + + absl::CivilDay june_1(2015, 6, 1); // Pass fields to c'tor. + int diff = day - june_1; // Num days between 'day' and June 1 + EXPECT_EQ(27, diff); + + // Fields smaller than alignment are floored to their minimum value. + absl::CivilDay day_floor(2015, 1, 2, 9, 9, 9); + EXPECT_EQ(0, day_floor.hour()); // 09:09:09 is floored + EXPECT_EQ(absl::CivilDay(2015, 1, 2), day_floor); + + // Unspecified fields default to their minium value + absl::CivilDay day_default(2015); // Defaults to Jan 1 + EXPECT_EQ(absl::CivilDay(2015, 1, 1), day_default); + + // Iterates all the days of June. + absl::CivilMonth june(day); // CivilDay -> CivilMonth + absl::CivilMonth july = june + 1; + for (absl::CivilDay day = june_1; day < july; ++day) { + // ... + } +} + +} // namespace
diff --git a/absl/time/clock.cc b/absl/time/clock.cc index 74ee140..fa0ed34 100644 --- a/absl/time/clock.cc +++ b/absl/time/clock.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -379,7 +379,7 @@ // // Manually mark this 'noinline' to minimize stack frame size of the fast // path. Without this, sometimes a compiler may inline this big block of code -// into the fast past. That causes lots of register spills and reloads that +// into the fast path. That causes lots of register spills and reloads that // are unnecessary unless the slow path is taken. // // TODO(absl-team): Remove this attribute when our compiler is smart enough
diff --git a/absl/time/clock.h b/absl/time/clock.h index 3753d4e..bb52e4f 100644 --- a/absl/time/clock.h +++ b/absl/time/clock.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/time/clock_benchmark.cc b/absl/time/clock_benchmark.cc index 3d3cd9d..a69fe00 100644 --- a/absl/time/clock_benchmark.cc +++ b/absl/time/clock_benchmark.cc
@@ -3,7 +3,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/time/clock_test.cc b/absl/time/clock_test.cc index 707166d..4bcfc6b 100644 --- a/absl/time/clock_test.cc +++ b/absl/time/clock_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/time/duration.cc b/absl/time/duration.cc index 2950c7c..67791fe 100644 --- a/absl/time/duration.cc +++ b/absl/time/duration.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -78,10 +78,16 @@ // Can't use std::isinfinite() because it doesn't exist on windows. inline bool IsFinite(double d) { + if (std::isnan(d)) return false; return d != std::numeric_limits<double>::infinity() && d != -std::numeric_limits<double>::infinity(); } +inline bool IsValidDivisor(double d) { + if (std::isnan(d)) return false; + return d != 0.0; +} + // Can't use std::round() because it is only available in C++11. // Note that we ignore the possibility of floating-point over/underflow. template <typename Double> @@ -455,7 +461,7 @@ } Duration& Duration::operator/=(double r) { - if (time_internal::IsInfiniteDuration(*this) || r == 0.0) { + if (time_internal::IsInfiniteDuration(*this) || !IsValidDivisor(r)) { const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0); return *this = is_neg ? -InfiniteDuration() : InfiniteDuration(); } @@ -743,9 +749,9 @@ } // namespace -// From Go's doc at http://golang.org/pkg/time/#Duration.String +// From Go's doc at https://golang.org/pkg/time/#Duration.String // [FormatDuration] returns a string representing the duration in the -// form "72h3m0.5s". Leading zero units are omitted. As a special +// 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. @@ -849,8 +855,8 @@ } // namespace -// From Go's doc at http://golang.org/pkg/time/#ParseDuration -// [ParseDuration] parses a duration string. A duration string is +// From Go's doc at https://golang.org/pkg/time/#ParseDuration +// [ParseDuration] parses a duration string. A duration string is // a possibly signed sequence of decimal numbers, each with optional // fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". // Valid time units are "ns", "us" "ms", "s", "m", "h". @@ -895,6 +901,7 @@ *d = dur; return true; } + bool ParseFlag(const std::string& text, Duration* dst, std::string* ) { return ParseDuration(text, dst); }
diff --git a/absl/time/duration_benchmark.cc b/absl/time/duration_benchmark.cc index d5657bd..83a836c 100644 --- a/absl/time/duration_benchmark.cc +++ b/absl/time/duration_benchmark.cc
@@ -3,7 +3,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -17,6 +17,7 @@ #include <ctime> #include <string> +#include "absl/base/attributes.h" #include "absl/time/time.h" #include "benchmark/benchmark.h"
diff --git a/absl/time/duration_test.cc b/absl/time/duration_test.cc index 7ae25dc..e3cede6 100644 --- a/absl/time/duration_test.cc +++ b/absl/time/duration_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -56,6 +56,17 @@ return false; } +TEST(Duration, ConstExpr) { + constexpr absl::Duration d0 = absl::ZeroDuration(); + static_assert(d0 == absl::ZeroDuration(), "ZeroDuration()"); + constexpr absl::Duration d1 = absl::Seconds(1); + static_assert(d1 == absl::Seconds(1), "Seconds(1)"); + static_assert(d1 != absl::ZeroDuration(), "Seconds(1)"); + constexpr absl::Duration d2 = absl::InfiniteDuration(); + static_assert(d2 == absl::InfiniteDuration(), "InfiniteDuration()"); + static_assert(d2 != absl::ZeroDuration(), "InfiniteDuration()"); +} + TEST(Duration, ValueSemantics) { // If this compiles, the test passes. constexpr absl::Duration a; // Default construction @@ -792,6 +803,40 @@ EXPECT_EQ(-dbl_inf, absl::FDivDuration(-any_dur, zero)); } +TEST(Duration, NaN) { + // Note that IEEE 754 does not define the behavior of a nan's sign when it is + // copied, so the code below allows for either + or - InfiniteDuration. +#define TEST_NAN_HANDLING(NAME, NAN) \ + do { \ + const auto inf = absl::InfiniteDuration(); \ + auto x = NAME(NAN); \ + EXPECT_TRUE(x == inf || x == -inf); \ + auto y = NAME(42); \ + y *= NAN; \ + EXPECT_TRUE(y == inf || y == -inf); \ + auto z = NAME(42); \ + z /= NAN; \ + EXPECT_TRUE(z == inf || z == -inf); \ + } while (0) + + const double nan = std::numeric_limits<double>::quiet_NaN(); + TEST_NAN_HANDLING(absl::Nanoseconds, nan); + TEST_NAN_HANDLING(absl::Microseconds, nan); + TEST_NAN_HANDLING(absl::Milliseconds, nan); + TEST_NAN_HANDLING(absl::Seconds, nan); + TEST_NAN_HANDLING(absl::Minutes, nan); + TEST_NAN_HANDLING(absl::Hours, nan); + + TEST_NAN_HANDLING(absl::Nanoseconds, -nan); + TEST_NAN_HANDLING(absl::Microseconds, -nan); + TEST_NAN_HANDLING(absl::Milliseconds, -nan); + TEST_NAN_HANDLING(absl::Seconds, -nan); + TEST_NAN_HANDLING(absl::Minutes, -nan); + TEST_NAN_HANDLING(absl::Hours, -nan); + +#undef TEST_NAN_HANDLING +} + TEST(Duration, Range) { const absl::Duration range = ApproxYears(100 * 1e9); const absl::Duration range_future = range; @@ -1726,7 +1771,7 @@ TEST(Duration, FormatParseRoundTrip) { #define TEST_PARSE_ROUNDTRIP(d) \ do { \ - std::string s = absl::FormatDuration(d); \ + std::string s = absl::FormatDuration(d); \ absl::Duration dur; \ EXPECT_TRUE(absl::ParseDuration(s, &dur)); \ EXPECT_EQ(d, dur); \
diff --git a/absl/time/format.cc b/absl/time/format.cc index ee597e4..d6ca860 100644 --- a/absl/time/format.cc +++ b/absl/time/format.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -67,7 +67,8 @@ } // namespace -std::string FormatTime(const std::string& format, absl::Time t, absl::TimeZone tz) { +std::string FormatTime(const std::string& format, absl::Time t, + absl::TimeZone tz) { if (t == absl::InfiniteFuture()) return kInfiniteFutureStr; if (t == absl::InfinitePast()) return kInfinitePastStr; const auto parts = Split(t); @@ -83,15 +84,15 @@ return absl::FormatTime(RFC3339_full, t, absl::LocalTimeZone()); } -bool ParseTime(const std::string& format, const std::string& input, absl::Time* time, - std::string* err) { +bool ParseTime(const std::string& format, const std::string& input, + absl::Time* time, std::string* err) { return absl::ParseTime(format, input, absl::UTCTimeZone(), time, err); } // If the input string does not contain an explicit UTC offset, interpret // the fields with respect to the given TimeZone. -bool ParseTime(const std::string& format, const std::string& input, absl::TimeZone tz, - absl::Time* time, std::string* err) { +bool ParseTime(const std::string& format, const std::string& input, + absl::TimeZone tz, absl::Time* time, std::string* err) { const char* data = input.c_str(); while (std::isspace(*data)) ++data;
diff --git a/absl/time/format_benchmark.cc b/absl/time/format_benchmark.cc index ee53d71..249c51d 100644 --- a/absl/time/format_benchmark.cc +++ b/absl/time/format_benchmark.cc
@@ -3,7 +3,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -38,7 +38,8 @@ const absl::TimeZone lax = absl::time_internal::LoadTimeZone("America/Los_Angeles"); const absl::Time t = - absl::FromDateTime(1977, 6, 28, 9, 8, 7, lax) + absl::Nanoseconds(1); + absl::FromCivil(absl::CivilSecond(1977, 6, 28, 9, 8, 7), lax) + + absl::Nanoseconds(1); while (state.KeepRunning()) { benchmark::DoNotOptimize(absl::FormatTime(fmt, t, lax).length()); } @@ -50,8 +51,8 @@ state.SetLabel(fmt); const absl::TimeZone lax = absl::time_internal::LoadTimeZone("America/Los_Angeles"); - absl::Time t = - absl::FromDateTime(1977, 6, 28, 9, 8, 7, lax) + absl::Nanoseconds(1); + absl::Time t = absl::FromCivil(absl::CivilSecond(1977, 6, 28, 9, 8, 7), lax) + + absl::Nanoseconds(1); const std::string when = absl::FormatTime(fmt, t, lax); std::string err; while (state.KeepRunning()) {
diff --git a/absl/time/format_test.cc b/absl/time/format_test.cc index 7c84c33..4a1f1aa 100644 --- a/absl/time/format_test.cc +++ b/absl/time/format_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -27,8 +27,8 @@ // A helper that tests the given format specifier by itself, and with leading // and trailing characters. For example: TestFormatSpecifier(t, "%a", "Thu"). -void TestFormatSpecifier(absl::Time t, absl::TimeZone tz, const std::string& fmt, - const std::string& ans) { +void TestFormatSpecifier(absl::Time t, absl::TimeZone tz, + const std::string& fmt, const std::string& ans) { EXPECT_EQ(ans, absl::FormatTime(fmt, t, tz)); EXPECT_EQ("xxx " + ans, absl::FormatTime("xxx " + fmt, t, tz)); EXPECT_EQ(ans + " yyy", absl::FormatTime(fmt + " yyy", t, tz)); @@ -118,7 +118,7 @@ absl::TimeZone tz = absl::UTCTimeZone(); // A year of 77 should be padded to 0077. - absl::Time t = absl::FromDateTime(77, 6, 28, 9, 8, 7, tz); + absl::Time t = absl::FromCivil(absl::CivilSecond(77, 6, 28, 9, 8, 7), tz); EXPECT_EQ("Mon, 28 Jun 0077 09:08:07 +0000", absl::FormatTime(absl::RFC1123_full, t, tz)); EXPECT_EQ("28 Jun 0077 09:08:07 +0000", @@ -154,9 +154,9 @@ EXPECT_TRUE(absl::ParseTime("%Y-%m-%d %H:%M:%S %z", "2013-06-28 19:08:09 -0800", &t, &err)) << err; - absl::Time::Breakdown bd = t.In(absl::FixedTimeZone(-8 * 60 * 60)); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -8 * 60 * 60, false); - EXPECT_EQ(absl::ZeroDuration(), bd.subsecond); + const auto ci = absl::FixedTimeZone(-8 * 60 * 60).At(t); + EXPECT_EQ(absl::CivilSecond(2013, 6, 28, 19, 8, 9), ci.cs); + EXPECT_EQ(absl::ZeroDuration(), ci.subsecond); } TEST(ParseTime, NullErrorString) { @@ -177,17 +177,17 @@ EXPECT_TRUE( absl::ParseTime("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &t, &e)) << e; - absl::Time::Breakdown bd = t.In(tz); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true); - EXPECT_EQ(absl::ZeroDuration(), bd.subsecond); + auto ci = tz.At(t); + EXPECT_EQ(absl::CivilSecond(2013, 6, 28, 19, 8, 9), ci.cs); + EXPECT_EQ(absl::ZeroDuration(), ci.subsecond); // But the timezone is ignored when a UTC offset is present. EXPECT_TRUE(absl::ParseTime("%Y-%m-%d %H:%M:%S %z", "2013-06-28 19:08:09 +0800", tz, &t, &e)) << e; - bd = t.In(absl::FixedTimeZone(8 * 60 * 60)); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, 8 * 60 * 60, false); - EXPECT_EQ(absl::ZeroDuration(), bd.subsecond); + ci = absl::FixedTimeZone(8 * 60 * 60).At(t); + EXPECT_EQ(absl::CivilSecond(2013, 6, 28, 19, 8, 9), ci.cs); + EXPECT_EQ(absl::ZeroDuration(), ci.subsecond); } TEST(ParseTime, ErrorCases) { @@ -332,15 +332,15 @@ EXPECT_TRUE(absl::ParseTime("infinite-future %H:%M", "infinite-future 03:04", &t, &err)); EXPECT_NE(absl::InfiniteFuture(), t); - EXPECT_EQ(3, t.In(tz).hour); - EXPECT_EQ(4, t.In(tz).minute); + EXPECT_EQ(3, tz.At(t).cs.hour()); + EXPECT_EQ(4, tz.At(t).cs.minute()); // "infinite-past" as literal std::string EXPECT_TRUE( absl::ParseTime("infinite-past %H:%M", "infinite-past 03:04", &t, &err)); EXPECT_NE(absl::InfinitePast(), t); - EXPECT_EQ(3, t.In(tz).hour); - EXPECT_EQ(4, t.In(tz).minute); + EXPECT_EQ(3, tz.At(t).cs.hour()); + EXPECT_EQ(4, tz.At(t).cs.minute()); // The input doesn't match the format. EXPECT_FALSE(absl::ParseTime("infinite-future %H:%M", "03:04", &t, &err)); @@ -365,16 +365,18 @@ // TEST(FormatParse, RoundTrip) { - const absl::TimeZone gst = + const absl::TimeZone lax = absl::time_internal::LoadTimeZone("America/Los_Angeles"); - const absl::Time in = absl::FromDateTime(1977, 6, 28, 9, 8, 7, gst); + const absl::Time in = + absl::FromCivil(absl::CivilSecond(1977, 6, 28, 9, 8, 7), lax); const absl::Duration subseconds = absl::Nanoseconds(654321); std::string err; // RFC3339, which renders subseconds. { absl::Time out; - const std::string s = absl::FormatTime(absl::RFC3339_full, in + subseconds, gst); + const std::string s = + absl::FormatTime(absl::RFC3339_full, in + subseconds, lax); EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err)) << s << ": " << err; EXPECT_EQ(in + subseconds, out); // RFC3339_full includes %Ez @@ -383,7 +385,7 @@ // RFC1123, which only does whole seconds. { absl::Time out; - const std::string s = absl::FormatTime(absl::RFC1123_full, in, gst); + const std::string s = absl::FormatTime(absl::RFC1123_full, in, lax); EXPECT_TRUE(absl::ParseTime(absl::RFC1123_full, s, &out, &err)) << s << ": " << err; EXPECT_EQ(in, out); // RFC1123_full includes %z @@ -393,7 +395,12 @@ // work. On Windows, `absl::ParseTime()` falls back to std::get_time() which // appears to fail on "%c" (or at least on the "%c" text produced by // `strftime()`). This makes it fail the round-trip test. -#ifndef _MSC_VER + // + // Under the emscripten compiler `absl::ParseTime() falls back to + // `strptime()`, but that ends up using a different definition for "%c" + // compared to `strftime()`, also causing the round-trip test to fail + // (see https://github.com/kripken/emscripten/pull/7491). +#if !defined(_MSC_VER) && !defined(__EMSCRIPTEN__) // Even though we don't know what %c will produce, it should roundtrip, // but only in the 0-offset timezone. { @@ -402,7 +409,7 @@ EXPECT_TRUE(absl::ParseTime("%c", s, &out, &err)) << s << ": " << err; EXPECT_EQ(in, out); } -#endif // _MSC_VER +#endif // !_MSC_VER && !__EMSCRIPTEN__ } TEST(FormatParse, RoundTripDistantFuture) {
diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel index 9f1ba21..903499b 100644 --- a/absl/time/internal/cctz/BUILD.bazel +++ b/absl/time/internal/cctz/BUILD.bazel
@@ -4,7 +4,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +package(features = ["-parse_headers"]) + licenses(["notice"]) # Apache License ### libraries @@ -85,6 +87,7 @@ "no_test_android_arm", "no_test_android_arm64", "no_test_android_x86", + "no_test_wasm", ], deps = [ ":civil_time", @@ -96,12 +99,14 @@ cc_test( name = "time_zone_lookup_test", size = "small", + timeout = "moderate", srcs = ["src/time_zone_lookup_test.cc"], data = [":zoneinfo"], tags = [ "no_test_android_arm", "no_test_android_arm64", "no_test_android_x86", + "no_test_wasm", ], deps = [ ":civil_time",
diff --git a/absl/time/internal/cctz/include/cctz/civil_time.h b/absl/time/internal/cctz/include/cctz/civil_time.h index 0842fa4..f844182 100644 --- a/absl/time/internal/cctz/include/cctz/civil_time.h +++ b/absl/time/internal/cctz/include/cctz/civil_time.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/time/internal/cctz/include/cctz/civil_time_detail.h b/absl/time/internal/cctz/include/cctz/civil_time_detail.h index d7f7271..a5923f1 100644 --- a/absl/time/internal/cctz/include/cctz/civil_time_detail.h +++ b/absl/time/internal/cctz/include/cctz/civil_time_detail.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -326,6 +326,37 @@ //////////////////////////////////////////////////////////////////////// +namespace impl { + +template <typename H> +H AbslHashValueImpl(second_tag, H h, fields f) { + return H::combine(std::move(h), f.y, f.m, f.d, f.hh, f.mm, f.ss); +} +template <typename H> +H AbslHashValueImpl(minute_tag, H h, fields f) { + return H::combine(std::move(h), f.y, f.m, f.d, f.hh, f.mm); +} +template <typename H> +H AbslHashValueImpl(hour_tag, H h, fields f) { + return H::combine(std::move(h), f.y, f.m, f.d, f.hh); +} +template <typename H> +H AbslHashValueImpl(day_tag, H h, fields f) { + return H::combine(std::move(h), f.y, f.m, f.d); +} +template <typename H> +H AbslHashValueImpl(month_tag, H h, fields f) { + return H::combine(std::move(h), f.y, f.m); +} +template <typename H> +H AbslHashValueImpl(year_tag, H h, fields f) { + return H::combine(std::move(h), f.y); +} + +} // namespace impl + +//////////////////////////////////////////////////////////////////////// + template <typename T> class civil_time { public: @@ -355,12 +386,12 @@ : civil_time(ct.f_) {} // Factories for the maximum/minimum representable civil_time. - static CONSTEXPR_F civil_time max() { - const auto max_year = std::numeric_limits<std::int_least64_t>::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() { - const auto min_year = std::numeric_limits<std::int_least64_t>::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); } @@ -378,7 +409,7 @@ return *this; } CONSTEXPR_M civil_time& operator-=(diff_t n) noexcept { - if (n != std::numeric_limits<diff_t>::min()) { + if (n != (std::numeric_limits<diff_t>::min)()) { f_ = step(T{}, f_, -n); } else { f_ = step(T{}, step(T{}, f_, -(n + 1)), 1); @@ -418,8 +449,7 @@ template <typename H> friend H AbslHashValue(H h, civil_time a) { - return H::combine(std::move(h), a.f_.y, a.f_.m, a.f_.d, - a.f_.hh, a.f_.mm, a.f_.ss); + return impl::AbslHashValueImpl(T{}, std::move(h), a.f_); } private: @@ -506,9 +536,11 @@ }; CONSTEXPR_F weekday get_weekday(const civil_day& cd) noexcept { - CONSTEXPR_D weekday k_weekday_by_sun_off[7] = { - weekday::sunday, weekday::monday, weekday::tuesday, - weekday::wednesday, weekday::thursday, weekday::friday, + CONSTEXPR_D weekday k_weekday_by_mon_off[13] = { + weekday::monday, weekday::tuesday, weekday::wednesday, + weekday::thursday, weekday::friday, weekday::saturday, + weekday::sunday, weekday::monday, weekday::tuesday, + weekday::wednesday, weekday::thursday, weekday::friday, weekday::saturday, }; CONSTEXPR_D int k_weekday_offsets[1 + 12] = { @@ -517,7 +549,7 @@ year_t wd = 2400 + (cd.year() % 400) - (cd.month() < 3); wd += wd / 4 - wd / 100 + wd / 400; wd += k_weekday_offsets[cd.month()] + cd.day(); - return k_weekday_by_sun_off[(wd % 7 + 7) % 7]; + return k_weekday_by_mon_off[wd % 7 + 6]; } ////////////////////////////////////////////////////////////////////////
diff --git a/absl/time/internal/cctz/include/cctz/time_zone.h b/absl/time/internal/cctz/include/cctz/time_zone.h index f28dad1..ef6c4ba 100644 --- a/absl/time/internal/cctz/include/cctz/time_zone.h +++ b/absl/time/internal/cctz/include/cctz/time_zone.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -72,7 +72,7 @@ // // See also: // - http://www.iana.org/time-zones -// - http://en.wikipedia.org/wiki/Zoneinfo +// - https://en.wikipedia.org/wiki/Zoneinfo class time_zone { public: time_zone() : time_zone(nullptr) {} // Equivalent to UTC
diff --git a/absl/time/internal/cctz/include/cctz/zone_info_source.h b/absl/time/internal/cctz/include/cctz/zone_info_source.h index 20a7697..2b898d1 100644 --- a/absl/time/internal/cctz/include/cctz/zone_info_source.h +++ b/absl/time/internal/cctz/include/cctz/zone_info_source.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/time/internal/cctz/src/cctz_benchmark.cc b/absl/time/internal/cctz/src/cctz_benchmark.cc index 4498d7d..445366e 100644 --- a/absl/time/internal/cctz/src/cctz_benchmark.cc +++ b/absl/time/internal/cctz/src/cctz_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -357,6 +357,7 @@ "Asia/Pontianak", "Asia/Pyongyang", "Asia/Qatar", + "Asia/Qostanay", "Asia/Qyzylorda", "Asia/Rangoon", "Asia/Riyadh",
diff --git a/absl/time/internal/cctz/src/civil_time_detail.cc b/absl/time/internal/cctz/src/civil_time_detail.cc index 780d5c9..cb40b6b 100644 --- a/absl/time/internal/cctz/src/civil_time_detail.cc +++ b/absl/time/internal/cctz/src/civil_time_detail.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/time/internal/cctz/src/civil_time_test.cc b/absl/time/internal/cctz/src/civil_time_test.cc index faffde4..e590ee3 100644 --- a/absl/time/internal/cctz/src/civil_time_test.cc +++ b/absl/time/internal/cctz/src/civil_time_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/time/internal/cctz/src/time_zone_fixed.cc b/absl/time/internal/cctz/src/time_zone_fixed.cc index db9a475..81ece72 100644 --- a/absl/time/internal/cctz/src/time_zone_fixed.cc +++ b/absl/time/internal/cctz/src/time_zone_fixed.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/time/internal/cctz/src/time_zone_fixed.h b/absl/time/internal/cctz/src/time_zone_fixed.h index 489b857..9c1f5e7 100644 --- a/absl/time/internal/cctz/src/time_zone_fixed.h +++ b/absl/time/internal/cctz/src/time_zone_fixed.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc index a02b1e3..2585098 100644 --- a/absl/time/internal/cctz/src/time_zone_format.cc +++ b/absl/time/internal/cctz/src/time_zone_format.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -13,7 +13,7 @@ // limitations under the License. #if !defined(HAS_STRPTIME) -# if !defined(_MSC_VER) +# if !defined(_MSC_VER) && !defined(__MINGW32__) # define HAS_STRPTIME 1 // assume everyone has strptime() except windows # endif #endif @@ -149,15 +149,25 @@ offset = -offset; // bounded by 24h so no overflow sign = '-'; } - char sep = mode[0]; - if (sep != '\0' && mode[1] == '*') { - ep = Format02d(ep, offset % 60); + const int seconds = offset % 60; + const int minutes = (offset /= 60) % 60; + const int hours = offset /= 60; + const char sep = mode[0]; + const bool ext = (sep != '\0' && mode[1] == '*'); + const bool ccc = (ext && mode[2] == ':'); + if (ext && (!ccc || seconds != 0)) { + ep = Format02d(ep, seconds); *--ep = sep; + } else { + // If we're not rendering seconds, sub-minute negative offsets + // should get a positive sign (e.g., offset=-10s => "+00:00"). + if (hours == 0 && minutes == 0) sign = '+'; } - int minutes = offset / 60; - ep = Format02d(ep, minutes % 60); - if (sep != '\0') *--ep = sep; - ep = Format02d(ep, minutes / 60); + if (!ccc || minutes != 0 || seconds != 0) { + ep = Format02d(ep, minutes); + if (sep != '\0') *--ep = sep; + } + ep = Format02d(ep, hours); *--ep = sign; return ep; } @@ -384,6 +394,44 @@ continue; } + // More complex specifiers that we handle ourselves. + if (*cur == ':' && cur + 1 != end) { + if (*(cur + 1) == 'z') { + // Formats %:z. + if (cur - 1 != pending) { + FormatTM(&result, std::string(pending, cur - 1), tm); + } + bp = FormatOffset(ep, al.offset, ":"); + result.append(bp, static_cast<std::size_t>(ep - bp)); + pending = cur += 2; + continue; + } + if (*(cur + 1) == ':' && cur + 2 != end) { + if (*(cur + 2) == 'z') { + // Formats %::z. + if (cur - 1 != pending) { + FormatTM(&result, std::string(pending, cur - 1), tm); + } + bp = FormatOffset(ep, al.offset, ":*"); + result.append(bp, static_cast<std::size_t>(ep - bp)); + pending = cur += 3; + continue; + } + if (*(cur + 2) == ':' && cur + 3 != end) { + if (*(cur + 3) == 'z') { + // Formats %:::z. + if (cur - 1 != pending) { + FormatTM(&result, std::string(pending, cur - 1), tm); + } + bp = FormatOffset(ep, al.offset, ":*:"); + result.append(bp, static_cast<std::size_t>(ep - bp)); + pending = cur += 4; + continue; + } + } + } + } + // Loop if there is no E modifier. if (*cur != 'E' || ++cur == end) continue; @@ -668,17 +716,27 @@ &percent_s); if (data != nullptr) saw_percent_s = true; continue; + case ':': + if (fmt[0] == 'z' || + (fmt[0] == ':' && + (fmt[1] == 'z' || (fmt[1] == ':' && fmt[2] == 'z')))) { + data = ParseOffset(data, ":", &offset); + if (data != nullptr) saw_offset = true; + fmt += (fmt[0] == 'z') ? 1 : (fmt[1] == 'z') ? 2 : 3; + continue; + } + break; case '%': data = (*data == '%' ? data + 1 : nullptr); continue; case 'E': - if (*fmt == 'z' || (*fmt == '*' && *(fmt + 1) == 'z')) { + if (fmt[0] == 'z' || (fmt[0] == '*' && fmt[1] == 'z')) { data = ParseOffset(data, ":", &offset); if (data != nullptr) saw_offset = true; - fmt += (*fmt == 'z') ? 1 : 2; + fmt += (fmt[0] == 'z') ? 1 : 2; continue; } - if (*fmt == '*' && *(fmt + 1) == 'S') { + if (fmt[0] == '*' && fmt[1] == 'S') { data = ParseInt(data, 2, 0, 60, &tm.tm_sec); if (data != nullptr && *data == '.') { data = ParseSubSeconds(data + 1, &subseconds); @@ -686,14 +744,14 @@ fmt += 2; continue; } - if (*fmt == '*' && *(fmt + 1) == 'f') { + if (fmt[0] == '*' && fmt[1] == 'f') { if (data != nullptr && std::isdigit(*data)) { data = ParseSubSeconds(data, &subseconds); } fmt += 2; continue; } - if (*fmt == '4' && *(fmt + 1) == 'Y') { + if (fmt[0] == '4' && fmt[1] == 'Y') { const char* bp = data; data = ParseInt(data, 4, year_t{-999}, year_t{9999}, &year); if (data != nullptr) {
diff --git a/absl/time/internal/cctz/src/time_zone_format_test.cc b/absl/time/internal/cctz/src/time_zone_format_test.cc index 6b9928e..705ccdc 100644 --- a/absl/time/internal/cctz/src/time_zone_format_test.cc +++ b/absl/time/internal/cctz/src/time_zone_format_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -64,17 +64,6 @@ EXPECT_EQ("xxx " + ans + " yyy", format("xxx " + fmt + " yyy", tp, tz)); } -// These tests sometimes run on platforms that have zoneinfo data so old -// that the transition we are attempting to check does not exist, most -// notably Android emulators. Fortunately, AndroidZoneInfoSource supports -// time_zone::version() so, in cases where we've learned that it matters, -// we can make the check conditionally. -int VersionCmp(time_zone tz, const std::string& target) { - std::string version = tz.version(); - if (version.empty() && !target.empty()) return 1; // unknown > known - return version.compare(target); -} - } // namespace // @@ -174,7 +163,9 @@ TestFormatSpecifier(tp, tz, "%M", "00"); TestFormatSpecifier(tp, tz, "%S", "00"); TestFormatSpecifier(tp, tz, "%U", "00"); +#if !defined(__EMSCRIPTEN__) TestFormatSpecifier(tp, tz, "%w", "4"); // 4=Thursday +#endif TestFormatSpecifier(tp, tz, "%W", "00"); TestFormatSpecifier(tp, tz, "%y", "70"); TestFormatSpecifier(tp, tz, "%Y", "1970"); @@ -436,51 +427,165 @@ } TEST(Format, ExtendedOffset) { - auto tp = chrono::system_clock::from_time_t(0); + const auto tp = chrono::system_clock::from_time_t(0); - time_zone tz = utc_time_zone(); + auto tz = fixed_time_zone(absl::time_internal::cctz::seconds::zero()); + TestFormatSpecifier(tp, tz, "%z", "+0000"); + TestFormatSpecifier(tp, tz, "%:z", "+00:00"); TestFormatSpecifier(tp, tz, "%Ez", "+00:00"); - EXPECT_TRUE(load_time_zone("America/New_York", &tz)); - TestFormatSpecifier(tp, tz, "%Ez", "-05:00"); + tz = fixed_time_zone(chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%z", "+0000"); + TestFormatSpecifier(tp, tz, "%:z", "+00:00"); + TestFormatSpecifier(tp, tz, "%Ez", "+00:00"); - EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz)); - TestFormatSpecifier(tp, tz, "%Ez", "-08:00"); + tz = fixed_time_zone(-chrono::seconds(56)); // NOTE: +00:00 + TestFormatSpecifier(tp, tz, "%z", "+0000"); + TestFormatSpecifier(tp, tz, "%:z", "+00:00"); + TestFormatSpecifier(tp, tz, "%Ez", "+00:00"); - EXPECT_TRUE(load_time_zone("Australia/Sydney", &tz)); - TestFormatSpecifier(tp, tz, "%Ez", "+10:00"); + tz = fixed_time_zone(chrono::minutes(34)); + TestFormatSpecifier(tp, tz, "%z", "+0034"); + TestFormatSpecifier(tp, tz, "%:z", "+00:34"); + TestFormatSpecifier(tp, tz, "%Ez", "+00:34"); - EXPECT_TRUE(load_time_zone("Africa/Monrovia", &tz)); - // The true offset is -00:44:30 but %z only gives (truncated) minutes. - TestFormatSpecifier(tp, tz, "%z", "-0044"); - TestFormatSpecifier(tp, tz, "%Ez", "-00:44"); + tz = fixed_time_zone(-chrono::minutes(34)); + TestFormatSpecifier(tp, tz, "%z", "-0034"); + TestFormatSpecifier(tp, tz, "%:z", "-00:34"); + TestFormatSpecifier(tp, tz, "%Ez", "-00:34"); + + tz = fixed_time_zone(chrono::minutes(34) + chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%z", "+0034"); + TestFormatSpecifier(tp, tz, "%:z", "+00:34"); + TestFormatSpecifier(tp, tz, "%Ez", "+00:34"); + + tz = fixed_time_zone(-chrono::minutes(34) - chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%z", "-0034"); + TestFormatSpecifier(tp, tz, "%:z", "-00:34"); + TestFormatSpecifier(tp, tz, "%Ez", "-00:34"); + + tz = fixed_time_zone(chrono::hours(12)); + TestFormatSpecifier(tp, tz, "%z", "+1200"); + TestFormatSpecifier(tp, tz, "%:z", "+12:00"); + TestFormatSpecifier(tp, tz, "%Ez", "+12:00"); + + tz = fixed_time_zone(-chrono::hours(12)); + TestFormatSpecifier(tp, tz, "%z", "-1200"); + TestFormatSpecifier(tp, tz, "%:z", "-12:00"); + TestFormatSpecifier(tp, tz, "%Ez", "-12:00"); + + tz = fixed_time_zone(chrono::hours(12) + chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%z", "+1200"); + TestFormatSpecifier(tp, tz, "%:z", "+12:00"); + TestFormatSpecifier(tp, tz, "%Ez", "+12:00"); + + tz = fixed_time_zone(-chrono::hours(12) - chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%z", "-1200"); + TestFormatSpecifier(tp, tz, "%:z", "-12:00"); + TestFormatSpecifier(tp, tz, "%Ez", "-12:00"); + + tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34)); + TestFormatSpecifier(tp, tz, "%z", "+1234"); + TestFormatSpecifier(tp, tz, "%:z", "+12:34"); + TestFormatSpecifier(tp, tz, "%Ez", "+12:34"); + + tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34)); + TestFormatSpecifier(tp, tz, "%z", "-1234"); + TestFormatSpecifier(tp, tz, "%:z", "-12:34"); + TestFormatSpecifier(tp, tz, "%Ez", "-12:34"); + + tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34) + + chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%z", "+1234"); + TestFormatSpecifier(tp, tz, "%:z", "+12:34"); + TestFormatSpecifier(tp, tz, "%Ez", "+12:34"); + + tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34) - + chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%z", "-1234"); + TestFormatSpecifier(tp, tz, "%:z", "-12:34"); + TestFormatSpecifier(tp, tz, "%Ez", "-12:34"); } TEST(Format, ExtendedSecondOffset) { - const time_zone utc = utc_time_zone(); - time_point<chrono::seconds> tp; - time_zone tz; + const auto tp = chrono::system_clock::from_time_t(0); - EXPECT_TRUE(load_time_zone("America/New_York", &tz)); - tp = convert(civil_second(1883, 11, 18, 16, 59, 59), utc); - if (tz.lookup(tp).offset == -5 * 60 * 60) { - // It looks like the tzdata is only 32 bit (probably macOS), - // which bottoms out at 1901-12-13T20:45:52+00:00. - } else { - TestFormatSpecifier(tp, tz, "%E*z", "-04:56:02"); - TestFormatSpecifier(tp, tz, "%Ez", "-04:56"); - } - tp += chrono::seconds(1); - TestFormatSpecifier(tp, tz, "%E*z", "-05:00:00"); + auto tz = fixed_time_zone(absl::time_internal::cctz::seconds::zero()); + TestFormatSpecifier(tp, tz, "%E*z", "+00:00:00"); + TestFormatSpecifier(tp, tz, "%::z", "+00:00:00"); + TestFormatSpecifier(tp, tz, "%:::z", "+00"); - EXPECT_TRUE(load_time_zone("Europe/Moscow", &tz)); - tp = convert(civil_second(1919, 6, 30, 23, 59, 59), utc); - if (VersionCmp(tz, "2016g") >= 0) { - TestFormatSpecifier(tp, tz, "%E*z", "+04:31:19"); - TestFormatSpecifier(tp, tz, "%Ez", "+04:31"); - } - tp += chrono::seconds(1); - TestFormatSpecifier(tp, tz, "%E*z", "+04:00:00"); + tz = fixed_time_zone(chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%E*z", "+00:00:56"); + TestFormatSpecifier(tp, tz, "%::z", "+00:00:56"); + TestFormatSpecifier(tp, tz, "%:::z", "+00:00:56"); + + tz = fixed_time_zone(-chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%E*z", "-00:00:56"); + TestFormatSpecifier(tp, tz, "%::z", "-00:00:56"); + TestFormatSpecifier(tp, tz, "%:::z", "-00:00:56"); + + tz = fixed_time_zone(chrono::minutes(34)); + TestFormatSpecifier(tp, tz, "%E*z", "+00:34:00"); + TestFormatSpecifier(tp, tz, "%::z", "+00:34:00"); + TestFormatSpecifier(tp, tz, "%:::z", "+00:34"); + + tz = fixed_time_zone(-chrono::minutes(34)); + TestFormatSpecifier(tp, tz, "%E*z", "-00:34:00"); + TestFormatSpecifier(tp, tz, "%::z", "-00:34:00"); + TestFormatSpecifier(tp, tz, "%:::z", "-00:34"); + + tz = fixed_time_zone(chrono::minutes(34) + chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%E*z", "+00:34:56"); + TestFormatSpecifier(tp, tz, "%::z", "+00:34:56"); + TestFormatSpecifier(tp, tz, "%:::z", "+00:34:56"); + + tz = fixed_time_zone(-chrono::minutes(34) - chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%E*z", "-00:34:56"); + TestFormatSpecifier(tp, tz, "%::z", "-00:34:56"); + TestFormatSpecifier(tp, tz, "%:::z", "-00:34:56"); + + tz = fixed_time_zone(chrono::hours(12)); + TestFormatSpecifier(tp, tz, "%E*z", "+12:00:00"); + TestFormatSpecifier(tp, tz, "%::z", "+12:00:00"); + TestFormatSpecifier(tp, tz, "%:::z", "+12"); + + tz = fixed_time_zone(-chrono::hours(12)); + TestFormatSpecifier(tp, tz, "%E*z", "-12:00:00"); + TestFormatSpecifier(tp, tz, "%::z", "-12:00:00"); + TestFormatSpecifier(tp, tz, "%:::z", "-12"); + + tz = fixed_time_zone(chrono::hours(12) + chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%E*z", "+12:00:56"); + TestFormatSpecifier(tp, tz, "%::z", "+12:00:56"); + TestFormatSpecifier(tp, tz, "%:::z", "+12:00:56"); + + tz = fixed_time_zone(-chrono::hours(12) - chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%E*z", "-12:00:56"); + TestFormatSpecifier(tp, tz, "%::z", "-12:00:56"); + TestFormatSpecifier(tp, tz, "%:::z", "-12:00:56"); + + tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34)); + TestFormatSpecifier(tp, tz, "%E*z", "+12:34:00"); + TestFormatSpecifier(tp, tz, "%::z", "+12:34:00"); + TestFormatSpecifier(tp, tz, "%:::z", "+12:34"); + + tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34)); + TestFormatSpecifier(tp, tz, "%E*z", "-12:34:00"); + TestFormatSpecifier(tp, tz, "%::z", "-12:34:00"); + TestFormatSpecifier(tp, tz, "%:::z", "-12:34"); + + tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34) + + chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%E*z", "+12:34:56"); + TestFormatSpecifier(tp, tz, "%::z", "+12:34:56"); + TestFormatSpecifier(tp, tz, "%:::z", "+12:34:56"); + + tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34) - + chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%E*z", "-12:34:56"); + TestFormatSpecifier(tp, tz, "%::z", "-12:34:56"); + TestFormatSpecifier(tp, tz, "%:::z", "-12:34:56"); } TEST(Format, ExtendedYears) { @@ -1160,25 +1265,6 @@ const time_zone utc = utc_time_zone(); time_point<absl::time_internal::cctz::seconds> tp; - // %z against +-HHMM. - EXPECT_TRUE(parse("%z", "+0000", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); - EXPECT_TRUE(parse("%z", "-1234", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); - EXPECT_TRUE(parse("%z", "+1234", utc, &tp)); - EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); - EXPECT_FALSE(parse("%z", "-123", utc, &tp)); - - // %z against +-HH. - EXPECT_TRUE(parse("%z", "+00", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); - EXPECT_TRUE(parse("%z", "-12", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp); - EXPECT_TRUE(parse("%z", "+12", utc, &tp)); - EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp); - EXPECT_FALSE(parse("%z", "-1", utc, &tp)); - - // %Ez against +-HH:MM. EXPECT_TRUE(parse("%Ez", "+00:00", utc, &tp)); EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); EXPECT_TRUE(parse("%Ez", "-12:34", utc, &tp)); @@ -1187,91 +1273,70 @@ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); EXPECT_FALSE(parse("%Ez", "-12:3", utc, &tp)); - // %Ez against +-HHMM. - EXPECT_TRUE(parse("%Ez", "+0000", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); - EXPECT_TRUE(parse("%Ez", "-1234", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); - EXPECT_TRUE(parse("%Ez", "+1234", utc, &tp)); - EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); - EXPECT_FALSE(parse("%Ez", "-123", utc, &tp)); + for (auto fmt : {"%Ez", "%z"}) { + EXPECT_TRUE(parse(fmt, "+0000", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "-1234", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "+1234", utc, &tp)); + EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); + EXPECT_FALSE(parse(fmt, "-123", utc, &tp)); - // %Ez against +-HH. - EXPECT_TRUE(parse("%Ez", "+00", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); - EXPECT_TRUE(parse("%Ez", "-12", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp); - EXPECT_TRUE(parse("%Ez", "+12", utc, &tp)); - EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp); - EXPECT_FALSE(parse("%Ez", "-1", utc, &tp)); + EXPECT_TRUE(parse(fmt, "+00", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "-12", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "+12", utc, &tp)); + EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp); + EXPECT_FALSE(parse(fmt, "-1", utc, &tp)); + } } TEST(Parse, ExtendedSecondOffset) { const time_zone utc = utc_time_zone(); time_point<absl::time_internal::cctz::seconds> tp; - // %Ez against +-HH:MM:SS. - EXPECT_TRUE(parse("%Ez", "+00:00:00", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); - EXPECT_TRUE(parse("%Ez", "-12:34:56", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp); - EXPECT_TRUE(parse("%Ez", "+12:34:56", utc, &tp)); - EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp); - EXPECT_FALSE(parse("%Ez", "-12:34:5", utc, &tp)); + for (auto fmt : {"%Ez", "%E*z", "%:z", "%::z", "%:::z"}) { + EXPECT_TRUE(parse(fmt, "+00:00:00", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "-12:34:56", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp); + EXPECT_TRUE(parse(fmt, "+12:34:56", utc, &tp)); + EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp); + EXPECT_FALSE(parse(fmt, "-12:34:5", utc, &tp)); - // %Ez against +-HHMMSS. - EXPECT_TRUE(parse("%Ez", "+000000", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); - EXPECT_TRUE(parse("%Ez", "-123456", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp); - EXPECT_TRUE(parse("%Ez", "+123456", utc, &tp)); - EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp); - EXPECT_FALSE(parse("%Ez", "-12345", utc, &tp)); + EXPECT_TRUE(parse(fmt, "+000000", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "-123456", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp); + EXPECT_TRUE(parse(fmt, "+123456", utc, &tp)); + EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp); + EXPECT_FALSE(parse(fmt, "-12345", utc, &tp)); - // %E*z against +-HH:MM:SS. - EXPECT_TRUE(parse("%E*z", "+00:00:00", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); - EXPECT_TRUE(parse("%E*z", "-12:34:56", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp); - EXPECT_TRUE(parse("%E*z", "+12:34:56", utc, &tp)); - EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp); - EXPECT_FALSE(parse("%E*z", "-12:34:5", utc, &tp)); + EXPECT_TRUE(parse(fmt, "+00:00", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "-12:34", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "+12:34", utc, &tp)); + EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); + EXPECT_FALSE(parse(fmt, "-12:3", utc, &tp)); - // %E*z against +-HHMMSS. - EXPECT_TRUE(parse("%E*z", "+000000", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); - EXPECT_TRUE(parse("%E*z", "-123456", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp); - EXPECT_TRUE(parse("%E*z", "+123456", utc, &tp)); - EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp); - EXPECT_FALSE(parse("%E*z", "-12345", utc, &tp)); + EXPECT_TRUE(parse(fmt, "+0000", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "-1234", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "+1234", utc, &tp)); + EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); + EXPECT_FALSE(parse(fmt, "-123", utc, &tp)); - // %E*z against +-HH:MM. - EXPECT_TRUE(parse("%E*z", "+00:00", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); - EXPECT_TRUE(parse("%E*z", "-12:34", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); - EXPECT_TRUE(parse("%E*z", "+12:34", utc, &tp)); - EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); - EXPECT_FALSE(parse("%E*z", "-12:3", utc, &tp)); - - // %E*z against +-HHMM. - EXPECT_TRUE(parse("%E*z", "+0000", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); - EXPECT_TRUE(parse("%E*z", "-1234", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); - EXPECT_TRUE(parse("%E*z", "+1234", utc, &tp)); - EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); - EXPECT_FALSE(parse("%E*z", "-123", utc, &tp)); - - // %E*z against +-HH. - EXPECT_TRUE(parse("%E*z", "+00", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); - EXPECT_TRUE(parse("%E*z", "-12", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp); - EXPECT_TRUE(parse("%E*z", "+12", utc, &tp)); - EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp); - EXPECT_FALSE(parse("%E*z", "-1", utc, &tp)); + EXPECT_TRUE(parse(fmt, "+00", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "-12", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "+12", utc, &tp)); + EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp); + EXPECT_FALSE(parse(fmt, "-1", utc, &tp)); + } } TEST(Parse, ExtendedYears) { @@ -1390,6 +1455,10 @@ #if defined(_WIN32) || defined(_WIN64) // Initial investigations indicate the %c does not roundtrip on Windows. // TODO: Figure out what is going on here (perhaps a locale problem). +#elif defined(__EMSCRIPTEN__) + // strftime() and strptime() use different defintions for "%c" under + // emscripten (see https://github.com/kripken/emscripten/pull/7491), + // causing its round-trip test to fail. #else // Even though we don't know what %c will produce, it should roundtrip, // but only in the 0-offset timezone.
diff --git a/absl/time/internal/cctz/src/time_zone_if.cc b/absl/time/internal/cctz/src/time_zone_if.cc index 380834a..09aaee5 100644 --- a/absl/time/internal/cctz/src/time_zone_if.cc +++ b/absl/time/internal/cctz/src/time_zone_if.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/time/internal/cctz/src/time_zone_if.h b/absl/time/internal/cctz/src/time_zone_if.h index e4bd386..d000b7a 100644 --- a/absl/time/internal/cctz/src/time_zone_if.h +++ b/absl/time/internal/cctz/src/time_zone_if.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/time/internal/cctz/src/time_zone_impl.cc b/absl/time/internal/cctz/src/time_zone_impl.cc index 3062ccd..3cbc674 100644 --- a/absl/time/internal/cctz/src/time_zone_impl.cc +++ b/absl/time/internal/cctz/src/time_zone_impl.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/time/internal/cctz/src/time_zone_impl.h b/absl/time/internal/cctz/src/time_zone_impl.h index 14965ef..b73fad9 100644 --- a/absl/time/internal/cctz/src/time_zone_impl.h +++ b/absl/time/internal/cctz/src/time_zone_impl.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/time/internal/cctz/src/time_zone_info.cc b/absl/time/internal/cctz/src/time_zone_info.cc index 2cb358d..50f7de5 100644 --- a/absl/time/internal/cctz/src/time_zone_info.cc +++ b/absl/time/internal/cctz/src/time_zone_info.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -25,7 +25,7 @@ // a grain of salt. // // For more information see tzfile(5), http://www.iana.org/time-zones, or -// http://en.wikipedia.org/wiki/Zoneinfo. +// https://en.wikipedia.org/wiki/Zoneinfo. // // Note that we assume the proleptic Gregorian calendar and 60-second // minutes throughout. @@ -921,7 +921,7 @@ ++begin; } std::int_fast64_t unix_time = ToUnixSeconds(tp); - const Transition target = { unix_time }; + const Transition target = {unix_time, 0, civil_second(), civil_second()}; const Transition* tr = std::upper_bound(begin, end, target, Transition::ByUnixTime()); for (; tr != end; ++tr) { // skip no-op transitions @@ -956,7 +956,7 @@ } unix_time += 1; // ceils } - const Transition target = { unix_time }; + const Transition target = {unix_time, 0, civil_second(), civil_second()}; const Transition* tr = std::lower_bound(begin, end, target, Transition::ByUnixTime()); for (; tr != begin; --tr) { // skip no-op transitions
diff --git a/absl/time/internal/cctz/src/time_zone_info.h b/absl/time/internal/cctz/src/time_zone_info.h index 958e9b6..bff639f 100644 --- a/absl/time/internal/cctz/src/time_zone_info.h +++ b/absl/time/internal/cctz/src/time_zone_info.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc index 074c8d0..3ab1623 100644 --- a/absl/time/internal/cctz/src/time_zone_libc.cc +++ b/absl/time/internal/cctz/src/time_zone_libc.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -20,6 +20,7 @@ #include <chrono> #include <ctime> +#include <limits> #include <tuple> #include <utility> @@ -85,6 +86,76 @@ #endif // !defined(__tm_gmtoff) && !defined(__tm_zone) #endif +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; +#else + return gmtime_r(timep, result); +#endif +} + +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; +#else + return localtime_r(timep, result); +#endif +} + +// Converts a civil second and "dst" flag into a time_t and UTC offset. +// Returns false if time_t cannot represent the requested civil second. +// Caller must have already checked that cs.year() will fit into a tm_year. +bool make_time(const civil_second& cs, int is_dst, std::time_t* t, int* off) { + std::tm tm; + tm.tm_year = static_cast<int>(cs.year() - year_t{1900}); + tm.tm_mon = cs.month() - 1; + tm.tm_mday = cs.day(); + tm.tm_hour = cs.hour(); + tm.tm_min = cs.minute(); + tm.tm_sec = cs.second(); + tm.tm_isdst = is_dst; + *t = std::mktime(&tm); + if (*t == std::time_t{-1}) { + std::tm tm2; + const std::tm* tmp = local_time(t, &tm2); + if (tmp == nullptr || tmp->tm_year != tm.tm_year || + tmp->tm_mon != tm.tm_mon || tmp->tm_mday != tm.tm_mday || + tmp->tm_hour != tm.tm_hour || tmp->tm_min != tm.tm_min || + tmp->tm_sec != tm.tm_sec) { + // A true error (not just one second before the epoch). + return false; + } + } + *off = get_offset_abbr(tm).first; + return true; +} + +// Find the least time_t in [lo:hi] where local time matches offset, given: +// (1) lo doesn't match, (2) hi does, and (3) there is only one transition. +std::time_t find_trans(std::time_t lo, std::time_t hi, int offset) { + std::tm tm; + while (lo + 1 != hi) { + const std::time_t mid = lo + (hi - lo) / 2; + if (std::tm* tmp = local_time(&mid, &tm)) { + if (get_offset_abbr(*tmp).first == offset) { + hi = mid; + } else { + lo = mid; + } + } else { + // 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)) { + if (get_offset_abbr(*tmp).first == offset) break; + } + } + return lo; + } + } + return hi; +} + } // namespace TimeZoneLibC::TimeZoneLibC(const std::string& name) @@ -93,59 +164,116 @@ time_zone::absolute_lookup TimeZoneLibC::BreakTime( const time_point<seconds>& tp) const { time_zone::absolute_lookup al; - std::time_t t = ToUnixSeconds(tp); - std::tm tm; - if (local_) { -#if defined(_WIN32) || defined(_WIN64) - localtime_s(&tm, &t); -#else - localtime_r(&t, &tm); -#endif - std::tie(al.offset, al.abbr) = get_offset_abbr(tm); - } else { -#if defined(_WIN32) || defined(_WIN64) - gmtime_s(&tm, &t); -#else - gmtime_r(&t, &tm); -#endif - al.offset = 0; - al.abbr = "UTC"; + al.offset = 0; + al.is_dst = false; + al.abbr = "-00"; + + const std::int_fast64_t s = ToUnixSeconds(tp); + + // If std::time_t cannot hold the input we saturate the output. + if (s < std::numeric_limits<std::time_t>::min()) { + al.cs = civil_second::min(); + return al; } - al.cs = civil_second(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); - al.is_dst = tm.tm_isdst > 0; + if (s > std::numeric_limits<std::time_t>::max()) { + al.cs = civil_second::max(); + return al; + } + + const std::time_t t = static_cast<std::time_t>(s); + std::tm tm; + std::tm* tmp = local_ ? local_time(&t, &tm) : gm_time(&t, &tm); + + // If std::tm cannot hold the result we saturate the output. + if (tmp == nullptr) { + al.cs = (s < 0) ? civil_second::min() : civil_second::max(); + return al; + } + + 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); + std::tie(al.offset, al.abbr) = get_offset_abbr(*tmp); + if (!local_) al.abbr = "UTC"; // as expected by cctz + al.is_dst = tmp->tm_isdst > 0; return al; } time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const { - time_zone::civil_lookup cl; - std::time_t t; - if (local_) { - // Does not handle SKIPPED/AMBIGUOUS or huge years. - std::tm tm; - tm.tm_year = static_cast<int>(cs.year() - 1900); - tm.tm_mon = cs.month() - 1; - tm.tm_mday = cs.day(); - tm.tm_hour = cs.hour(); - tm.tm_min = cs.minute(); - tm.tm_sec = cs.second(); - tm.tm_isdst = -1; - t = std::mktime(&tm); - } else { - t = cs - civil_second(); + if (!local_) { + // If time_point<seconds> cannot hold the result we saturate. + static const civil_second min_tp_cs = + 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()); + return {time_zone::civil_lookup::UNIQUE, tp, tp, tp}; } - cl.kind = time_zone::civil_lookup::UNIQUE; - cl.pre = cl.trans = cl.post = FromUnixSeconds(t); - return cl; + + // If tm_year cannot hold the requested year we saturate the result. + if (cs.year() < 0) { + if (cs.year() < std::numeric_limits<int>::min() + year_t{1900}) { + const time_point<seconds> tp = time_point<seconds>::min(); + return {time_zone::civil_lookup::UNIQUE, tp, tp, tp}; + } + } else { + if (cs.year() - year_t{1900} > std::numeric_limits<int>::max()) { + const time_point<seconds> tp = time_point<seconds>::max(); + return {time_zone::civil_lookup::UNIQUE, tp, tp, tp}; + } + } + + // We probe with "is_dst" values of 0 and 1 to try to distinguish unique + // civil seconds from skipped or repeated ones. This is not always possible + // however, as the "dst" flag does not change over some offset transitions. + // We are also subject to the vagaries of mktime() implementations. + std::time_t t0, t1; + int offset0, offset1; + if (make_time(cs, 0, &t0, &offset0) && make_time(cs, 1, &t1, &offset1)) { + if (t0 == t1) { + // The civil time was singular (pre == trans == post). + const time_point<seconds> tp = FromUnixSeconds(t0); + return {time_zone::civil_lookup::UNIQUE, tp, tp, tp}; + } + + if (t0 > t1) { + std::swap(t0, t1); + std::swap(offset0, offset1); + } + const std::time_t tt = find_trans(t0, t1, offset1); + const time_point<seconds> trans = FromUnixSeconds(tt); + + if (offset0 < offset1) { + // The civil time did not exist (pre >= trans > post). + const time_point<seconds> pre = FromUnixSeconds(t1); + const time_point<seconds> post = FromUnixSeconds(t0); + return {time_zone::civil_lookup::SKIPPED, pre, trans, post}; + } + + // The civil time was ambiguous (pre < trans <= post). + const time_point<seconds> pre = FromUnixSeconds(t0); + const time_point<seconds> post = FromUnixSeconds(t1); + return {time_zone::civil_lookup::REPEATED, pre, trans, post}; + } + + // make_time() failed somehow so we saturate the result. + const time_point<seconds> tp = (cs < civil_second()) + ? time_point<seconds>::min() + : time_point<seconds>::max(); + return {time_zone::civil_lookup::UNIQUE, tp, tp, tp}; } -bool TimeZoneLibC::NextTransition(const time_point<seconds>& tp, - time_zone::civil_transition* trans) const { +bool TimeZoneLibC::NextTransition(const time_point<seconds>&, + time_zone::civil_transition*) const { return false; } -bool TimeZoneLibC::PrevTransition(const time_point<seconds>& tp, - time_zone::civil_transition* trans) const { +bool TimeZoneLibC::PrevTransition(const time_point<seconds>&, + time_zone::civil_transition*) const { return false; }
diff --git a/absl/time/internal/cctz/src/time_zone_libc.h b/absl/time/internal/cctz/src/time_zone_libc.h index 4e40c61..0d18e9a 100644 --- a/absl/time/internal/cctz/src/time_zone_libc.h +++ b/absl/time/internal/cctz/src/time_zone_libc.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc index f2d151e..fd04e2d 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -20,6 +20,11 @@ #include <dlfcn.h> #endif #endif + +#if defined(__APPLE__) +#include <CoreFoundation/CFTimeZone.h> +#endif + #include <cstdlib> #include <cstring> #include <string> @@ -121,6 +126,11 @@ char* tz_env = nullptr; #if defined(_MSC_VER) _dupenv_s(&tz_env, nullptr, "TZ"); +#elif defined(__APPLE__) + CFTimeZoneRef system_time_zone = CFTimeZoneCopyDefault(); + CFStringRef tz_name = CFTimeZoneGetName(system_time_zone); + tz_env = strdup(CFStringGetCStringPtr(tz_name, CFStringGetSystemEncoding())); + CFRelease(system_time_zone); #else tz_env = std::getenv("TZ"); #endif @@ -153,6 +163,8 @@ #if defined(_MSC_VER) free(localtime_env); free(tz_env); +#elif defined(__APPLE__) + free(tz_env); #endif time_zone tz;
diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc index 551292f..8068e2f 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -16,7 +16,9 @@ #include <chrono> #include <cstddef> +#include <cstdlib> #include <future> +#include <limits> #include <string> #include <thread> #include <vector> @@ -335,6 +337,7 @@ "Asia/Pontianak", "Asia/Pyongyang", "Asia/Qatar", + "Asia/Qostanay", "Asia/Qyzylorda", "Asia/Rangoon", "Asia/Riyadh", @@ -664,6 +667,7 @@ } // namespace +#if !defined(__EMSCRIPTEN__) TEST(TimeZones, LoadZonesConcurrently) { std::promise<void> ready_promise; std::shared_future<void> ready_future(ready_promise.get_future()); @@ -711,6 +715,7 @@ } EXPECT_LE(failures.size(), max_failures) << testing::PrintToString(failures); } +#endif TEST(TimeZone, NamedTimeZones) { const time_zone utc = utc_time_zone(); @@ -925,7 +930,7 @@ EXPECT_EQ(tp, convert(civil_second(2009, 2, 13, 18, 30, 90), tz)); // second } -// NOTE: Run this with --copt=-ftrapv to detect overflow problems. +// NOTE: Run this with -ftrapv to detect overflow problems. TEST(MakeTime, SysSecondsLimits) { const char RFC3339[] = "%Y-%m-%dT%H:%M:%S%Ez"; const time_zone utc = utc_time_zone(); @@ -990,6 +995,106 @@ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); tp = convert(civil_second::min(), west); EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); + + // Some similar checks for the "libc" time-zone implementation. + if (sizeof(std::time_t) >= 8) { + // Checks that "tm_year + 1900", as used by the "libc" implementation, + // can produce year values beyond the range on an int without overflow. +#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 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)); + 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)); +#endif + } +} + +TEST(MakeTime, LocalTimeLibC) { + // Checks that cctz and libc agree on transition points in [1970:2037]. + // + // We limit this test case to environments where: + // 1) we know how to change the time zone used by localtime()/mktime(), + // 2) cctz and localtime()/mktime() will use similar-enough tzdata, and + // 3) we have some idea about how mktime() behaves during transitions. +#if defined(__linux__) && !defined(__ANDROID__) + const char* const ep = getenv("TZ"); + std::string tz_name = (ep != nullptr) ? ep : ""; + for (const char* const* np = kTimeZoneNames; *np != nullptr; ++np) { + 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; + 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); + 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); + const auto trans = fcl.trans; + const auto tal = zi.lookup(trans); + const auto tprev = trans - absl::time_internal::cctz::seconds(1); + const auto pal = zi.lookup(tprev); + if (pal.is_dst == tal.is_dst) { + ASSERT_STRNE(pal.abbr, tal.abbr); + } + continue; + } + ASSERT_EQ(time_zone::civil_lookup::REPEATED, tcl.kind); + cs = trans.to; + } else { + ASSERT_EQ(time_zone::civil_lookup::UNIQUE, tcl.kind); + ASSERT_EQ(time_zone::civil_lookup::SKIPPED, fcl.kind); + cs = trans.from; + } + if (cs.year() > 2037) break; // limit test time (and to 32-bit time_t) + const auto cl_zi = zi.lookup(cs); + if (zi.lookup(cl_zi.pre).is_dst == zi.lookup(cl_zi.post).is_dst) { + // The "libc" implementation cannot correctly classify transitions + // that don't change the "tm_isdst" flag. In Europe/Volgograd, for + // example, there is a SKIPPED transition from +03 to +04 with dst=F + // on both sides ... + // 1540681199 = 2018-10-28 01:59:59 +03:00:00 [dst=F off=10800] + // 1540681200 = 2018-10-28 03:00:00 +04:00:00 [dst=F off=14400] + // but std::mktime(2018-10-28 02:00:00, tm_isdst=0) fails, unlike, + // say, the similar Europe/Chisinau transition from +02 to +03 ... + // 1521935999 = 2018-03-25 01:59:59 +02:00:00 [dst=F off=7200] + // 1521936000 = 2018-03-25 03:00:00 +03:00:00 [dst=T off=10800] + // where std::mktime(2018-03-25 02:00:00, tm_isdst=0) succeeds and + // returns 1521936000. + continue; + } + if (cs == civil_second(2037, 10, 4, 2, 0, 0)) { + const std::string tzname = *np; + if (tzname == "Africa/Casablanca" || tzname == "Africa/El_Aaiun") { + // The "libc" implementation gets this transition wrong (at least + // until 2018g when it was removed), returning an offset of 3600 + // instead of 0. TODO: Revert this when 2018g is ubiquitous. + continue; + } + } + const auto cl_lc = lc.lookup(cs); + SCOPED_TRACE(testing::Message() << "For " << cs << " in " << *np); + EXPECT_EQ(cl_zi.kind, cl_lc.kind); + EXPECT_EQ(cl_zi.pre, cl_lc.pre); + EXPECT_EQ(cl_zi.trans, cl_lc.trans); + EXPECT_EQ(cl_zi.post, cl_lc.post); + } + } + if (ep == nullptr) { + ASSERT_EQ(0, unsetenv("TZ")); + } else { + ASSERT_EQ(0, setenv("TZ", tz_name.c_str(), 1)); + } +#endif } TEST(NextTransition, UTC) {
diff --git a/absl/time/internal/cctz/src/time_zone_posix.cc b/absl/time/internal/cctz/src/time_zone_posix.cc index 75ad8bc..993901a 100644 --- a/absl/time/internal/cctz/src/time_zone_posix.cc +++ b/absl/time/internal/cctz/src/time_zone_posix.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/time/internal/cctz/src/time_zone_posix.h b/absl/time/internal/cctz/src/time_zone_posix.h index 9ccd4a8..6a60022 100644 --- a/absl/time/internal/cctz/src/time_zone_posix.h +++ b/absl/time/internal/cctz/src/time_zone_posix.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -68,25 +68,35 @@ // it would take us to another day, and perhaps week, or even month. struct PosixTransition { enum DateFormat { J, N, M }; - struct { - DateFormat fmt; - union { - struct { - std::int_fast16_t day; // day of non-leap year [1:365] - } j; - struct { - std::int_fast16_t day; // day of year [0:365] - } n; - struct { - std::int_fast8_t month; // month of year [1:12] - std::int_fast8_t week; // week of month [1:5] (5==last) - std::int_fast8_t weekday; // 0==Sun, ..., 6=Sat - } m; + + struct Date { + struct NonLeapDay { + std::int_fast16_t day; // day of non-leap year [1:365] }; - } date; - struct { + struct Day { + std::int_fast16_t day; // day of year [0:365] + }; + struct MonthWeekWeekday { + std::int_fast8_t month; // month of year [1:12] + std::int_fast8_t week; // week of month [1:5] (5==last) + std::int_fast8_t weekday; // 0==Sun, ..., 6=Sat + }; + + DateFormat fmt; + + union { + NonLeapDay j; + Day n; + MonthWeekWeekday m; + }; + }; + + struct Time { std::int_fast32_t offset; // seconds before/after 00:00:00 - } time; + }; + + Date date; + Time time; }; // The entirety of a POSIX-string specified time-zone rule. The standard
diff --git a/absl/time/internal/cctz/src/tzfile.h b/absl/time/internal/cctz/src/tzfile.h index 90cfc0c..4485ba5 100644 --- a/absl/time/internal/cctz/src/tzfile.h +++ b/absl/time/internal/cctz/src/tzfile.h
@@ -1,3 +1,5 @@ +/* Layout and location of TZif files. */ + #ifndef TZFILE_H #define TZFILE_H
diff --git a/absl/time/internal/cctz/src/zone_info_source.cc b/absl/time/internal/cctz/src/zone_info_source.cc index bf2d2d2..1324846 100644 --- a/absl/time/internal/cctz/src/zone_info_source.cc +++ b/absl/time/internal/cctz/src/zone_info_source.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -54,7 +54,7 @@ #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) +#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")
diff --git a/absl/time/internal/cctz/testdata/version b/absl/time/internal/cctz/testdata/version index fe86b5c..63f5800 100644 --- a/absl/time/internal/cctz/testdata/version +++ b/absl/time/internal/cctz/testdata/version
@@ -1 +1 @@ -2018e-2-g99dd695 +2018i
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan index 6fd1af3..65d19ec 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra index 8726e80..eaaa818 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa index 39631f2..6e19601 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers index 2a25f3a..a5867a6 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara index 39631f2..6e19601 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera index 39631f2..6e19601 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako index 6fd1af3..65d19ec 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui index b1c97cc..cbdc045 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul index 6fd1af3..65d19ec 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau index 8e32be3..82ea5aa 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre index 5b871db..31cfad7 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville index b1c97cc..cbdc045 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura index 5b871db..31cfad7 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo index ba09750..0272fa1 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca index 65de344..4c57054 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta index aaa657f..dd75e3e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry index 6fd1af3..65d19ec 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar index 6fd1af3..65d19ec 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam index 39631f2..6e19601 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti index 39631f2..6e19601 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala index b1c97cc..cbdc045 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun b/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun index f5f8ffb..0ea0253 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown index 6fd1af3..65d19ec 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone index 5b871db..31cfad7 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare index 5b871db..31cfad7 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg index ddf3652..b8b9270 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba index 9fa7119..83eca03 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala index 39631f2..6e19601 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum index f2c9e30..549dae2 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali index 5b871db..31cfad7 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa index b1c97cc..cbdc045 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos index b1c97cc..cbdc045 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville index b1c97cc..cbdc045 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome index 6fd1af3..65d19ec 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda index b1c97cc..cbdc045 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi index 5b871db..31cfad7 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka index 5b871db..31cfad7 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo index b1c97cc..cbdc045 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo index 5b871db..31cfad7 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru index ddf3652..b8b9270 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane index ddf3652..b8b9270 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu index 39631f2..6e19601 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia index b434c67..2a154f4 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi index 39631f2..6e19601 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena index bbfe19d..8779590 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey index b1c97cc..cbdc045 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott index 6fd1af3..65d19ec 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou index 6fd1af3..65d19ec 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo index b1c97cc..cbdc045 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome index a4ece7f..59f3759 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu index 6fd1af3..65d19ec 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli index b32e220..bd88531 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis index 4bd3885..0cd8ffb 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek index f5d40ba..6766185 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek +++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Adak b/absl/time/internal/cctz/testdata/zoneinfo/America/Adak index 5696e0f..4323649 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Adak +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Adak Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage b/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage index 6c8bdf2..9bbb2fd 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla b/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla index 447efbe..bdedd1b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua b/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua index 447efbe..bdedd1b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina b/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina index 8b295a9..bc9a522 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires index e4866ce..dfebfb9 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca index 9fe9ad6..b798105 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia index 9fe9ad6..b798105 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba index 8c58f8c..5df3cf6 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy index a74ba04..7d2ba91 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja index cb184d6..7654aeb 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza index 5e8c44c..1032356 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos index 966a529..3c849fc 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta index b19aa22..a4b71c1 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan index 9e5ade6..948a390 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis index af8aa99..acfbbe4 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman index bbb03a0..085fc9c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia index 07e4e9f..1fc3256 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba b/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba index d308336..d3b318d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion b/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion index 3c61ddb..831bf84 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan b/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan index 5708b55..629ed42 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Atka b/absl/time/internal/cctz/testdata/zoneinfo/America/Atka index 5696e0f..4323649 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Atka +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Atka Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia index 6008a57..143eafc 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas index 21e2b71..cd53107 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados b/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados index 6339936..7bb7ac4 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Belem b/absl/time/internal/cctz/testdata/zoneinfo/America/Belem index b8e13b0..ab3c8a6 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Belem +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Belem Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Belize b/absl/time/internal/cctz/testdata/zoneinfo/America/Belize index 7dcc4fc..fd69321 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Belize +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Belize Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon b/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon index abcde7d..f9f13a1 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista b/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista index f776904..69e17a0 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota b/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota index d893446..b7ded8e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Boise b/absl/time/internal/cctz/testdata/zoneinfo/America/Boise index ada6d64..f8d54e2 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Boise +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Boise Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires b/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires index e4866ce..dfebfb9 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay b/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay index d322f01..f8db4b6 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande b/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande index de52bb6..495ef45 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun b/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun index 7e69f73..de6930c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas b/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas index c8cab1a..9abd028 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca b/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca index 9fe9ad6..b798105 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne index 6db6409..ff59657 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman index 5c1c063..55b0834 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago b/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago index 3dd8f0f..a5b1617 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua b/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua index e3adbdb..b268724 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour b/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour index 5708b55..629ed42 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba b/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba index 8c58f8c..5df3cf6 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica b/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica index c247133..525a67e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Creston b/absl/time/internal/cctz/testdata/zoneinfo/America/Creston index 798f627..0fba741 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Creston +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Creston Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba b/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba index 145c89e..8a4ee7d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao b/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao index d308336..d3b318d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn b/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn index ad68c72..9549adc 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson index 61c9688..db9cead 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek index 78f9076..db9e339 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Denver b/absl/time/internal/cctz/testdata/zoneinfo/America/Denver index 7fc6691..5fbe26b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Denver +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Denver Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit b/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit index e3ea5c3..5e02260 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica b/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica index 447efbe..bdedd1b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton b/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton index d02fbcd..3fa0579 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe b/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe index 41047f2..99b7d06 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador b/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador index 9b8bc7a..ac774e8 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada b/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada index 29c83e7..ada6bf7 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson b/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson index 5923cc6..5a0b7f1 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne b/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne index 4a92c06..09511cc 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza b/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza index 22396bb..e637170 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay b/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay index f58522b..48412a4 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab b/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab index ea293cc..0160308 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay b/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay index b4b945e..a3f2990 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk b/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk index 4c8ca6f..4597a62 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada b/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada index 447efbe..bdedd1b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe b/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe index 447efbe..bdedd1b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala b/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala index abf943b..6118b5c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil b/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil index 92de38b..bf087a0 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana b/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana index 7d29876..d1dd2fa 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax b/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax index f86ece4..756099a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Havana b/absl/time/internal/cctz/testdata/zoneinfo/America/Havana index 1a58fcd..8186060 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Havana +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Havana Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo b/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo index ec435c2..26c269d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis index 4a92c06..09511cc 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox index cc785da..fcd408d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo index a23d7b7..1abf75e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg index f16cb30..0133548 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City index 0250bf9..4ce95c1 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay index e934de6..d236b7c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes index adbdbee..c818929 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac index b34f7b2..630935c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis b/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis index 4a92c06..09511cc 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik b/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik index 1388e8a..e107dc4 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit b/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit index 0785ac5..c8138bd 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica b/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica index 7aedd26..162306f 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy b/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy index a74ba04..7d2ba91 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau b/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau index d00668a..451f349 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville b/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville index fdf2e88..f4c4cf9 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello b/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello index 60991aa..438e3ea 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN b/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN index cc785da..fcd408d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk b/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk index d308336..d3b318d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz b/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz index bc3df52..5e5fec5 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Lima b/absl/time/internal/cctz/testdata/zoneinfo/America/Lima index 44280a5..d9fec37 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Lima +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Lima Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles b/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles index c0ce440..9dad4f4 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville b/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville index fdf2e88..f4c4cf9 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes b/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes index d308336..d3b318d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio b/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio index 54442dc..fec8a8b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Managua b/absl/time/internal/cctz/testdata/zoneinfo/America/Managua index c543ffd..69256c6 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Managua +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Managua Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus b/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus index 855cb02..b10241e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot b/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot index 447efbe..bdedd1b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique b/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique index f9e2399..79716de 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros b/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros index 5671d25..5c59984 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan b/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan index afa94c2..43ee12d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza b/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza index 5e8c44c..1032356 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee b/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee index 55d6e32..3146138 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Merida b/absl/time/internal/cctz/testdata/zoneinfo/America/Merida index ecc1856..b46298e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Merida +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Merida Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla b/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla index c033597..85a7e16 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City b/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City index f11e3d2..1434ab0 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon b/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon index 75bbcf2..06ceaad 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton b/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton index 51cb1ba..9df8d0f 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey b/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey index dcac92b..7dc5057 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo b/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo index f524fd2..0d1e565 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal b/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal index 7b4682a..6752c5b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat b/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat index 447efbe..bdedd1b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau b/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau index e5d0289..5091eb5 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/New_York b/absl/time/internal/cctz/testdata/zoneinfo/America/New_York index 7553fee..2f75480 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/New_York +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/New_York Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon b/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon index f8a0292..f6a856e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Nome b/absl/time/internal/cctz/testdata/zoneinfo/America/Nome index c886c9b..10998df 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Nome +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Nome Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha b/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha index 6d91f91..95ff8a2 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah index 8174c88..246345d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center index 8035b24..1fa0703 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem index 5b630ee..123f2ae 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga b/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga index 190c5c8..37d7830 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Panama b/absl/time/internal/cctz/testdata/zoneinfo/America/Panama index 5c1c063..55b0834 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Panama +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Panama Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung b/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung index df78b62..3e4e0db 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo b/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo index 1b608b3..b95c784 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix b/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix index adf2823..4d51271 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince b/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince index 7306cae..d959010 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain b/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain index 447efbe..bdedd1b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre index b612ac2..16b7f92 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho index 2423fc1..10cb02b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico b/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico index d4525a6..a662a57 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas b/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas index 4d84eed..a5a8af5 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River b/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River index 70dcd2d..ea66099 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet b/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet index 9f50f36..61ff6fc 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Recife b/absl/time/internal/cctz/testdata/zoneinfo/America/Recife index fe55739..c6d99b3 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Recife +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Recife Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Regina b/absl/time/internal/cctz/testdata/zoneinfo/America/Regina index 5fe8d6b..20c9c84 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Regina +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Regina Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute b/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute index 884b1f6..4365a5c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco b/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco index b612ac2..16b7f92 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario b/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario index 8c58f8c..5df3cf6 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel b/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel index 29c83e7..ada6bf7 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem b/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem index d776a43..8080efa 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago b/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago index ab766a4..816a042 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo b/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo index cc2cbf2..4e5eba5 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo b/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo index 308a545..c417ba1 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund b/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund index 8e1366c..e20e9e1 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock b/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock index 7fc6691..5fbe26b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka b/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka index 662b8b6..31f7061 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy index 447efbe..bdedd1b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns index a1d1485..65a5b0c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts index 447efbe..bdedd1b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia index 447efbe..bdedd1b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas index 447efbe..bdedd1b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent index 447efbe..bdedd1b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current b/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current index 4db1300..8e9ef25 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa b/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa index 7aea8f9..477e939 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Thule b/absl/time/internal/cctz/testdata/zoneinfo/America/Thule index deefcc8..2969ebe 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Thule +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Thule Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay b/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay index aa1d486..e504c9a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana b/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana index 29c83e7..ada6bf7 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto b/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto index 7b4682a..6752c5b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola b/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola index 447efbe..bdedd1b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver b/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver index 9b5d924..0f9f832 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin b/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin index 447efbe..bdedd1b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse b/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse index 6b62e2d..fb3cd71 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg b/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg index 2ffe3d8..3718d47 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat b/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat index 523b0a1..da209f9 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife b/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife index d9d6eff..e6afa39 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife +++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey index d0bbacc..f100f47 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey +++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis index 40a9926..916f2c2 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis +++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville index 0686353..bd6563e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville +++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie index aea2be7..83c308a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie +++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson index 5197dd9..e1f0b09 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson +++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo index a5f5b6d..60bcef6 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo +++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer index 43a01d3..3dd85f8 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer +++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera index 56913f8..7940e6e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera +++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole index a5f5b6d..60bcef6 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole +++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa index 94a9d5a..4bb041a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa +++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll index 3757fac..5e565da 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll +++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok index 9fa335c..5696abf 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok +++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen b/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen index 239c017..c6842af 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen +++ b/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden index e71bc4e..b2f9a25 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty index 49a4b4d..d93201c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman index c3f0994..281b304 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr index 0e623cf..6a96601 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau index 5803a3d..78cbcf0 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe index 808a502..7504052 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat index 046c472..8d9e03c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad index 046c472..8d9e03c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau index 27072eb..317466d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad index 3aacd78..97fa6c7 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain index a0c5f66..f514092 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku index a17d1ad..8a090d7 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok index 8db5e8a..7249640 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul index 60efb41..82cc49c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut index 72f0896..efb24c2 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek index e3f81ee..f7a7d54 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei index cad16b0..8624c7a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta index b57972d..e1cfcb8 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita index 95f5645..3baf752 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan index 15b358f..79b9d3c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing index dbd132f..ce9e00a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking index dbd132f..ce9e00a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo index 28fe430..4fc96c8 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca index 98881f0..776f27d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus index ac45764..4b610b5 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka index 98881f0..776f27d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili index c94fa61..f6ce91a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai index c12f31a..7880d5d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe index 67c772b..694f6e6 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta index 021f8a2..653b146 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza index 60d0de0..cf54deb 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin index dbd132f..ce9e00a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron index a2e1b36..09c876a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh index 9264267..eab94fe 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong index dc9058e..91eaff4 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd index f367a55..8eb5f64 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk index 8413636..e8c53c0 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul index 9a53b3a..833d4eb 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta index 37b4edd..673d480 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura index 39ddc84..a4c0829 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem index df51199..2d14c99 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul index 80429ec..a22cf59 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka index fab27de..b9ed49c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi index b7dcaab..337e1d5 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar index b44a1e1..0342b43 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu index 0cbd295..2f810b1 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu index 0cbd295..2f810b1 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga index 9183695..2b2f5bf 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata index b57972d..e1cfcb8 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk index faec35d..59efd24 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur index 5c95ebc..6d7d47b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching index 62b5389..4878622 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait index e71bc4e..b2f9a25 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao index 2c20a32..d801000 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau index 2c20a32..d801000 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan index 2db0635..b20cc57 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar index 3a5dcb2..ed55442 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila index 06859a7..2c9220c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat index c12f31a..7880d5d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia index 3e663b2..f7f10ab 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk index ed4b248..2576a3b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk index a5d39df..95e3c73 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk index 5e0d9b6..d805e4f 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral index b8eb58d..e36aec4 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh index 8db5e8a..7249640 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak index ec98c62..9377d03 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang index dc24926..dd54989 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar index a0c5f66..f514092 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay new file mode 100644 index 0000000..cb6e2d9 --- /dev/null +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda index 0fc7fad..fc636b3 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon index 3cc2aaf..a00282d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh index e71bc4e..b2f9a25 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon index 9264267..eab94fe 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin index 8d6b4df..9c94900 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand index 10c7af7..a5d1e97 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul index 312ec40..fa1cbd3 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai index dbd132f..ce9e00a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore index 7858366..ebc4b0d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk index 16b1cd8..f8b7bb2 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei index 748873b..f9cbe67 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent index 6f7dea4..e75bb36 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi index 4b2d2e2..09bb06e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran index 3157f80..0ae2f65 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv index df51199..2d14c99 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu index a8bddb9..06d3324 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu index a8bddb9..06d3324 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo index 8ad44ba..26f4d34 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk index 919b003..28da9c9 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang index 3a5dcb2..ed55442 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar index 94ddfea..82fd476 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator index 94ddfea..82fd476 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi index b44a1e1..0342b43 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera index 7431eb9..c0c3767 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane index 8db5e8a..7249640 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok index 80b170b..15731ab 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk index 220ad3d..1f86e77 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon index 3cc2aaf..a00282d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg index c1abb93..fff9f3b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan index 4c4e045..409c3b1 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan +++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores index 1895e1b..56593db 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores +++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda index 548d979..3a5c6db 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda +++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary index 544f443..f319215 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary +++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde index 6bda6db..e2a49d2 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde +++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe index c486518..4dab7ef 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe +++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe index c486518..4dab7ef 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe +++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen index 239c017..c6842af 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen +++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira index e25f8a5..5213761 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira +++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik index dc49c32..ac6bd69 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik +++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia index 56b383b..b3311b6 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia +++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena index 6fd1af3..65d19ec 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena +++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley index 3649415..2fd42a2 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley +++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT b/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT index aaed12c..4ed4467 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide index 4f331a8..190b0e3 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane index a327d83..26ffd9a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill index 768b167..874c865 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra index aaed12c..4ed4467 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie index a3f6f29..865801e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin index c6ae9a7..cf42d1d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla index 99f07a9..c49d499 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart index 07784ce..92d1215 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI b/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI index 57597b0..8c6c7dd 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman index 71ca143..8ee1a6f 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe index 57597b0..8c6c7dd 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne index ec8dfe0..3f2d3d7 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW b/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW index aaed12c..4ed4467 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/North b/absl/time/internal/cctz/testdata/zoneinfo/Australia/North index c6ae9a7..cf42d1d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/North +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/North Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth index 85c26d5..d38b67e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland index a327d83..26ffd9a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/South b/absl/time/internal/cctz/testdata/zoneinfo/Australia/South index 4f331a8..190b0e3 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/South +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/South Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney index aaed12c..4ed4467 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania index 07784ce..92d1215 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria index ec8dfe0..3f2d3d7 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/West b/absl/time/internal/cctz/testdata/zoneinfo/Australia/West index 85c26d5..d38b67e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/West +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/West Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna index 768b167..874c865 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna +++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre index b612ac2..16b7f92 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre +++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha index 6d91f91..95ff8a2 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha +++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East index 308a545..c417ba1 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East +++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West index 855cb02..b10241e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West +++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/CET b/absl/time/internal/cctz/testdata/zoneinfo/CET index 4c4f8ef..d585656 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/CET +++ b/absl/time/internal/cctz/testdata/zoneinfo/CET Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT b/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT index 5c8a1d9..41c4136 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT +++ b/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic index f86ece4..756099a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic +++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central index 2ffe3d8..3718d47 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central +++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern index 7b4682a..6752c5b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern +++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain index d02fbcd..3fa0579 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain +++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland index a1d1485..65a5b0c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland +++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific index 9b5d924..0f9f832 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific +++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan index 5fe8d6b..20c9c84 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan +++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon index 6b62e2d..fb3cd71 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon +++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental b/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental index ab766a4..816a042 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental +++ b/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland b/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland index 060bef8..cae3744 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland +++ b/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Cuba b/absl/time/internal/cctz/testdata/zoneinfo/Cuba index 1a58fcd..8186060 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Cuba +++ b/absl/time/internal/cctz/testdata/zoneinfo/Cuba Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/EET b/absl/time/internal/cctz/testdata/zoneinfo/EET index beb273a..d2f54c9 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/EET +++ b/absl/time/internal/cctz/testdata/zoneinfo/EET Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/EST b/absl/time/internal/cctz/testdata/zoneinfo/EST index ae34663..074a4fc 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/EST +++ b/absl/time/internal/cctz/testdata/zoneinfo/EST Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT b/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT index 54541fc..087b641 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT +++ b/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Egypt b/absl/time/internal/cctz/testdata/zoneinfo/Egypt index ba09750..0272fa1 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Egypt +++ b/absl/time/internal/cctz/testdata/zoneinfo/Egypt Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Eire b/absl/time/internal/cctz/testdata/zoneinfo/Eire index 655daf3..5c5a7a3 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Eire +++ b/absl/time/internal/cctz/testdata/zoneinfo/Eire Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT index c05e45f..2ee1429 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0 index c05e45f..2ee1429 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1 index 082986e..087d1f9 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10 index 23276cd..6437c68 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11 index 28c579d..72a912e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12 index c740603..6938a1a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2 index 721cde2..a315577 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3 index ae06bcb..ee77619 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4 index 5a7f878..1ea7da2 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5 index 18cbf1f..dda1a9e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6 index 1aa4be8..f4a0385 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7 index cd8ed49..2d2ccd0 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8 index e0ba6b8..826c770 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9 index eee1bcb..b125ad2 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0 index c05e45f..2ee1429 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1 index 4ff8701..dde682d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10 index e12e461..352ec08 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11 index 37f2739..dfa27fe 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12 index 09297f1..eef949d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13 index 97ae1e1..f9363b2 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14 index 58d6d1b..35add05 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2 index f0dc706..315cae4 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3 index a0790fe..7489a15 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4 index a75a173..560243e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5 index 85ebf22..b2bbe97 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6 index 95def1f..b979dbb 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7 index c6a776e..365ab1f 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8 index f74a16f..742082f 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9 index 9b647c0..abc0b27 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0 index c05e45f..2ee1429 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0 +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich index c05e45f..2ee1429 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT index 40147b9..a88c4b6 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC index c3b97f1..5583f5b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal index c3b97f1..5583f5b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu index c3b97f1..5583f5b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu +++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam index 6dae5e4..ed064ed 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra index b06de7a..5962550 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan index 90d7c2a..5e069ea 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens index 0001602..9f3a067 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast index 4527515..a340326 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade index 79c25d7..32a5722 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin index b4f2a2a..7ddd510 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava index ba82f31..85036de 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels index d8f19a6..d0d0a08 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest index e0eac4c..4eb7ed0 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest index 3ddf6a5..dfdc6d2 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen index 9c2b600..ad6cf59 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau index 2109b52..5bc1bfe 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen index be87cf1..cb2ec06 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin index 655daf3..5c5a7a3 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar index a7105fa..117aadb 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey index 4527515..a340326 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki index 29b3c81..b4f8f9c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man index 4527515..a340326 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul index 9a53b3a..833d4eb 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey index 4527515..a340326 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad index 37280d0..982d82a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev index b3e20a7..9337c9e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov index 40b558f..a3b5320 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon index a856530..355817b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana index 79c25d7..32a5722 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/London b/absl/time/internal/cctz/testdata/zoneinfo/Europe/London index 4527515..a340326 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/London +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/London Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg index 6fae86c..6c194a5 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid index 9b51a73..ccc9d85 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta index c1208e2..bf2452d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn index 29b3c81..b4f8f9c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk index 60041a4..801aead 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco index 0b40f1e..686ae88 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow index 906bd05..ddb3f4e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia index 3e663b2..f7f10ab 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo index 239c017..c6842af 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris index cf6e2e2..ca85435 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica index 79c25d7..32a5722 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague index ba82f31..85036de 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga index b729ee8..8495c50 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome index bdd3449..78a131b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara index 0539acf..97d5dd9 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino b/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino index bdd3449..78a131b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo index 79c25d7..32a5722 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov index e8cd6b1..8fd5f6d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol index f3b42b0..e82dbbc 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje index 79c25d7..32a5722 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia index 763e074..dcfdd08 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm index 43c7f2e..f3e0c7f 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn index 18f903f..3a744cc 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane index 52c16a4..0b86017 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol index 2109b52..5bc1bfe 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk index c280f43..7b61bdc 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod index 8ddba90..677f088 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz index 9c2b600..ad6cf59 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican index bdd3449..78a131b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna index 9c0fac5..9e2d0c9 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius index da380af..46ce484 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd index f4cb64f..8f170dd 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw index 5cbba41..d6bb156 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb index 79c25d7..32a5722 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye index 6f14850..e42edfc 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich index 9c2b600..ad6cf59 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich +++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Factory b/absl/time/internal/cctz/testdata/zoneinfo/Factory index afeeb88..95bc3a3 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Factory +++ b/absl/time/internal/cctz/testdata/zoneinfo/Factory Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GB b/absl/time/internal/cctz/testdata/zoneinfo/GB index 4527515..a340326 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/GB +++ b/absl/time/internal/cctz/testdata/zoneinfo/GB Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire b/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire index 4527515..a340326 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire +++ b/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT b/absl/time/internal/cctz/testdata/zoneinfo/GMT index c05e45f..2ee1429 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/GMT +++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT+0 b/absl/time/internal/cctz/testdata/zoneinfo/GMT+0 index c05e45f..2ee1429 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/GMT+0 +++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT+0 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT-0 b/absl/time/internal/cctz/testdata/zoneinfo/GMT-0 index c05e45f..2ee1429 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/GMT-0 +++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT-0 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT0 b/absl/time/internal/cctz/testdata/zoneinfo/GMT0 index c05e45f..2ee1429 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/GMT0 +++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT0 Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Greenwich b/absl/time/internal/cctz/testdata/zoneinfo/Greenwich index c05e45f..2ee1429 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Greenwich +++ b/absl/time/internal/cctz/testdata/zoneinfo/Greenwich Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/HST b/absl/time/internal/cctz/testdata/zoneinfo/HST index 03e4db0..616c31b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/HST +++ b/absl/time/internal/cctz/testdata/zoneinfo/HST Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Hongkong b/absl/time/internal/cctz/testdata/zoneinfo/Hongkong index dc9058e..91eaff4 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Hongkong +++ b/absl/time/internal/cctz/testdata/zoneinfo/Hongkong Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Iceland b/absl/time/internal/cctz/testdata/zoneinfo/Iceland index dc49c32..ac6bd69 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Iceland +++ b/absl/time/internal/cctz/testdata/zoneinfo/Iceland Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo index 39631f2..6e19601 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo +++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos index 0e5e719..f609611 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos +++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas index 066c1e9..6babdee 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas +++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos index 34a2457..58f8051 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos +++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro index 39631f2..6e19601 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro +++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen index e7d4d3d..2cb6f3e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen +++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe index db8ac68..49e23e5 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe +++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives index 3f1a76e..ffa3365 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives +++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius index fd8d911..b23e2ce 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius +++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte index 39631f2..6e19601 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte +++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion index d5f9aa4..11c6002 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion +++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Iran b/absl/time/internal/cctz/testdata/zoneinfo/Iran index 3157f80..0ae2f65 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Iran +++ b/absl/time/internal/cctz/testdata/zoneinfo/Iran Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Israel b/absl/time/internal/cctz/testdata/zoneinfo/Israel index df51199..2d14c99 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Israel +++ b/absl/time/internal/cctz/testdata/zoneinfo/Israel Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Jamaica b/absl/time/internal/cctz/testdata/zoneinfo/Jamaica index 7aedd26..162306f 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Jamaica +++ b/absl/time/internal/cctz/testdata/zoneinfo/Jamaica Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Japan b/absl/time/internal/cctz/testdata/zoneinfo/Japan index 8ad44ba..26f4d34 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Japan +++ b/absl/time/internal/cctz/testdata/zoneinfo/Japan Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein b/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein index 1a27122..d641357 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein +++ b/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Libya b/absl/time/internal/cctz/testdata/zoneinfo/Libya index b32e220..bd88531 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Libya +++ b/absl/time/internal/cctz/testdata/zoneinfo/Libya Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/MET b/absl/time/internal/cctz/testdata/zoneinfo/MET index 71963d5..388dd74 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/MET +++ b/absl/time/internal/cctz/testdata/zoneinfo/MET Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/MST b/absl/time/internal/cctz/testdata/zoneinfo/MST index a1bee7c..da3e926 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/MST +++ b/absl/time/internal/cctz/testdata/zoneinfo/MST Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT b/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT index 726a7e5..ddca8d1 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT +++ b/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte index 29c83e7..ada6bf7 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte +++ b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur index afa94c2..43ee12d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur +++ b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General index f11e3d2..1434ab0 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General +++ b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/NZ b/absl/time/internal/cctz/testdata/zoneinfo/NZ index a5f5b6d..60bcef6 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/NZ +++ b/absl/time/internal/cctz/testdata/zoneinfo/NZ Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT b/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT index 957c80b..abe09cb 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT +++ b/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Navajo b/absl/time/internal/cctz/testdata/zoneinfo/Navajo index 7fc6691..5fbe26b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Navajo +++ b/absl/time/internal/cctz/testdata/zoneinfo/Navajo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/PRC b/absl/time/internal/cctz/testdata/zoneinfo/PRC index dbd132f..ce9e00a 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/PRC +++ b/absl/time/internal/cctz/testdata/zoneinfo/PRC Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT b/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT index 6242ac0..d773e28 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT +++ b/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia index 4091a85..fd03ff7 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland index a5f5b6d..60bcef6 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville index dc5a7d7..6a6c2da 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham index 957c80b..abe09cb 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk index 289b795..8004d65 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter index 060bef8..cae3744 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate index 5cee55d..d650a05 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury index a3f30e5..8087350 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo index 6e4b8af..4fa169f 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji index 912db18..61a6695 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti index 3289094..e6a1544 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos index 76b2b3a..859b76d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier index 625016d..4e9e36c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal index 0c24095..908ccc1 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam index 4286e6b..e224247 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu index bd85577..c7cd060 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston index bd85577..c7cd060 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati index 762275d..cf5b3bd 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae index f8222e6..11583b1 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein index 1a27122..d641357 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro index b3a8c18..65990cb 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas index 10c5c9b..5fad0e1 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway index 3e38e97..72707b5 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru index 6092119..86d3b7d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue index df6110d..1d58fe3 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk index d0b9607..f630a65 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea index d9c68f8..99f6bca 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago index 3e38e97..72707b5 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau index e1bbea5..05633b8 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn index 54783cf..9092e48 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei index 9743bc3..090429c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape index 9743bc3..090429c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby index 3fa1f7f..f6fd51c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga index ace1ce4..9708b87 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan index 4286e6b..e224247 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa index 3e38e97..72707b5 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti index 7867d8b..37e4e88 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa index 3340413..e23c0cd 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu index b3a5a89..35c9e2c 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk index 289b795..8004d65 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake index 2dc630c..837ce1f 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis index b4f0f9b..8be9ac4 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap index 289b795..8004d65 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap +++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Poland b/absl/time/internal/cctz/testdata/zoneinfo/Poland index 5cbba41..d6bb156 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Poland +++ b/absl/time/internal/cctz/testdata/zoneinfo/Poland Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Portugal b/absl/time/internal/cctz/testdata/zoneinfo/Portugal index a856530..355817b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Portugal +++ b/absl/time/internal/cctz/testdata/zoneinfo/Portugal Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/ROC b/absl/time/internal/cctz/testdata/zoneinfo/ROC index 748873b..f9cbe67 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/ROC +++ b/absl/time/internal/cctz/testdata/zoneinfo/ROC Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/ROK b/absl/time/internal/cctz/testdata/zoneinfo/ROK index 312ec40..fa1cbd3 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/ROK +++ b/absl/time/internal/cctz/testdata/zoneinfo/ROK Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Singapore b/absl/time/internal/cctz/testdata/zoneinfo/Singapore index 7858366..ebc4b0d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Singapore +++ b/absl/time/internal/cctz/testdata/zoneinfo/Singapore Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Turkey b/absl/time/internal/cctz/testdata/zoneinfo/Turkey index 9a53b3a..833d4eb 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Turkey +++ b/absl/time/internal/cctz/testdata/zoneinfo/Turkey Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/UCT b/absl/time/internal/cctz/testdata/zoneinfo/UCT index 40147b9..a88c4b6 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/UCT +++ b/absl/time/internal/cctz/testdata/zoneinfo/UCT Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska b/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska index 6c8bdf2..9bbb2fd 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska +++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian b/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian index 5696e0f..4323649 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian +++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona b/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona index adf2823..4d51271 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona +++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Central b/absl/time/internal/cctz/testdata/zoneinfo/US/Central index 3dd8f0f..a5b1617 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/US/Central +++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Central Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana b/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana index 4a92c06..09511cc 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana +++ b/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern b/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern index 7553fee..2f75480 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern +++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii b/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii index bd85577..c7cd060 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii +++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke b/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke index cc785da..fcd408d 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke +++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan b/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan index e3ea5c3..5e02260 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan +++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain b/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain index 7fc6691..5fbe26b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain +++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific b/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific index c0ce440..9dad4f4 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific +++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa b/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa index 3e38e97..72707b5 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa +++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/UTC b/absl/time/internal/cctz/testdata/zoneinfo/UTC index c3b97f1..5583f5b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/UTC +++ b/absl/time/internal/cctz/testdata/zoneinfo/UTC Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Universal b/absl/time/internal/cctz/testdata/zoneinfo/Universal index c3b97f1..5583f5b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Universal +++ b/absl/time/internal/cctz/testdata/zoneinfo/Universal Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/W-SU b/absl/time/internal/cctz/testdata/zoneinfo/W-SU index 906bd05..ddb3f4e 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/W-SU +++ b/absl/time/internal/cctz/testdata/zoneinfo/W-SU Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/WET b/absl/time/internal/cctz/testdata/zoneinfo/WET index 444a193..9b03a17 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/WET +++ b/absl/time/internal/cctz/testdata/zoneinfo/WET Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Zulu b/absl/time/internal/cctz/testdata/zoneinfo/Zulu index c3b97f1..5583f5b 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/Zulu +++ b/absl/time/internal/cctz/testdata/zoneinfo/Zulu Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab b/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab index c2e0f8e..4e4a5c3 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab +++ b/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab
@@ -10,7 +10,7 @@ # # 1. ISO 3166-1 alpha-2 country code, current as of # ISO 3166-1 N905 (2016-11-15). See: Updates on ISO 3166-1 -# http://isotc.iso.org/livelink/livelink/Open/16944257 +# https://isotc.iso.org/livelink/livelink/Open/16944257 # 2. The usual English name for the coded region, # chosen so that alphabetic sorting of subsets produces helpful lists. # This is not the same as the English name in the ISO 3166 tables.
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab index 2d90ed7..9a8e424 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab +++ b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
@@ -1,35 +1,35 @@ -# tz zone descriptions +# tzdb timezone descriptions # # This file is in the public domain. # -# From Paul Eggert (2017-10-01): -# This file contains a table where each row stands for a zone where -# civil time stamps have agreed since 1970. Columns are separated by +# From Paul Eggert (2018-06-27): +# This file contains a table where each row stands for a timezone where +# civil timestamps have agreed since 1970. Columns are separated by # a single tab. Lines beginning with '#' are comments. All text uses # UTF-8 encoding. The columns of the table are as follows: # -# 1. The countries that overlap the zone, as a comma-separated list +# 1. The countries that overlap the timezone, as a comma-separated list # of ISO 3166 2-character country codes. See the file 'iso3166.tab'. -# 2. Latitude and longitude of the zone's principal location +# 2. Latitude and longitude of the timezone's principal location # in ISO 6709 sign-degrees-minutes-seconds format, # either ±DDMM±DDDMM or ±DDMMSS±DDDMMSS, # first latitude (+ is north), then longitude (+ is east). -# 3. Zone name used in value of TZ environment variable. -# Please see the theory.html file for how zone names are chosen. -# If multiple zones overlap a country, each has a row in the +# 3. Timezone name used in value of TZ environment variable. +# Please see the theory.html file for how these names are chosen. +# If multiple timezones overlap a country, each has a row in the # table, with each column 1 containing the country code. -# 4. Comments; present if and only if a country has multiple zones. +# 4. Comments; present if and only if a country has multiple timezones. # -# If a zone covers multiple countries, the most-populous city is used, +# If a timezone covers multiple countries, the most-populous city is used, # and that country is listed first in column 1; any other countries # are listed alphabetically by country code. The table is sorted # first by country code, then (if possible) by an order within the # country that (1) makes some geographical sense, and (2) puts the -# most populous zones first, where that does not contradict (1). +# most populous timezones first, where that does not contradict (1). # -# This table is intended as an aid for users, to help them select time -# zone data entries appropriate for their practical needs. It is not -# intended to take or endorse any position on legal or territorial claims. +# This table is intended as an aid for users, to help them select timezones +# appropriate for their practical needs. It is not intended to take or +# endorse any position on legal or territorial claims. # #country- #codes coordinates TZ comments @@ -211,6 +211,7 @@ KR +3733+12658 Asia/Seoul KZ +4315+07657 Asia/Almaty Kazakhstan (most areas) KZ +4448+06528 Asia/Qyzylorda Qyzylorda/Kyzylorda/Kzyl-Orda +KZ +5312+06337 Asia/Qostanay Qostanay/Kostanay/Kustanay KZ +5017+05710 Asia/Aqtobe Aqtöbe/Aktobe KZ +4431+05016 Asia/Aqtau MangghystaÅ«/Mankistau KZ +4707+05156 Asia/Atyrau AtyraÅ«/Atirau/Gur'yev @@ -231,7 +232,7 @@ MN +4755+10653 Asia/Ulaanbaatar Mongolia (most areas) MN +4801+09139 Asia/Hovd Bayan-Ölgii, Govi-Altai, Hovd, Uvs, Zavkhan MN +4804+11430 Asia/Choibalsan Dornod, Sükhbaatar -MO +2214+11335 Asia/Macau +MO +221150+1133230 Asia/Macau MQ +1436-06105 America/Martinique MT +3554+01431 Europe/Malta MU -2010+05730 Indian/Mauritius @@ -289,9 +290,9 @@ RU +5443+02030 Europe/Kaliningrad MSK-01 - Kaliningrad RU +554521+0373704 Europe/Moscow MSK+00 - Moscow area RU +4457+03406 Europe/Simferopol MSK+00 - Crimea -RU +4844+04425 Europe/Volgograd MSK+00 - Volgograd RU +5836+04939 Europe/Kirov MSK+00 - Kirov RU +4621+04803 Europe/Astrakhan MSK+01 - Astrakhan +RU +4844+04425 Europe/Volgograd MSK+01 - Volgograd RU +5134+04602 Europe/Saratov MSK+01 - Saratov RU +5420+04824 Europe/Ulyanovsk MSK+01 - Ulyanovsk RU +5312+05009 Europe/Samara MSK+01 - Samara, Udmurtia
diff --git a/absl/time/internal/get_current_time_chrono.inc b/absl/time/internal/get_current_time_chrono.inc index cf884a1..5180230 100644 --- a/absl/time/internal/get_current_time_chrono.inc +++ b/absl/time/internal/get_current_time_chrono.inc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/time/internal/test_util.cc b/absl/time/internal/test_util.cc index bbbef7d..59166a7 100644 --- a/absl/time/internal/test_util.cc +++ b/absl/time/internal/test_util.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -26,12 +26,6 @@ namespace absl { namespace time_internal { -#if GTEST_USES_SIMPLE_RE -extern const char kZoneAbbrRE[] = ".*"; // just punt -#else -extern const char kZoneAbbrRE[] = "[A-Za-z]{3,4}|[-+][0-9]{2}([0-9]{2})?"; -#endif - TimeZone LoadTimeZone(const std::string& name) { TimeZone tz; ABSL_RAW_CHECK(LoadTimeZone(name, &tz), name.c_str());
diff --git a/absl/time/internal/test_util.h b/absl/time/internal/test_util.h index 8fd5fb9..d7319ea 100644 --- a/absl/time/internal/test_util.h +++ b/absl/time/internal/test_util.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -17,35 +17,11 @@ #include <string> -#include "gmock/gmock.h" -#include "gtest/gtest.h" #include "absl/time/time.h" -// This helper is a macro so that failed expectations show up with the -// correct line numbers. -// -// This is for internal testing of the Base Time library itself. This is not -// part of a public API. -#define ABSL_INTERNAL_EXPECT_TIME(bd, y, m, d, h, min, s, off, isdst) \ - do { \ - EXPECT_EQ(y, bd.year); \ - EXPECT_EQ(m, bd.month); \ - EXPECT_EQ(d, bd.day); \ - EXPECT_EQ(h, bd.hour); \ - EXPECT_EQ(min, bd.minute); \ - EXPECT_EQ(s, bd.second); \ - EXPECT_EQ(off, bd.offset); \ - EXPECT_EQ(isdst, bd.is_dst); \ - EXPECT_THAT(bd.zone_abbr, \ - testing::MatchesRegex(absl::time_internal::kZoneAbbrRE)); \ - } while (0) - namespace absl { namespace time_internal { -// A regular expression that matches all zone abbreviations (%Z). -extern const char kZoneAbbrRE[]; - // Loads the named timezone, but dies on any failure. absl::TimeZone LoadTimeZone(const std::string& name);
diff --git a/absl/time/time.cc b/absl/time/time.cc index 71fd8ee..977a951 100644 --- a/absl/time/time.cc +++ b/absl/time/time.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -22,13 +22,14 @@ // NOTE: To keep type verbosity to a minimum, the following variable naming // conventions are used throughout this file. // -// cz: A cctz::time_zone // tz: An absl::TimeZone +// ci: An absl::TimeZone::CivilInfo +// ti: An absl::TimeZone::TimeInfo +// cd: An absl::CivilDay or a cctz::civil_day +// cs: An absl::CivilSecond or a cctz::civil_second +// bd: An absl::Time::Breakdown // cl: A cctz::time_zone::civil_lookup // al: A cctz::time_zone::absolute_lookup -// cd: A cctz::civil_day -// cs: A cctz::civil_second -// bd: An absl::Time::Breakdown #include "absl/time/time.h" @@ -40,6 +41,7 @@ #include "absl/time/internal/cctz/include/cctz/time_zone.h" namespace cctz = absl::time_internal::cctz; + namespace absl { namespace { @@ -75,7 +77,7 @@ return bd; } -inline Time::Breakdown InfinitePastBreakdown() { +inline absl::Time::Breakdown InfinitePastBreakdown() { Time::Breakdown bd; bd.year = std::numeric_limits<int64_t>::min(); bd.month = 1; @@ -92,6 +94,26 @@ return bd; } +inline absl::TimeZone::CivilInfo InfiniteFutureCivilInfo() { + TimeZone::CivilInfo ci; + ci.cs = CivilSecond::max(); + ci.subsecond = InfiniteDuration(); + ci.offset = 0; + ci.is_dst = false; + ci.zone_abbr = "-00"; + return ci; +} + +inline absl::TimeZone::CivilInfo InfinitePastCivilInfo() { + TimeZone::CivilInfo ci; + ci.cs = CivilSecond::min(); + ci.subsecond = -InfiniteDuration(); + ci.offset = 0; + ci.is_dst = false; + ci.zone_abbr = "-00"; + return ci; +} + inline absl::TimeConversion InfiniteFutureTimeConversion() { absl::TimeConversion tc; tc.pre = tc.trans = tc.post = absl::InfiniteFuture(); @@ -134,19 +156,6 @@ return time_internal::FromUnixDuration(time_internal::MakeDuration(hi)); } -inline absl::TimeConversion::Kind MapKind( - const cctz::time_zone::civil_lookup::civil_kind& kind) { - switch (kind) { - case cctz::time_zone::civil_lookup::UNIQUE: - return absl::TimeConversion::UNIQUE; - case cctz::time_zone::civil_lookup::SKIPPED: - return absl::TimeConversion::SKIPPED; - case cctz::time_zone::civil_lookup::REPEATED: - return absl::TimeConversion::REPEATED; - } - return absl::TimeConversion::UNIQUE; -} - // Returns Mon=1..Sun=7. inline int MapWeekday(const cctz::weekday& wd) { switch (wd) { @@ -168,11 +177,29 @@ return 1; } +bool FindTransition(const cctz::time_zone& tz, + bool (cctz::time_zone::*find_transition)( + const cctz::time_point<cctz::seconds>& tp, + cctz::time_zone::civil_transition* trans) const, + Time t, TimeZone::CivilTransition* trans) { + // Transitions are second-aligned, so we can discard any fractional part. + const auto tp = unix_epoch() + cctz::seconds(ToUnixSeconds(t)); + cctz::time_zone::civil_transition tr; + if (!(tz.*find_transition)(tp, &tr)) return false; + trans->from = CivilSecond(tr.from); + trans->to = CivilSecond(tr.to); + return true; +} + } // namespace +// +// Time +// + absl::Time::Breakdown Time::In(absl::TimeZone tz) const { - if (*this == absl::InfiniteFuture()) return absl::InfiniteFutureBreakdown(); - if (*this == absl::InfinitePast()) return absl::InfinitePastBreakdown(); + if (*this == absl::InfiniteFuture()) return InfiniteFutureBreakdown(); + if (*this == absl::InfinitePast()) return InfinitePastBreakdown(); const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(rep_)); const auto al = cctz::time_zone(tz).lookup(tp); @@ -187,92 +214,18 @@ bd.minute = cs.minute(); bd.second = cs.second(); bd.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(rep_)); - bd.weekday = MapWeekday(get_weekday(cd)); - bd.yearday = get_yearday(cd); + bd.weekday = MapWeekday(cctz::get_weekday(cd)); + bd.yearday = cctz::get_yearday(cd); bd.offset = al.offset; bd.is_dst = al.is_dst; bd.zone_abbr = al.abbr; return bd; } -absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) { - const auto cz = cctz::time_zone(tz); - const auto cs = - cctz::civil_second(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); - const auto cl = cz.lookup(cs); - const auto tp = tm.tm_isdst == 0 ? cl.post : cl.pre; - return MakeTimeWithOverflow(tp, cs, cz); -} - -struct tm ToTM(absl::Time t, absl::TimeZone tz) { - const absl::Time::Breakdown bd = t.In(tz); - struct tm tm; - std::memset(&tm, 0, sizeof(tm)); - tm.tm_sec = bd.second; - tm.tm_min = bd.minute; - tm.tm_hour = bd.hour; - tm.tm_mday = bd.day; - tm.tm_mon = bd.month - 1; - - // Saturates tm.tm_year in cases of over/underflow, accounting for the fact - // that tm.tm_year is years since 1900. - if (bd.year < std::numeric_limits<int>::min() + 1900) { - tm.tm_year = std::numeric_limits<int>::min(); - } else if (bd.year > std::numeric_limits<int>::max()) { - tm.tm_year = std::numeric_limits<int>::max() - 1900; - } else { - tm.tm_year = static_cast<int>(bd.year - 1900); - } - - tm.tm_wday = bd.weekday % 7; - tm.tm_yday = bd.yearday - 1; - tm.tm_isdst = bd.is_dst ? 1 : 0; - - return tm; -} - // -// Factory functions. +// Conversions from/to other time types. // -absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour, - int min, int sec, TimeZone tz) { - // Avoids years that are too extreme for civil_second to normalize. - if (year > 300000000000) return InfiniteFutureTimeConversion(); - if (year < -300000000000) return InfinitePastTimeConversion(); - const auto cz = cctz::time_zone(tz); - const auto cs = cctz::civil_second(year, mon, day, hour, min, sec); - absl::TimeConversion tc; - tc.normalized = year != cs.year() || mon != cs.month() || day != cs.day() || - hour != cs.hour() || min != cs.minute() || sec != cs.second(); - const auto cl = cz.lookup(cs); - // Converts the civil_lookup struct to a TimeConversion. - tc.pre = MakeTimeWithOverflow(cl.pre, cs, cz, &tc.normalized); - tc.trans = MakeTimeWithOverflow(cl.trans, cs, cz, &tc.normalized); - tc.post = MakeTimeWithOverflow(cl.post, cs, cz, &tc.normalized); - tc.kind = MapKind(cl.kind); - return tc; -} - -absl::Time FromDateTime(int64_t year, int mon, int day, int hour, int min, - int sec, TimeZone tz) { - if (year > 300000000000) return InfiniteFuture(); - if (year < -300000000000) return InfinitePast(); - const auto cz = cctz::time_zone(tz); - const auto cs = cctz::civil_second(year, mon, day, hour, min, sec); - const auto cl = cz.lookup(cs); - return MakeTimeWithOverflow(cl.pre, cs, cz); -} - -absl::Time TimeFromTimespec(timespec ts) { - return time_internal::FromUnixDuration(absl::DurationFromTimespec(ts)); -} - -absl::Time TimeFromTimeval(timeval tv) { - return time_internal::FromUnixDuration(absl::DurationFromTimeval(tv)); -} - absl::Time FromUDate(double udate) { return time_internal::FromUnixDuration(absl::Milliseconds(udate)); } @@ -281,10 +234,6 @@ return absl::UniversalEpoch() + 100 * absl::Nanoseconds(universal); } -// -// Conversion to other time types. -// - int64_t ToUnixNanos(Time t) { if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 && time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 33 == 0) { @@ -321,6 +270,23 @@ time_t ToTimeT(Time t) { return absl::ToTimespec(t).tv_sec; } +double ToUDate(Time t) { + return absl::FDivDuration(time_internal::ToUnixDuration(t), + absl::Milliseconds(1)); +} + +int64_t ToUniversal(absl::Time t) { + return absl::FloorToUnit(t - absl::UniversalEpoch(), absl::Nanoseconds(100)); +} + +absl::Time TimeFromTimespec(timespec ts) { + return time_internal::FromUnixDuration(absl::DurationFromTimespec(ts)); +} + +absl::Time TimeFromTimeval(timeval tv) { + return time_internal::FromUnixDuration(absl::DurationFromTimeval(tv)); +} + timespec ToTimespec(Time t) { timespec ts; absl::Duration d = time_internal::ToUnixDuration(t); @@ -359,15 +325,6 @@ return tv; } -double ToUDate(Time t) { - return absl::FDivDuration(time_internal::ToUnixDuration(t), - absl::Milliseconds(1)); -} - -int64_t ToUniversal(absl::Time t) { - return absl::FloorToUnit(t - absl::UniversalEpoch(), absl::Nanoseconds(100)); -} - Time FromChrono(const std::chrono::system_clock::time_point& tp) { return time_internal::FromUnixDuration(time_internal::FromChrono( tp - std::chrono::system_clock::from_time_t(0))); @@ -381,4 +338,149 @@ time_internal::ToChronoDuration<D>(d); } +// +// TimeZone +// + +absl::TimeZone::CivilInfo TimeZone::At(Time t) const { + if (t == absl::InfiniteFuture()) return InfiniteFutureCivilInfo(); + if (t == absl::InfinitePast()) return InfinitePastCivilInfo(); + + const auto ud = time_internal::ToUnixDuration(t); + const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(ud)); + const auto al = cz_.lookup(tp); + + TimeZone::CivilInfo ci; + ci.cs = CivilSecond(al.cs); + ci.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(ud)); + ci.offset = al.offset; + ci.is_dst = al.is_dst; + ci.zone_abbr = al.abbr; + return ci; +} + +absl::TimeZone::TimeInfo TimeZone::At(CivilSecond ct) const { + const cctz::civil_second cs(ct); + const auto cl = cz_.lookup(cs); + + TimeZone::TimeInfo ti; + switch (cl.kind) { + case cctz::time_zone::civil_lookup::UNIQUE: + ti.kind = TimeZone::TimeInfo::UNIQUE; + break; + case cctz::time_zone::civil_lookup::SKIPPED: + ti.kind = TimeZone::TimeInfo::SKIPPED; + break; + case cctz::time_zone::civil_lookup::REPEATED: + ti.kind = TimeZone::TimeInfo::REPEATED; + break; + } + ti.pre = MakeTimeWithOverflow(cl.pre, cs, cz_); + ti.trans = MakeTimeWithOverflow(cl.trans, cs, cz_); + ti.post = MakeTimeWithOverflow(cl.post, cs, cz_); + return ti; +} + +bool TimeZone::NextTransition(Time t, CivilTransition* trans) const { + return FindTransition(cz_, &cctz::time_zone::next_transition, t, trans); +} + +bool TimeZone::PrevTransition(Time t, CivilTransition* trans) const { + return FindTransition(cz_, &cctz::time_zone::prev_transition, t, trans); +} + +// +// Conversions involving time zones. +// + +absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour, + int min, int sec, TimeZone tz) { + // Avoids years that are too extreme for CivilSecond to normalize. + if (year > 300000000000) return InfiniteFutureTimeConversion(); + if (year < -300000000000) return InfinitePastTimeConversion(); + + const CivilSecond cs(year, mon, day, hour, min, sec); + const auto ti = tz.At(cs); + + TimeConversion tc; + tc.pre = ti.pre; + tc.trans = ti.trans; + tc.post = ti.post; + switch (ti.kind) { + case TimeZone::TimeInfo::UNIQUE: + tc.kind = TimeConversion::UNIQUE; + break; + case TimeZone::TimeInfo::SKIPPED: + tc.kind = TimeConversion::SKIPPED; + break; + case TimeZone::TimeInfo::REPEATED: + tc.kind = TimeConversion::REPEATED; + break; + } + tc.normalized = false; + if (year != cs.year() || mon != cs.month() || day != cs.day() || + hour != cs.hour() || min != cs.minute() || sec != cs.second()) { + tc.normalized = true; + } + return tc; +} + +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); + return tm.tm_isdst == 0 ? ti.post : ti.pre; +} + +struct tm ToTM(absl::Time t, absl::TimeZone tz) { + struct tm tm = {}; + + const auto ci = tz.At(t); + const auto& cs = ci.cs; + tm.tm_sec = cs.second(); + tm.tm_min = cs.minute(); + tm.tm_hour = cs.hour(); + tm.tm_mday = cs.day(); + tm.tm_mon = cs.month() - 1; + + // Saturates tm.tm_year in cases of over/underflow, accounting for the fact + // that tm.tm_year is years since 1900. + if (cs.year() < std::numeric_limits<int>::min() + 1900) { + tm.tm_year = std::numeric_limits<int>::min(); + } else if (cs.year() > std::numeric_limits<int>::max()) { + tm.tm_year = std::numeric_limits<int>::max() - 1900; + } else { + tm.tm_year = static_cast<int>(cs.year() - 1900); + } + + const CivilDay cd(cs); + switch (GetWeekday(cd)) { + 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_yday = GetYearDay(cd) - 1; + tm.tm_isdst = ci.is_dst ? 1 : 0; + + return tm; +} + } // namespace absl
diff --git a/absl/time/time.h b/absl/time/time.h index 50bf971..594396c 100644 --- a/absl/time/time.h +++ b/absl/time/time.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -25,18 +25,29 @@ // * `absl::TimeZone` defines geopolitical time zone regions (as collected // within the IANA Time Zone database (https://www.iana.org/time-zones)). // +// Note: Absolute times are distinct from civil times, which refer to the +// human-scale time commonly represented by `YYYY-MM-DD hh:mm:ss`. The mapping +// between absolute and civil times can be specified by use of time zones +// (`absl::TimeZone` within this API). That is: +// +// Civil Time = F(Absolute Time, Time Zone) +// Absolute Time = G(Civil Time, Time Zone) +// +// See civil_time.h for abstractions related to constructing and manipulating +// civil time. // // Example: // // absl::TimeZone nyc; -// // // LoadTimeZone() may fail so it's always better to check for success. // if (!absl::LoadTimeZone("America/New_York", &nyc)) { // // handle error case // } // // // My flight leaves NYC on Jan 2, 2017 at 03:04:05 -// absl::Time takeoff = absl::FromDateTime(2017, 1, 2, 3, 4, 5, nyc); +// absl::CivilSecond cs(2017, 1, 2, 3, 4, 5); +// absl::Time takeoff = absl::FromCivil(cs, nyc); +// // absl::Duration flight_duration = absl::Hours(21) + absl::Minutes(35); // absl::Time landing = takeoff + flight_duration; // @@ -47,7 +58,7 @@ // std::string s = absl::FormatTime( // "My flight will land in Sydney on %Y-%m-%d at %H:%M:%S", // landing, syd); -// + #ifndef ABSL_TIME_TIME_H_ #define ABSL_TIME_TIME_H_ @@ -57,6 +68,7 @@ #include <winsock2.h> #endif #include <chrono> // NOLINT(build/c++11) +#include <cmath> #include <cstdint> #include <ctime> #include <ostream> @@ -64,8 +76,8 @@ #include <type_traits> #include <utility> -#include "absl/base/port.h" // Needed for string vs std::string #include "absl/strings/string_view.h" +#include "absl/time/civil_time.h" #include "absl/time/internal/cctz/include/cctz/time_zone.h" namespace absl { @@ -140,6 +152,16 @@ // Value semantics. constexpr Duration() : rep_hi_(0), rep_lo_(0) {} // zero-length duration + // Copyable. +#if !defined(__clang__) && defined(_MSC_VER) && _MSC_VER < 1910 + // Explicitly defining the constexpr copy constructor avoids an MSVC bug. + constexpr Duration(const Duration& d) + : rep_hi_(d.rep_hi_), rep_lo_(d.rep_lo_) {} +#else + constexpr Duration(const Duration& d) = default; +#endif + Duration& operator=(const Duration& d) = default; + // Compound assignment operators. Duration& operator+=(Duration d); Duration& operator-=(Duration d); @@ -348,11 +370,11 @@ // Factory functions for constructing `Duration` values from an integral number // of the unit indicated by the factory function's name. // -// Note: no "Days()" factory function exists because "a day" is ambiguous. Civil -// days are not always 24 hours long, and a 24-hour duration often does not -// correspond with a civil day. If a 24-hour duration is needed, use -// `absl::Hours(24)`. -// +// Note: no "Days()" factory function exists because "a day" is ambiguous. +// Civil days are not always 24 hours long, and a 24-hour duration often does +// not correspond with a civil day. If a 24-hour duration is needed, use +// `absl::Hours(24)`. (If you actually want a civil day, use absl::CivilDay +// from civil_time.h.) // // Example: // @@ -371,6 +393,7 @@ // factories, which should be preferred. // // Example: +// // auto a = absl::Seconds(1.5); // OK // auto b = absl::Milliseconds(1500); // BETTER template <typename T, time_internal::EnableIfFloat<T> = 0> @@ -387,11 +410,13 @@ } template <typename T, time_internal::EnableIfFloat<T> = 0> Duration Seconds(T n) { - if (n >= 0) { - if (n >= std::numeric_limits<int64_t>::max()) return InfiniteDuration(); + if (n >= 0) { // Note: `NaN >= 0` is false. + if (n >= (std::numeric_limits<int64_t>::max)()) return InfiniteDuration(); return time_internal::MakePosDoubleDuration(n); } else { - if (n <= std::numeric_limits<int64_t>::min()) return -InfiniteDuration(); + if (std::isnan(n)) + return std::signbit(n) ? -InfiniteDuration() : InfiniteDuration(); + if (n <= (std::numeric_limits<int64_t>::min)()) return -InfiniteDuration(); return -time_internal::MakePosDoubleDuration(-n); } } @@ -543,10 +568,9 @@ // The `absl::Time` class represents an instant in time as a count of clock // ticks of some granularity (resolution) from some starting point (epoch). // -// // `absl::Time` uses a resolution that is high enough to avoid loss in // precision, and a range that is wide enough to avoid overflow, when -// converting between tick counts in most Google time scales (i.e., precision +// converting between tick counts in most Google time scales (i.e., resolution // of at least one nanosecond, and range +/-100 billion years). Conversions // between the time scales are performed by truncating (towards negative // infinity) to the nearest representable point. @@ -556,7 +580,6 @@ // absl::Time t1 = ...; // absl::Time t2 = t1 + absl::Minutes(2); // absl::Duration d = t2 - t1; // == absl::Minutes(2) -// absl::Time::Breakdown bd = t1.In(absl::LocalTimeZone()); // class Time { public: @@ -571,7 +594,11 @@ // absl::Time t = absl::Now(); // absl::Time t = absl::TimeFromTimeval(tv); // absl::Time t = absl::InfinitePast(); - constexpr Time() {} + constexpr Time() = default; + + // Copyable. + constexpr Time(const Time& t) = default; + Time& operator=(const Time& t) = default; // Assignment operators. Time& operator+=(Duration d) { @@ -590,7 +617,10 @@ // intended to represent an instant in time. So, rather than passing // a `Time::Breakdown` to a function, pass an `absl::Time` and an // `absl::TimeZone`. - struct Breakdown { + // + // Deprecated. Use `absl::TimeZone::CivilInfo`. + struct + Breakdown { int64_t year; // year (e.g., 2013) int month; // month of year [1:12] int day; // day of month [1:31] @@ -614,6 +644,8 @@ // Time::In() // // Returns the breakdown of this instant in the given TimeZone. + // + // Deprecated. Use `absl::TimeZone::At(Time)`. Breakdown In(TimeZone tz) const; template <typename H> @@ -668,7 +700,7 @@ // Returns an `absl::Time` that is infinitely far in the future. constexpr Time InfiniteFuture() { return Time( - time_internal::MakeDuration(std::numeric_limits<int64_t>::max(), ~0U)); + time_internal::MakeDuration((std::numeric_limits<int64_t>::max)(), ~0U)); } // InfinitePast() @@ -676,129 +708,9 @@ // Returns an `absl::Time` that is infinitely far in the past. constexpr Time InfinitePast() { return Time( - time_internal::MakeDuration(std::numeric_limits<int64_t>::min(), ~0U)); + time_internal::MakeDuration((std::numeric_limits<int64_t>::min)(), ~0U)); } -// TimeConversion -// -// An `absl::TimeConversion` represents the conversion of year, month, day, -// hour, minute, and second values (i.e., a civil time), in a particular -// `absl::TimeZone`, to a time instant (an absolute time), as returned by -// `absl::ConvertDateTime()`. (Subseconds must be handled separately.) -// -// It is possible, though, for a caller to try to convert values that -// do not represent an actual or unique instant in time (due to a shift -// in UTC offset in the `absl::TimeZone`, which results in a discontinuity in -// the civil-time components). For example, a daylight-saving-time -// transition skips or repeats civil times---in the United States, March -// 13, 2011 02:15 never occurred, while November 6, 2011 01:15 occurred -// twice---so requests for such times are not well-defined. -// -// To account for these possibilities, `absl::TimeConversion` is richer -// than just a single `absl::Time`. When the civil time is skipped or -// repeated, `absl::ConvertDateTime()` returns times calculated using the -// pre-transition and post-transition UTC offsets, plus the transition -// time itself. -// -// Examples: -// -// absl::TimeZone lax; -// if (!absl::LoadTimeZone("America/Los_Angeles", &lax)) { -// // handle error case -// } -// -// // A unique civil time -// absl::TimeConversion jan01 = -// absl::ConvertDateTime(2011, 1, 1, 0, 0, 0, lax); -// // jan01.kind == TimeConversion::UNIQUE -// // jan01.pre is 2011/01/01 00:00:00 -0800 -// // jan01.trans is 2011/01/01 00:00:00 -0800 -// // jan01.post is 2011/01/01 00:00:00 -0800 -// -// // A Spring DST transition, when there is a gap in civil time -// absl::TimeConversion mar13 = -// absl::ConvertDateTime(2011, 3, 13, 2, 15, 0, lax); -// // mar13.kind == TimeConversion::SKIPPED -// // mar13.pre is 2011/03/13 03:15:00 -0700 -// // mar13.trans is 2011/03/13 03:00:00 -0700 -// // mar13.post is 2011/03/13 01:15:00 -0800 -// -// // A Fall DST transition, when civil times are repeated -// absl::TimeConversion nov06 = -// absl::ConvertDateTime(2011, 11, 6, 1, 15, 0, lax); -// // nov06.kind == TimeConversion::REPEATED -// // nov06.pre is 2011/11/06 01:15:00 -0700 -// // nov06.trans is 2011/11/06 01:00:00 -0800 -// // nov06.post is 2011/11/06 01:15:00 -0800 -// -// The input month, day, hour, minute, and second values can also be -// outside of their valid ranges, in which case they will be "normalized" -// during the conversion. -// -// Example: -// -// // "October 32" normalizes to "November 1". -// absl::TimeZone tz = absl::LocalTimeZone(); -// absl::TimeConversion tc = -// absl::ConvertDateTime(2013, 10, 32, 8, 30, 0, tz); -// // tc.kind == TimeConversion::UNIQUE && tc.normalized == true -// // tc.pre.In(tz).month == 11 && tc.pre.In(tz).day == 1 -struct TimeConversion { - Time pre; // time calculated using the pre-transition offset - Time trans; // when the civil-time discontinuity occurred - Time post; // time calculated using the post-transition offset - - enum Kind { - UNIQUE, // the civil time was singular (pre == trans == post) - SKIPPED, // the civil time did not exist - REPEATED, // the civil time was ambiguous - }; - Kind kind; - - bool normalized; // input values were outside their valid ranges -}; - -// ConvertDateTime() -// -// The full generality of a civil time to absl::Time conversion. -TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour, - int min, int sec, TimeZone tz); - -// FromDateTime() -// -// A convenience wrapper for `absl::ConvertDateTime()` that simply returns the -// "pre" `absl::Time`. That is, the unique result, or the instant that -// is correct using the pre-transition offset (as if the transition -// never happened). This is typically the answer that humans expected when -// faced with non-unique times, such as near daylight-saving time transitions. -// -// Example: -// -// absl::TimeZone seattle; -// if (!absl::LoadTimeZone("America/Los_Angeles", &seattle)) { -// // handle error case -// } -// absl::Time t = absl::FromDateTime(2017, 9, 26, 9, 30, 0, seattle); -Time FromDateTime(int64_t year, int mon, int day, int hour, int min, int sec, - TimeZone tz); - -// FromTM() -// -// Converts the `tm_year`, `tm_mon`, `tm_mday`, `tm_hour`, `tm_min`, and -// `tm_sec` fields to an `absl::Time` using the given time zone. See ctime(3) -// for a description of the expected values of the tm fields. IFF the indicated -// time instant is not unique (see `absl::ConvertDateTime()` above), the -// `tm_isdst` field is consulted to select the desired instant (`tm_isdst` > 0 -// means DST, `tm_isdst` == 0 means no DST, `tm_isdst` < 0 means use the default -// like `absl::FromDateTime()`). -Time FromTM(const struct tm& tm, TimeZone tz); - -// ToTM() -// -// Converts the given `absl::Time` to a struct tm using the given time zone. -// See ctime(3) for a description of the values of the tm fields. -struct tm ToTM(Time t, TimeZone tz); - // FromUnixNanos() // FromUnixMicros() // FromUnixMillis() @@ -883,140 +795,6 @@ // // tp == std::chrono::system_clock::from_time_t(123); std::chrono::system_clock::time_point ToChronoTime(Time); -// RFC3339_full -// RFC3339_sec -// -// FormatTime()/ParseTime() format specifiers for RFC3339 date/time strings, -// with trailing zeros trimmed or with fractional seconds omitted altogether. -// -// Note that RFC3339_sec[] matches an ISO 8601 extended format for date and -// time with UTC offset. 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 - -// RFC1123_full -// RFC1123_no_wday -// -// FormatTime()/ParseTime() format specifiers for RFC1123 date/time strings. -extern const char RFC1123_full[]; // %a, %d %b %E4Y %H:%M:%S %z -extern const char RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z - -// FormatTime() -// -// Formats the given `absl::Time` in the `absl::TimeZone` according to the -// provided format string. Uses strftime()-like formatting options, with -// the following extensions: -// -// - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm) -// - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss) -// - %E#S - Seconds with # digits of fractional precision -// - %E*S - Seconds with full fractional precision (a literal '*') -// - %E#f - Fractional seconds with # digits of precision -// - %E*f - Fractional seconds with full precision (a literal '*') -// - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999) -// -// Note that %E0S behaves like %S, and %E0f produces no characters. In -// contrast %E*f always produces at least one digit, which may be '0'. -// -// Note that %Y produces as many characters as it takes to fully render the -// year. A year outside of [-999:9999] when formatted with %E4Y will produce -// more than four characters, just like %Y. -// -// We recommend that format strings include the UTC offset (%z, %Ez, or %E*z) -// so that the result uniquely identifies a time instant. -// -// Example: -// -// absl::TimeZone lax; -// if (!absl::LoadTimeZone("America/Los_Angeles", &lax)) { -// // handle error case -// } -// absl::Time t = absl::FromDateTime(2013, 1, 2, 3, 4, 5, lax); -// -// string f = absl::FormatTime("%H:%M:%S", t, lax); // "03:04:05" -// f = absl::FormatTime("%H:%M:%E3S", t, lax); // "03:04:05.000" -// -// Note: If the given `absl::Time` is `absl::InfiniteFuture()`, the returned -// string will be exactly "infinite-future". If the given `absl::Time` is -// `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); - -// Convenience functions that format the given time using the RFC3339_full -// format. The first overload uses the provided TimeZone, while the second -// uses LocalTimeZone(). -std::string FormatTime(Time t, TimeZone tz); -std::string FormatTime(Time t); - -// Output stream operator. -inline std::ostream& operator<<(std::ostream& os, Time t) { - return os << FormatTime(t); -} - -// ParseTime() -// -// Parses an input string according to the provided format string and -// returns the corresponding `absl::Time`. Uses strftime()-like formatting -// options, with the same extensions as FormatTime(), but with the -// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez -// and %E*z also accept the same inputs. -// -// %Y consumes as many numeric characters as it can, so the matching data -// should always be terminated with a non-numeric. %E4Y always consumes -// exactly four characters, including any sign. -// -// Unspecified fields are taken from the default date and time of ... -// -// "1970-01-01 00:00:00.0 +0000" -// -// For example, parsing a string of "15:45" (%H:%M) will return an absl::Time -// that represents "1970-01-01 15:45:00.0 +0000". -// -// Note that since ParseTime() returns time instants, it makes the most sense -// to parse fully-specified date/time strings that include a UTC offset (%z, -// %Ez, or %E*z). -// -// Note also that `absl::ParseTime()` only heeds the fields year, month, day, -// hour, minute, (fractional) second, and UTC offset. Other fields, like -// weekday (%a or %A), while parsed for syntactic validity, are ignored -// in the conversion. -// -// Date and time fields that are out-of-range will be treated as errors -// rather than normalizing them like `absl::FromDateTime()` does. For example, -// it is an error to parse the date "Oct 32, 2013" because 32 is out of range. -// -// A leap second of ":60" is normalized to ":00" of the following minute -// with fractional seconds discarded. The following table shows how the -// given seconds and subseconds will be parsed: -// -// "59.x" -> 59.x // exact -// "60.x" -> 00.0 // normalized -// "00.x" -> 00.x // exact -// -// Errors are indicated by returning false and assigning an error message -// to the "err" out param if it is non-null. -// -// Note: If the input string is exactly "infinite-future", the returned -// `absl::Time` will be `absl::InfiniteFuture()` and `true` will be returned. -// 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, - std::string* err); - -// Like ParseTime() above, but if the format string does not contain a UTC -// offset specification (%z/%Ez/%E*z) then the input is interpreted in the -// given TimeZone. This means that the input, by itself, does not identify a -// unique instant. Being time-zone dependent, it also admits the possibility -// of ambiguity or non-existence, in which case the "pre" time (as defined -// for ConvertDateTime()) is returned. For these reasons we recommend that -// all date/time strings include a UTC offset so they're context independent. -bool ParseTime(const std::string& format, const std::string& input, TimeZone tz, - Time* time, std::string* err); - // Support for flag values of type Time. Time flags must be specified in a // format that matches absl::RFC3339_full. For example: // @@ -1056,12 +834,14 @@ // // See also: // - https://github.com/google/cctz -// - http://www.iana.org/time-zones -// - http://en.wikipedia.org/wiki/Zoneinfo +// - https://www.iana.org/time-zones +// - https://en.wikipedia.org/wiki/Zoneinfo class TimeZone { public: explicit TimeZone(time_internal::cctz::time_zone tz) : cz_(tz) {} TimeZone() = default; // UTC, but prefer UTCTimeZone() to be explicit. + + // Copyable. TimeZone(const TimeZone&) = default; TimeZone& operator=(const TimeZone&) = default; @@ -1069,6 +849,136 @@ std::string name() const { return cz_.name(); } + // TimeZone::CivilInfo + // + // Information about the civil time corresponding to an absolute time. + // This struct is not intended to represent an instant in time. So, rather + // than passing a `TimeZone::CivilInfo` to a function, pass an `absl::Time` + // and an `absl::TimeZone`. + struct CivilInfo { + CivilSecond cs; + Duration subsecond; + + // Note: The following fields exist for backward compatibility + // with older APIs. Accessing these fields directly is a sign of + // imprudent logic in the calling code. Modern time-related code + // should only access this data indirectly by way of FormatTime(). + // These fields are undefined for InfiniteFuture() and InfinitePast(). + int offset; // seconds east of UTC + bool is_dst; // is offset non-standard? + const char* zone_abbr; // time-zone abbreviation (e.g., "PST") + }; + + // TimeZone::At(Time) + // + // Returns the civil time for this TimeZone at a certain `absl::Time`. + // If the input time is infinite, the output civil second will be set to + // CivilSecond::max() or min(), and the subsecond will be infinite. + // + // Example: + // + // const auto epoch = lax.At(absl::UnixEpoch()); + // // epoch.cs == 1969-12-31 16:00:00 + // // epoch.subsecond == absl::ZeroDuration() + // // epoch.offset == -28800 + // // epoch.is_dst == false + // // epoch.abbr == "PST" + CivilInfo At(Time t) const; + + // TimeZone::TimeInfo + // + // Information about the absolute times corresponding to a civil time. + // (Subseconds must be handled separately.) + // + // It is possible for a caller to pass a civil-time value that does + // not represent an actual or unique instant in time (due to a shift + // in UTC offset in the TimeZone, which results in a discontinuity in + // the civil-time components). For example, a daylight-saving-time + // transition skips or repeats civil times---in the United States, + // March 13, 2011 02:15 never occurred, while November 6, 2011 01:15 + // occurred twice---so requests for such times are not well-defined. + // To account for these possibilities, `absl::TimeZone::TimeInfo` is + // richer than just a single `absl::Time`. + struct TimeInfo { + enum CivilKind { + UNIQUE, // the civil time was singular (pre == trans == post) + SKIPPED, // the civil time did not exist (pre >= trans > post) + REPEATED, // the civil time was ambiguous (pre < trans <= post) + } kind; + Time pre; // time calculated using the pre-transition offset + Time trans; // when the civil-time discontinuity occurred + Time post; // time calculated using the post-transition offset + }; + + // TimeZone::At(CivilSecond) + // + // Returns an `absl::TimeInfo` containing the absolute time(s) for this + // TimeZone at an `absl::CivilSecond`. When the civil time is skipped or + // repeated, returns times calculated using the pre-transition and post- + // transition UTC offsets, plus the transition time itself. + // + // Examples: + // + // // A unique civil time + // const auto jan01 = lax.At(absl::CivilSecond(2011, 1, 1, 0, 0, 0)); + // // jan01.kind == TimeZone::TimeInfo::UNIQUE + // // jan01.pre is 2011-01-01 00:00:00 -0800 + // // jan01.trans is 2011-01-01 00:00:00 -0800 + // // jan01.post is 2011-01-01 00:00:00 -0800 + // + // // A Spring DST transition, when there is a gap in civil time + // const auto mar13 = lax.At(absl::CivilSecond(2011, 3, 13, 2, 15, 0)); + // // mar13.kind == TimeZone::TimeInfo::SKIPPED + // // mar13.pre is 2011-03-13 03:15:00 -0700 + // // mar13.trans is 2011-03-13 03:00:00 -0700 + // // mar13.post is 2011-03-13 01:15:00 -0800 + // + // // A Fall DST transition, when civil times are repeated + // const auto nov06 = lax.At(absl::CivilSecond(2011, 11, 6, 1, 15, 0)); + // // nov06.kind == TimeZone::TimeInfo::REPEATED + // // nov06.pre is 2011-11-06 01:15:00 -0700 + // // nov06.trans is 2011-11-06 01:00:00 -0800 + // // nov06.post is 2011-11-06 01:15:00 -0800 + TimeInfo At(CivilSecond ct) const; + + // TimeZone::NextTransition() + // TimeZone::PrevTransition() + // + // Finds the time of the next/previous offset change in this time zone. + // + // By definition, `NextTransition(t, &trans)` returns false when `t` is + // `InfiniteFuture()`, and `PrevTransition(t, &trans)` returns false + // when `t` is `InfinitePast()`. If the zone has no transitions, the + // result will also be false no matter what the argument. + // + // Otherwise, when `t` is `InfinitePast()`, `NextTransition(t, &trans)` + // returns true and sets `trans` to the first recorded transition. Chains + // of calls to `NextTransition()/PrevTransition()` will eventually return + // false, but it is unspecified exactly when `NextTransition(t, &trans)` + // jumps to false, or what time is set by `PrevTransition(t, &trans)` for + // a very distant `t`. + // + // Note: Enumeration of time-zone transitions is for informational purposes + // only. Modern time-related code should not care about when offset changes + // occur. + // + // Example: + // absl::TimeZone nyc; + // if (!absl::LoadTimeZone("America/New_York", &nyc)) { ... } + // const auto now = absl::Now(); + // auto t = absl::InfinitePast(); + // absl::TimeZone::CivilTransition trans; + // while (t <= now && nyc.NextTransition(t, &trans)) { + // // transition: trans.from -> trans.to + // t = nyc.At(trans.to).trans; + // } + struct CivilTransition { + CivilSecond from; // the civil time we jump from + CivilSecond to; // the civil time we jump to + }; + bool NextTransition(Time t, CivilTransition* trans) const; + bool PrevTransition(Time t, CivilTransition* trans) const; + template <typename H> friend H AbslHashValue(H h, TimeZone tz) { return H::combine(std::move(h), tz.cz_); @@ -1127,6 +1037,270 @@ return TimeZone(time_internal::cctz::local_time_zone()); } +// ToCivilSecond() +// ToCivilMinute() +// ToCivilHour() +// ToCivilDay() +// ToCivilMonth() +// ToCivilYear() +// +// Helpers for TimeZone::At(Time) to return particularly aligned civil times. +// +// Example: +// +// absl::Time t = ...; +// absl::TimeZone tz = ...; +// const auto cd = absl::ToCivilDay(t, tz); +inline CivilSecond ToCivilSecond(Time t, TimeZone tz) { + return tz.At(t).cs; // already a CivilSecond +} +inline CivilMinute ToCivilMinute(Time t, TimeZone tz) { + return CivilMinute(tz.At(t).cs); +} +inline CivilHour ToCivilHour(Time t, TimeZone tz) { + return CivilHour(tz.At(t).cs); +} +inline CivilDay ToCivilDay(Time t, TimeZone tz) { + return CivilDay(tz.At(t).cs); +} +inline CivilMonth ToCivilMonth(Time t, TimeZone tz) { + return CivilMonth(tz.At(t).cs); +} +inline CivilYear ToCivilYear(Time t, TimeZone tz) { + return CivilYear(tz.At(t).cs); +} + +// FromCivil() +// +// Helper for TimeZone::At(CivilSecond) that provides "order-preserving +// semantics." If the civil time maps to a unique time, that time is +// returned. If the civil time is repeated in the given time zone, the +// time using the pre-transition offset is returned. Otherwise, the +// civil time is skipped in the given time zone, and the transition time +// is returned. This means that for any two civil times, ct1 and ct2, +// (ct1 < ct2) => (FromCivil(ct1) <= FromCivil(ct2)), the equal case +// being when two non-existent civil times map to the same transition time. +// +// Note: Accepts civil times of any alignment. +inline Time FromCivil(CivilSecond ct, TimeZone tz) { + const auto ti = tz.At(ct); + if (ti.kind == TimeZone::TimeInfo::SKIPPED) return ti.trans; + return ti.pre; +} + +// TimeConversion +// +// An `absl::TimeConversion` represents the conversion of year, month, day, +// hour, minute, and second values (i.e., a civil time), in a particular +// `absl::TimeZone`, to a time instant (an absolute time), as returned by +// `absl::ConvertDateTime()`. Lecacy version of `absl::TimeZone::TimeInfo`. +// +// Deprecated. Use `absl::TimeZone::TimeInfo`. +struct + TimeConversion { + Time pre; // time calculated using the pre-transition offset + Time trans; // when the civil-time discontinuity occurred + Time post; // time calculated using the post-transition offset + + enum Kind { + UNIQUE, // the civil time was singular (pre == trans == post) + SKIPPED, // the civil time did not exist + REPEATED, // the civil time was ambiguous + }; + Kind kind; + + bool normalized; // input values were outside their valid ranges +}; + +// ConvertDateTime() +// +// Legacy version of `absl::TimeZone::At(absl::CivilSecond)` that takes +// the civil time as six, separate values (YMDHMS). +// +// The input month, day, hour, minute, and second values can be outside +// of their valid ranges, in which case they will be "normalized" during +// the conversion. +// +// Example: +// +// // "October 32" normalizes to "November 1". +// absl::TimeConversion tc = +// absl::ConvertDateTime(2013, 10, 32, 8, 30, 0, lax); +// // tc.kind == TimeConversion::UNIQUE && tc.normalized == true +// // absl::ToCivilDay(tc.pre, tz).month() == 11 +// // absl::ToCivilDay(tc.pre, tz).day() == 1 +// +// Deprecated. Use `absl::TimeZone::At(CivilSecond)`. +TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour, + int min, int sec, TimeZone tz); + +// FromDateTime() +// +// A convenience wrapper for `absl::ConvertDateTime()` that simply returns +// the "pre" `absl::Time`. That is, the unique result, or the instant that +// is correct using the pre-transition offset (as if the transition never +// happened). +// +// Example: +// +// absl::Time t = absl::FromDateTime(2017, 9, 26, 9, 30, 0, lax); +// // t = 2017-09-26 09:30:00 -0700 +// +// Deprecated. Use `absl::FromCivil(CivilSecond, TimeZone)`. Note that the +// behavior of `FromCivil()` differs from `FromDateTime()` for skipped civil +// times. If you care about that see `absl::TimeZone::At(absl::CivilSecond)`. +inline Time FromDateTime(int64_t year, int mon, int day, int hour, + int min, int sec, TimeZone tz) { + return ConvertDateTime(year, mon, day, hour, min, sec, tz).pre; +} + +// FromTM() +// +// Converts the `tm_year`, `tm_mon`, `tm_mday`, `tm_hour`, `tm_min`, and +// `tm_sec` fields to an `absl::Time` using the given time zone. See ctime(3) +// for a description of the expected values of the tm fields. If the indicated +// time instant is not unique (see `absl::TimeZone::At(absl::CivilSecond)` +// above), the `tm_isdst` field is consulted to select the desired instant +// (`tm_isdst` > 0 means DST, `tm_isdst` == 0 means no DST, `tm_isdst` < 0 +// means use the post-transition offset). +Time FromTM(const struct tm& tm, TimeZone tz); + +// ToTM() +// +// Converts the given `absl::Time` to a struct tm using the given time zone. +// See ctime(3) for a description of the values of the tm fields. +struct tm ToTM(Time t, TimeZone tz); + +// RFC3339_full +// RFC3339_sec +// +// FormatTime()/ParseTime() format specifiers for RFC3339 date/time strings, +// with trailing zeros trimmed or with fractional seconds omitted altogether. +// +// Note that RFC3339_sec[] matches an ISO 8601 extended format for date and +// time with UTC offset. 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 + +// RFC1123_full +// RFC1123_no_wday +// +// FormatTime()/ParseTime() format specifiers for RFC1123 date/time strings. +extern const char RFC1123_full[]; // %a, %d %b %E4Y %H:%M:%S %z +extern const char RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z + +// FormatTime() +// +// Formats the given `absl::Time` in the `absl::TimeZone` according to the +// provided format string. Uses strftime()-like formatting options, with +// the following extensions: +// +// - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm) +// - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss) +// - %E#S - Seconds with # digits of fractional precision +// - %E*S - Seconds with full fractional precision (a literal '*') +// - %E#f - Fractional seconds with # digits of precision +// - %E*f - Fractional seconds with full precision (a literal '*') +// - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999) +// +// Note that %E0S behaves like %S, and %E0f produces no characters. In +// contrast %E*f always produces at least one digit, which may be '0'. +// +// Note that %Y produces as many characters as it takes to fully render the +// year. A year outside of [-999:9999] when formatted with %E4Y will produce +// more than four characters, just like %Y. +// +// We recommend that format strings include the UTC offset (%z, %Ez, or %E*z) +// so that the result uniquely identifies a time instant. +// +// Example: +// +// absl::CivilSecond cs(2013, 1, 2, 3, 4, 5); +// absl::Time t = absl::FromCivil(cs, lax); +// std::string f = absl::FormatTime("%H:%M:%S", t, lax); // "03:04:05" +// f = absl::FormatTime("%H:%M:%E3S", t, lax); // "03:04:05.000" +// +// Note: If the given `absl::Time` is `absl::InfiniteFuture()`, the returned +// string will be exactly "infinite-future". If the given `absl::Time` is +// `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); + +// Convenience functions that format the given time using the RFC3339_full +// format. The first overload uses the provided TimeZone, while the second +// uses LocalTimeZone(). +std::string FormatTime(Time t, TimeZone tz); +std::string FormatTime(Time t); + +// Output stream operator. +inline std::ostream& operator<<(std::ostream& os, Time t) { + return os << FormatTime(t); +} + +// ParseTime() +// +// Parses an input string according to the provided format string and +// returns the corresponding `absl::Time`. Uses strftime()-like formatting +// options, with the same extensions as FormatTime(), but with the +// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez +// and %E*z also accept the same inputs. +// +// %Y consumes as many numeric characters as it can, so the matching data +// should always be terminated with a non-numeric. %E4Y always consumes +// exactly four characters, including any sign. +// +// Unspecified fields are taken from the default date and time of ... +// +// "1970-01-01 00:00:00.0 +0000" +// +// For example, parsing a string of "15:45" (%H:%M) will return an absl::Time +// that represents "1970-01-01 15:45:00.0 +0000". +// +// Note that since ParseTime() returns time instants, it makes the most sense +// to parse fully-specified date/time strings that include a UTC offset (%z, +// %Ez, or %E*z). +// +// Note also that `absl::ParseTime()` only heeds the fields year, month, day, +// hour, minute, (fractional) second, and UTC offset. Other fields, like +// weekday (%a or %A), while parsed for syntactic validity, are ignored +// in the conversion. +// +// Date and time fields that are out-of-range will be treated as errors +// rather than normalizing them like `absl::CivilSecond` does. For example, +// it is an error to parse the date "Oct 32, 2013" because 32 is out of range. +// +// A leap second of ":60" is normalized to ":00" of the following minute +// with fractional seconds discarded. The following table shows how the +// given seconds and subseconds will be parsed: +// +// "59.x" -> 59.x // exact +// "60.x" -> 00.0 // normalized +// "00.x" -> 00.x // exact +// +// Errors are indicated by returning false and assigning an error message +// to the "err" out param if it is non-null. +// +// Note: If the input string is exactly "infinite-future", the returned +// `absl::Time` will be `absl::InfiniteFuture()` and `true` will be returned. +// 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, + std::string* err); + +// Like ParseTime() above, but if the format string does not contain a UTC +// offset specification (%z/%Ez/%E*z) then the input is interpreted in the +// given TimeZone. This means that the input, by itself, does not identify a +// unique instant. Being time-zone dependent, it also admits the possibility +// of ambiguity or non-existence, in which case the "pre" time (as defined +// 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, + Time* time, std::string* err); + // ============================================================================ // Implementation Details Follow // ============================================================================ @@ -1164,17 +1338,20 @@ return (ticks < 0) ? MakeDuration(sec - 1, ticks + kTicksPerSecond) : MakeDuration(sec, ticks); } + // Provide access to the Duration representation. constexpr int64_t GetRepHi(Duration d) { return d.rep_hi_; } constexpr uint32_t GetRepLo(Duration d) { return d.rep_lo_; } + +// Returns true iff d is positive or negative infinity. constexpr bool IsInfiniteDuration(Duration d) { return GetRepLo(d) == ~0U; } // Returns an infinite Duration with the opposite sign. // REQUIRES: IsInfiniteDuration(d) constexpr Duration OppositeInfinity(Duration d) { return GetRepHi(d) < 0 - ? MakeDuration(std::numeric_limits<int64_t>::max(), ~0U) - : MakeDuration(std::numeric_limits<int64_t>::min(), ~0U); + ? MakeDuration((std::numeric_limits<int64_t>::max)(), ~0U) + : MakeDuration((std::numeric_limits<int64_t>::min)(), ~0U); } // Returns (-n)-1 (equivalently -(n+1)) without avoidable overflow. @@ -1199,14 +1376,14 @@ v / N, v % N * kTicksPerNanosecond * 1000 * 1000 * 1000 / N); } constexpr Duration FromInt64(int64_t v, std::ratio<60>) { - return (v <= std::numeric_limits<int64_t>::max() / 60 && - v >= std::numeric_limits<int64_t>::min() / 60) + return (v <= (std::numeric_limits<int64_t>::max)() / 60 && + v >= (std::numeric_limits<int64_t>::min)() / 60) ? MakeDuration(v * 60) : v > 0 ? InfiniteDuration() : -InfiniteDuration(); } constexpr Duration FromInt64(int64_t v, std::ratio<3600>) { - return (v <= std::numeric_limits<int64_t>::max() / 3600 && - v >= std::numeric_limits<int64_t>::min() / 3600) + return (v <= (std::numeric_limits<int64_t>::max)() / 3600 && + v >= (std::numeric_limits<int64_t>::min)() / 3600) ? MakeDuration(v * 3600) : v > 0 ? InfiniteDuration() : -InfiniteDuration(); } @@ -1263,14 +1440,15 @@ using Period = typename T::period; static_assert(IsValidRep64<Rep>(0), "duration::rep is invalid"); if (time_internal::IsInfiniteDuration(d)) - return d < ZeroDuration() ? T::min() : T::max(); + return d < ZeroDuration() ? (T::min)() : (T::max)(); const auto v = ToInt64(d, Period{}); - if (v > std::numeric_limits<Rep>::max()) return T::max(); - if (v < std::numeric_limits<Rep>::min()) return T::min(); + if (v > (std::numeric_limits<Rep>::max)()) return (T::max)(); + if (v < (std::numeric_limits<Rep>::min)()) return (T::min)(); return T{v}; } } // namespace time_internal + constexpr Duration Nanoseconds(int64_t n) { return time_internal::FromInt64(n, std::nano{}); } @@ -1293,7 +1471,8 @@ 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::GetRepHi(lhs) == + (std::numeric_limits<int64_t>::min)() ? time_internal::GetRepLo(lhs) + 1 < time_internal::GetRepLo(rhs) + 1 : time_internal::GetRepLo(lhs) < @@ -1318,7 +1497,8 @@ // a second's worth of ticks and avoid overflow (as negating int64_t-min + 1 // is safe). return time_internal::GetRepLo(d) == 0 - ? time_internal::GetRepHi(d) == std::numeric_limits<int64_t>::min() + ? time_internal::GetRepHi(d) == + (std::numeric_limits<int64_t>::min)() ? InfiniteDuration() : time_internal::MakeDuration(-time_internal::GetRepHi(d)) : time_internal::IsInfiniteDuration(d) @@ -1331,7 +1511,8 @@ } constexpr Duration InfiniteDuration() { - return time_internal::MakeDuration(std::numeric_limits<int64_t>::max(), ~0U); + return time_internal::MakeDuration((std::numeric_limits<int64_t>::max)(), + ~0U); } constexpr Duration FromChrono(const std::chrono::nanoseconds& d) {
diff --git a/absl/time/time_benchmark.cc b/absl/time/time_benchmark.cc index e100994..99e6279 100644 --- a/absl/time/time_benchmark.cc +++ b/absl/time/time_benchmark.cc
@@ -3,7 +3,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -169,32 +169,32 @@ BENCHMARK(BM_Time_ToUnixSeconds); // -// FromDateTime +// FromCivil // -// In each "FromDateTime" benchmark we switch between two YMDhms -// values separated by at least one transition in order to defeat any -// internal caching of previous results (e.g., see time_local_hint_). +// In each "FromCivil" benchmark we switch between two YMDhms values +// separated by at least one transition in order to defeat any internal +// caching of previous results (e.g., see time_local_hint_). // // The "UTC" variants use UTC instead of the Google/local time zone. // The "Day0" variants require normalization of the day of month. // -void BM_Time_FromDateTime_Absl(benchmark::State& state) { +void BM_Time_FromCivil_Absl(benchmark::State& state) { const absl::TimeZone tz = absl::time_internal::LoadTimeZone("America/Los_Angeles"); int i = 0; while (state.KeepRunning()) { if ((i & 1) == 0) { - absl::FromDateTime(2014, 12, 18, 20, 16, 18, tz); + absl::FromCivil(absl::CivilSecond(2014, 12, 18, 20, 16, 18), tz); } else { - absl::FromDateTime(2013, 11, 15, 18, 30, 27, tz); + absl::FromCivil(absl::CivilSecond(2013, 11, 15, 18, 30, 27), tz); } ++i; } } -BENCHMARK(BM_Time_FromDateTime_Absl); +BENCHMARK(BM_Time_FromCivil_Absl); -void BM_Time_FromDateTime_Libc(benchmark::State& state) { +void BM_Time_FromCivil_Libc(benchmark::State& state) { // No timezone support, so just use localtime. int i = 0; while (state.KeepRunning()) { @@ -219,32 +219,32 @@ ++i; } } -BENCHMARK(BM_Time_FromDateTime_Libc); +BENCHMARK(BM_Time_FromCivil_Libc); -void BM_Time_FromDateTimeUTC_Absl(benchmark::State& state) { +void BM_Time_FromCivilUTC_Absl(benchmark::State& state) { const absl::TimeZone tz = absl::UTCTimeZone(); while (state.KeepRunning()) { - FromDateTime(2014, 12, 18, 20, 16, 18, tz); + absl::FromCivil(absl::CivilSecond(2014, 12, 18, 20, 16, 18), tz); } } -BENCHMARK(BM_Time_FromDateTimeUTC_Absl); +BENCHMARK(BM_Time_FromCivilUTC_Absl); -void BM_Time_FromDateTimeDay0_Absl(benchmark::State& state) { +void BM_Time_FromCivilDay0_Absl(benchmark::State& state) { const absl::TimeZone tz = absl::time_internal::LoadTimeZone("America/Los_Angeles"); int i = 0; while (state.KeepRunning()) { if ((i & 1) == 0) { - absl::FromDateTime(2014, 12, 0, 20, 16, 18, tz); + absl::FromCivil(absl::CivilSecond(2014, 12, 0, 20, 16, 18), tz); } else { - absl::FromDateTime(2013, 11, 0, 18, 30, 27, tz); + absl::FromCivil(absl::CivilSecond(2013, 11, 0, 18, 30, 27), tz); } ++i; } } -BENCHMARK(BM_Time_FromDateTimeDay0_Absl); +BENCHMARK(BM_Time_FromCivilDay0_Absl); -void BM_Time_FromDateTimeDay0_Libc(benchmark::State& state) { +void BM_Time_FromCivilDay0_Libc(benchmark::State& state) { // No timezone support, so just use localtime. int i = 0; while (state.KeepRunning()) { @@ -269,7 +269,7 @@ ++i; } } -BENCHMARK(BM_Time_FromDateTimeDay0_Libc); +BENCHMARK(BM_Time_FromCivilDay0_Libc); // // To/FromTimespec
diff --git a/absl/time/time_norm_test.cc b/absl/time/time_norm_test.cc deleted file mode 100644 index 4436242..0000000 --- a/absl/time/time_norm_test.cc +++ /dev/null
@@ -1,306 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// This file contains tests for FromDateTime() normalization, which is -// time-zone independent so we just use UTC throughout. - -#include <cstdint> -#include <limits> - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/time/internal/test_util.h" -#include "absl/time/time.h" - -namespace { - -TEST(TimeNormCase, SimpleOverflow) { - const absl::TimeZone utc = absl::UTCTimeZone(); - - absl::TimeConversion tc = - absl::ConvertDateTime(2013, 11, 15, 16, 32, 59 + 1, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - absl::Time::Breakdown bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 33, 0, 0, false); - - tc = absl::ConvertDateTime(2013, 11, 15, 16, 59 + 1, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 17, 0, 14, 0, false); - - tc = absl::ConvertDateTime(2013, 11, 15, 23 + 1, 32, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 16, 0, 32, 14, 0, false); - - tc = absl::ConvertDateTime(2013, 11, 30 + 1, 16, 32, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 1, 16, 32, 14, 0, false); - - tc = absl::ConvertDateTime(2013, 12 + 1, 15, 16, 32, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 15, 16, 32, 14, 0, false); -} - -TEST(TimeNormCase, SimpleUnderflow) { - const absl::TimeZone utc = absl::UTCTimeZone(); - - absl::TimeConversion tc = ConvertDateTime(2013, 11, 15, 16, 32, 0 - 1, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - absl::Time::Breakdown bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 31, 59, 0, false); - - tc = ConvertDateTime(2013, 11, 15, 16, 0 - 1, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 15, 59, 14, 0, false); - - tc = ConvertDateTime(2013, 11, 15, 0 - 1, 32, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 14, 23, 32, 14, 0, false); - - tc = ConvertDateTime(2013, 11, 1 - 1, 16, 32, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 10, 31, 16, 32, 14, 0, false); - - tc = ConvertDateTime(2013, 1 - 1, 15, 16, 32, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 12, 15, 16, 32, 14, 0, false); -} - -TEST(TimeNormCase, MultipleOverflow) { - const absl::TimeZone utc = absl::UTCTimeZone(); - absl::TimeConversion tc = ConvertDateTime(2013, 12, 31, 23, 59, 59 + 1, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - absl::Time::Breakdown bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 1, 0, 0, 0, 0, false); -} - -TEST(TimeNormCase, MultipleUnderflow) { - const absl::TimeZone utc = absl::UTCTimeZone(); - absl::TimeConversion tc = absl::ConvertDateTime(2014, 1, 1, 0, 0, 0 - 1, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - absl::Time::Breakdown bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 31, 23, 59, 59, 0, false); -} - -TEST(TimeNormCase, OverflowLimits) { - const absl::TimeZone utc = absl::UTCTimeZone(); - absl::TimeConversion tc; - absl::Time::Breakdown bd; - - const int kintmax = std::numeric_limits<int>::max(); - tc = absl::ConvertDateTime(0, kintmax, kintmax, kintmax, kintmax, kintmax, - utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 185085715, 11, 27, 12, 21, 7, 0, false); - - const int kintmin = std::numeric_limits<int>::min(); - tc = absl::ConvertDateTime(0, kintmin, kintmin, kintmin, kintmin, kintmin, - utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, -185085717, 10, 31, 10, 37, 52, 0, false); - - const int64_t max_year = std::numeric_limits<int64_t>::max(); - tc = absl::ConvertDateTime(max_year, 12, 31, 23, 59, 59, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - EXPECT_EQ(absl::InfiniteFuture(), tc.pre); - - const int64_t min_year = std::numeric_limits<int64_t>::min(); - tc = absl::ConvertDateTime(min_year, 1, 1, 0, 0, 0, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - EXPECT_EQ(absl::InfinitePast(), tc.pre); -} - -TEST(TimeNormCase, ComplexOverflow) { - const absl::TimeZone utc = absl::UTCTimeZone(); - - absl::TimeConversion tc = - ConvertDateTime(2013, 11, 15, 16, 32, 14 + 123456789, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - absl::Time::Breakdown bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 10, 14, 14, 5, 23, 0, false); - - tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 + 1234567, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2016, 3, 22, 0, 39, 14, 0, false); - - tc = absl::ConvertDateTime(2013, 11, 15, 16 + 123456, 32, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2027, 12, 16, 16, 32, 14, 0, false); - - tc = absl::ConvertDateTime(2013, 11, 15 + 1234, 16, 32, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 4, 2, 16, 32, 14, 0, false); - - tc = absl::ConvertDateTime(2013, 11 + 123, 15, 16, 32, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2024, 2, 15, 16, 32, 14, 0, false); -} - -TEST(TimeNormCase, ComplexUnderflow) { - const absl::TimeZone utc = absl::UTCTimeZone(); - - absl::TimeConversion tc = - absl::ConvertDateTime(1999, 3, 0, 0, 0, 0, utc); // year 400 - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - absl::Time::Breakdown bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 2, 28, 0, 0, 0, 0, false); - - tc = absl::ConvertDateTime(2013, 11, 15, 16, 32, 14 - 123456789, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2009, 12, 17, 18, 59, 5, 0, false); - - tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 - 1234567, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2011, 7, 12, 8, 25, 14, 0, false); - - tc = absl::ConvertDateTime(2013, 11, 15, 16 - 123456, 32, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 10, 16, 16, 32, 14, 0, false); - - tc = absl::ConvertDateTime(2013, 11, 15 - 1234, 16, 32, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2010, 6, 30, 16, 32, 14, 0, false); - - tc = absl::ConvertDateTime(2013, 11 - 123, 15, 16, 32, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2003, 8, 15, 16, 32, 14, 0, false); -} - -TEST(TimeNormCase, Mishmash) { - const absl::TimeZone utc = absl::UTCTimeZone(); - - absl::TimeConversion tc = - absl::ConvertDateTime(2013, 11 - 123, 15 + 1234, 16 - 123456, - 32 + 1234567, 14 - 123456789, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - absl::Time::Breakdown bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 1991, 5, 9, 3, 6, 5, 0, false); - - tc = absl::ConvertDateTime(2013, 11 + 123, 15 - 1234, 16 + 123456, - 32 - 1234567, 14 + 123456789, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2036, 5, 24, 5, 58, 23, 0, false); - - // Here is a normalization case we got wrong for a while. Because the - // day is converted to "1" within a 400-year (146097-day) period, we - // didn't need to roll the month and so we didn't mark it as normalized. - tc = absl::ConvertDateTime(2013, 11, -146097 + 1, 16, 32, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 1613, 11, 1, 16, 32, 14, 0, false); - - // Even though the month overflow compensates for the day underflow, - // this should still be marked as normalized. - tc = absl::ConvertDateTime(2013, 11 + 400 * 12, -146097 + 1, 16, 32, 14, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 1, 16, 32, 14, 0, false); -} - -TEST(TimeNormCase, LeapYears) { - const absl::TimeZone utc = absl::UTCTimeZone(); - - absl::TimeConversion tc = - absl::ConvertDateTime(2013, 2, 28 + 1, 0, 0, 0, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - absl::Time::Breakdown bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 3, 1, 0, 0, 0, 0, false); - - tc = absl::ConvertDateTime(2012, 2, 28 + 1, 0, 0, 0, utc); - EXPECT_FALSE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 2, 29, 0, 0, 0, 0, false); - - tc = absl::ConvertDateTime(2000, 2, 28 + 1, 0, 0, 0, utc); - EXPECT_FALSE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 2000, 2, 29, 0, 0, 0, 0, false); - - tc = absl::ConvertDateTime(1900, 2, 28 + 1, 0, 0, 0, utc); - EXPECT_TRUE(tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - bd = tc.pre.In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, 1900, 3, 1, 0, 0, 0, 0, false); -} - -// Convert all the days from 1970-1-1 to 1970-1-146097 (aka 2369-12-31) -// and check that they normalize to the expected time. 146097 days span -// the 400-year Gregorian cycle used during normalization. -TEST(TimeNormCase, AllTheDays) { - const absl::TimeZone utc = absl::UTCTimeZone(); - absl::Time exp_time = absl::UnixEpoch(); - - for (int day = 1; day <= 146097; ++day) { - absl::TimeConversion tc = absl::ConvertDateTime(1970, 1, day, 0, 0, 0, utc); - EXPECT_EQ(day > 31, tc.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); - EXPECT_EQ(exp_time, tc.pre); - exp_time += absl::Hours(24); - } -} - -} // namespace
diff --git a/absl/time/time_test.cc b/absl/time/time_test.cc index 4f8f58a..74148d5 100644 --- a/absl/time/time_test.cc +++ b/absl/time/time_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -28,6 +28,27 @@ namespace { +#if GTEST_USES_SIMPLE_RE +const char kZoneAbbrRE[] = ".*"; // just punt +#else +const char kZoneAbbrRE[] = "[A-Za-z]{3,4}|[-+][0-9]{2}([0-9]{2})?"; +#endif + +// This helper is a macro so that failed expectations show up with the +// correct line numbers. +#define EXPECT_CIVIL_INFO(ci, y, m, d, h, min, s, off, isdst) \ + do { \ + EXPECT_EQ(y, ci.cs.year()); \ + EXPECT_EQ(m, ci.cs.month()); \ + EXPECT_EQ(d, ci.cs.day()); \ + EXPECT_EQ(h, ci.cs.hour()); \ + EXPECT_EQ(min, ci.cs.minute()); \ + EXPECT_EQ(s, ci.cs.second()); \ + EXPECT_EQ(off, ci.offset); \ + EXPECT_EQ(isdst, ci.is_dst); \ + EXPECT_THAT(ci.zone_abbr, testing::MatchesRegex(kZoneAbbrRE)); \ + } while (0) + // A gMock matcher to match timespec values. Use this matcher like: // timespec ts1, ts2; // EXPECT_THAT(ts1, TimespecMatcher(ts2)); @@ -84,10 +105,10 @@ } TEST(Time, UnixEpoch) { - absl::Time::Breakdown bd = absl::UnixEpoch().In(absl::UTCTimeZone()); - ABSL_INTERNAL_EXPECT_TIME(bd, 1970, 1, 1, 0, 0, 0, 0, false); - EXPECT_EQ(absl::ZeroDuration(), bd.subsecond); - EXPECT_EQ(4, bd.weekday); // Thursday + const auto ci = absl::UTCTimeZone().At(absl::UnixEpoch()); + EXPECT_EQ(absl::CivilSecond(1970, 1, 1, 0, 0, 0), ci.cs); + EXPECT_EQ(absl::ZeroDuration(), ci.subsecond); + EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(absl::CivilDay(ci.cs))); } TEST(Time, Breakdown) { @@ -95,26 +116,26 @@ absl::Time t = absl::UnixEpoch(); // The Unix epoch as seen in NYC. - absl::Time::Breakdown bd = t.In(tz); - ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 19, 0, 0, -18000, false); - EXPECT_EQ(absl::ZeroDuration(), bd.subsecond); - EXPECT_EQ(3, bd.weekday); // Wednesday + auto ci = tz.At(t); + EXPECT_CIVIL_INFO(ci, 1969, 12, 31, 19, 0, 0, -18000, false); + EXPECT_EQ(absl::ZeroDuration(), ci.subsecond); + EXPECT_EQ(absl::Weekday::wednesday, absl::GetWeekday(absl::CivilDay(ci.cs))); // Just before the epoch. t -= absl::Nanoseconds(1); - bd = t.In(tz); - ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 18, 59, 59, -18000, false); - EXPECT_EQ(absl::Nanoseconds(999999999), bd.subsecond); - EXPECT_EQ(3, bd.weekday); // Wednesday + ci = tz.At(t); + EXPECT_CIVIL_INFO(ci, 1969, 12, 31, 18, 59, 59, -18000, false); + EXPECT_EQ(absl::Nanoseconds(999999999), ci.subsecond); + EXPECT_EQ(absl::Weekday::wednesday, absl::GetWeekday(absl::CivilDay(ci.cs))); // Some time later. t += absl::Hours(24) * 2735; t += absl::Hours(18) + absl::Minutes(30) + absl::Seconds(15) + absl::Nanoseconds(9); - bd = t.In(tz); - ABSL_INTERNAL_EXPECT_TIME(bd, 1977, 6, 28, 14, 30, 15, -14400, true); - EXPECT_EQ(8, bd.subsecond / absl::Nanoseconds(1)); - EXPECT_EQ(2, bd.weekday); // Tuesday + ci = tz.At(t); + EXPECT_CIVIL_INFO(ci, 1977, 6, 28, 14, 30, 15, -14400, true); + EXPECT_EQ(8, ci.subsecond / absl::Nanoseconds(1)); + EXPECT_EQ(absl::Weekday::tuesday, absl::GetWeekday(absl::CivilDay(ci.cs))); } TEST(Time, AdditiveOperators) { @@ -550,67 +571,63 @@ absl::ToChronoTime(absl::UnixEpoch() - tick)); } -TEST(Time, ConvertDateTime) { - const absl::TimeZone utc = absl::UTCTimeZone(); - const absl::TimeZone goog = - absl::time_internal::LoadTimeZone("America/Los_Angeles"); +TEST(Time, TimeZoneAt) { const absl::TimeZone nyc = absl::time_internal::LoadTimeZone("America/New_York"); const std::string fmt = "%a, %e %b %Y %H:%M:%S %z (%Z)"; - // A simple case of normalization. - absl::TimeConversion oct32 = ConvertDateTime(2013, 10, 32, 8, 30, 0, goog); - EXPECT_TRUE(oct32.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, oct32.kind); - absl::TimeConversion nov01 = ConvertDateTime(2013, 11, 1, 8, 30, 0, goog); - EXPECT_FALSE(nov01.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, nov01.kind); - EXPECT_EQ(oct32.pre, nov01.pre); - EXPECT_EQ("Fri, 1 Nov 2013 08:30:00 -0700 (PDT)", - absl::FormatTime(fmt, nov01.pre, goog)); + // A non-transition where the civil time is unique. + absl::CivilSecond nov01(2013, 11, 1, 8, 30, 0); + const auto nov01_ci = nyc.At(nov01); + EXPECT_EQ(absl::TimeZone::TimeInfo::UNIQUE, nov01_ci.kind); + EXPECT_EQ("Fri, 1 Nov 2013 08:30:00 -0400 (EDT)", + absl::FormatTime(fmt, nov01_ci.pre, nyc)); + EXPECT_EQ(nov01_ci.pre, nov01_ci.trans); + EXPECT_EQ(nov01_ci.pre, nov01_ci.post); + EXPECT_EQ(nov01_ci.pre, absl::FromCivil(nov01, nyc)); // A Spring DST transition, when there is a gap in civil time // and we prefer the later of the possible interpretations of a // non-existent time. - absl::TimeConversion mar13 = ConvertDateTime(2011, 3, 13, 2, 15, 0, nyc); - EXPECT_FALSE(mar13.normalized); - EXPECT_EQ(absl::TimeConversion::SKIPPED, mar13.kind); + absl::CivilSecond mar13(2011, 3, 13, 2, 15, 0); + const auto mar_ci = nyc.At(mar13); + EXPECT_EQ(absl::TimeZone::TimeInfo::SKIPPED, mar_ci.kind); EXPECT_EQ("Sun, 13 Mar 2011 03:15:00 -0400 (EDT)", - absl::FormatTime(fmt, mar13.pre, nyc)); + absl::FormatTime(fmt, mar_ci.pre, nyc)); EXPECT_EQ("Sun, 13 Mar 2011 03:00:00 -0400 (EDT)", - absl::FormatTime(fmt, mar13.trans, nyc)); + absl::FormatTime(fmt, mar_ci.trans, nyc)); EXPECT_EQ("Sun, 13 Mar 2011 01:15:00 -0500 (EST)", - absl::FormatTime(fmt, mar13.post, nyc)); - EXPECT_EQ(mar13.pre, absl::FromDateTime(2011, 3, 13, 2, 15, 0, nyc)); + absl::FormatTime(fmt, mar_ci.post, nyc)); + EXPECT_EQ(mar_ci.trans, absl::FromCivil(mar13, nyc)); // A Fall DST transition, when civil times are repeated and // we prefer the earlier of the possible interpretations of an // ambiguous time. - absl::TimeConversion nov06 = ConvertDateTime(2011, 11, 6, 1, 15, 0, nyc); - EXPECT_FALSE(nov06.normalized); - EXPECT_EQ(absl::TimeConversion::REPEATED, nov06.kind); + absl::CivilSecond nov06(2011, 11, 6, 1, 15, 0); + const auto nov06_ci = nyc.At(nov06); + EXPECT_EQ(absl::TimeZone::TimeInfo::REPEATED, nov06_ci.kind); EXPECT_EQ("Sun, 6 Nov 2011 01:15:00 -0400 (EDT)", - absl::FormatTime(fmt, nov06.pre, nyc)); + absl::FormatTime(fmt, nov06_ci.pre, nyc)); EXPECT_EQ("Sun, 6 Nov 2011 01:00:00 -0500 (EST)", - absl::FormatTime(fmt, nov06.trans, nyc)); + absl::FormatTime(fmt, nov06_ci.trans, nyc)); EXPECT_EQ("Sun, 6 Nov 2011 01:15:00 -0500 (EST)", - absl::FormatTime(fmt, nov06.post, nyc)); - EXPECT_EQ(nov06.pre, absl::FromDateTime(2011, 11, 6, 1, 15, 0, nyc)); + absl::FormatTime(fmt, nov06_ci.post, nyc)); + EXPECT_EQ(nov06_ci.pre, absl::FromCivil(nov06, nyc)); // Check that (time_t) -1 is handled correctly. - absl::TimeConversion minus1 = ConvertDateTime(1969, 12, 31, 18, 59, 59, nyc); - EXPECT_FALSE(minus1.normalized); - EXPECT_EQ(absl::TimeConversion::UNIQUE, minus1.kind); - EXPECT_EQ(-1, absl::ToTimeT(minus1.pre)); + absl::CivilSecond minus1(1969, 12, 31, 18, 59, 59); + const auto minus1_cl = nyc.At(minus1); + EXPECT_EQ(absl::TimeZone::TimeInfo::UNIQUE, minus1_cl.kind); + EXPECT_EQ(-1, absl::ToTimeT(minus1_cl.pre)); EXPECT_EQ("Wed, 31 Dec 1969 18:59:59 -0500 (EST)", - absl::FormatTime(fmt, minus1.pre, nyc)); + absl::FormatTime(fmt, minus1_cl.pre, nyc)); EXPECT_EQ("Wed, 31 Dec 1969 23:59:59 +0000 (UTC)", - absl::FormatTime(fmt, minus1.pre, utc)); + absl::FormatTime(fmt, minus1_cl.pre, absl::UTCTimeZone())); } -// FromDateTime(year, mon, day, hour, min, sec, UTCTimeZone()) has -// a specialized fastpath implementation which we exercise here. -TEST(Time, FromDateTimeUTC) { +// FromCivil(CivilSecond(year, mon, day, hour, min, sec), UTCTimeZone()) +// has a specialized fastpath implementation, which we exercise here. +TEST(Time, FromCivilUTC) { const absl::TimeZone utc = absl::UTCTimeZone(); const std::string fmt = "%a, %e %b %Y %H:%M:%S %z (%Z)"; const int kMax = std::numeric_limits<int>::max(); @@ -618,65 +635,36 @@ absl::Time t; // 292091940881 is the last positive year to use the fastpath. - t = absl::FromDateTime(292091940881, kMax, kMax, kMax, kMax, kMax, utc); + t = absl::FromCivil( + absl::CivilSecond(292091940881, kMax, kMax, kMax, kMax, kMax), utc); EXPECT_EQ("Fri, 25 Nov 292277026596 12:21:07 +0000 (UTC)", absl::FormatTime(fmt, t, utc)); - t = absl::FromDateTime(292091940882, kMax, kMax, kMax, kMax, kMax, utc); - EXPECT_EQ("infinite-future", absl::FormatTime(fmt, t, utc)); // no overflow - t = absl::FromDateTime( - std::numeric_limits<int64_t>::max(), kMax, kMax, kMax, kMax, kMax, utc); + t = absl::FromCivil( + absl::CivilSecond(292091940882, kMax, kMax, kMax, kMax, kMax), utc); EXPECT_EQ("infinite-future", absl::FormatTime(fmt, t, utc)); // no overflow // -292091936940 is the last negative year to use the fastpath. - t = absl::FromDateTime(-292091936940, kMin, kMin, kMin, kMin, kMin, utc); + t = absl::FromCivil( + absl::CivilSecond(-292091936940, kMin, kMin, kMin, kMin, kMin), utc); EXPECT_EQ("Fri, 1 Nov -292277022657 10:37:52 +0000 (UTC)", absl::FormatTime(fmt, t, utc)); - t = absl::FromDateTime(-292091936941, kMin, kMin, kMin, kMin, kMin, utc); + t = absl::FromCivil( + absl::CivilSecond(-292091936941, kMin, kMin, kMin, kMin, kMin), utc); EXPECT_EQ("infinite-past", absl::FormatTime(fmt, t, utc)); // no underflow - t = absl::FromDateTime( - std::numeric_limits<int64_t>::min(), kMin, kMin, kMin, kMin, kMin, utc); - EXPECT_EQ("infinite-past", absl::FormatTime(fmt, t, utc)); // no overflow // Check that we're counting leap years correctly. - t = absl::FromDateTime(1900, 2, 28, 23, 59, 59, utc); + t = absl::FromCivil(absl::CivilSecond(1900, 2, 28, 23, 59, 59), utc); EXPECT_EQ("Wed, 28 Feb 1900 23:59:59 +0000 (UTC)", absl::FormatTime(fmt, t, utc)); - t = absl::FromDateTime(1900, 3, 1, 0, 0, 0, utc); + t = absl::FromCivil(absl::CivilSecond(1900, 3, 1, 0, 0, 0), utc); EXPECT_EQ("Thu, 1 Mar 1900 00:00:00 +0000 (UTC)", absl::FormatTime(fmt, t, utc)); - t = absl::FromDateTime(2000, 2, 29, 23, 59, 59, utc); + t = absl::FromCivil(absl::CivilSecond(2000, 2, 29, 23, 59, 59), utc); EXPECT_EQ("Tue, 29 Feb 2000 23:59:59 +0000 (UTC)", absl::FormatTime(fmt, t, utc)); - t = absl::FromDateTime(2000, 3, 1, 0, 0, 0, utc); + t = absl::FromCivil(absl::CivilSecond(2000, 3, 1, 0, 0, 0), utc); EXPECT_EQ("Wed, 1 Mar 2000 00:00:00 +0000 (UTC)", absl::FormatTime(fmt, t, utc)); - - // Check normalization. - const std::string ymdhms = "%Y-%m-%d %H:%M:%S"; - t = absl::FromDateTime(2015, 1, 1, 0, 0, 60, utc); - EXPECT_EQ("2015-01-01 00:01:00", absl::FormatTime(ymdhms, t, utc)); - t = absl::FromDateTime(2015, 1, 1, 0, 60, 0, utc); - EXPECT_EQ("2015-01-01 01:00:00", absl::FormatTime(ymdhms, t, utc)); - t = absl::FromDateTime(2015, 1, 1, 24, 0, 0, utc); - EXPECT_EQ("2015-01-02 00:00:00", absl::FormatTime(ymdhms, t, utc)); - t = absl::FromDateTime(2015, 1, 32, 0, 0, 0, utc); - EXPECT_EQ("2015-02-01 00:00:00", absl::FormatTime(ymdhms, t, utc)); - t = absl::FromDateTime(2015, 13, 1, 0, 0, 0, utc); - EXPECT_EQ("2016-01-01 00:00:00", absl::FormatTime(ymdhms, t, utc)); - t = absl::FromDateTime(2015, 13, 32, 60, 60, 60, utc); - EXPECT_EQ("2016-02-03 13:01:00", absl::FormatTime(ymdhms, t, utc)); - t = absl::FromDateTime(2015, 1, 1, 0, 0, -1, utc); - EXPECT_EQ("2014-12-31 23:59:59", absl::FormatTime(ymdhms, t, utc)); - t = absl::FromDateTime(2015, 1, 1, 0, -1, 0, utc); - EXPECT_EQ("2014-12-31 23:59:00", absl::FormatTime(ymdhms, t, utc)); - t = absl::FromDateTime(2015, 1, 1, -1, 0, 0, utc); - EXPECT_EQ("2014-12-31 23:00:00", absl::FormatTime(ymdhms, t, utc)); - t = absl::FromDateTime(2015, 1, -1, 0, 0, 0, utc); - EXPECT_EQ("2014-12-30 00:00:00", absl::FormatTime(ymdhms, t, utc)); - t = absl::FromDateTime(2015, -1, 1, 0, 0, 0, utc); - EXPECT_EQ("2014-11-01 00:00:00", absl::FormatTime(ymdhms, t, utc)); - t = absl::FromDateTime(2015, -1, -1, -1, -1, -1, utc); - EXPECT_EQ("2014-10-29 22:58:59", absl::FormatTime(ymdhms, t, utc)); } TEST(Time, ToTM) { @@ -684,8 +672,10 @@ // Compares the results of ToTM() to gmtime_r() for lots of times over the // course of a few days. - const absl::Time start = absl::FromDateTime(2014, 1, 2, 3, 4, 5, utc); - const absl::Time end = absl::FromDateTime(2014, 1, 5, 3, 4, 5, utc); + const absl::Time start = + absl::FromCivil(absl::CivilSecond(2014, 1, 2, 3, 4, 5), utc); + const absl::Time end = + absl::FromCivil(absl::CivilSecond(2014, 1, 5, 3, 4, 5), utc); for (absl::Time t = start; t < end; t += absl::Seconds(30)) { const struct tm tm_bt = ToTM(t, utc); const time_t tt = absl::ToTimeT(t); @@ -711,12 +701,12 @@ // Checks that the tm_isdst field is correct when in standard time. const absl::TimeZone nyc = absl::time_internal::LoadTimeZone("America/New_York"); - absl::Time t = absl::FromDateTime(2014, 3, 1, 0, 0, 0, nyc); + absl::Time t = absl::FromCivil(absl::CivilSecond(2014, 3, 1, 0, 0, 0), nyc); struct tm tm = ToTM(t, nyc); EXPECT_FALSE(tm.tm_isdst); // Checks that the tm_isdst field is correct when in daylight time. - t = absl::FromDateTime(2014, 4, 1, 0, 0, 0, nyc); + t = absl::FromCivil(absl::CivilSecond(2014, 4, 1, 0, 0, 0), nyc); tm = ToTM(t, nyc); EXPECT_TRUE(tm.tm_isdst); @@ -808,8 +798,8 @@ absl::time_internal::LoadTimeZone("America/New_York"); // Test round-tripping across a skipped transition - absl::Time start = absl::FromDateTime(2014, 3, 9, 0, 0, 0, nyc); - absl::Time end = absl::FromDateTime(2014, 3, 9, 4, 0, 0, nyc); + absl::Time start = absl::FromCivil(absl::CivilHour(2014, 3, 9, 0), nyc); + absl::Time end = absl::FromCivil(absl::CivilHour(2014, 3, 9, 4), nyc); for (absl::Time t = start; t < end; t += absl::Minutes(1)) { struct tm tm = ToTM(t, nyc); absl::Time rt = FromTM(tm, nyc); @@ -817,8 +807,8 @@ } // Test round-tripping across an ambiguous transition - start = absl::FromDateTime(2014, 11, 2, 0, 0, 0, nyc); - end = absl::FromDateTime(2014, 11, 2, 4, 0, 0, nyc); + start = absl::FromCivil(absl::CivilHour(2014, 11, 2, 0), nyc); + end = absl::FromCivil(absl::CivilHour(2014, 11, 2, 4), nyc); for (absl::Time t = start; t < end; t += absl::Minutes(1)) { struct tm tm = ToTM(t, nyc); absl::Time rt = FromTM(tm, nyc); @@ -826,8 +816,8 @@ } // Test round-tripping of unique instants crossing a day boundary - start = absl::FromDateTime(2014, 6, 27, 22, 0, 0, nyc); - end = absl::FromDateTime(2014, 6, 28, 4, 0, 0, nyc); + start = absl::FromCivil(absl::CivilHour(2014, 6, 27, 22), nyc); + end = absl::FromCivil(absl::CivilHour(2014, 6, 28, 4), nyc); for (absl::Time t = start; t < end; t += absl::Minutes(1)) { struct tm tm = ToTM(t, nyc); absl::Time rt = FromTM(tm, nyc); @@ -980,27 +970,27 @@ EXPECT_EQ(min_timespec_sec, ts.tv_sec); EXPECT_EQ(0, ts.tv_nsec); - // Checks how Time::In() saturates on infinities. - absl::Time::Breakdown bd = absl::InfiniteFuture().In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits<int64_t>::max(), 12, 31, 23, + // 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_EQ(absl::InfiniteDuration(), bd.subsecond); - EXPECT_EQ(4, bd.weekday); // Thursday - EXPECT_EQ(365, bd.yearday); - EXPECT_STREQ("-00", bd.zone_abbr); // artifact of absl::Time::In() - bd = absl::InfinitePast().In(utc); - ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits<int64_t>::min(), 1, 1, 0, 0, + EXPECT_EQ(absl::InfiniteDuration(), ci.subsecond); + EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(absl::CivilDay(ci.cs))); + EXPECT_EQ(365, absl::GetYearDay(absl::CivilDay(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_EQ(-absl::InfiniteDuration(), bd.subsecond); - EXPECT_EQ(7, bd.weekday); // Sunday - EXPECT_EQ(1, bd.yearday); - EXPECT_STREQ("-00", bd.zone_abbr); // artifact of absl::Time::In() + EXPECT_EQ(-absl::InfiniteDuration(), ci.subsecond); + EXPECT_EQ(absl::Weekday::sunday, absl::GetWeekday(absl::CivilDay(ci.cs))); + EXPECT_EQ(1, absl::GetYearDay(absl::CivilDay(ci.cs))); + EXPECT_STREQ("-00", ci.zone_abbr); // artifact of TimeZone::At() // Approach the maximal Time value from below. - t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 6, utc); + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 6), utc); EXPECT_EQ("292277026596-12-04T15:30:06+00:00", absl::FormatTime(absl::RFC3339_full, t, utc)); - t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 7, utc); + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 7), utc); EXPECT_EQ("292277026596-12-04T15:30:07+00:00", absl::FormatTime(absl::RFC3339_full, t, utc)); EXPECT_EQ( @@ -1008,21 +998,21 @@ // Checks that we can also get the maximal Time value for a far-east zone. const absl::TimeZone plus14 = absl::FixedTimeZone(14 * 60 * 60); - t = absl::FromDateTime(292277026596, 12, 5, 5, 30, 7, plus14); + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 5, 5, 30, 7), plus14); EXPECT_EQ("292277026596-12-05T05:30:07+14:00", absl::FormatTime(absl::RFC3339_full, t, plus14)); EXPECT_EQ( absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t); // One second later should push us to infinity. - t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 8, utc); + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 8), utc); EXPECT_EQ("infinite-future", absl::FormatTime(absl::RFC3339_full, t, utc)); // Approach the minimal Time value from above. - t = absl::FromDateTime(-292277022657, 1, 27, 8, 29, 53, utc); + t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 53), utc); EXPECT_EQ("-292277022657-01-27T08:29:53+00:00", absl::FormatTime(absl::RFC3339_full, t, utc)); - t = absl::FromDateTime(-292277022657, 1, 27, 8, 29, 52, utc); + t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 52), utc); EXPECT_EQ("-292277022657-01-27T08:29:52+00:00", absl::FormatTime(absl::RFC3339_full, t, utc)); EXPECT_EQ( @@ -1030,14 +1020,15 @@ // Checks that we can also get the minimal Time value for a far-west zone. const absl::TimeZone minus12 = absl::FixedTimeZone(-12 * 60 * 60); - t = absl::FromDateTime(-292277022657, 1, 26, 20, 29, 52, minus12); + t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 26, 20, 29, 52), + minus12); EXPECT_EQ("-292277022657-01-26T20:29:52-12:00", absl::FormatTime(absl::RFC3339_full, t, minus12)); EXPECT_EQ( absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t); // One second before should push us to -infinity. - t = absl::FromDateTime(-292277022657, 1, 27, 8, 29, 51, utc); + t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 51), utc); EXPECT_EQ("infinite-past", absl::FormatTime(absl::RFC3339_full, t, utc)); } @@ -1051,38 +1042,160 @@ absl::time_internal::LoadTimeZone("America/New_York"); const absl::Time max = absl::FromUnixSeconds(std::numeric_limits<int64_t>::max()); - absl::Time::Breakdown bd; + absl::TimeZone::CivilInfo ci; absl::Time t; // The maximal time converted in each zone. - bd = max.In(syd); - ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 5, 2, 30, 7, 39600, true); - t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 7, syd); + ci = syd.At(max); + EXPECT_CIVIL_INFO(ci, 292277026596, 12, 5, 2, 30, 7, 39600, true); + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 5, 2, 30, 7), syd); EXPECT_EQ(max, t); - bd = max.In(nyc); - ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 4, 10, 30, 7, -18000, false); - t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 7, nyc); + ci = nyc.At(max); + EXPECT_CIVIL_INFO(ci, 292277026596, 12, 4, 10, 30, 7, -18000, false); + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 10, 30, 7), nyc); EXPECT_EQ(max, t); // One second later should push us to infinity. - t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 8, syd); + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 5, 2, 30, 8), syd); EXPECT_EQ(absl::InfiniteFuture(), t); - t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 8, nyc); + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 10, 30, 8), nyc); EXPECT_EQ(absl::InfiniteFuture(), t); // And we should stick there. - t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 9, syd); + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 5, 2, 30, 9), syd); EXPECT_EQ(absl::InfiniteFuture(), t); - t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 9, nyc); + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 10, 30, 9), nyc); EXPECT_EQ(absl::InfiniteFuture(), t); // All the way up to a saturated date/time, without overflow. - t = absl::FromDateTime( - std::numeric_limits<int64_t>::max(), 12, 31, 23, 59, 59, syd); + t = absl::FromCivil(absl::CivilSecond::max(), syd); EXPECT_EQ(absl::InfiniteFuture(), t); - t = absl::FromDateTime( - std::numeric_limits<int64_t>::max(), 12, 31, 23, 59, 59, nyc); + t = absl::FromCivil(absl::CivilSecond::max(), nyc); EXPECT_EQ(absl::InfiniteFuture(), t); } +TEST(Time, FromCivilAlignment) { + const absl::TimeZone utc = absl::UTCTimeZone(); + const absl::CivilSecond cs(2015, 2, 3, 4, 5, 6); + absl::Time t = absl::FromCivil(cs, utc); + EXPECT_EQ("2015-02-03T04:05:06+00:00", absl::FormatTime(t, utc)); + t = absl::FromCivil(absl::CivilMinute(cs), utc); + EXPECT_EQ("2015-02-03T04:05:00+00:00", absl::FormatTime(t, utc)); + t = absl::FromCivil(absl::CivilHour(cs), utc); + EXPECT_EQ("2015-02-03T04:00:00+00:00", absl::FormatTime(t, utc)); + t = absl::FromCivil(absl::CivilDay(cs), utc); + EXPECT_EQ("2015-02-03T00:00:00+00:00", absl::FormatTime(t, utc)); + t = absl::FromCivil(absl::CivilMonth(cs), utc); + EXPECT_EQ("2015-02-01T00:00:00+00:00", absl::FormatTime(t, utc)); + t = absl::FromCivil(absl::CivilYear(cs), utc); + EXPECT_EQ("2015-01-01T00:00:00+00:00", absl::FormatTime(t, utc)); +} + +TEST(Time, LegacyDateTime) { + const absl::TimeZone utc = absl::UTCTimeZone(); + const std::string ymdhms = "%Y-%m-%d %H:%M:%S"; + const int kMax = std::numeric_limits<int>::max(); + 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); + 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 + + // Check normalization. + EXPECT_TRUE(absl::ConvertDateTime(2013, 10, 32, 8, 30, 0, utc).normalized); + t = absl::FromDateTime(2015, 1, 1, 0, 0, 60, utc); + EXPECT_EQ("2015-01-01 00:01:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 1, 1, 0, 60, 0, utc); + EXPECT_EQ("2015-01-01 01:00:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 1, 1, 24, 0, 0, utc); + EXPECT_EQ("2015-01-02 00:00:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 1, 32, 0, 0, 0, utc); + EXPECT_EQ("2015-02-01 00:00:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 13, 1, 0, 0, 0, utc); + EXPECT_EQ("2016-01-01 00:00:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 13, 32, 60, 60, 60, utc); + EXPECT_EQ("2016-02-03 13:01:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 1, 1, 0, 0, -1, utc); + EXPECT_EQ("2014-12-31 23:59:59", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 1, 1, 0, -1, 0, utc); + EXPECT_EQ("2014-12-31 23:59:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 1, 1, -1, 0, 0, utc); + EXPECT_EQ("2014-12-31 23:00:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 1, -1, 0, 0, 0, utc); + EXPECT_EQ("2014-12-30 00:00:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, -1, 1, 0, 0, 0, utc); + EXPECT_EQ("2014-11-01 00:00:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, -1, -1, -1, -1, -1, utc); + EXPECT_EQ("2014-10-29 22:58:59", absl::FormatTime(ymdhms, t, utc)); +} + +TEST(Time, NextTransitionUTC) { + const auto tz = absl::UTCTimeZone(); + absl::TimeZone::CivilTransition trans; + + auto t = absl::InfinitePast(); + EXPECT_FALSE(tz.NextTransition(t, &trans)); + + t = absl::InfiniteFuture(); + EXPECT_FALSE(tz.NextTransition(t, &trans)); +} + +TEST(Time, PrevTransitionUTC) { + const auto tz = absl::UTCTimeZone(); + absl::TimeZone::CivilTransition trans; + + auto t = absl::InfiniteFuture(); + EXPECT_FALSE(tz.PrevTransition(t, &trans)); + + t = absl::InfinitePast(); + EXPECT_FALSE(tz.PrevTransition(t, &trans)); +} + +TEST(Time, NextTransitionNYC) { + const auto tz = absl::time_internal::LoadTimeZone("America/New_York"); + absl::TimeZone::CivilTransition trans; + + auto t = absl::FromCivil(absl::CivilSecond(2018, 6, 30, 0, 0, 0), tz); + EXPECT_TRUE(tz.NextTransition(t, &trans)); + EXPECT_EQ(absl::CivilSecond(2018, 11, 4, 2, 0, 0), trans.from); + EXPECT_EQ(absl::CivilSecond(2018, 11, 4, 1, 0, 0), trans.to); + + t = absl::InfiniteFuture(); + EXPECT_FALSE(tz.NextTransition(t, &trans)); + + t = absl::InfinitePast(); + EXPECT_TRUE(tz.NextTransition(t, &trans)); + if (trans.from == absl::CivilSecond(1918, 03, 31, 2, 0, 0)) { + // It looks like the tzdata is only 32 bit (probably macOS), + // which bottoms out at 1901-12-13T20:45:52+00:00. + EXPECT_EQ(absl::CivilSecond(1918, 3, 31, 3, 0, 0), trans.to); + } else { + EXPECT_EQ(absl::CivilSecond(1883, 11, 18, 12, 3, 58), trans.from); + EXPECT_EQ(absl::CivilSecond(1883, 11, 18, 12, 0, 0), trans.to); + } +} + +TEST(Time, PrevTransitionNYC) { + const auto tz = absl::time_internal::LoadTimeZone("America/New_York"); + absl::TimeZone::CivilTransition trans; + + auto t = absl::FromCivil(absl::CivilSecond(2018, 6, 30, 0, 0, 0), tz); + EXPECT_TRUE(tz.PrevTransition(t, &trans)); + EXPECT_EQ(absl::CivilSecond(2018, 3, 11, 2, 0, 0), trans.from); + EXPECT_EQ(absl::CivilSecond(2018, 3, 11, 3, 0, 0), trans.to); + + t = absl::InfinitePast(); + EXPECT_FALSE(tz.PrevTransition(t, &trans)); + + t = absl::InfiniteFuture(); + EXPECT_TRUE(tz.PrevTransition(t, &trans)); + // We have a transition but we don't know which one. +} + } // namespace
diff --git a/absl/time/time_zone_test.cc b/absl/time/time_zone_test.cc index 43d9190..8f1e74a 100644 --- a/absl/time/time_zone_test.cc +++ b/absl/time/time_zone_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel index 32f690c..7da0003 100644 --- a/absl/types/BUILD.bazel +++ b/absl/types/BUILD.bazel
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -15,7 +15,7 @@ # load( - "//absl:copts.bzl", + "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_TEST_COPTS", "ABSL_EXCEPTIONS_FLAG", @@ -168,6 +168,7 @@ deps = [ ":bad_optional_access", "//absl/base:config", + "//absl/base:core_headers", "//absl/memory", "//absl/meta:type_traits", "//absl/utility", @@ -286,6 +287,7 @@ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, deps = [ ":variant", + "//absl/base:config", "//absl/base:exception_safety_testing", "//absl/memory", "@com_google_googletest//:gtest_main",
diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt index 2f2e3a7..8afde46 100644 --- a/absl/types/CMakeLists.txt +++ b/absl/types/CMakeLists.txt
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -13,216 +13,306 @@ # See the License for the specific language governing permissions and # limitations under the License. # - -list(APPEND TYPES_PUBLIC_HEADERS - "any.h" - "bad_any_cast.h" - "bad_optional_access.h" - "optional.h" - "span.h" - "variant.h" -) - - -# any library -absl_header_library( - TARGET - absl_any - PUBLIC_LIBRARIES - absl::bad_any_cast - absl::base - absl::meta - absl::utility - PRIVATE_COMPILE_FLAGS - ${ABSL_EXCEPTIONS_FLAG} - EXPORT_NAME +absl_cc_library( + NAME any -) - -# span library -absl_header_library( - TARGET - absl_span - PUBLIC_LIBRARIES + HDRS + "any.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::bad_any_cast + absl::config + absl::core_headers + absl::type_traits absl::utility - EXPORT_NAME - span + PUBLIC ) - -# bad_any_cast library -list(APPEND BAD_ANY_CAST_SRC - "bad_any_cast.cc" - ${TYPES_PUBLIC_HEADERS} -) - -absl_library( - TARGET - absl_bad_any_cast - SOURCES - ${BAD_ANY_CAST_SRC} - PUBLIC_LIBRARIES - EXPORT_NAME +absl_cc_library( + NAME bad_any_cast + HDRS + "bad_any_cast.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::bad_any_cast_impl + absl::config + PUBLIC ) - -# optional library -list(APPEND OPTIONAL_SRC - "optional.cc" -) - -absl_library( - TARGET - absl_optional - SOURCES - ${OPTIONAL_SRC} - PUBLIC_LIBRARIES - absl::bad_optional_access +absl_cc_library( + NAME + bad_any_cast_impl + SRCS + "bad_any_cast.h" + "bad_any_cast.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS absl::base - absl::memory - absl::meta - absl::utility - EXPORT_NAME - optional + absl::config ) - -set(BAD_OPTIONAL_ACCESS_SRC "bad_optional_access.cc") -set(BAD_OPTIONAL_ACCESS_LIBRARIES absl::base) - -absl_library( - TARGET - absl_bad_optional_access - SOURCES - ${BAD_OPTIONAL_ACCESS_SRC} - PUBLIC_LIBRARIES - ${BAD_OPTIONAL_ACCESS_PUBLIC_LIBRARIES} - EXPORT_NAME - bad_optional_access -) - -# variant library -absl_library( - TARGET - absl_variant - SOURCES - "bad_variant_access.h" "bad_variant_access.cc" "variant.h" "internal/variant.h" - PUBLIC_LIBRARIES - absl::base absl::meta absl::utility - PRIVATE_COMPILE_FLAGS - ${ABSL_EXCEPTIONS_FLAG} - EXPORT_NAME - variant -) - -# -## TESTS -# - - -# test any_test -set(ANY_TEST_SRC "any_test.cc") -set(ANY_TEST_PUBLIC_LIBRARIES absl::base absl::throw_delegate absl::any absl::bad_any_cast test_instance_tracker_lib) - -absl_test( - TARGET +absl_cc_test( + NAME any_test - SOURCES - ${ANY_TEST_SRC} - PUBLIC_LIBRARIES - ${ANY_TEST_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS + SRCS + "any_test.cc" + COPTS + ${ABSL_TEST_COPTS} ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::any + absl::base + absl::config + absl::exception_testing + absl::test_instance_tracker + gmock_main ) - -# test any_test_noexceptions -absl_test( - TARGET +absl_cc_test( + NAME any_test_noexceptions - SOURCES - ${ANY_TEST_SRC} - PUBLIC_LIBRARIES - ${ANY_TEST_PUBLIC_LIBRARIES} + SRCS + "any_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::any + absl::base + absl::config + absl::exception_testing + absl::test_instance_tracker + gmock_main ) -# test any_exception_safety_test -set(ANY_EXCEPTION_SAFETY_TEST_SRC "any_exception_safety_test.cc") -set(ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES - absl::any - absl::base - absl_base_internal_exception_safety_testing -) - -absl_test( - TARGET +absl_cc_test( + NAME any_exception_safety_test - SOURCES - ${ANY_EXCEPTION_SAFETY_TEST_SRC} - PUBLIC_LIBRARIES - ${ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS + SRCS + "any_exception_safety_test.cc" + COPTS + ${ABSL_TEST_COPTS} ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::any + absl::exception_safety_testing + gmock_main ) +absl_cc_library( + NAME + span + HDRS + "span.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::algorithm + absl::core_headers + absl::throw_delegate + absl::type_traits + PUBLIC +) -# test span_test -set(SPAN_TEST_SRC "span_test.cc") -set(SPAN_TEST_PUBLIC_LIBRARIES absl::base absl::strings absl::throw_delegate absl::span test_instance_tracker_lib) - -absl_test( - TARGET +absl_cc_test( + NAME span_test - SOURCES - ${SPAN_TEST_SRC} - PUBLIC_LIBRARIES - ${SPAN_TEST_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS + SRCS + "span_test.cc" + COPTS + ${ABSL_TEST_COPTS} ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::span + absl::base + absl::config + absl::core_headers + absl::exception_testing + absl::fixed_array + absl::inlined_vector + absl::hash_testing + absl::strings + gmock_main ) - -# test span_test_noexceptions -absl_test( - TARGET +absl_cc_test( + NAME span_test_noexceptions - SOURCES - ${SPAN_TEST_SRC} - PUBLIC_LIBRARIES - ${SPAN_TEST_PUBLIC_LIBRARIES} + SRCS + "span_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::span + absl::base + absl::config + absl::core_headers + absl::exception_testing + absl::fixed_array + absl::inlined_vector + absl::hash_testing + absl::strings + gmock_main ) - - -# test optional_test -set(OPTIONAL_TEST_SRC "optional_test.cc") -set(OPTIONAL_TEST_PUBLIC_LIBRARIES absl::base absl::throw_delegate absl::optional absl_bad_optional_access) - -absl_test( - TARGET - optional_test - SOURCES - ${OPTIONAL_TEST_SRC} - PUBLIC_LIBRARIES - ${OPTIONAL_TEST_PUBLIC_LIBRARIES} +absl_cc_library( + NAME + optional + HDRS + "optional.h" + SRCS + "optional.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::bad_optional_access + absl::config + absl::core_headers + absl::memory + absl::type_traits + absl::utility + PUBLIC ) - -# test optional_exception_safety_test -set(OPTIONAL_EXCEPTION_SAFETY_TEST_SRC "optional_exception_safety_test.cc") -set(OPTIONAL_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES - absl::optional - absl_base_internal_exception_safety_testing -) - -absl_test( - TARGET - optional_exception_safety_test - SOURCES - ${OPTIONAL_EXCEPTION_SAFETY_TEST_SRC} - PUBLIC_LIBRARIES - ${OPTIONAL_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS +absl_cc_library( + NAME + bad_optional_access + HDRS + "bad_optional_access.h" + SRCS + "bad_optional_access.cc" + COPTS + ${ABSL_DEFAULT_COPTS} ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::base + absl::config + PUBLIC ) + +absl_cc_library( + NAME + bad_variant_access + HDRS + "bad_variant_access.h" + SRCS + "bad_variant_access.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::base + absl::config + PUBLIC +) + +absl_cc_test( + NAME + optional_test + SRCS + "optional_test.cc" + COPTS + ${ABSL_TEST_COPTS} + ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::optional + absl::base + absl::config + absl::type_traits + absl::strings + gmock_main +) + +absl_cc_test( + NAME + optional_exception_safety_test + SRCS + "optional_exception_safety_test.cc" + COPTS + ${ABSL_TEST_COPTS} + ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::optional + absl::exception_safety_testing + gmock_main +) + +absl_cc_library( + NAME + variant + HDRS + "variant.h" + SRCS + "internal/variant.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::bad_variant_access + absl::base_internal + absl::config + absl::core_headers + absl::type_traits + absl::utility + PUBLIC +) + +absl_cc_test( + NAME + variant_test + SRCS + "variant_test.cc" + COPTS + ${ABSL_TEST_COPTS} + ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::variant + absl::config + absl::core_headers + absl::memory + absl::type_traits + absl::strings + gmock_main +) + +# TODO(cohenjon,zhangxy) Figure out why this test is failing on gcc 4.8 +if(CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.9) +absl_cc_test( + NAME + variant_exception_safety_test + SRCS + "variant_exception_safety_test.cc" + COPTS + ${ABSL_TEST_COPTS} + ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::variant + absl::config + absl::exception_safety_testing + absl::memory + gmock_main +) +endif()
diff --git a/absl/types/any.h b/absl/types/any.h index a973c6d..f3a3281 100644 --- a/absl/types/any.h +++ b/absl/types/any.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -58,7 +58,7 @@ #ifdef ABSL_HAVE_STD_ANY -#include <any> +#include <any> // IWYU pragma: export namespace absl { using std::any;
diff --git a/absl/types/any_exception_safety_test.cc b/absl/types/any_exception_safety_test.cc index f9dd8c4..5d7d8a5 100644 --- a/absl/types/any_exception_safety_test.cc +++ b/absl/types/any_exception_safety_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -135,6 +135,7 @@ EXPECT_TRUE(strong_empty_any_tester.Test(assign_val)); EXPECT_TRUE(strong_empty_any_tester.Test(move)); } + // libstdc++ std::any fails this test #if !defined(ABSL_HAVE_STD_ANY) TEST(AnyExceptionSafety, Emplace) {
diff --git a/absl/types/any_test.cc b/absl/types/any_test.cc index 115e78d..a6351bf 100644 --- a/absl/types/any_test.cc +++ b/absl/types/any_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/types/bad_any_cast.cc b/absl/types/bad_any_cast.cc index 2e2fd29..505919a 100644 --- a/absl/types/bad_any_cast.cc +++ b/absl/types/bad_any_cast.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/types/bad_any_cast.h b/absl/types/bad_any_cast.h index 6039013..8d020ed 100644 --- a/absl/types/bad_any_cast.h +++ b/absl/types/bad_any_cast.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/types/bad_optional_access.cc b/absl/types/bad_optional_access.cc index 5587077..a791c7c 100644 --- a/absl/types/bad_optional_access.cc +++ b/absl/types/bad_optional_access.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/types/bad_optional_access.h b/absl/types/bad_optional_access.h index c6c2746..add5c45 100644 --- a/absl/types/bad_optional_access.h +++ b/absl/types/bad_optional_access.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/types/bad_variant_access.cc b/absl/types/bad_variant_access.cc index d27d775..a4325c8 100644 --- a/absl/types/bad_variant_access.cc +++ b/absl/types/bad_variant_access.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/types/bad_variant_access.h b/absl/types/bad_variant_access.h index e7355a5..637db43 100644 --- a/absl/types/bad_variant_access.h +++ b/absl/types/bad_variant_access.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/types/internal/variant.h b/absl/types/internal/variant.h index eff4fef..5ca66e2 100644 --- a/absl/types/internal/variant.h +++ b/absl/types/internal/variant.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -1234,23 +1234,29 @@ // Base that is dependent on whether or not the move-assign can be trivial. template <class... T> using VariantMoveAssignBase = absl::conditional_t< - absl::disjunction<absl::conjunction<absl::is_move_assignable<Union<T...>>, - std::is_move_constructible<Union<T...>>, - std::is_destructible<Union<T...>>>, - absl::negation<absl::conjunction< - std::is_move_constructible<T>..., - absl::is_move_assignable<T>...>>>::value, + absl::disjunction< + absl::conjunction<absl::is_move_assignable<Union<T...>>, + std::is_move_constructible<Union<T...>>, + std::is_destructible<Union<T...>>>, + absl::negation<absl::conjunction<std::is_move_constructible<T>..., + // Note: We're not qualifying this with + // absl:: because it doesn't compile + // under MSVC. + is_move_assignable<T>...>>>::value, VariantCopyBase<T...>, VariantMoveAssignBaseNontrivial<T...>>; // Base that is dependent on whether or not the copy-assign can be trivial. template <class... T> using VariantCopyAssignBase = absl::conditional_t< - absl::disjunction<absl::conjunction<absl::is_copy_assignable<Union<T...>>, - std::is_copy_constructible<Union<T...>>, - std::is_destructible<Union<T...>>>, - absl::negation<absl::conjunction< - std::is_copy_constructible<T>..., - absl::is_copy_assignable<T>...>>>::value, + absl::disjunction< + absl::conjunction<absl::is_copy_assignable<Union<T...>>, + std::is_copy_constructible<Union<T...>>, + std::is_destructible<Union<T...>>>, + absl::negation<absl::conjunction<std::is_copy_constructible<T>..., + // Note: We're not qualifying this with + // absl:: because it doesn't compile + // under MSVC. + is_copy_assignable<T>...>>>::value, VariantMoveAssignBase<T...>, VariantCopyAssignBaseNontrivial<T...>>; template <class... T> @@ -1542,8 +1548,8 @@ variant<Types...>* w; template <std::size_t I> void operator()(SizeT<I>) const { - using std::swap; - swap(VariantCoreAccess::Access<I>(*v), VariantCoreAccess::Access<I>(*w)); + type_traits_internal::Swap(VariantCoreAccess::Access<I>(*v), + VariantCoreAccess::Access<I>(*w)); } void operator()(SizeT<variant_npos>) const {} @@ -1598,11 +1604,12 @@ template <typename Variant, typename... Ts> struct VariantHashBase<Variant, absl::enable_if_t<absl::conjunction< - type_traits_internal::IsHashEnabled<Ts>...>::value>, + type_traits_internal::IsHashable<Ts>...>::value>, Ts...> { using argument_type = Variant; using result_type = size_t; size_t operator()(const Variant& var) const { + type_traits_internal::AssertHashEnabled<Ts...>(); if (var.valueless_by_exception()) { return 239799884; }
diff --git a/absl/types/optional.cc b/absl/types/optional.cc index ef27290..44ff829 100644 --- a/absl/types/optional.cc +++ b/absl/types/optional.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/types/optional.h b/absl/types/optional.h index 1421001..f0ae9a1 100644 --- a/absl/types/optional.h +++ b/absl/types/optional.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -36,11 +36,12 @@ #define ABSL_TYPES_OPTIONAL_H_ #include "absl/base/config.h" +#include "absl/memory/memory.h" #include "absl/utility/utility.h" #ifdef ABSL_HAVE_STD_OPTIONAL -#include <optional> +#include <optional> // IWYU pragma: export namespace absl { using std::bad_optional_access; @@ -60,7 +61,6 @@ #include <utility> #include "absl/base/attributes.h" -#include "absl/memory/memory.h" #include "absl/meta/type_traits.h" #include "absl/types/bad_optional_access.h" @@ -114,10 +114,6 @@ // need the inline variable support in C++17 for external linkage. // * Throws `absl::bad_optional_access` instead of // `std::bad_optional_access`. -// * `optional::swap()` and `absl::swap()` relies on -// `std::is_(nothrow_)swappable()`, which has been introduced in C++17. -// As a workaround, we assume `is_swappable()` is always `true` -// and `is_nothrow_swappable()` is the same as `std::is_trivial()`. // * `make_optional()` cannot be declared `constexpr` due to the absence of // guaranteed copy elision. // * The move constructor's `noexcept` specification is stronger, i.e. if the @@ -163,7 +159,7 @@ // This class stores the data in optional<T>. // It is specialized based on whether T is trivially destructible. // This is the specialization for non trivially destructible type. -template <typename T, bool = std::is_trivially_destructible<T>::value> +template <typename T, bool unused = std::is_trivially_destructible<T>::value> class optional_data_dtor_base { struct dummy_type { static_assert(sizeof(T) % sizeof(empty_struct) == 0, ""); @@ -261,10 +257,10 @@ // have trivial move but nontrivial copy. // Also, we should be checking is_trivially_copyable here, which is not // supported now, so we use is_trivially_* traits instead. -template <typename T, bool = absl::is_trivially_copy_constructible<T>::value&& - absl::is_trivially_copy_assignable< - typename std::remove_cv<T>::type>::value&& - std::is_trivially_destructible<T>::value> +template <typename T, + bool unused = absl::is_trivially_copy_constructible<T>::value&& + absl::is_trivially_copy_assignable<typename std::remove_cv< + T>::type>::value&& std::is_trivially_destructible<T>::value> class optional_data; // Trivially copyable types @@ -295,7 +291,7 @@ optional_data() = default; - optional_data(const optional_data& rhs) { + optional_data(const optional_data& rhs) : optional_data_base<T>() { if (rhs.engaged_) { this->construct(rhs.data_); } @@ -303,7 +299,8 @@ optional_data(optional_data&& rhs) noexcept( absl::default_allocator_is_nothrow::value || - std::is_nothrow_move_constructible<T>::value) { + std::is_nothrow_move_constructible<T>::value) + : optional_data_base<T>() { if (rhs.engaged_) { this->construct(std::move(rhs.data_)); } @@ -403,23 +400,24 @@ }; template <typename T> -constexpr copy_traits get_ctor_copy_traits() { - return std::is_copy_constructible<T>::value - ? copy_traits::copyable - : std::is_move_constructible<T>::value ? copy_traits::movable - : copy_traits::non_movable; -} +struct ctor_copy_traits { + static constexpr copy_traits traits = + std::is_copy_constructible<T>::value + ? copy_traits::copyable + : std::is_move_constructible<T>::value ? copy_traits::movable + : copy_traits::non_movable; +}; template <typename T> -constexpr copy_traits get_assign_copy_traits() { - return absl::is_copy_assignable<T>::value && - std::is_copy_constructible<T>::value - ? copy_traits::copyable - : absl::is_move_assignable<T>::value && - std::is_move_constructible<T>::value - ? copy_traits::movable - : copy_traits::non_movable; -} +struct assign_copy_traits { + static constexpr copy_traits traits = + absl::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value + ? copy_traits::copyable + : absl::is_move_assignable<T>::value && + std::is_move_constructible<T>::value + ? copy_traits::movable + : copy_traits::non_movable; +}; // Whether T is constructible or convertible from optional<U>. template <typename T, typename U> @@ -467,6 +465,7 @@ using argument_type = absl::optional<T>; using result_type = size_t; size_t operator()(const absl::optional<T>& opt) const { + absl::type_traits_internal::AssertHashEnabled<absl::remove_const_t<T>>(); if (opt) { return std::hash<absl::remove_const_t<T> >()(*opt); } else { @@ -484,9 +483,9 @@ template <typename T> class optional : private optional_internal::optional_data<T>, private optional_internal::optional_ctor_base< - optional_internal::get_ctor_copy_traits<T>()>, + optional_internal::ctor_copy_traits<T>::traits>, private optional_internal::optional_assign_base< - optional_internal::get_assign_copy_traits<T>()> { + optional_internal::assign_copy_traits<T>::traits> { using data_base = optional_internal::optional_data<T>; public: @@ -511,10 +510,11 @@ // the arguments `std::forward<Args>(args)...` within the `optional`. // (The `in_place_t` is a tag used to indicate that the contained object // should be constructed in-place.) - // - // TODO(absl-team): Add std::is_constructible<T, Args&&...> SFINAE. - template <typename... Args> - constexpr explicit optional(in_place_t, Args&&... args) + template <typename InPlaceT, typename... Args, + absl::enable_if_t<absl::conjunction< + std::is_same<InPlaceT, in_place_t>, + std::is_constructible<T, Args&&...> >::value>* = nullptr> + constexpr explicit optional(InPlaceT, Args&&... args) : data_base(in_place_t(), absl::forward<Args>(args)...) {} // Constructs a non-empty `optional` direct-initialized value of type `T` from @@ -750,11 +750,10 @@ // Swap, standard semantics void swap(optional& rhs) noexcept( std::is_nothrow_move_constructible<T>::value&& - std::is_trivial<T>::value) { + type_traits_internal::IsNothrowSwappable<T>::value) { if (*this) { if (rhs) { - using std::swap; - swap(**this, *rhs); + type_traits_internal::Swap(**this, *rhs); } else { rhs.construct(std::move(**this)); this->destruct(); @@ -906,12 +905,10 @@ // // Performs a swap between two `absl::optional` objects, using standard // semantics. -// -// NOTE: we assume `is_swappable()` is always `true`. A compile error will -// result if this is not the case. -template <typename T, - typename std::enable_if<std::is_move_constructible<T>::value, - bool>::type = false> +template <typename T, typename std::enable_if< + std::is_move_constructible<T>::value && + type_traits_internal::IsSwappable<T>::value, + bool>::type = false> void swap(optional<T>& a, optional<T>& b) noexcept(noexcept(a.swap(b))) { a.swap(b); }
diff --git a/absl/types/optional_exception_safety_test.cc b/absl/types/optional_exception_safety_test.cc index d117ee5..aaf8ebc 100644 --- a/absl/types/optional_exception_safety_test.cc +++ b/absl/types/optional_exception_safety_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/types/optional_test.cc b/absl/types/optional_test.cc index d90db9f..0665488 100644 --- a/absl/types/optional_test.cc +++ b/absl/types/optional_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -157,6 +157,16 @@ NonMovable& operator=(NonMovable&&) = delete; }; +struct NoDefault { + NoDefault() = delete; + NoDefault(const NoDefault&) {} + NoDefault& operator=(const NoDefault&) { return *this; } +}; + +struct ConvertsFromInPlaceT { + ConvertsFromInPlaceT(absl::in_place_t) {} // NOLINT +}; + TEST(optionalTest, DefaultConstructor) { absl::optional<int> empty; EXPECT_FALSE(empty); @@ -337,16 +347,18 @@ static_assert((*opt2).x == ConstexprType::kCtorInitializerList, ""); #endif - // TODO(absl-team): uncomment these when std::is_constructible<T, Args&&...> - // SFINAE is added to optional::optional(absl::in_place_t, Args&&...). - // struct I { - // I(absl::in_place_t); - // }; + EXPECT_FALSE((std::is_constructible<absl::optional<ConvertsFromInPlaceT>, + absl::in_place_t>::value)); + EXPECT_FALSE((std::is_constructible<absl::optional<ConvertsFromInPlaceT>, + const absl::in_place_t&>::value)); + EXPECT_TRUE( + (std::is_constructible<absl::optional<ConvertsFromInPlaceT>, + absl::in_place_t, absl::in_place_t>::value)); - // EXPECT_FALSE((std::is_constructible<absl::optional<I>, - // absl::in_place_t>::value)); - // EXPECT_FALSE((std::is_constructible<absl::optional<I>, const - // absl::in_place_t&>::value)); + EXPECT_FALSE((std::is_constructible<absl::optional<NoDefault>, + absl::in_place_t>::value)); + EXPECT_FALSE((std::is_constructible<absl::optional<NoDefault>, + absl::in_place_t&&>::value)); } // template<U=T> optional(U&&); @@ -1042,9 +1054,9 @@ // test exception throw on value() absl::optional<int> empty; #ifdef ABSL_HAVE_EXCEPTIONS - EXPECT_THROW(empty.value(), absl::bad_optional_access); + EXPECT_THROW((void)empty.value(), absl::bad_optional_access); #else - EXPECT_DEATH(empty.value(), "Bad optional access"); + EXPECT_DEATH((void)empty.value(), "Bad optional access"); #endif // test constexpr value() @@ -1476,8 +1488,8 @@ TEST(optionalTest, ValueType) { EXPECT_TRUE((std::is_same<absl::optional<int>::value_type, int>::value)); - EXPECT_TRUE( - (std::is_same<absl::optional<std::string>::value_type, std::string>::value)); + EXPECT_TRUE((std::is_same<absl::optional<std::string>::value_type, + std::string>::value)); EXPECT_FALSE( (std::is_same<absl::optional<int>::value_type, absl::nullopt_t>::value)); } @@ -1504,18 +1516,19 @@ static_assert(is_hash_enabled_for<absl::optional<int>>::value, ""); static_assert(is_hash_enabled_for<absl::optional<Hashable>>::value, ""); + static_assert( + absl::type_traits_internal::IsHashable<absl::optional<int>>::value, ""); + static_assert( + absl::type_traits_internal::IsHashable<absl::optional<Hashable>>::value, + ""); + absl::type_traits_internal::AssertHashEnabled<absl::optional<int>>(); + absl::type_traits_internal::AssertHashEnabled<absl::optional<Hashable>>(); -#if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \ - _LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11) - // For MSVC and libc++ (< 4.0 and c++14), std::hash primary template has a - // static_assert to catch any user-defined type that doesn't provide a hash - // specialization. So instantiating std::hash<absl::optional<T>> will result - // in a hard error which is not SFINAE friendly. -#define ABSL_STD_HASH_NOT_SFINAE_FRIENDLY 1 -#endif - -#ifndef ABSL_STD_HASH_NOT_SFINAE_FRIENDLY +#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ static_assert(!is_hash_enabled_for<absl::optional<NonHashable>>::value, ""); + static_assert(!absl::type_traits_internal::IsHashable< + absl::optional<NonHashable>>::value, + ""); #endif // libstdc++ std::optional is missing remove_const_t, i.e. it's using @@ -1623,4 +1636,29 @@ EXPECT_TRUE(absl::is_copy_assignable<absl::optional<AnyLike>>::value); } +#if !defined(ABSL_HAVE_STD_OPTIONAL) && !defined(_LIBCPP_VERSION) +struct NestedClassBug { + struct Inner { + bool dummy = false; + }; + absl::optional<Inner> value; +}; + +TEST(optionalTest, InPlaceTSFINAEBug) { + NestedClassBug b; + ((void)b); + using Inner = NestedClassBug::Inner; + + EXPECT_TRUE((std::is_default_constructible<Inner>::value)); + EXPECT_TRUE((std::is_constructible<Inner>::value)); + EXPECT_TRUE( + (std::is_constructible<absl::optional<Inner>, absl::in_place_t>::value)); + + absl::optional<Inner> o(absl::in_place); + EXPECT_TRUE(o.has_value()); + o.emplace(); + EXPECT_TRUE(o.has_value()); +} +#endif // !defined(ABSL_HAVE_STD_OPTIONAL) && !defined(_LIBCPP_VERSION) + } // namespace
diff --git a/absl/types/span.h b/absl/types/span.h index 911af0c..d7f48d9 100644 --- a/absl/types/span.h +++ b/absl/types/span.h
@@ -5,7 +5,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -87,7 +87,7 @@ return c.data(); } -// Before C++17, string::data returns a const char* in all cases. +// Before C++17, std::string::data returns a const char* in all cases. inline char* GetDataImpl(std::string& s, // NOLINT(runtime/references) int) noexcept { return &s[0]; @@ -485,6 +485,40 @@ : (base_internal::ThrowStdOutOfRange("pos > size()"), Span()); } + // Span::first() + // + // Returns a `Span` containing first `len` elements. Parameter `len` is of + // type `size_type` and thus non-negative. `len` value must be <= size(). + // + // Examples: + // + // std::vector<int> vec = {10, 11, 12, 13}; + // absl::MakeSpan(vec).first(1); // {10} + // absl::MakeSpan(vec).first(3); // {10, 11, 12} + // absl::MakeSpan(vec).first(5); // throws std::out_of_range + constexpr Span first(size_type len) const { + return (len <= size()) + ? Span(data(), len) + : (base_internal::ThrowStdOutOfRange("len > size()"), Span()); + } + + // Span::last() + // + // Returns a `Span` containing last `len` elements. Parameter `len` is of + // type `size_type` and thus non-negative. `len` value must be <= size(). + // + // Examples: + // + // std::vector<int> vec = {10, 11, 12, 13}; + // absl::MakeSpan(vec).last(1); // {13} + // absl::MakeSpan(vec).last(3); // {11, 12, 13} + // absl::MakeSpan(vec).last(5); // throws std::out_of_range + constexpr Span last(size_type len) const { + return (len <= size()) + ? Span(size() - len + data(), len) + : (base_internal::ThrowStdOutOfRange("len > size()"), Span()); + } + // Support for absl::Hash. template <typename H> friend H AbslHashValue(H h, Span v) {
diff --git a/absl/types/span_test.cc b/absl/types/span_test.cc index bd739ff..9269f91 100644 --- a/absl/types/span_test.cc +++ b/absl/types/span_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -139,8 +139,10 @@ EXPECT_THAT(s_const_abc, SpanIs(abc)); EXPECT_FALSE((std::is_constructible<absl::Span<int>, std::string>::value)); - EXPECT_FALSE((std::is_constructible<absl::Span<const int>, std::string>::value)); - EXPECT_TRUE((std::is_convertible<std::string, absl::Span<const char>>::value)); + EXPECT_FALSE( + (std::is_constructible<absl::Span<const int>, std::string>::value)); + EXPECT_TRUE( + (std::is_convertible<std::string, absl::Span<const char>>::value)); } TEST(IntSpan, FromConstPointer) { @@ -293,6 +295,38 @@ #endif } +TEST(IntSpan, First) { + std::vector<int> empty; + EXPECT_THAT(absl::MakeSpan(empty).first(0), SpanIs(empty)); + + auto ramp = MakeRamp(10); + EXPECT_THAT(absl::MakeSpan(ramp).first(0), SpanIs(ramp.data(), 0)); + EXPECT_THAT(absl::MakeSpan(ramp).first(10), SpanIs(ramp)); + EXPECT_THAT(absl::MakeSpan(ramp).first(3), SpanIs(ramp.data(), 3)); + +#ifdef ABSL_HAVE_EXCEPTIONS + EXPECT_THROW(absl::MakeSpan(ramp).first(11), std::out_of_range); +#else + EXPECT_DEATH_IF_SUPPORTED(absl::MakeSpan(ramp).first(11), ""); +#endif +} + +TEST(IntSpan, Last) { + std::vector<int> empty; + EXPECT_THAT(absl::MakeSpan(empty).last(0), SpanIs(empty)); + + auto ramp = MakeRamp(10); + EXPECT_THAT(absl::MakeSpan(ramp).last(0), SpanIs(ramp.data() + 10, 0)); + EXPECT_THAT(absl::MakeSpan(ramp).last(10), SpanIs(ramp)); + EXPECT_THAT(absl::MakeSpan(ramp).last(3), SpanIs(ramp.data() + 7, 3)); + +#ifdef ABSL_HAVE_EXCEPTIONS + EXPECT_THROW(absl::MakeSpan(ramp).last(11), std::out_of_range); +#else + EXPECT_DEATH_IF_SUPPORTED(absl::MakeSpan(ramp).last(11), ""); +#endif +} + TEST(IntSpan, MakeSpanPtrLength) { std::vector<int> empty; auto s_empty = absl::MakeSpan(empty.data(), empty.size()); @@ -767,6 +801,8 @@ ABSL_TEST_CONSTEXPR(span.begin()); ABSL_TEST_CONSTEXPR(span.cbegin()); ABSL_TEST_CONSTEXPR(span.subspan(0, 0)); + ABSL_TEST_CONSTEXPR(span.first(1)); + ABSL_TEST_CONSTEXPR(span.last(1)); ABSL_TEST_CONSTEXPR(span[0]); } @@ -779,4 +815,19 @@ EXPECT_LE(sizeof(absl::Span<BigStruct>), 2 * sizeof(void*)); } +TEST(Span, Hash) { + int array[] = {1, 2, 3, 4}; + int array2[] = {1, 2, 3}; + using T = absl::Span<const int>; + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( + {// Empties + T(), T(nullptr, 0), T(array, 0), T(array2, 0), + // Different array with same value + T(array, 3), T(array2), T({1, 2, 3}), + // Same array, but different length + T(array, 1), T(array, 2), + // Same length, but different array + T(array + 1, 2), T(array + 2, 2)})); +} + } // namespace
diff --git a/absl/types/variant.h b/absl/types/variant.h index 2f78722..ebd52d2 100644 --- a/absl/types/variant.h +++ b/absl/types/variant.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -47,7 +47,7 @@ #ifdef ABSL_HAVE_STD_VARIANT -#include <variant> +#include <variant> // IWYU pragma: export namespace absl { using std::bad_variant_access; @@ -82,7 +82,7 @@ // absl::variant // ----------------------------------------------------------------------------- // -// An 'absl::variant` type is a form of type-safe union. An `absl::variant` -- +// An `absl::variant` type is a form of type-safe union. An `absl::variant` -- // except in exceptional cases -- always holds a value of one of its alternative // types. // @@ -129,14 +129,19 @@ // type (in which case, they will be swapped) or to two different types (in // which case the values will need to be moved). // -template <typename... Ts> +template < + typename... Ts, + absl::enable_if_t< + absl::conjunction<std::is_move_constructible<Ts>..., + type_traits_internal::IsSwappable<Ts>...>::value, + int> = 0> void swap(variant<Ts...>& v, variant<Ts...>& w) noexcept(noexcept(v.swap(w))) { v.swap(w); } // variant_size // -// Returns the number of alterative types available for a given `absl::variant` +// Returns the number of alternative types available for a given `absl::variant` // type as a compile-time constant expression. As this is a class template, it // is not generally useful for accessing the number of alternative types of // any given `absl::variant` instance. @@ -399,9 +404,9 @@ // Calls a provided functor on a given set of variants. `absl::visit()` is // commonly used to conditionally inspect the state of a given variant (or set // of variants). -// Requires: The expression in the Effects: element shall be a valid expression -// of the same type and value category, for all combinations of alternative -// types of all variants. Otherwise, the program is ill-formed. +// +// The functor must return the same type when called with any of the variants' +// alternatives. // // Example: // @@ -414,6 +419,7 @@ // }; // // // Declare our variant, and call `absl::visit()` on it. +// // Note that `GetVariant()` returns void in either case. // absl::variant<int, std::string> foo = std::string("foo"); // GetVariant visitor; // absl::visit(visitor, foo); // Prints `The variant's value is: foo' @@ -453,7 +459,7 @@ std::is_object<Tn>...>::value, "Attempted to instantiate a variant containing a non-object " "type."); - // Intentionally not qualifing `negation` with `absl::` to work around a bug + // Intentionally not qualifying `negation` with `absl::` to work around a bug // in MSVC 2015 with inline namespace and variadic template. static_assert(absl::conjunction<negation<std::is_array<T0> >, negation<std::is_array<Tn> >...>::value, @@ -561,7 +567,7 @@ // Assignment Operators - // Copy assignement operator + // Copy assignment operator variant& operator=(const variant& other) = default; // Move assignment operator @@ -687,12 +693,12 @@ // // Swaps the values of two variant objects. // - // TODO(calabrese) - // `variant::swap()` and `swap()` rely on `std::is_(nothrow)_swappable()` - // which is introduced in C++17. So we assume `is_swappable()` is always - // true and `is_nothrow_swappable()` is same as `std::is_trivial()`. void swap(variant& rhs) noexcept( - absl::conjunction<std::is_trivial<T0>, std::is_trivial<Tn>...>::value) { + absl::conjunction< + std::is_nothrow_move_constructible<T0>, + std::is_nothrow_move_constructible<Tn>..., + type_traits_internal::IsNothrowSwappable<T0>, + type_traits_internal::IsNothrowSwappable<Tn>...>::value) { return variant_internal::VisitIndices<sizeof...(Tn) + 1>::Run( variant_internal::Swap<T0, Tn...>{this, &rhs}, rhs.index()); }
diff --git a/absl/types/variant_benchmark.cc b/absl/types/variant_benchmark.cc index 99658ac..a5f5216 100644 --- a/absl/types/variant_benchmark.cc +++ b/absl/types/variant_benchmark.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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,
diff --git a/absl/types/variant_exception_safety_test.cc b/absl/types/variant_exception_safety_test.cc index 58436f0..76beb59 100644 --- a/absl/types/variant_exception_safety_test.cc +++ b/absl/types/variant_exception_safety_test.cc
@@ -4,13 +4,14 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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/variant.h" #include <iostream> @@ -20,9 +21,13 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/base/config.h" #include "absl/base/internal/exception_safety_testing.h" #include "absl/memory/memory.h" +// See comment in absl/base/config.h +#if !defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE) + namespace absl { namespace { @@ -311,6 +316,12 @@ EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test()); } { + // libstdc++ introduced a regression between 2018-09-25 and 2019-01-06. + // 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) && \ + defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8) // - otherwise (index() != j), equivalent to // emplace<j>(get<j>(std::move(rhs))) // - If an exception is thrown during the call to Tj's move construction @@ -326,6 +337,8 @@ auto copy = rhs; *lhs = std::move(copy); })); +#endif // !(defined(ABSL_HAVE_STD_VARIANT) && + // defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8) } } @@ -506,3 +519,5 @@ } // namespace } // namespace absl + +#endif // !defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)
diff --git a/absl/types/variant_test.cc b/absl/types/variant_test.cc index bfb8bd7..ab40ed2 100644 --- a/absl/types/variant_test.cc +++ b/absl/types/variant_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -52,7 +52,7 @@ #endif // ABSL_HAVE_EXCEPTIONS #define ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(...) \ - ABSL_VARIANT_TEST_EXPECT_FAIL((__VA_ARGS__), absl::bad_variant_access, \ + ABSL_VARIANT_TEST_EXPECT_FAIL((void)(__VA_ARGS__), absl::bad_variant_access, \ "Bad variant access") struct Hashable {}; @@ -257,7 +257,7 @@ // each type. template <typename T> class VariantTypesTest : public ::testing::Test {}; -TYPED_TEST_CASE(VariantTypesTest, VariantTypes); +TYPED_TEST_SUITE(VariantTypesTest, VariantTypes); //////////////////// // [variant.ctor] // @@ -484,7 +484,8 @@ } TEST(VariantTest, InPlaceTypeInitializerList) { - using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; + using Var = + variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; Var v1(in_place_type_t<MoveOnlyWithListConstructor>(), {1, 2, 3, 4, 5}, 6); ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1)); @@ -519,7 +520,8 @@ } TEST(VariantTest, InPlaceIndexInitializerList) { - using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; + using Var = + variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; Var v1(in_place_index_t<3>(), {1, 2, 3, 4, 5}, 6); ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1)); @@ -560,8 +562,14 @@ #ifdef ABSL_HAVE_EXCEPTIONS +// See comment in absl/base/config.h +#if defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE) +TEST(VariantTest, DISABLED_TestDtorValuelessByException) +#else // Test destruction when in the valueless_by_exception state. -TEST(VariantTest, TestDtorValuelessByException) { +TEST(VariantTest, TestDtorValuelessByException) +#endif +{ int counter = 0; IncrementInDtor counter_adjuster(&counter); @@ -826,7 +834,8 @@ } TEST(VariantTest, TestEmplaceInitializerList) { - using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; + using Var = + variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; Var v1(absl::in_place_index_t<0>{}, 555); MoveOnlyWithListConstructor& emplace_result = @@ -863,7 +872,8 @@ } TEST(VariantTest, TestEmplaceIndexInitializerList) { - using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; + using Var = + variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; Var v1(absl::in_place_index_t<0>{}, 555); MoveOnlyWithListConstructor& emplace_result = @@ -1301,7 +1311,8 @@ absl::get<std::string>(std::move(v))); const Var& const_v = v; - ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<std::string>(const_v)); + ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS( + absl::get<std::string>(const_v)); ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS( absl::get<std::string>(std::move(const_v))); // NOLINT } @@ -1358,7 +1369,8 @@ EXPECT_EQ(*elem, 0); { auto* bad_elem = absl::get_if<1>(&const_v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), const std::string*>::value)); + EXPECT_TRUE( + (std::is_same<decltype(bad_elem), const std::string*>::value)); EXPECT_EQ(bad_elem, nullptr); } { @@ -1467,7 +1479,8 @@ } { auto* bad_elem = absl::get_if<1>(&const_v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), const std::string*>::value)); + EXPECT_TRUE( + (std::is_same<decltype(bad_elem), const std::string*>::value)); EXPECT_EQ(bad_elem, nullptr); } { @@ -1520,7 +1533,8 @@ } { auto* bad_elem = absl::get_if<1>(&const_v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), const std::string*>::value)); + EXPECT_TRUE( + (std::is_same<decltype(bad_elem), const std::string*>::value)); EXPECT_EQ(bad_elem, nullptr); } { @@ -1723,9 +1737,13 @@ bool operator()(std::string&&) const { return true; } // NOLINT int operator()(const std::string&, const std::string&) const { return 0; } - int operator()(const std::string&, std::string&&) const { return 1; } // NOLINT - int operator()(std::string&&, const std::string&) const { return 2; } // NOLINT - int operator()(std::string&&, std::string&&) const { return 3; } // NOLINT + int operator()(const std::string&, std::string&&) const { + return 1; + } // NOLINT + int operator()(std::string&&, const std::string&) const { + return 2; + } // NOLINT + int operator()(std::string&&, std::string&&) const { return 3; } // NOLINT }; EXPECT_FALSE(absl::visit(Visitor{}, v)); EXPECT_TRUE(absl::visit(Visitor{}, absl::move(v))); @@ -1801,9 +1819,9 @@ EXPECT_THAT(absl::visit(Visitor(), A(std::string("BBBBB")), B(std::unique_ptr<int>(new int(7)))), ::testing::Pair(5, 7)); - EXPECT_THAT( - absl::visit(Visitor(), A(std::string("BBBBB")), B(absl::string_view("ABC"))), - ::testing::Pair(5, 3)); + EXPECT_THAT(absl::visit(Visitor(), A(std::string("BBBBB")), + B(absl::string_view("ABC"))), + ::testing::Pair(5, 3)); } TEST(VariantTest, VisitNoArgs) { @@ -1972,29 +1990,17 @@ } TEST(VariantTest, Hash) { - static_assert(type_traits_internal::IsHashEnabled<variant<int>>::value, ""); - static_assert(type_traits_internal::IsHashEnabled<variant<Hashable>>::value, + static_assert(type_traits_internal::IsHashable<variant<int>>::value, ""); + static_assert(type_traits_internal::IsHashable<variant<Hashable>>::value, ""); + static_assert(type_traits_internal::IsHashable<variant<int, Hashable>>::value, + ""); + +#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ + static_assert(!type_traits_internal::IsHashable<variant<NonHashable>>::value, ""); static_assert( - type_traits_internal::IsHashEnabled<variant<int, Hashable>>::value, ""); - -#if defined(_MSC_VER) || \ - (defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 4000 && \ - _LIBCPP_STD_VER > 11) || \ - defined(__APPLE__) - // For MSVC and libc++ (< 4.0 and c++14), std::hash primary template has a - // static_assert to catch any user-defined type T that doesn't provide a hash - // specialization. So instantiating std::hash<variant<T>> will result - // in a hard error which is not SFINAE friendly. -#define ABSL_STD_HASH_NOT_SFINAE_FRIENDLY 1 -#endif - -#ifndef ABSL_STD_HASH_NOT_SFINAE_FRIENDLY - static_assert( - !type_traits_internal::IsHashEnabled<variant<NonHashable>>::value, ""); - static_assert(!type_traits_internal::IsHashEnabled< - variant<Hashable, NonHashable>>::value, - ""); + !type_traits_internal::IsHashable<variant<Hashable, NonHashable>>::value, + ""); #endif // MSVC std::hash<std::variant> does not use the index, thus produce the same @@ -2018,11 +2024,10 @@ EXPECT_GT(hashcodes.size(), 90); // test const-qualified + static_assert(type_traits_internal::IsHashable<variant<const int>>::value, + ""); static_assert( - type_traits_internal::IsHashEnabled<variant<const int>>::value, ""); - static_assert( - type_traits_internal::IsHashEnabled<variant<const Hashable>>::value, - ""); + type_traits_internal::IsHashable<variant<const Hashable>>::value, ""); std::hash<absl::variant<const int>> c_hash; for (int i = 0; i < 100; ++i) { EXPECT_EQ(hash(i), c_hash(i)); @@ -2171,7 +2176,8 @@ // We still need the explicit cast for std::string, because C++ won't apply // two user-defined implicit conversions in a row. - EXPECT_TRUE(absl::holds_alternative<std::string>(PassThrough(std::string("foo")))); + EXPECT_TRUE( + absl::holds_alternative<std::string>(PassThrough(std::string("foo")))); } struct Convertible2; @@ -2195,7 +2201,8 @@ TEST(VariantTest, TestRvalueConversion) { variant<double, std::string> var( - ConvertVariantTo<variant<double, std::string>>(variant<std::string, int>(0))); + ConvertVariantTo<variant<double, std::string>>( + variant<std::string, int>(0))); ASSERT_TRUE(absl::holds_alternative<double>(var)); EXPECT_EQ(0.0, absl::get<double>(var)); @@ -2287,7 +2294,8 @@ TEST(VariantTest, TestMoveConversion) { using Variant = variant<std::unique_ptr<const int>, std::unique_ptr<const std::string>>; - using OtherVariant = variant<std::unique_ptr<int>, std::unique_ptr<std::string>>; + using OtherVariant = + variant<std::unique_ptr<int>, std::unique_ptr<std::string>>; Variant var( ConvertVariantTo<Variant>(OtherVariant{absl::make_unique<int>(0)})); @@ -2295,8 +2303,8 @@ ASSERT_NE(absl::get<std::unique_ptr<const int>>(var), nullptr); EXPECT_EQ(0, *absl::get<std::unique_ptr<const int>>(var)); - var = - ConvertVariantTo<Variant>(OtherVariant(absl::make_unique<std::string>("foo"))); + var = ConvertVariantTo<Variant>( + OtherVariant(absl::make_unique<std::string>("foo"))); ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<const std::string>>(var)); EXPECT_EQ("foo", *absl::get<std::unique_ptr<const std::string>>(var)); } @@ -2307,7 +2315,8 @@ // whether moving or copying has occurred. using Variant = variant<std::shared_ptr<const int>, std::shared_ptr<const std::string>>; - using OtherVariant = variant<std::shared_ptr<int>, std::shared_ptr<std::string>>; + using OtherVariant = + variant<std::shared_ptr<int>, std::shared_ptr<std::string>>; Variant v1(std::make_shared<const int>(0)); @@ -2336,7 +2345,8 @@ TEST(VariantTest, TestRvalueConversionViaConvertVariantTo) { variant<double, std::string> var( - ConvertVariantTo<variant<double, std::string>>(variant<std::string, int>(3))); + ConvertVariantTo<variant<double, std::string>>( + variant<std::string, int>(3))); EXPECT_THAT(absl::get_if<double>(&var), Pointee(3.0)); var = ConvertVariantTo<variant<double, std::string>>( @@ -2378,7 +2388,8 @@ variant<const char*, float> source2 = "foo"; destination = ConvertVariantTo<variant<double, std::string>>(source2); - EXPECT_THAT(absl::get_if<std::string>(&destination), Pointee(std::string("foo"))); + EXPECT_THAT(absl::get_if<std::string>(&destination), + Pointee(std::string("foo"))); variant<int, float> source3(42); variant<double> singleton(ConvertVariantTo<variant<double>>(source3)); @@ -2415,15 +2426,16 @@ TEST(VariantTest, TestMoveConversionViaConvertVariantTo) { using Variant = variant<std::unique_ptr<const int>, std::unique_ptr<const std::string>>; - using OtherVariant = variant<std::unique_ptr<int>, std::unique_ptr<std::string>>; + using OtherVariant = + variant<std::unique_ptr<int>, std::unique_ptr<std::string>>; Variant var( ConvertVariantTo<Variant>(OtherVariant{absl::make_unique<int>(3)})); EXPECT_THAT(absl::get_if<std::unique_ptr<const int>>(&var), Pointee(Pointee(3))); - var = - ConvertVariantTo<Variant>(OtherVariant(absl::make_unique<std::string>("foo"))); + var = ConvertVariantTo<Variant>( + OtherVariant(absl::make_unique<std::string>("foo"))); EXPECT_THAT(absl::get_if<std::unique_ptr<const std::string>>(&var), Pointee(Pointee(std::string("foo")))); }
diff --git a/absl/utility/BUILD.bazel b/absl/utility/BUILD.bazel index c01b49b..5185ccd 100644 --- a/absl/utility/BUILD.bazel +++ b/absl/utility/BUILD.bazel
@@ -1,5 +1,5 @@ load( - "//absl:copts.bzl", + "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_TEST_COPTS", )
diff --git a/absl/utility/CMakeLists.txt b/absl/utility/CMakeLists.txt index dc3a631..e1edd19 100644 --- a/absl/utility/CMakeLists.txt +++ b/absl/utility/CMakeLists.txt
@@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -14,39 +14,31 @@ # limitations under the License. # - -list(APPEND UTILITY_PUBLIC_HEADERS - "utility.h" -) - -absl_header_library( - TARGET - absl_utility - PUBLIC_LIBRARIES - absl::base - EXPORT_NAME +absl_cc_library( + NAME utility + HDRS + "utility.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::base_internal + absl::config + absl::type_traits + PUBLIC ) - -# -## TESTS -# - -# test utility_test -set(UTILITY_TEST_SRC "utility_test.cc") -set(UTILITY_TEST_PUBLIC_LIBRARIES - absl::base - absl::memory - absl::strings - absl::utility -) - -absl_test( - TARGET +absl_cc_test( + NAME utility_test - SOURCES - ${UTILITY_TEST_SRC} - PUBLIC_LIBRARIES - ${UTILITY_TEST_PUBLIC_LIBRARIES} + SRCS + "utility_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::utility + absl::core_headers + absl::memory + absl::strings + gmock_main )
diff --git a/absl/utility/utility.h b/absl/utility/utility.h index aef4baa..853c1fb 100644 --- a/absl/utility/utility.h +++ b/absl/utility/utility.h
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -32,10 +32,9 @@ // // References: // -// http://en.cppreference.com/w/cpp/utility/integer_sequence -// http://en.cppreference.com/w/cpp/utility/apply +// https://en.cppreference.com/w/cpp/utility/integer_sequence +// https://en.cppreference.com/w/cpp/utility/apply // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3658.html -// #ifndef ABSL_UTILITY_UTILITY_H_ #define ABSL_UTILITY_UTILITY_H_ @@ -234,25 +233,33 @@ // // Example: // -// class Foo{void Bar(int);}; -// void user_function(int, string); -// void user_function(std::unique_ptr<Foo>); +// class Foo { +// public: +// void Bar(int); +// }; +// void user_function1(int, std::string); +// void user_function2(std::unique_ptr<Foo>); +// auto user_lambda = [](int, int) {}; // // int main() // { -// std::tuple<int, string> tuple1(42, "bar"); -// // Invokes the user function overload on int, string. -// absl::apply(&user_function, tuple1); +// std::tuple<int, std::string> tuple1(42, "bar"); +// // Invokes the first user function on int, std::string. +// absl::apply(&user_function1, tuple1); // -// auto foo = absl::make_unique<Foo>(); -// std::tuple<Foo*, int> tuple2(foo.get(), 42); -// // Invokes the method Bar on foo with one argument 42. -// absl::apply(&Foo::Bar, foo.get(), 42); -// -// std::tuple<std::unique_ptr<Foo>> tuple3(absl::make_unique<Foo>()); +// std::tuple<std::unique_ptr<Foo>> tuple2(absl::make_unique<Foo>()); // // Invokes the user function that takes ownership of the unique // // pointer. -// absl::apply(&user_function, std::move(tuple)); +// absl::apply(&user_function2, std::move(tuple2)); +// +// auto foo = absl::make_unique<Foo>(); +// std::tuple<Foo*, int> tuple3(foo.get(), 42); +// // Invokes the method Bar on foo with one argument, 42. +// absl::apply(&Foo::Bar, tuple3); +// +// std::tuple<int, int> tuple4(8, 9); +// // Invokes a lambda. +// absl::apply(user_lambda, tuple4); // } template <typename Functor, typename Tuple> auto apply(Functor&& functor, Tuple&& t)
diff --git a/absl/utility/utility_test.cc b/absl/utility/utility_test.cc index 3c447b2..5a4972b 100644 --- a/absl/utility/utility_test.cc +++ b/absl/utility/utility_test.cc
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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, @@ -135,7 +135,7 @@ template <typename Tup, size_t... Is> std::vector<std::string> TupStringVecImpl(const Tup& tup, - absl::index_sequence<Is...>) { + absl::index_sequence<Is...>) { return {Fmt(std::get<Is>(tup))...}; }
diff --git a/api/array_view.h b/api/array_view.h index efc642d..bf91484 100644 --- a/api/array_view.h +++ b/api/array_view.h
@@ -231,6 +231,12 @@ HasDataAndSize<U, T>::value>::type* = nullptr> ArrayView(U& u) // NOLINT : ArrayView(u.data(), u.size()) {} + template < + typename U, + typename std::enable_if<Size == impl::kArrayViewVarSize && + HasDataAndSize<U, T>::value>::type* = nullptr> + ArrayView(const U& u) // NOLINT(runtime/explicit) + : ArrayView(u.data(), u.size()) {} // Indexing and iteration. These allow mutation even if the ArrayView is // const, because the ArrayView doesn't own the array. (To prevent mutation,
diff --git a/api/array_view_unittest.cc b/api/array_view_unittest.cc index 694ed0b..62b51c0 100644 --- a/api/array_view_unittest.cc +++ b/api/array_view_unittest.cc
@@ -28,16 +28,21 @@ using ::testing::IsEmpty; template <typename T> -void Call(ArrayView<T>) {} +size_t Call(ArrayView<T> av) { + return av.size(); +} + +template <typename T, size_t N> +void CallFixed(ArrayView<T, N> av) {} } // namespace TEST(ArrayViewTest, TestConstructFromPtrAndArray) { char arr[] = "Arrr!"; const char carr[] = "Carrr!"; - Call<const char>(arr); - Call<const char>(carr); - Call<char>(arr); + EXPECT_EQ(6u, Call<const char>(arr)); + EXPECT_EQ(7u, Call<const char>(carr)); + EXPECT_EQ(6u, Call<char>(arr)); // Call<char>(carr); // Compile error, because can't drop const. // Call<int>(arr); // Compile error, because incompatible types. ArrayView<int*> x; @@ -182,6 +187,8 @@ } TEST(ArrayViewTest, TestStdArray) { + EXPECT_EQ(4u, Call<const int>(std::array<int, 4>{1, 2, 3, 4})); + CallFixed<const int, 3>(std::array<int, 3>{2, 3, 4}); constexpr size_t size = 5; std::array<float, size> arr{}; // Fixed size view. @@ -214,11 +221,12 @@ } TEST(ArrayViewTest, TestStdVector) { + EXPECT_EQ(3u, Call<const int>(std::vector<int>{4, 5, 6})); std::vector<int> v; v.push_back(3); v.push_back(11); - Call<const int>(v); - Call<int>(v); + EXPECT_EQ(2u, Call<const int>(v)); + EXPECT_EQ(2u, Call<int>(v)); // Call<unsigned int>(v); // Compile error, because incompatible types. ArrayView<int> x = v; EXPECT_EQ(2u, x.size()); @@ -229,7 +237,7 @@ EXPECT_EQ(v.data(), y.data()); // ArrayView<double> d = v; // Compile error, because incompatible types. const std::vector<int> cv; - Call<const int>(cv); + EXPECT_EQ(0u, Call<const int>(cv)); // Call<int>(cv); // Compile error, because can't drop const. ArrayView<const int> z = cv; EXPECT_EQ(0u, z.size()); @@ -239,8 +247,8 @@ TEST(ArrayViewTest, TestRtcBuffer) { rtc::Buffer b = "so buffer"; - Call<const uint8_t>(b); - Call<uint8_t>(b); + EXPECT_EQ(10u, Call<const uint8_t>(b)); + EXPECT_EQ(10u, Call<uint8_t>(b)); // Call<int8_t>(b); // Compile error, because incompatible types. ArrayView<uint8_t> x = b; EXPECT_EQ(10u, x.size()); @@ -251,7 +259,7 @@ EXPECT_EQ(b.data(), y.data()); // ArrayView<char> d = b; // Compile error, because incompatible types. const rtc::Buffer cb = "very const"; - Call<const uint8_t>(cb); + EXPECT_EQ(11u, Call<const uint8_t>(cb)); // Call<uint8_t>(cb); // Compile error, because can't drop const. ArrayView<const uint8_t> z = cb; EXPECT_EQ(11u, z.size());
diff --git a/api/async_resolver_factory.h b/api/async_resolver_factory.h new file mode 100644 index 0000000..93d3f79 --- /dev/null +++ b/api/async_resolver_factory.h
@@ -0,0 +1,32 @@ +/* + * Copyright 2018 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_ASYNC_RESOLVER_FACTORY_H_ +#define API_ASYNC_RESOLVER_FACTORY_H_ + +#include "rtc_base/async_resolver_interface.h" + +namespace webrtc { + +// An abstract factory for creating AsyncResolverInterfaces. This allows +// client applications to provide WebRTC with their own mechanism for +// performing DNS resolution. +class AsyncResolverFactory { + public: + AsyncResolverFactory() = default; + virtual ~AsyncResolverFactory() = default; + + // The caller should call Destroy on the returned object to delete it. + virtual rtc::AsyncResolverInterface* Create() = 0; +}; + +} // namespace webrtc + +#endif // API_ASYNC_RESOLVER_FACTORY_H_
diff --git a/api/audio/audio_frame.cc b/api/audio/audio_frame.cc index 75d30b0..1e706b9 100644 --- a/api/audio/audio_frame.cc +++ b/api/audio/audio_frame.cc
@@ -13,7 +13,7 @@ #include <string.h> #include "rtc_base/checks.h" -#include "rtc_base/timeutils.h" +#include "rtc_base/time_utils.h" namespace webrtc {
diff --git a/api/audio/audio_frame.h b/api/audio/audio_frame.h index dd6ac02..8f1dc62 100644 --- a/api/audio/audio_frame.h +++ b/api/audio/audio_frame.h
@@ -14,7 +14,7 @@ #include <stddef.h> #include <stdint.h> -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/api/audio/audio_mixer.h b/api/audio/audio_mixer.h index 14eefc1..b290cfa 100644 --- a/api/audio/audio_mixer.h +++ b/api/audio/audio_mixer.h
@@ -14,7 +14,7 @@ #include <memory> #include "api/audio/audio_frame.h" -#include "rtc_base/refcount.h" +#include "rtc_base/ref_count.h" namespace webrtc {
diff --git a/api/audio/echo_canceller3_config.cc b/api/audio/echo_canceller3_config.cc index 3eb2a8d..a560c9e 100644 --- a/api/audio/echo_canceller3_config.cc +++ b/api/audio/echo_canceller3_config.cc
@@ -87,19 +87,11 @@ c->delay.down_sampling_factor = 4; res = false; } - if (c->delay.delay_headroom_blocks <= 1 && - c->delay.hysteresis_limit_1_blocks == 1) { - c->delay.hysteresis_limit_1_blocks = 0; - res = false; - } + res = res & Limit(&c->delay.default_delay, 0, 5000); res = res & Limit(&c->delay.num_filters, 0, 5000); - res = res & Limit(&c->delay.api_call_jitter_blocks, 1, 5000); - res = res & Limit(&c->delay.min_echo_path_delay_blocks, 0, 5000); - res = res & Limit(&c->delay.delay_headroom_blocks, 0, 5000); - res = res & Limit(&c->delay.hysteresis_limit_1_blocks, 0, 5000); - res = res & Limit(&c->delay.hysteresis_limit_2_blocks, 0, 5000); - res = res & Limit(&c->delay.skew_hysteresis_blocks, 0, 5000); + res = res & Limit(&c->delay.delay_headroom_samples, 0, 5000); + res = res & Limit(&c->delay.hysteresis_limit_blocks, 0, 5000); res = res & Limit(&c->delay.fixed_capture_delay_samples, 0, 5000); res = res & Limit(&c->delay.delay_estimate_smoothing, 0.f, 1.f); res = res & Limit(&c->delay.delay_candidate_detection_threshold, 0.f, 1.f); @@ -150,9 +142,7 @@ } res = res & Limit(&c->erle.num_sections, 1, c->filter.main.length_blocks); - res = res & Limit(&c->ep_strength.lf, 0.f, 1000000.f); - res = res & Limit(&c->ep_strength.mf, 0.f, 1000000.f); - res = res & Limit(&c->ep_strength.hf, 0.f, 1000000.f); + res = res & Limit(&c->ep_strength.default_gain, 0.f, 1000000.f); res = res & Limit(&c->ep_strength.default_len, -1.f, 1.f); res = @@ -174,15 +164,6 @@ res = res & Limit(&c->render_levels.poor_excitation_render_limit_ds8, 0.f, 32768.f * 32768.f); - res = - res & Limit(&c->echo_removal_control.gain_rampup.initial_gain, 0.f, 1.f); - res = res & Limit(&c->echo_removal_control.gain_rampup.first_non_zero_gain, - 0.f, 1.f); - res = res & Limit(&c->echo_removal_control.gain_rampup.non_zero_gain_blocks, - 0, 100000); - res = res & - Limit(&c->echo_removal_control.gain_rampup.full_gain_blocks, 0, 100000); - res = res & Limit(&c->echo_model.noise_floor_hold, 0, 1000); res = res & Limit(&c->echo_model.min_noise_floor_power, 0, 2000000.f); res = res & Limit(&c->echo_model.stationary_gate_slope, 0, 1000000.f); @@ -244,12 +225,6 @@ res = res & Limit(&c->suppressor.floor_first_increase, 0.f, 1000000.f); - if (c->delay.delay_headroom_blocks > - c->filter.main_initial.length_blocks - 1) { - c->delay.delay_headroom_blocks = c->filter.main_initial.length_blocks - 1; - res = false; - } - return res; } } // namespace webrtc
diff --git a/api/audio/echo_canceller3_config.h b/api/audio/echo_canceller3_config.h index ffe17f2..7dcc7dd 100644 --- a/api/audio/echo_canceller3_config.h +++ b/api/audio/echo_canceller3_config.h
@@ -27,7 +27,6 @@ EchoCanceller3Config(const EchoCanceller3Config& e); struct Buffering { - bool use_new_render_buffering = true; size_t excess_render_detection_interval_blocks = 250; size_t max_allowed_excess_render_blocks = 8; } buffering; @@ -38,12 +37,8 @@ size_t default_delay = 5; size_t down_sampling_factor = 4; size_t num_filters = 5; - size_t api_call_jitter_blocks = 26; - size_t min_echo_path_delay_blocks = 0; - size_t delay_headroom_blocks = 2; - size_t hysteresis_limit_1_blocks = 1; - size_t hysteresis_limit_2_blocks = 1; - size_t skew_hysteresis_blocks = 3; + size_t delay_headroom_samples = 32; + size_t hysteresis_limit_blocks = 1; size_t fixed_capture_delay_samples = 0; float delay_estimate_smoothing = 0.7f; float delay_candidate_detection_threshold = 0.2f; @@ -91,9 +86,7 @@ } erle; struct EpStrength { - float lf = 1.f; - float mf = 1.f; - float hf = 1.f; + float default_gain = 1.f; float default_len = 0.83f; bool reverb_based_on_render = true; bool echo_can_saturate = true; @@ -118,12 +111,6 @@ } render_levels; struct EchoRemovalControl { - struct GainRampup { - float initial_gain = 0.0f; - float first_non_zero_gain = 0.001f; - int non_zero_gain_blocks = 187; - int full_gain_blocks = 312; - } gain_rampup; bool has_clock_drift = false; bool linear_and_stable_echo_path = false; } echo_removal_control;
diff --git a/api/audio/echo_canceller3_config_json.cc b/api/audio/echo_canceller3_config_json.cc index 01a831c..4c8c8ab 100644 --- a/api/audio/echo_canceller3_config_json.cc +++ b/api/audio/echo_canceller3_config_json.cc
@@ -9,9 +9,11 @@ */ #include "api/audio/echo_canceller3_config_json.h" +#include <stddef.h> #include <string> #include <vector> +#include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/strings/json.h" #include "rtc_base/strings/string_builder.h" @@ -136,8 +138,6 @@ Json::Value section; if (rtc::GetValueFromJsonObject(root, "buffering", §ion)) { - ReadParam(section, "use_new_render_buffering", - &cfg.buffering.use_new_render_buffering); ReadParam(section, "excess_render_detection_interval_blocks", &cfg.buffering.excess_render_detection_interval_blocks); ReadParam(section, "max_allowed_excess_render_blocks", @@ -148,18 +148,10 @@ ReadParam(section, "default_delay", &cfg.delay.default_delay); ReadParam(section, "down_sampling_factor", &cfg.delay.down_sampling_factor); ReadParam(section, "num_filters", &cfg.delay.num_filters); - ReadParam(section, "api_call_jitter_blocks", - &cfg.delay.api_call_jitter_blocks); - ReadParam(section, "min_echo_path_delay_blocks", - &cfg.delay.min_echo_path_delay_blocks); - ReadParam(section, "delay_headroom_blocks", - &cfg.delay.delay_headroom_blocks); - ReadParam(section, "hysteresis_limit_1_blocks", - &cfg.delay.hysteresis_limit_1_blocks); - ReadParam(section, "hysteresis_limit_2_blocks", - &cfg.delay.hysteresis_limit_2_blocks); - ReadParam(section, "skew_hysteresis_blocks", - &cfg.delay.skew_hysteresis_blocks); + ReadParam(section, "delay_headroom_samples", + &cfg.delay.delay_headroom_samples); + ReadParam(section, "hysteresis_limit_blocks", + &cfg.delay.hysteresis_limit_blocks); ReadParam(section, "fixed_capture_delay_samples", &cfg.delay.fixed_capture_delay_samples); ReadParam(section, "delay_estimate_smoothing", @@ -201,9 +193,7 @@ } if (rtc::GetValueFromJsonObject(aec3_root, "ep_strength", §ion)) { - ReadParam(section, "lf", &cfg.ep_strength.lf); - ReadParam(section, "mf", &cfg.ep_strength.mf); - ReadParam(section, "hf", &cfg.ep_strength.hf); + ReadParam(section, "default_gain", &cfg.ep_strength.default_gain); ReadParam(section, "default_len", &cfg.ep_strength.default_len); ReadParam(section, "reverb_based_on_render", &cfg.ep_strength.reverb_based_on_render); @@ -241,17 +231,6 @@ if (rtc::GetValueFromJsonObject(aec3_root, "echo_removal_control", §ion)) { - Json::Value subsection; - if (rtc::GetValueFromJsonObject(section, "gain_rampup", &subsection)) { - ReadParam(subsection, "initial_gain", - &cfg.echo_removal_control.gain_rampup.initial_gain); - ReadParam(subsection, "first_non_zero_gain", - &cfg.echo_removal_control.gain_rampup.first_non_zero_gain); - ReadParam(subsection, "non_zero_gain_blocks", - &cfg.echo_removal_control.gain_rampup.non_zero_gain_blocks); - ReadParam(subsection, "full_gain_blocks", - &cfg.echo_removal_control.gain_rampup.full_gain_blocks); - } ReadParam(section, "has_clock_drift", &cfg.echo_removal_control.has_clock_drift); ReadParam(section, "linear_and_stable_echo_path", @@ -352,17 +331,9 @@ ost << "\"down_sampling_factor\": " << config.delay.down_sampling_factor << ","; ost << "\"num_filters\": " << config.delay.num_filters << ","; - ost << "\"api_call_jitter_blocks\": " << config.delay.api_call_jitter_blocks + ost << "\"delay_headroom_samples\": " << config.delay.delay_headroom_samples << ","; - ost << "\"min_echo_path_delay_blocks\": " - << config.delay.min_echo_path_delay_blocks << ","; - ost << "\"delay_headroom_blocks\": " << config.delay.delay_headroom_blocks - << ","; - ost << "\"hysteresis_limit_1_blocks\": " - << config.delay.hysteresis_limit_1_blocks << ","; - ost << "\"hysteresis_limit_2_blocks\": " - << config.delay.hysteresis_limit_2_blocks << ","; - ost << "\"skew_hysteresis_blocks\": " << config.delay.skew_hysteresis_blocks + ost << "\"hysteresis_limit_blocks\": " << config.delay.hysteresis_limit_blocks << ","; ost << "\"fixed_capture_delay_samples\": " << config.delay.fixed_capture_delay_samples << ","; @@ -431,9 +402,7 @@ ost << "},"; ost << "\"ep_strength\": {"; - ost << "\"lf\": " << config.ep_strength.lf << ","; - ost << "\"mf\": " << config.ep_strength.mf << ","; - ost << "\"hf\": " << config.ep_strength.hf << ","; + ost << "\"default_gain\": " << config.ep_strength.default_gain << ","; ost << "\"default_len\": " << config.ep_strength.default_len << ","; ost << "\"reverb_based_on_render\": " << (config.ep_strength.reverb_based_on_render ? "true" : "false") << ","; @@ -474,16 +443,6 @@ ost << "},"; ost << "\"echo_removal_control\": {"; - ost << "\"gain_rampup\": {"; - ost << "\"initial_gain\": " - << config.echo_removal_control.gain_rampup.initial_gain << ","; - ost << "\"first_non_zero_gain\": " - << config.echo_removal_control.gain_rampup.first_non_zero_gain << ","; - ost << "\"non_zero_gain_blocks\": " - << config.echo_removal_control.gain_rampup.non_zero_gain_blocks << ","; - ost << "\"full_gain_blocks\": " - << config.echo_removal_control.gain_rampup.full_gain_blocks; - ost << "},"; ost << "\"has_clock_drift\": " << (config.echo_removal_control.has_clock_drift ? "true" : "false") << ",";
diff --git a/api/audio_options.cc b/api/audio_options.cc index e33214b..16c0430 100644 --- a/api/audio_options.cc +++ b/api/audio_options.cc
@@ -10,6 +10,7 @@ #include "api/audio_options.h" +#include "api/array_view.h" #include "rtc_base/strings/string_builder.h" namespace cricket { @@ -51,6 +52,8 @@ change.audio_jitter_buffer_fast_accelerate); SetFrom(&audio_jitter_buffer_min_delay_ms, change.audio_jitter_buffer_min_delay_ms); + SetFrom(&audio_jitter_buffer_enable_rtx_handling, + change.audio_jitter_buffer_enable_rtx_handling); SetFrom(&typing_detection, change.typing_detection); SetFrom(&experimental_agc, change.experimental_agc); SetFrom(&extended_filter_aec, change.extended_filter_aec); @@ -80,6 +83,8 @@ o.audio_jitter_buffer_fast_accelerate && audio_jitter_buffer_min_delay_ms == o.audio_jitter_buffer_min_delay_ms && + audio_jitter_buffer_enable_rtx_handling == + o.audio_jitter_buffer_enable_rtx_handling && typing_detection == o.typing_detection && experimental_agc == o.experimental_agc && extended_filter_aec == o.extended_filter_aec && @@ -113,6 +118,8 @@ audio_jitter_buffer_fast_accelerate); ToStringIfSet(&result, "audio_jitter_buffer_min_delay_ms", audio_jitter_buffer_min_delay_ms); + ToStringIfSet(&result, "audio_jitter_buffer_enable_rtx_handling", + audio_jitter_buffer_enable_rtx_handling); ToStringIfSet(&result, "typing", typing_detection); ToStringIfSet(&result, "experimental_agc", experimental_agc); ToStringIfSet(&result, "extended_filter_aec", extended_filter_aec);
diff --git a/api/audio_options.h b/api/audio_options.h index c2d1f44..478bff6 100644 --- a/api/audio_options.h +++ b/api/audio_options.h
@@ -56,6 +56,8 @@ absl::optional<bool> audio_jitter_buffer_fast_accelerate; // Audio receiver jitter buffer (NetEq) minimum target delay in milliseconds. absl::optional<int> audio_jitter_buffer_min_delay_ms; + // Audio receiver jitter buffer (NetEq) should handle retransmitted packets. + absl::optional<bool> audio_jitter_buffer_enable_rtx_handling; // Audio processing to detect typing. absl::optional<bool> typing_detection; absl::optional<bool> experimental_agc;
diff --git a/api/candidate.cc b/api/candidate.cc index 275b173..c857f89 100644 --- a/api/candidate.cc +++ b/api/candidate.cc
@@ -11,7 +11,7 @@ #include "api/candidate.h" #include "rtc_base/helpers.h" -#include "rtc_base/ipaddress.h" +#include "rtc_base/ip_address.h" #include "rtc_base/strings/string_builder.h" namespace cricket { @@ -125,4 +125,19 @@ return !(*this == o); } +Candidate Candidate::ToSanitizedCopy(bool use_hostname_address, + bool filter_related_address) const { + Candidate copy(*this); + if (use_hostname_address) { + rtc::SocketAddress hostname_only_addr(address().hostname(), + address().port()); + copy.set_address(hostname_only_addr); + } + if (filter_related_address) { + copy.set_related_address( + rtc::EmptySocketAddressWithFamily(copy.address().family())); + } + return copy; +} + } // namespace cricket
diff --git a/api/candidate.h b/api/candidate.h index 4c650d9..7452055 100644 --- a/api/candidate.h +++ b/api/candidate.h
@@ -19,7 +19,7 @@ #include "rtc_base/checks.h" #include "rtc_base/network_constants.h" -#include "rtc_base/socketaddress.h" +#include "rtc_base/socket_address.h" #include "rtc_base/system/rtc_export.h" namespace cricket { @@ -166,6 +166,16 @@ bool operator==(const Candidate& o) const; bool operator!=(const Candidate& o) const; + // Returns a sanitized copy configured by the given booleans. If + // |use_host_address| is true, the returned copy has its IP removed from + // |address()|, which leads |address()| to be a hostname address. If + // |filter_related_address|, the returned copy has its related address reset + // to the wildcard address (i.e. 0.0.0.0 for IPv4 and :: for IPv6). Note that + // setting both booleans to false returns an identical copy to the original + // candidate. + Candidate ToSanitizedCopy(bool use_hostname_address, + bool filter_related_address) const; + private: std::string ToStringInternal(bool sensitive) const;
diff --git a/api/create_peerconnection_factory.cc b/api/create_peerconnection_factory.cc index 1a6d086..0d15e8c 100644 --- a/api/create_peerconnection_factory.cc +++ b/api/create_peerconnection_factory.cc
@@ -13,104 +13,26 @@ #include <memory> #include <utility> -#include "api/call/callfactoryinterface.h" -#include "api/peerconnectioninterface.h" +#include "api/audio/audio_mixer.h" +#include "api/audio_codecs/audio_decoder_factory.h" +#include "api/audio_codecs/audio_encoder_factory.h" +#include "api/call/call_factory_interface.h" +#include "api/fec_controller.h" +#include "api/peer_connection_interface.h" +#include "api/scoped_refptr.h" +#include "api/transport/network_control.h" #include "api/video_codecs/video_decoder_factory.h" #include "api/video_codecs/video_encoder_factory.h" #include "logging/rtc_event_log/rtc_event_log_factory.h" #include "logging/rtc_event_log/rtc_event_log_factory_interface.h" -#include "media/engine/webrtcmediaengine.h" +#include "media/base/media_engine.h" +#include "media/engine/webrtc_media_engine.h" #include "modules/audio_device/include/audio_device.h" #include "modules/audio_processing/include/audio_processing.h" -#include "rtc_base/bind.h" -#include "rtc_base/scoped_ref_ptr.h" #include "rtc_base/thread.h" namespace webrtc { -#if defined(USE_BUILTIN_SW_CODECS) -rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory( - rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory, - rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory) { - return CreatePeerConnectionFactoryWithAudioMixer( - nullptr /*network_thread*/, nullptr /*worker_thread*/, - nullptr /*signaling_thread*/, nullptr /*default_adm*/, - audio_encoder_factory, audio_decoder_factory, - nullptr /*video_encoder_factory*/, nullptr /*video_decoder_factory*/, - nullptr /*audio_mixer*/); -} - -// Note: all the other CreatePeerConnectionFactory variants just end up calling -// this, ultimately. -rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory( - rtc::Thread* network_thread, - rtc::Thread* worker_thread, - rtc::Thread* signaling_thread, - AudioDeviceModule* default_adm, - rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory, - rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory, - cricket::WebRtcVideoEncoderFactory* video_encoder_factory, - cricket::WebRtcVideoDecoderFactory* video_decoder_factory, - rtc::scoped_refptr<AudioMixer> audio_mixer, - rtc::scoped_refptr<AudioProcessing> audio_processing) { - rtc::scoped_refptr<AudioProcessing> audio_processing_use = audio_processing; - if (!audio_processing_use) { - audio_processing_use = AudioProcessingBuilder().Create(); - } - - std::unique_ptr<cricket::MediaEngineInterface> media_engine( - cricket::WebRtcMediaEngineFactory::Create( - default_adm, audio_encoder_factory, audio_decoder_factory, - video_encoder_factory, video_decoder_factory, audio_mixer, - audio_processing_use)); - - std::unique_ptr<CallFactoryInterface> call_factory = CreateCallFactory(); - - std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory = - CreateRtcEventLogFactory(); - - return CreateModularPeerConnectionFactory( - network_thread, worker_thread, signaling_thread, std::move(media_engine), - std::move(call_factory), std::move(event_log_factory)); -} - -rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory( - rtc::Thread* network_thread, - rtc::Thread* worker_thread, - rtc::Thread* signaling_thread, - AudioDeviceModule* default_adm, - rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory, - rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory, - cricket::WebRtcVideoEncoderFactory* video_encoder_factory, - cricket::WebRtcVideoDecoderFactory* video_decoder_factory, - rtc::scoped_refptr<AudioMixer> audio_mixer, - rtc::scoped_refptr<AudioProcessing> audio_processing, - std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory, - std::unique_ptr<NetworkControllerFactoryInterface> - network_controller_factory) { - rtc::scoped_refptr<AudioProcessing> audio_processing_use = audio_processing; - if (!audio_processing_use) { - audio_processing_use = AudioProcessingBuilder().Create(); - } - - std::unique_ptr<cricket::MediaEngineInterface> media_engine( - cricket::WebRtcMediaEngineFactory::Create( - default_adm, audio_encoder_factory, audio_decoder_factory, - video_encoder_factory, video_decoder_factory, audio_mixer, - audio_processing_use)); - - std::unique_ptr<CallFactoryInterface> call_factory = CreateCallFactory(); - - std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory = - CreateRtcEventLogFactory(); - - return CreateModularPeerConnectionFactory( - network_thread, worker_thread, signaling_thread, std::move(media_engine), - std::move(call_factory), std::move(event_log_factory), - std::move(fec_controller_factory), std::move(network_controller_factory)); -} -#endif - rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory( rtc::Thread* network_thread, rtc::Thread* worker_thread, @@ -145,38 +67,4 @@ return CreateModularPeerConnectionFactory(std::move(dependencies)); } -#if defined(USE_BUILTIN_SW_CODECS) -rtc::scoped_refptr<PeerConnectionFactoryInterface> -CreatePeerConnectionFactoryWithAudioMixer( - rtc::Thread* network_thread, - rtc::Thread* worker_thread, - rtc::Thread* signaling_thread, - AudioDeviceModule* default_adm, - rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory, - rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory, - cricket::WebRtcVideoEncoderFactory* video_encoder_factory, - cricket::WebRtcVideoDecoderFactory* video_decoder_factory, - rtc::scoped_refptr<AudioMixer> audio_mixer) { - return CreatePeerConnectionFactory( - network_thread, worker_thread, signaling_thread, default_adm, - audio_encoder_factory, audio_decoder_factory, video_encoder_factory, - video_decoder_factory, audio_mixer, nullptr); -} - -rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory( - rtc::Thread* network_thread, - rtc::Thread* worker_thread, - rtc::Thread* signaling_thread, - AudioDeviceModule* default_adm, - rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory, - rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory, - cricket::WebRtcVideoEncoderFactory* video_encoder_factory, - cricket::WebRtcVideoDecoderFactory* video_decoder_factory) { - return CreatePeerConnectionFactoryWithAudioMixer( - network_thread, worker_thread, signaling_thread, default_adm, - audio_encoder_factory, audio_decoder_factory, video_encoder_factory, - video_decoder_factory, nullptr); -} -#endif - } // namespace webrtc
diff --git a/api/create_peerconnection_factory.h b/api/create_peerconnection_factory.h index baa50c7..40f1276 100644 --- a/api/create_peerconnection_factory.h +++ b/api/create_peerconnection_factory.h
@@ -17,9 +17,10 @@ #include "api/audio_codecs/audio_decoder_factory.h" #include "api/audio_codecs/audio_encoder_factory.h" #include "api/fec_controller.h" -#include "api/peerconnectioninterface.h" +#include "api/peer_connection_interface.h" +#include "api/scoped_refptr.h" #include "api/transport/network_control.h" -#include "rtc_base/scoped_ref_ptr.h" +#include "rtc_base/deprecation.h" namespace rtc { // TODO(bugs.webrtc.org/9987): Move rtc::Thread to api/ or expose a better @@ -28,104 +29,14 @@ class Thread; } // namespace rtc -namespace cricket { -class WebRtcVideoDecoderFactory; -class WebRtcVideoEncoderFactory; -} // namespace cricket - namespace webrtc { class AudioDeviceModule; class AudioProcessing; -#if defined(USE_BUILTIN_SW_CODECS) -// Create a new instance of PeerConnectionFactoryInterface. -// -// This method relies on the thread it's called on as the "signaling thread" -// for the PeerConnectionFactory it creates. -// -// As such, if the current thread is not already running an rtc::Thread message -// loop, an application using this method must eventually either call -// rtc::Thread::Current()->Run(), or call -// rtc::Thread::Current()->ProcessMessages() within the application's own -// message loop. -RTC_EXPORT rtc::scoped_refptr<PeerConnectionFactoryInterface> -CreatePeerConnectionFactory( - rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory, - rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory); - -// Create a new instance of PeerConnectionFactoryInterface. -// -// |network_thread|, |worker_thread| and |signaling_thread| are -// the only mandatory parameters. -// -// If non-null, a reference is added to |default_adm|, and ownership of -// |video_encoder_factory| and |video_decoder_factory| is transferred to the -// returned factory. -// TODO(deadbeef): Use rtc::scoped_refptr<> and std::unique_ptr<> to make this -// ownership transfer and ref counting more obvious. -RTC_EXPORT rtc::scoped_refptr<PeerConnectionFactoryInterface> -CreatePeerConnectionFactory( - rtc::Thread* network_thread, - rtc::Thread* worker_thread, - rtc::Thread* signaling_thread, - AudioDeviceModule* default_adm, - rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory, - rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory, - cricket::WebRtcVideoEncoderFactory* video_encoder_factory, - cricket::WebRtcVideoDecoderFactory* video_decoder_factory); - -// Create a new instance of PeerConnectionFactoryInterface with optional -// external audio mixed and audio processing modules. -// -// If |audio_mixer| is null, an internal audio mixer will be created and used. -// If |audio_processing| is null, an internal audio processing module will be -// created and used. -RTC_EXPORT rtc::scoped_refptr<PeerConnectionFactoryInterface> -CreatePeerConnectionFactory( - rtc::Thread* network_thread, - rtc::Thread* worker_thread, - rtc::Thread* signaling_thread, - AudioDeviceModule* default_adm, - rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory, - rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory, - cricket::WebRtcVideoEncoderFactory* video_encoder_factory, - cricket::WebRtcVideoDecoderFactory* video_decoder_factory, - rtc::scoped_refptr<AudioMixer> audio_mixer, - rtc::scoped_refptr<AudioProcessing> audio_processing); - -// Create a new instance of PeerConnectionFactoryInterface with optional -// external audio mixer, audio processing, and fec controller modules. -// -// If |audio_mixer| is null, an internal audio mixer will be created and used. -// If |audio_processing| is null, an internal audio processing module will be -// created and used. -// If |fec_controller_factory| is null, an internal fec controller module will -// be created and used. -// If |network_controller_factory| is provided, it will be used if enabled via -// field trial. -RTC_EXPORT rtc::scoped_refptr<PeerConnectionFactoryInterface> -CreatePeerConnectionFactory( - rtc::Thread* network_thread, - rtc::Thread* worker_thread, - rtc::Thread* signaling_thread, - AudioDeviceModule* default_adm, - rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory, - rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory, - cricket::WebRtcVideoEncoderFactory* video_encoder_factory, - cricket::WebRtcVideoDecoderFactory* video_decoder_factory, - rtc::scoped_refptr<AudioMixer> audio_mixer, - rtc::scoped_refptr<AudioProcessing> audio_processing, - std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory, - std::unique_ptr<NetworkControllerFactoryInterface> - network_controller_factory = nullptr); -#endif // defined(USE_BUILTIN_SW_CODECS) - // Create a new instance of PeerConnectionFactoryInterface with optional video // codec factories. These video factories represents all video codecs, i.e. no // extra internal video codecs will be added. -// When building WebRTC with rtc_use_builtin_sw_codecs = false, this is the -// only available CreatePeerConnectionFactory overload. RTC_EXPORT rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory( rtc::Thread* network_thread, @@ -139,41 +50,6 @@ rtc::scoped_refptr<AudioMixer> audio_mixer, rtc::scoped_refptr<AudioProcessing> audio_processing); -#if defined(USE_BUILTIN_SW_CODECS) -// Create a new instance of PeerConnectionFactoryInterface with external audio -// mixer. -// -// If |audio_mixer| is null, an internal audio mixer will be created and used. -RTC_EXPORT rtc::scoped_refptr<PeerConnectionFactoryInterface> -CreatePeerConnectionFactoryWithAudioMixer( - rtc::Thread* network_thread, - rtc::Thread* worker_thread, - rtc::Thread* signaling_thread, - AudioDeviceModule* default_adm, - rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory, - rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory, - cricket::WebRtcVideoEncoderFactory* video_encoder_factory, - cricket::WebRtcVideoDecoderFactory* video_decoder_factory, - rtc::scoped_refptr<AudioMixer> audio_mixer); - -// Create a new instance of PeerConnectionFactoryInterface. -// Same thread is used as worker and network thread. -RTC_EXPORT inline rtc::scoped_refptr<PeerConnectionFactoryInterface> -CreatePeerConnectionFactory( - rtc::Thread* worker_and_network_thread, - rtc::Thread* signaling_thread, - AudioDeviceModule* default_adm, - rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory, - rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory, - cricket::WebRtcVideoEncoderFactory* video_encoder_factory, - cricket::WebRtcVideoDecoderFactory* video_decoder_factory) { - return CreatePeerConnectionFactory( - worker_and_network_thread, worker_and_network_thread, signaling_thread, - default_adm, audio_encoder_factory, audio_decoder_factory, - video_encoder_factory, video_decoder_factory); -} -#endif // defined(USE_BUILTIN_SW_CODECS) - } // namespace webrtc #endif // API_CREATE_PEERCONNECTION_FACTORY_H_
diff --git a/api/crypto_params.h b/api/crypto_params.h new file mode 100644 index 0000000..5da352c --- /dev/null +++ b/api/crypto_params.h
@@ -0,0 +1,41 @@ +/* + * Copyright (c) 2004 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_CRYPTO_PARAMS_H_ +#define API_CRYPTO_PARAMS_H_ + +#include <string> + +namespace cricket { + +// Parameters for SRTP negotiation, as described in RFC 4568. +// TODO(benwright) - Rename to SrtpCryptoParams as these only apply to SRTP and +// not generic crypto parameters for WebRTC. +struct CryptoParams { + CryptoParams() : tag(0) {} + CryptoParams(int t, + const std::string& cs, + const std::string& kp, + const std::string& sp) + : tag(t), cipher_suite(cs), key_params(kp), session_params(sp) {} + + bool Matches(const CryptoParams& params) const { + return (tag == params.tag && cipher_suite == params.cipher_suite); + } + + int tag; + std::string cipher_suite; + std::string key_params; + std::string session_params; +}; + +} // namespace cricket + +#endif // API_CRYPTO_PARAMS_H_
diff --git a/api/data_channel_interface.cc b/api/data_channel_interface.cc new file mode 100644 index 0000000..240ccbe --- /dev/null +++ b/api/data_channel_interface.cc
@@ -0,0 +1,35 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/data_channel_interface.h" + +namespace webrtc { + +bool DataChannelInterface::ordered() const { + return false; +} + +uint16_t DataChannelInterface::maxRetransmitTime() const { + return 0; +} + +uint16_t DataChannelInterface::maxRetransmits() const { + return 0; +} + +std::string DataChannelInterface::protocol() const { + return std::string(); +} + +bool DataChannelInterface::negotiated() const { + return false; +} + +} // namespace webrtc
diff --git a/api/data_channel_interface.h b/api/data_channel_interface.h new file mode 100644 index 0000000..91a9804 --- /dev/null +++ b/api/data_channel_interface.h
@@ -0,0 +1,180 @@ +/* + * Copyright 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This file contains interfaces for DataChannels +// http://dev.w3.org/2011/webrtc/editor/webrtc.html#rtcdatachannel + +#ifndef API_DATA_CHANNEL_INTERFACE_H_ +#define API_DATA_CHANNEL_INTERFACE_H_ + +#include <stddef.h> +#include <stdint.h> +#include <string> + +#include "rtc_base/checks.h" +#include "rtc_base/copy_on_write_buffer.h" +#include "rtc_base/ref_count.h" + +namespace webrtc { + +// C++ version of: https://www.w3.org/TR/webrtc/#idl-def-rtcdatachannelinit +// TODO(deadbeef): Use absl::optional for the "-1 if unset" things. +struct DataChannelInit { + // Deprecated. Reliability is assumed, and channel will be unreliable if + // maxRetransmitTime or MaxRetransmits is set. + bool reliable = false; + + // True if ordered delivery is required. + bool ordered = true; + + // The max period of time in milliseconds in which retransmissions will be + // sent. After this time, no more retransmissions will be sent. -1 if unset. + // + // Cannot be set along with |maxRetransmits|. + int maxRetransmitTime = -1; + + // The max number of retransmissions. -1 if unset. + // + // Cannot be set along with |maxRetransmitTime|. + int maxRetransmits = -1; + + // This is set by the application and opaque to the WebRTC implementation. + std::string protocol; + + // True if the channel has been externally negotiated and we do not send an + // in-band signalling in the form of an "open" message. If this is true, |id| + // below must be set; otherwise it should be unset and will be negotiated + // in-band. + bool negotiated = false; + + // The stream id, or SID, for SCTP data channels. -1 if unset (see above). + int id = -1; +}; + +// At the JavaScript level, data can be passed in as a string or a blob, so +// this structure's |binary| flag tells whether the data should be interpreted +// as binary or text. +struct DataBuffer { + DataBuffer(const rtc::CopyOnWriteBuffer& data, bool binary) + : data(data), binary(binary) {} + // For convenience for unit tests. + explicit DataBuffer(const std::string& text) + : data(text.data(), text.length()), binary(false) {} + size_t size() const { return data.size(); } + + rtc::CopyOnWriteBuffer data; + // Indicates if the received data contains UTF-8 or binary data. + // Note that the upper layers are left to verify the UTF-8 encoding. + // TODO(jiayl): prefer to use an enum instead of a bool. + bool binary; +}; + +// Used to implement RTCDataChannel events. +// +// The code responding to these callbacks should unwind the stack before +// using any other webrtc APIs; re-entrancy is not supported. +class DataChannelObserver { + public: + // The data channel state have changed. + virtual void OnStateChange() = 0; + // A data buffer was successfully received. + virtual void OnMessage(const DataBuffer& buffer) = 0; + // The data channel's buffered_amount has changed. + virtual void OnBufferedAmountChange(uint64_t previous_amount) {} + + protected: + virtual ~DataChannelObserver() = default; +}; + +class DataChannelInterface : public rtc::RefCountInterface { + public: + // C++ version of: https://www.w3.org/TR/webrtc/#idl-def-rtcdatachannelstate + // Unlikely to change, but keep in sync with DataChannel.java:State and + // RTCDataChannel.h:RTCDataChannelState. + enum DataState { + kConnecting, + kOpen, // The DataChannel is ready to send data. + kClosing, + kClosed + }; + + static const char* DataStateString(DataState state) { + switch (state) { + case kConnecting: + return "connecting"; + case kOpen: + return "open"; + case kClosing: + return "closing"; + case kClosed: + return "closed"; + } + RTC_CHECK(false) << "Unknown DataChannel state: " << state; + return ""; + } + + // Used to receive events from the data channel. Only one observer can be + // registered at a time. UnregisterObserver should be called before the + // observer object is destroyed. + virtual void RegisterObserver(DataChannelObserver* observer) = 0; + virtual void UnregisterObserver() = 0; + + // The label attribute represents a label that can be used to distinguish this + // DataChannel object from other DataChannel objects. + virtual std::string label() const = 0; + + // The accessors below simply return the properties from the DataChannelInit + // the data channel was constructed with. + virtual bool reliable() const = 0; + // TODO(deadbeef): Remove these dummy implementations when all classes have + // implemented these APIs. They should all just return the values the + // DataChannel was created with. + virtual bool ordered() const; + virtual uint16_t maxRetransmitTime() const; + virtual uint16_t maxRetransmits() const; + virtual std::string protocol() const; + virtual bool negotiated() const; + + // Returns the ID from the DataChannelInit, if it was negotiated out-of-band. + // If negotiated in-band, this ID will be populated once the DTLS role is + // determined, and until then this will return -1. + virtual int id() const = 0; + virtual DataState state() const = 0; + virtual uint32_t messages_sent() const = 0; + virtual uint64_t bytes_sent() const = 0; + virtual uint32_t messages_received() const = 0; + virtual uint64_t bytes_received() const = 0; + + // Returns the number of bytes of application data (UTF-8 text and binary + // data) that have been queued using Send but have not yet been processed at + // the SCTP level. See comment above Send below. + virtual uint64_t buffered_amount() const = 0; + + // Begins the graceful data channel closing procedure. See: + // https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-6.7 + virtual void Close() = 0; + + // Sends |data| to the remote peer. If the data can't be sent at the SCTP + // level (due to congestion control), it's buffered at the data channel level, + // up to a maximum of 16MB. If Send is called while this buffer is full, the + // data channel will be closed abruptly. + // + // So, it's important to use buffered_amount() and OnBufferedAmountChange to + // ensure the data channel is used efficiently but without filling this + // buffer. + virtual bool Send(const DataBuffer& buffer) = 0; + + protected: + ~DataChannelInterface() override = default; +}; + +} // namespace webrtc + +#endif // API_DATA_CHANNEL_INTERFACE_H_
diff --git a/api/dtls_transport_interface.h b/api/dtls_transport_interface.h new file mode 100644 index 0000000..7f35a23 --- /dev/null +++ b/api/dtls_transport_interface.h
@@ -0,0 +1,76 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_DTLS_TRANSPORT_INTERFACE_H_ +#define API_DTLS_TRANSPORT_INTERFACE_H_ + +#include "api/ice_transport_interface.h" +#include "api/rtc_error.h" +#include "api/scoped_refptr.h" +#include "rtc_base/ref_count.h" + +namespace webrtc { + +// States of a DTLS transport, corresponding to the JS API specification. +// http://w3c.github.io/webrtc-pc/#dom-rtcdtlstransportstate +enum class DtlsTransportState { + kNew, // Has not started negotiating yet. + kConnecting, // In the process of negotiating a secure connection. + kConnected, // Completed negotiation and verified fingerprints. + kClosed, // Intentionally closed. + kFailed, // Failure due to an error or failing to verify a remote + // fingerprint. + kNumValues +}; + +// This object gives snapshot information about the changeable state of a +// DTLSTransport. +class DtlsTransportInformation { + public: + explicit DtlsTransportInformation(DtlsTransportState state) : state_(state) {} + DtlsTransportState state() const { return state_; } + // TODO(hta): Add remote certificate access + private: + DtlsTransportState state_; +}; + +class DtlsTransportObserverInterface { + public: + // This callback carries information about the state of the transport. + // The argument is a pass-by-value snapshot of the state. + virtual void OnStateChange(DtlsTransportInformation info) = 0; + // This callback is called when an error occurs, causing the transport + // to go to the kFailed state. + virtual void OnError(RTCError error) = 0; + + protected: + virtual ~DtlsTransportObserverInterface() = default; +}; + +// A DTLS transport, as represented to the outside world. +// This object is created on the network thread, and can only be +// accessed on that thread, except for functions explicitly marked otherwise. +// References can be held by other threads, and destruction can therefore +// be initiated by other threads. +class DtlsTransportInterface : public rtc::RefCountInterface { + public: + // Returns a pointer to the ICE transport that is owned by the DTLS transport. + virtual rtc::scoped_refptr<IceTransportInterface> ice_transport() = 0; + // Returns information on the state of the DtlsTransport. + // This function can be called from other threads. + virtual DtlsTransportInformation Information() = 0; + // Observer management. + virtual void RegisterObserver(DtlsTransportObserverInterface* observer) = 0; + virtual void UnregisterObserver() = 0; +}; + +} // namespace webrtc + +#endif // API_DTLS_TRANSPORT_INTERFACE_H_
diff --git a/api/dtmf_sender_interface.h b/api/dtmf_sender_interface.h new file mode 100644 index 0000000..9cdfba1 --- /dev/null +++ b/api/dtmf_sender_interface.h
@@ -0,0 +1,100 @@ +/* + * Copyright 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_DTMF_SENDER_INTERFACE_H_ +#define API_DTMF_SENDER_INTERFACE_H_ + +#include <string> + +#include "api/media_stream_interface.h" +#include "rtc_base/ref_count.h" + +namespace webrtc { + +// DtmfSender callback interface, used to implement RTCDtmfSender events. +// Applications should implement this interface to get notifications from the +// DtmfSender. +class DtmfSenderObserverInterface { + public: + // Triggered when DTMF |tone| is sent. + // If |tone| is empty that means the DtmfSender has sent out all the given + // tones. + // The callback includes the state of the tone buffer at the time when + // the tone finished playing. + virtual void OnToneChange(const std::string& tone, + const std::string& tone_buffer) {} + // DEPRECATED: Older API without tone buffer. + // TODO(bugs.webrtc.org/9725): Remove old API and default implementation + // when old callers are gone. + virtual void OnToneChange(const std::string& tone) {} + + protected: + virtual ~DtmfSenderObserverInterface() = default; +}; + +// The interface of native implementation of the RTCDTMFSender defined by the +// WebRTC W3C Editor's Draft. +// See: https://www.w3.org/TR/webrtc/#peer-to-peer-dtmf +class DtmfSenderInterface : public rtc::RefCountInterface { + public: + // Used to receive events from the DTMF sender. Only one observer can be + // registered at a time. UnregisterObserver should be called before the + // observer object is destroyed. + virtual void RegisterObserver(DtmfSenderObserverInterface* observer) = 0; + virtual void UnregisterObserver() = 0; + + // Returns true if this DtmfSender is capable of sending DTMF. Otherwise + // returns false. To be able to send DTMF, the associated RtpSender must be + // able to send packets, and a "telephone-event" codec must be negotiated. + virtual bool CanInsertDtmf() = 0; + + // Queues a task that sends the DTMF |tones|. The |tones| parameter is treated + // as a series of characters. The characters 0 through 9, A through D, #, and + // * generate the associated DTMF tones. The characters a to d are equivalent + // to A to D. The character ',' indicates a delay of 2 seconds before + // processing the next character in the tones parameter. + // + // Unrecognized characters are ignored. + // + // The |duration| parameter indicates the duration in ms to use for each + // character passed in the |tones| parameter. The duration cannot be more + // than 6000 or less than 70. + // + // The |inter_tone_gap| parameter indicates the gap between tones in ms. The + // |inter_tone_gap| must be at least 50 ms but should be as short as + // possible. + // + // If InsertDtmf is called on the same object while an existing task for this + // object to generate DTMF is still running, the previous task is canceled. + // Returns true on success and false on failure. + virtual bool InsertDtmf(const std::string& tones, + int duration, + int inter_tone_gap) = 0; + + // Returns the tones remaining to be played out. + virtual std::string tones() const = 0; + + // Returns the current tone duration value in ms. + // This value will be the value last set via the InsertDtmf() method, or the + // default value of 100 ms if InsertDtmf() was never called. + virtual int duration() const = 0; + + // Returns the current value of the between-tone gap in ms. + // This value will be the value last set via the InsertDtmf() method, or the + // default value of 50 ms if InsertDtmf() was never called. + virtual int inter_tone_gap() const = 0; + + protected: + ~DtmfSenderInterface() override = default; +}; + +} // namespace webrtc + +#endif // API_DTMF_SENDER_INTERFACE_H_
diff --git a/api/ice_transport_factory.cc b/api/ice_transport_factory.cc new file mode 100644 index 0000000..6cc399a --- /dev/null +++ b/api/ice_transport_factory.cc
@@ -0,0 +1,58 @@ +/* + * Copyright 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/ice_transport_factory.h" + +#include <memory> +#include <utility> + +#include "absl/memory/memory.h" +#include "p2p/base/ice_transport_internal.h" +#include "p2p/base/p2p_transport_channel.h" +#include "p2p/base/port_allocator.h" +#include "rtc_base/thread.h" + +namespace webrtc { + +namespace { + +// This implementation of IceTransportInterface is used in cases where +// the only reference to the P2PTransport will be through this class. +// It must be constructed, accessed and destroyed on the signaling thread. +class IceTransportWithTransportChannel : public IceTransportInterface { + public: + IceTransportWithTransportChannel( + std::unique_ptr<cricket::IceTransportInternal> internal) + : internal_(std::move(internal)) {} + + ~IceTransportWithTransportChannel() override { + RTC_DCHECK_RUN_ON(&thread_checker_); + } + + cricket::IceTransportInternal* internal() override { + RTC_DCHECK_RUN_ON(&thread_checker_); + return internal_.get(); + } + + private: + const rtc::ThreadChecker thread_checker_{}; + const std::unique_ptr<cricket::IceTransportInternal> internal_ + RTC_GUARDED_BY(thread_checker_); +}; + +} // namespace + +rtc::scoped_refptr<IceTransportInterface> CreateIceTransport( + cricket::PortAllocator* port_allocator) { + return new rtc::RefCountedObject<IceTransportWithTransportChannel>( + absl::make_unique<cricket::P2PTransportChannel>("", 0, port_allocator)); +} + +} // namespace webrtc
diff --git a/api/ice_transport_factory.h b/api/ice_transport_factory.h new file mode 100644 index 0000000..a8330df --- /dev/null +++ b/api/ice_transport_factory.h
@@ -0,0 +1,33 @@ +/* + * Copyright 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_ICE_TRANSPORT_FACTORY_H_ +#define API_ICE_TRANSPORT_FACTORY_H_ + +#include "api/ice_transport_interface.h" +#include "api/scoped_refptr.h" + +namespace cricket { +class PortAllocator; +} + +namespace webrtc { + +// Static factory for an IceTransport object that can be created +// without using a webrtc::PeerConnection. +// The returned object must be accessed and destroyed on the thread that +// created it. +// The PortAllocator must outlive the created IceTransportInterface object. +rtc::scoped_refptr<IceTransportInterface> CreateIceTransport( + cricket::PortAllocator* port_allocator); + +} // namespace webrtc + +#endif // API_ICE_TRANSPORT_FACTORY_H_
diff --git a/api/ice_transport_interface.h b/api/ice_transport_interface.h new file mode 100644 index 0000000..6e63045 --- /dev/null +++ b/api/ice_transport_interface.h
@@ -0,0 +1,38 @@ +/* + * Copyright 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_ICE_TRANSPORT_INTERFACE_H_ +#define API_ICE_TRANSPORT_INTERFACE_H_ + +#include "api/rtc_error.h" +#include "api/scoped_refptr.h" +#include "rtc_base/ref_count.h" + +namespace cricket { +class IceTransportInternal; +} // namespace cricket + +namespace webrtc { + +// An ICE transport, as represented to the outside world. +// This object is refcounted, and is therefore alive until the +// last holder has released it. +class IceTransportInterface : public rtc::RefCountInterface { + public: + // Accessor for the internal representation of an ICE transport. + // The returned object can only be safely used on the signalling thread. + // TODO(crbug.com/907849): Add API calls for the functions that have to + // be exposed to clients, and stop allowing access to the + // cricket::IceTransportInternal API. + virtual cricket::IceTransportInternal* internal() = 0; +}; + +} // namespace webrtc +#endif // API_ICE_TRANSPORT_INTERFACE_H_
diff --git a/api/jsep.h b/api/jsep.h index 1c50455..6da7827 100644 --- a/api/jsep.h +++ b/api/jsep.h
@@ -27,8 +27,8 @@ #include <vector> #include "absl/types/optional.h" -#include "api/rtcerror.h" -#include "rtc_base/refcount.h" +#include "api/rtc_error.h" +#include "rtc_base/ref_count.h" #include "rtc_base/system/rtc_export.h" namespace cricket {
diff --git a/api/jsep_ice_candidate.cc b/api/jsep_ice_candidate.cc new file mode 100644 index 0000000..59da4e4 --- /dev/null +++ b/api/jsep_ice_candidate.cc
@@ -0,0 +1,86 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/jsep_ice_candidate.h" + +#include <algorithm> +#include <utility> + +namespace webrtc { + +std::string JsepIceCandidate::sdp_mid() const { + return sdp_mid_; +} + +int JsepIceCandidate::sdp_mline_index() const { + return sdp_mline_index_; +} + +const cricket::Candidate& JsepIceCandidate::candidate() const { + return candidate_; +} + +std::string JsepIceCandidate::server_url() const { + return candidate_.url(); +} + +JsepCandidateCollection::JsepCandidateCollection() = default; + +JsepCandidateCollection::JsepCandidateCollection(JsepCandidateCollection&& o) + : candidates_(std::move(o.candidates_)) {} + +size_t JsepCandidateCollection::count() const { + return candidates_.size(); +} + +void JsepCandidateCollection::add(JsepIceCandidate* candidate) { + candidates_.push_back(candidate); +} + +const IceCandidateInterface* JsepCandidateCollection::at(size_t index) const { + return candidates_[index]; +} + +JsepCandidateCollection::~JsepCandidateCollection() { + for (std::vector<JsepIceCandidate*>::iterator it = candidates_.begin(); + it != candidates_.end(); ++it) { + delete *it; + } +} + +bool JsepCandidateCollection::HasCandidate( + const IceCandidateInterface* candidate) const { + bool ret = false; + for (std::vector<JsepIceCandidate*>::const_iterator it = candidates_.begin(); + it != candidates_.end(); ++it) { + if ((*it)->sdp_mid() == candidate->sdp_mid() && + (*it)->sdp_mline_index() == candidate->sdp_mline_index() && + (*it)->candidate().IsEquivalent(candidate->candidate())) { + ret = true; + break; + } + } + return ret; +} + +size_t JsepCandidateCollection::remove(const cricket::Candidate& candidate) { + auto iter = std::find_if(candidates_.begin(), candidates_.end(), + [candidate](JsepIceCandidate* c) { + return candidate.MatchesForRemoval(c->candidate()); + }); + if (iter != candidates_.end()) { + delete *iter; + candidates_.erase(iter); + return 1; + } + return 0; +} + +} // namespace webrtc
diff --git a/api/jsep_ice_candidate.h b/api/jsep_ice_candidate.h new file mode 100644 index 0000000..5b22454 --- /dev/null +++ b/api/jsep_ice_candidate.h
@@ -0,0 +1,85 @@ +/* + * Copyright 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// TODO(deadbeef): Move this out of api/; it's an implementation detail and +// shouldn't be used externally. + +#ifndef API_JSEP_ICE_CANDIDATE_H_ +#define API_JSEP_ICE_CANDIDATE_H_ + +#include <stddef.h> +#include <string> +#include <vector> + +#include "api/candidate.h" +#include "api/jsep.h" +#include "rtc_base/constructor_magic.h" + +namespace webrtc { + +// Implementation of IceCandidateInterface. +class JsepIceCandidate : public IceCandidateInterface { + public: + JsepIceCandidate(const std::string& sdp_mid, int sdp_mline_index); + JsepIceCandidate(const std::string& sdp_mid, + int sdp_mline_index, + const cricket::Candidate& candidate); + ~JsepIceCandidate() override; + // |err| may be null. + bool Initialize(const std::string& sdp, SdpParseError* err); + void SetCandidate(const cricket::Candidate& candidate) { + candidate_ = candidate; + } + + std::string sdp_mid() const override; + int sdp_mline_index() const override; + const cricket::Candidate& candidate() const override; + + std::string server_url() const override; + + bool ToString(std::string* out) const override; + + private: + std::string sdp_mid_; + int sdp_mline_index_; + cricket::Candidate candidate_; + + RTC_DISALLOW_COPY_AND_ASSIGN(JsepIceCandidate); +}; + +// Implementation of IceCandidateCollection which stores JsepIceCandidates. +class JsepCandidateCollection : public IceCandidateCollection { + public: + JsepCandidateCollection(); + // Move constructor is defined so that a vector of JsepCandidateCollections + // can be resized. + JsepCandidateCollection(JsepCandidateCollection&& o); + ~JsepCandidateCollection() override; + size_t count() const override; + bool HasCandidate(const IceCandidateInterface* candidate) const override; + // Adds and takes ownership of the JsepIceCandidate. + // TODO(deadbeef): Make this use an std::unique_ptr<>, so ownership logic is + // more clear. + virtual void add(JsepIceCandidate* candidate); + const IceCandidateInterface* at(size_t index) const override; + // Removes the candidate that has a matching address and protocol. + // + // Returns the number of candidates that were removed. + size_t remove(const cricket::Candidate& candidate); + + private: + std::vector<JsepIceCandidate*> candidates_; + + RTC_DISALLOW_COPY_AND_ASSIGN(JsepCandidateCollection); +}; + +} // namespace webrtc + +#endif // API_JSEP_ICE_CANDIDATE_H_
diff --git a/api/jsep_session_description.h b/api/jsep_session_description.h new file mode 100644 index 0000000..75ae0cd --- /dev/null +++ b/api/jsep_session_description.h
@@ -0,0 +1,91 @@ +/* + * Copyright 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// TODO(deadbeef): Move this out of api/; it's an implementation detail and +// shouldn't be used externally. + +#ifndef API_JSEP_SESSION_DESCRIPTION_H_ +#define API_JSEP_SESSION_DESCRIPTION_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "absl/strings/string_view.h" +#include "api/candidate.h" +#include "api/jsep.h" +#include "api/jsep_ice_candidate.h" +#include "rtc_base/constructor_magic.h" + +namespace cricket { +class SessionDescription; +} + +namespace webrtc { + +// Implementation of SessionDescriptionInterface. +class JsepSessionDescription : public SessionDescriptionInterface { + public: + explicit JsepSessionDescription(SdpType type); + // TODO(steveanton): Remove this once callers have switched to SdpType. + explicit JsepSessionDescription(const std::string& type); + JsepSessionDescription( + SdpType type, + std::unique_ptr<cricket::SessionDescription> description, + absl::string_view session_id, + absl::string_view session_version); + virtual ~JsepSessionDescription(); + + // Takes ownership of |description|. + // TODO(deadbeef): Make this use an std::unique_ptr<>, so ownership logic is + // more clear. + bool Initialize(cricket::SessionDescription* description, + const std::string& session_id, + const std::string& session_version); + + virtual cricket::SessionDescription* description() { + return description_.get(); + } + virtual const cricket::SessionDescription* description() const { + return description_.get(); + } + virtual std::string session_id() const { return session_id_; } + virtual std::string session_version() const { return session_version_; } + virtual SdpType GetType() const { return type_; } + virtual std::string type() const { return SdpTypeToString(type_); } + // Allows changing the type. Used for testing. + virtual bool AddCandidate(const IceCandidateInterface* candidate); + virtual size_t RemoveCandidates( + const std::vector<cricket::Candidate>& candidates); + virtual size_t number_of_mediasections() const; + virtual const IceCandidateCollection* candidates( + size_t mediasection_index) const; + virtual bool ToString(std::string* out) const; + + static const int kDefaultVideoCodecId; + static const char kDefaultVideoCodecName[]; + + private: + std::unique_ptr<cricket::SessionDescription> description_; + std::string session_id_; + std::string session_version_; + SdpType type_; + std::vector<JsepCandidateCollection> candidate_collection_; + + bool GetMediasectionIndex(const IceCandidateInterface* candidate, + size_t* index); + int GetMediasectionIndex(const cricket::Candidate& candidate); + + RTC_DISALLOW_COPY_AND_ASSIGN(JsepSessionDescription); +}; + +} // namespace webrtc + +#endif // API_JSEP_SESSION_DESCRIPTION_H_
diff --git a/api/media_stream_interface.cc b/api/media_stream_interface.cc new file mode 100644 index 0000000..cf994cb --- /dev/null +++ b/api/media_stream_interface.cc
@@ -0,0 +1,39 @@ +/* + * Copyright 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/media_stream_interface.h" + +namespace webrtc { + +const char MediaStreamTrackInterface::kVideoKind[] = "video"; +const char MediaStreamTrackInterface::kAudioKind[] = "audio"; + +VideoTrackInterface::ContentHint VideoTrackInterface::content_hint() const { + return ContentHint::kNone; +} + +bool AudioTrackInterface::GetSignalLevel(int* level) { + return false; +} + +rtc::scoped_refptr<AudioProcessorInterface> +AudioTrackInterface::GetAudioProcessor() { + return nullptr; +} + +const cricket::AudioOptions AudioSourceInterface::options() const { + return {}; +} + +double MediaSourceInterface::GetLatency() const { + return 0.0; +} + +} // namespace webrtc
diff --git a/api/media_stream_interface.h b/api/media_stream_interface.h new file mode 100644 index 0000000..1249b85 --- /dev/null +++ b/api/media_stream_interface.h
@@ -0,0 +1,304 @@ +/* + * Copyright 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This file contains interfaces for MediaStream, MediaTrack and MediaSource. +// These interfaces are used for implementing MediaStream and MediaTrack as +// defined in http://dev.w3.org/2011/webrtc/editor/webrtc.html#stream-api. These +// interfaces must be used only with PeerConnection. PeerConnectionManager +// interface provides the factory methods to create MediaStream and MediaTracks. + +#ifndef API_MEDIA_STREAM_INTERFACE_H_ +#define API_MEDIA_STREAM_INTERFACE_H_ + +#include <stddef.h> + +#include <string> +#include <vector> + +#include "absl/types/optional.h" +#include "api/audio_options.h" +#include "api/scoped_refptr.h" +#include "api/video/video_frame.h" +#include "api/video/video_sink_interface.h" +#include "api/video/video_source_interface.h" +#include "modules/audio_processing/include/audio_processing_statistics.h" +#include "rtc_base/ref_count.h" + +namespace webrtc { + +// Generic observer interface. +class ObserverInterface { + public: + virtual void OnChanged() = 0; + + protected: + virtual ~ObserverInterface() {} +}; + +class NotifierInterface { + public: + virtual void RegisterObserver(ObserverInterface* observer) = 0; + virtual void UnregisterObserver(ObserverInterface* observer) = 0; + + virtual ~NotifierInterface() {} +}; + +// Base class for sources. A MediaStreamTrack has an underlying source that +// provides media. A source can be shared by multiple tracks. +class MediaSourceInterface : public rtc::RefCountInterface, + public NotifierInterface { + public: + enum SourceState { kInitializing, kLive, kEnded, kMuted }; + + virtual SourceState state() const = 0; + + virtual bool remote() const = 0; + + // Sets the minimum latency of the remote source until audio playout. Actual + // observered latency may differ depending on the source. |latency| is in the + // range of [0.0, 10.0] seconds. + // TODO(kuddai) make pure virtual once not only remote tracks support latency. + virtual void SetLatency(double latency) {} + virtual double GetLatency() const; + + protected: + ~MediaSourceInterface() override = default; +}; + +// C++ version of MediaStreamTrack. +// See: https://www.w3.org/TR/mediacapture-streams/#mediastreamtrack +class MediaStreamTrackInterface : public rtc::RefCountInterface, + public NotifierInterface { + public: + enum TrackState { + kLive, + kEnded, + }; + + static const char kAudioKind[]; + static const char kVideoKind[]; + + // The kind() method must return kAudioKind only if the object is a + // subclass of AudioTrackInterface, and kVideoKind only if the + // object is a subclass of VideoTrackInterface. It is typically used + // to protect a static_cast<> to the corresponding subclass. + virtual std::string kind() const = 0; + + // Track identifier. + virtual std::string id() const = 0; + + // A disabled track will produce silence (if audio) or black frames (if + // video). Can be disabled and re-enabled. + virtual bool enabled() const = 0; + virtual bool set_enabled(bool enable) = 0; + + // Live or ended. A track will never be live again after becoming ended. + virtual TrackState state() const = 0; + + protected: + ~MediaStreamTrackInterface() override = default; +}; + +// VideoTrackSourceInterface is a reference counted source used for +// VideoTracks. The same source can be used by multiple VideoTracks. +// VideoTrackSourceInterface is designed to be invoked on the signaling thread +// except for rtc::VideoSourceInterface<VideoFrame> methods that will be invoked +// on the worker thread via a VideoTrack. A custom implementation of a source +// can inherit AdaptedVideoTrackSource instead of directly implementing this +// interface. +class VideoTrackSourceInterface : public MediaSourceInterface, + public rtc::VideoSourceInterface<VideoFrame> { + public: + struct Stats { + // Original size of captured frame, before video adaptation. + int input_width; + int input_height; + }; + + // Indicates that parameters suitable for screencasts should be automatically + // applied to RtpSenders. + // TODO(perkj): Remove these once all known applications have moved to + // explicitly setting suitable parameters for screencasts and don't need this + // implicit behavior. + virtual bool is_screencast() const = 0; + + // Indicates that the encoder should denoise video before encoding it. + // If it is not set, the default configuration is used which is different + // depending on video codec. + // TODO(perkj): Remove this once denoising is done by the source, and not by + // the encoder. + virtual absl::optional<bool> needs_denoising() const = 0; + + // Returns false if no stats are available, e.g, for a remote source, or a + // source which has not seen its first frame yet. + // + // Implementation should avoid blocking. + virtual bool GetStats(Stats* stats) = 0; + + protected: + ~VideoTrackSourceInterface() override = default; +}; + +// VideoTrackInterface is designed to be invoked on the signaling thread except +// for rtc::VideoSourceInterface<VideoFrame> methods that must be invoked +// on the worker thread. +// PeerConnectionFactory::CreateVideoTrack can be used for creating a VideoTrack +// that ensures thread safety and that all methods are called on the right +// thread. +class VideoTrackInterface : public MediaStreamTrackInterface, + public rtc::VideoSourceInterface<VideoFrame> { + public: + // Video track content hint, used to override the source is_screencast + // property. + // See https://crbug.com/653531 and https://w3c.github.io/mst-content-hint. + enum class ContentHint { kNone, kFluid, kDetailed, kText }; + + // Register a video sink for this track. Used to connect the track to the + // underlying video engine. + void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, + const rtc::VideoSinkWants& wants) override {} + void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override {} + + virtual VideoTrackSourceInterface* GetSource() const = 0; + + virtual ContentHint content_hint() const; + virtual void set_content_hint(ContentHint hint) {} + + protected: + ~VideoTrackInterface() override = default; +}; + +// Interface for receiving audio data from a AudioTrack. +class AudioTrackSinkInterface { + public: + virtual void OnData(const void* audio_data, + int bits_per_sample, + int sample_rate, + size_t number_of_channels, + size_t number_of_frames) = 0; + + protected: + virtual ~AudioTrackSinkInterface() {} +}; + +// AudioSourceInterface is a reference counted source used for AudioTracks. +// The same source can be used by multiple AudioTracks. +class AudioSourceInterface : public MediaSourceInterface { + public: + class AudioObserver { + public: + virtual void OnSetVolume(double volume) = 0; + + protected: + virtual ~AudioObserver() {} + }; + + // TODO(deadbeef): Makes all the interfaces pure virtual after they're + // implemented in chromium. + + // Sets the volume of the source. |volume| is in the range of [0, 10]. + // TODO(tommi): This method should be on the track and ideally volume should + // be applied in the track in a way that does not affect clones of the track. + virtual void SetVolume(double volume) {} + + // Registers/unregisters observers to the audio source. + virtual void RegisterAudioObserver(AudioObserver* observer) {} + virtual void UnregisterAudioObserver(AudioObserver* observer) {} + + // TODO(tommi): Make pure virtual. + virtual void AddSink(AudioTrackSinkInterface* sink) {} + virtual void RemoveSink(AudioTrackSinkInterface* sink) {} + + // Returns options for the AudioSource. + // (for some of the settings this approach is broken, e.g. setting + // audio network adaptation on the source is the wrong layer of abstraction). + virtual const cricket::AudioOptions options() const; +}; + +// Interface of the audio processor used by the audio track to collect +// statistics. +class AudioProcessorInterface : public rtc::RefCountInterface { + public: + struct AudioProcessorStatistics { + bool typing_noise_detected = false; + AudioProcessingStats apm_statistics; + }; + + // Get audio processor statistics. The |has_remote_tracks| argument should be + // set if there are active remote tracks (this would usually be true during + // a call). If there are no remote tracks some of the stats will not be set by + // the AudioProcessor, because they only make sense if there is at least one + // remote track. + virtual AudioProcessorStatistics GetStats(bool has_remote_tracks) = 0; + + protected: + ~AudioProcessorInterface() override = default; +}; + +class AudioTrackInterface : public MediaStreamTrackInterface { + public: + // TODO(deadbeef): Figure out if the following interface should be const or + // not. + virtual AudioSourceInterface* GetSource() const = 0; + + // Add/Remove a sink that will receive the audio data from the track. + virtual void AddSink(AudioTrackSinkInterface* sink) = 0; + virtual void RemoveSink(AudioTrackSinkInterface* sink) = 0; + + // Get the signal level from the audio track. + // Return true on success, otherwise false. + // TODO(deadbeef): Change the interface to int GetSignalLevel() and pure + // virtual after it's implemented in chromium. + virtual bool GetSignalLevel(int* level); + + // Get the audio processor used by the audio track. Return null if the track + // does not have any processor. + // TODO(deadbeef): Make the interface pure virtual. + virtual rtc::scoped_refptr<AudioProcessorInterface> GetAudioProcessor(); + + protected: + ~AudioTrackInterface() override = default; +}; + +typedef std::vector<rtc::scoped_refptr<AudioTrackInterface> > AudioTrackVector; +typedef std::vector<rtc::scoped_refptr<VideoTrackInterface> > VideoTrackVector; + +// C++ version of https://www.w3.org/TR/mediacapture-streams/#mediastream. +// +// A major difference is that remote audio/video tracks (received by a +// PeerConnection/RtpReceiver) are not synchronized simply by adding them to +// the same stream; a session description with the correct "a=msid" attributes +// must be pushed down. +// +// Thus, this interface acts as simply a container for tracks. +class MediaStreamInterface : public rtc::RefCountInterface, + public NotifierInterface { + public: + virtual std::string id() const = 0; + + virtual AudioTrackVector GetAudioTracks() = 0; + virtual VideoTrackVector GetVideoTracks() = 0; + virtual rtc::scoped_refptr<AudioTrackInterface> FindAudioTrack( + const std::string& track_id) = 0; + virtual rtc::scoped_refptr<VideoTrackInterface> FindVideoTrack( + const std::string& track_id) = 0; + + virtual bool AddTrack(AudioTrackInterface* track) = 0; + virtual bool AddTrack(VideoTrackInterface* track) = 0; + virtual bool RemoveTrack(AudioTrackInterface* track) = 0; + virtual bool RemoveTrack(VideoTrackInterface* track) = 0; + + protected: + ~MediaStreamInterface() override = default; +}; + +} // namespace webrtc + +#endif // API_MEDIA_STREAM_INTERFACE_H_
diff --git a/api/media_stream_proxy.h b/api/media_stream_proxy.h new file mode 100644 index 0000000..5169679 --- /dev/null +++ b/api/media_stream_proxy.h
@@ -0,0 +1,44 @@ +/* + * Copyright 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_MEDIA_STREAM_PROXY_H_ +#define API_MEDIA_STREAM_PROXY_H_ + +#include <string> + +#include "api/media_stream_interface.h" +#include "api/proxy.h" + +namespace webrtc { + +// TODO(deadbeef): Move this to .cc file and out of api/. What threads methods +// are called on is an implementation detail. +BEGIN_SIGNALING_PROXY_MAP(MediaStream) +PROXY_SIGNALING_THREAD_DESTRUCTOR() +PROXY_CONSTMETHOD0(std::string, id) +PROXY_METHOD0(AudioTrackVector, GetAudioTracks) +PROXY_METHOD0(VideoTrackVector, GetVideoTracks) +PROXY_METHOD1(rtc::scoped_refptr<AudioTrackInterface>, + FindAudioTrack, + const std::string&) +PROXY_METHOD1(rtc::scoped_refptr<VideoTrackInterface>, + FindVideoTrack, + const std::string&) +PROXY_METHOD1(bool, AddTrack, AudioTrackInterface*) +PROXY_METHOD1(bool, AddTrack, VideoTrackInterface*) +PROXY_METHOD1(bool, RemoveTrack, AudioTrackInterface*) +PROXY_METHOD1(bool, RemoveTrack, VideoTrackInterface*) +PROXY_METHOD1(void, RegisterObserver, ObserverInterface*) +PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*) +END_PROXY_MAP() + +} // namespace webrtc + +#endif // API_MEDIA_STREAM_PROXY_H_
diff --git a/api/media_stream_track_proxy.h b/api/media_stream_track_proxy.h new file mode 100644 index 0000000..d3dc255 --- /dev/null +++ b/api/media_stream_track_proxy.h
@@ -0,0 +1,65 @@ +/* + * Copyright 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This file includes proxy classes for tracks. The purpose is +// to make sure tracks are only accessed from the signaling thread. + +#ifndef API_MEDIA_STREAM_TRACK_PROXY_H_ +#define API_MEDIA_STREAM_TRACK_PROXY_H_ + +#include <string> + +#include "api/media_stream_interface.h" +#include "api/proxy.h" + +namespace webrtc { + +// TODO(deadbeef): Move this to .cc file and out of api/. What threads methods +// are called on is an implementation detail. + +BEGIN_SIGNALING_PROXY_MAP(AudioTrack) +PROXY_SIGNALING_THREAD_DESTRUCTOR() +PROXY_CONSTMETHOD0(std::string, kind) +PROXY_CONSTMETHOD0(std::string, id) +PROXY_CONSTMETHOD0(TrackState, state) +PROXY_CONSTMETHOD0(bool, enabled) +PROXY_CONSTMETHOD0(AudioSourceInterface*, GetSource) +PROXY_METHOD1(void, AddSink, AudioTrackSinkInterface*) +PROXY_METHOD1(void, RemoveSink, AudioTrackSinkInterface*) +PROXY_METHOD1(bool, GetSignalLevel, int*) +PROXY_METHOD0(rtc::scoped_refptr<AudioProcessorInterface>, GetAudioProcessor) +PROXY_METHOD1(bool, set_enabled, bool) +PROXY_METHOD1(void, RegisterObserver, ObserverInterface*) +PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*) +END_PROXY_MAP() + +BEGIN_PROXY_MAP(VideoTrack) +PROXY_SIGNALING_THREAD_DESTRUCTOR() +PROXY_CONSTMETHOD0(std::string, kind) +PROXY_CONSTMETHOD0(std::string, id) +PROXY_CONSTMETHOD0(TrackState, state) +PROXY_CONSTMETHOD0(bool, enabled) +PROXY_METHOD1(bool, set_enabled, bool) +PROXY_CONSTMETHOD0(ContentHint, content_hint) +PROXY_METHOD1(void, set_content_hint, ContentHint) +PROXY_WORKER_METHOD2(void, + AddOrUpdateSink, + rtc::VideoSinkInterface<VideoFrame>*, + const rtc::VideoSinkWants&) +PROXY_WORKER_METHOD1(void, RemoveSink, rtc::VideoSinkInterface<VideoFrame>*) +PROXY_CONSTMETHOD0(VideoTrackSourceInterface*, GetSource) + +PROXY_METHOD1(void, RegisterObserver, ObserverInterface*) +PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*) +END_PROXY_MAP() + +} // namespace webrtc + +#endif // API_MEDIA_STREAM_TRACK_PROXY_H_
diff --git a/api/media_transport_interface.cc b/api/media_transport_interface.cc index ef223aa..20bbe26 100644 --- a/api/media_transport_interface.cc +++ b/api/media_transport_interface.cc
@@ -29,71 +29,9 @@ const MediaTransportSettings&) = default; MediaTransportSettings::~MediaTransportSettings() = default; -MediaTransportEncodedAudioFrame::~MediaTransportEncodedAudioFrame() {} - -MediaTransportEncodedAudioFrame::MediaTransportEncodedAudioFrame( - int sampling_rate_hz, - int starting_sample_index, - int samples_per_channel, - int sequence_number, - FrameType frame_type, - uint8_t payload_type, - std::vector<uint8_t> encoded_data) - : sampling_rate_hz_(sampling_rate_hz), - starting_sample_index_(starting_sample_index), - samples_per_channel_(samples_per_channel), - sequence_number_(sequence_number), - frame_type_(frame_type), - payload_type_(payload_type), - encoded_data_(std::move(encoded_data)) {} - -MediaTransportEncodedAudioFrame& MediaTransportEncodedAudioFrame::operator=( - const MediaTransportEncodedAudioFrame&) = default; - -MediaTransportEncodedAudioFrame& MediaTransportEncodedAudioFrame::operator=( - MediaTransportEncodedAudioFrame&&) = default; - -MediaTransportEncodedAudioFrame::MediaTransportEncodedAudioFrame( - const MediaTransportEncodedAudioFrame&) = default; - -MediaTransportEncodedAudioFrame::MediaTransportEncodedAudioFrame( - MediaTransportEncodedAudioFrame&&) = default; - -MediaTransportEncodedVideoFrame::~MediaTransportEncodedVideoFrame() {} - -MediaTransportEncodedVideoFrame::MediaTransportEncodedVideoFrame( - int64_t frame_id, - std::vector<int64_t> referenced_frame_ids, - VideoCodecType codec_type, - const webrtc::EncodedImage& encoded_image) - : codec_type_(codec_type), - encoded_image_(encoded_image), - frame_id_(frame_id), - referenced_frame_ids_(std::move(referenced_frame_ids)) {} - -MediaTransportEncodedVideoFrame& MediaTransportEncodedVideoFrame::operator=( - const MediaTransportEncodedVideoFrame&) = default; - -MediaTransportEncodedVideoFrame& MediaTransportEncodedVideoFrame::operator=( - MediaTransportEncodedVideoFrame&&) = default; - -MediaTransportEncodedVideoFrame::MediaTransportEncodedVideoFrame( - const MediaTransportEncodedVideoFrame&) = default; - -MediaTransportEncodedVideoFrame::MediaTransportEncodedVideoFrame( - MediaTransportEncodedVideoFrame&&) = default; SendDataParams::SendDataParams() = default; - -RTCErrorOr<std::unique_ptr<MediaTransportInterface>> -MediaTransportFactory::CreateMediaTransport( - rtc::PacketTransportInternal* packet_transport, - rtc::Thread* network_thread, - bool is_caller) { - MediaTransportSettings settings; - settings.is_caller = is_caller; - return CreateMediaTransport(packet_transport, network_thread, settings); -} +SendDataParams::SendDataParams(const SendDataParams&) = default; RTCErrorOr<std::unique_ptr<MediaTransportInterface>> MediaTransportFactory::CreateMediaTransport( @@ -103,22 +41,60 @@ return std::unique_ptr<MediaTransportInterface>(nullptr); } +RTCErrorOr<std::unique_ptr<MediaTransportInterface>> +MediaTransportFactory::CreateMediaTransport( + rtc::Thread* network_thread, + const MediaTransportSettings& settings) { + return std::unique_ptr<MediaTransportInterface>(nullptr); +} + +std::string MediaTransportFactory::GetTransportName() const { + return ""; +} + +MediaTransportInterface::MediaTransportInterface() = default; +MediaTransportInterface::~MediaTransportInterface() = default; + +absl::optional<std::string> +MediaTransportInterface::GetTransportParametersOffer() const { + return absl::nullopt; +} + +void MediaTransportInterface::Connect( + rtc::PacketTransportInternal* packet_transport) {} + +void MediaTransportInterface::SetKeyFrameRequestCallback( + MediaTransportKeyFrameRequestCallback* callback) {} + absl::optional<TargetTransferRate> MediaTransportInterface::GetLatestTargetTransferRate() { return absl::nullopt; } -void MediaTransportInterface::SetNetworkChangeCallback( +void MediaTransportInterface::AddNetworkChangeCallback( MediaTransportNetworkChangeCallback* callback) {} -void MediaTransportInterface::RemoveTargetTransferRateObserver( - webrtc::TargetTransferRateObserver* observer) {} +void MediaTransportInterface::RemoveNetworkChangeCallback( + MediaTransportNetworkChangeCallback* callback) {} + +void MediaTransportInterface::SetFirstAudioPacketReceivedObserver( + AudioPacketReceivedObserver* observer) {} void MediaTransportInterface::AddTargetTransferRateObserver( - webrtc::TargetTransferRateObserver* observer) {} + TargetTransferRateObserver* observer) {} +void MediaTransportInterface::RemoveTargetTransferRateObserver( + TargetTransferRateObserver* observer) {} + +void MediaTransportInterface::AddRttObserver( + MediaTransportRttObserver* observer) {} +void MediaTransportInterface::RemoveRttObserver( + MediaTransportRttObserver* observer) {} size_t MediaTransportInterface::GetAudioPacketOverhead() const { return 0; } +void MediaTransportInterface::SetAllocatedBitrateLimits( + const MediaTransportAllocatedBitrateLimits& limits) {} + } // namespace webrtc
diff --git a/api/media_transport_interface.h b/api/media_transport_interface.h index b10dd63..d333bec 100644 --- a/api/media_transport_interface.h +++ b/api/media_transport_interface.h
@@ -21,14 +21,15 @@ #include <memory> #include <string> #include <utility> -#include <vector> #include "absl/types/optional.h" #include "api/array_view.h" -#include "api/rtcerror.h" -#include "api/video/encoded_image.h" -#include "rtc_base/copyonwritebuffer.h" -#include "rtc_base/networkroute.h" +#include "api/rtc_error.h" +#include "api/transport/media/audio_transport.h" +#include "api/transport/media/video_transport.h" +#include "api/units/data_rate.h" +#include "rtc_base/copy_on_write_buffer.h" +#include "rtc_base/network_route.h" namespace rtc { class PacketTransportInternal; @@ -37,6 +38,23 @@ namespace webrtc { +class RtcEventLog; + +class AudioPacketReceivedObserver { + public: + virtual ~AudioPacketReceivedObserver() = default; + + // Invoked for the first received audio packet on a given channel id. + // It will be invoked once for each channel id. + virtual void OnFirstAudioPacketReceived(int64_t channel_id) = 0; +}; + +struct MediaTransportAllocatedBitrateLimits { + DataRate min_pacing_rate = DataRate::Zero(); + DataRate max_padding_bitrate = DataRate::Zero(); + DataRate max_total_allocated_bitrate = DataRate::Zero(); +}; + // A collection of settings for creation of media transport. struct MediaTransportSettings final { MediaTransportSettings(); @@ -52,91 +70,15 @@ // TODO(bugs.webrtc.org/9944): This should become zero buffer in the distant // future. absl::optional<std::string> pre_shared_key; -}; -// Represents encoded audio frame in any encoding (type of encoding is opaque). -// To avoid copying of encoded data use move semantics when passing by value. -class MediaTransportEncodedAudioFrame final { - public: - enum class FrameType { - // Normal audio frame (equivalent to webrtc::kAudioFrameSpeech). - kSpeech, + // If present, this is a config passed from the caller to the answerer in the + // offer. Each media transport knows how to understand its own parameters. + absl::optional<std::string> remote_transport_parameters; - // DTX frame (equivalent to webrtc::kAudioFrameCN). - // DTX frame (equivalent to webrtc::kAudioFrameCN). - kDiscontinuousTransmission, - // TODO(nisse): Mis-spelled version, update users, then delete. - kDiscountinuousTransmission = kDiscontinuousTransmission, - }; - - MediaTransportEncodedAudioFrame( - // Audio sampling rate, for example 48000. - int sampling_rate_hz, - - // Starting sample index of the frame, i.e. how many audio samples were - // before this frame since the beginning of the call or beginning of time - // in one channel (the starting point should not matter for NetEq). In - // WebRTC it is used as a timestamp of the frame. - // TODO(sukhanov): Starting_sample_index is currently adjusted on the - // receiver side in RTP path. Non-RTP implementations should preserve it. - // For NetEq initial offset should not matter so we should consider fixing - // RTP path. - int starting_sample_index, - - // Number of audio samples in audio frame in 1 channel. - int samples_per_channel, - - // Sequence number of the frame in the order sent, it is currently - // required by NetEq, but we can fix NetEq, because starting_sample_index - // should be enough. - int sequence_number, - - // If audio frame is a speech or discontinued transmission. - FrameType frame_type, - - // Opaque payload type. In RTP codepath payload type is stored in RTP - // header. In other implementations it should be simply passed through the - // wire -- it's needed for decoder. - uint8_t payload_type, - - // Vector with opaque encoded data. - std::vector<uint8_t> encoded_data); - - ~MediaTransportEncodedAudioFrame(); - MediaTransportEncodedAudioFrame(const MediaTransportEncodedAudioFrame&); - MediaTransportEncodedAudioFrame& operator=( - const MediaTransportEncodedAudioFrame& other); - MediaTransportEncodedAudioFrame& operator=( - MediaTransportEncodedAudioFrame&& other); - MediaTransportEncodedAudioFrame(MediaTransportEncodedAudioFrame&&); - - // Getters. - int sampling_rate_hz() const { return sampling_rate_hz_; } - int starting_sample_index() const { return starting_sample_index_; } - int samples_per_channel() const { return samples_per_channel_; } - int sequence_number() const { return sequence_number_; } - - uint8_t payload_type() const { return payload_type_; } - FrameType frame_type() const { return frame_type_; } - - rtc::ArrayView<const uint8_t> encoded_data() const { return encoded_data_; } - - private: - int sampling_rate_hz_; - int starting_sample_index_; - int samples_per_channel_; - - // TODO(sukhanov): Refactor NetEq so we don't need sequence number. - // Having sample_index and samples_per_channel should be enough. - int sequence_number_; - - FrameType frame_type_; - - // TODO(sukhanov): Consider enumerating allowed encodings and store enum - // instead of uint payload_type. - uint8_t payload_type_; - - std::vector<uint8_t> encoded_data_; + // If present, provides the event log that media transport should use. + // Media transport does not own it. The lifetime of |event_log| will exceed + // the lifetime of the instance of MediaTransportInterface instance. + RtcEventLog* event_log = nullptr; }; // Callback to notify about network route changes. @@ -149,79 +91,6 @@ const rtc::NetworkRoute& new_network_route) = 0; }; -// Interface for receiving encoded audio frames from MediaTransportInterface -// implementations. -class MediaTransportAudioSinkInterface { - public: - virtual ~MediaTransportAudioSinkInterface() = default; - - // Called when new encoded audio frame is received. - virtual void OnData(uint64_t channel_id, - MediaTransportEncodedAudioFrame frame) = 0; -}; - -// Represents encoded video frame, along with the codec information. -class MediaTransportEncodedVideoFrame final { - public: - MediaTransportEncodedVideoFrame(int64_t frame_id, - std::vector<int64_t> referenced_frame_ids, - VideoCodecType codec_type, - const webrtc::EncodedImage& encoded_image); - ~MediaTransportEncodedVideoFrame(); - MediaTransportEncodedVideoFrame(const MediaTransportEncodedVideoFrame&); - MediaTransportEncodedVideoFrame& operator=( - const MediaTransportEncodedVideoFrame& other); - MediaTransportEncodedVideoFrame& operator=( - MediaTransportEncodedVideoFrame&& other); - MediaTransportEncodedVideoFrame(MediaTransportEncodedVideoFrame&&); - - VideoCodecType codec_type() const { return codec_type_; } - const webrtc::EncodedImage& encoded_image() const { return encoded_image_; } - - int64_t frame_id() const { return frame_id_; } - const std::vector<int64_t>& referenced_frame_ids() const { - return referenced_frame_ids_; - } - - private: - VideoCodecType codec_type_; - - // The buffer is not owned by the encoded image by default. On the sender it - // means that it will need to make a copy of it if it wants to deliver it - // asynchronously. - webrtc::EncodedImage encoded_image_; - - // Frame id uniquely identifies a frame in a stream. It needs to be unique in - // a given time window (i.e. technically unique identifier for the lifetime of - // the connection is not needed, but you need to guarantee that remote side - // got rid of the previous frame_id if you plan to reuse it). - // - // It is required by a remote jitter buffer, and is the same as - // EncodedFrame::id::picture_id. - // - // This data must be opaque to the media transport, and media transport should - // itself not make any assumptions about what it is and its uniqueness. - int64_t frame_id_; - - // A single frame might depend on other frames. This is set of identifiers on - // which the current frame depends. - std::vector<int64_t> referenced_frame_ids_; -}; - -// Interface for receiving encoded video frames from MediaTransportInterface -// implementations. -class MediaTransportVideoSinkInterface { - public: - virtual ~MediaTransportVideoSinkInterface() = default; - - // Called when new encoded video frame is received. - virtual void OnData(uint64_t channel_id, - MediaTransportEncodedVideoFrame frame) = 0; - - // Called when the request for keyframe is received. - virtual void OnKeyFrameRequested(uint64_t channel_id) = 0; -}; - // State of the media transport. Media transport begins in the pending state. // It transitions to writable when it is ready to send media. It may transition // back to pending if the connection is blocked. It may transition to closed at @@ -241,6 +110,19 @@ virtual void OnStateChanged(MediaTransportState state) = 0; }; +// Callback for RTT measurements on the receive side. +// TODO(nisse): Related interfaces: CallStatsObserver and RtcpRttStats. It's +// somewhat unclear what type of measurement is needed. It's used to configure +// NACK generation and playout buffer. Either raw measurement values or recent +// maximum would make sense for this use. Need consolidation of RTT signalling. +class MediaTransportRttObserver { + public: + virtual ~MediaTransportRttObserver() = default; + + // Invoked when a new RTT measurement is available, typically once per ACK. + virtual void OnRttUpdated(int64_t rtt_ms) = 0; +}; + // Supported types of application data messages. enum class DataMessageType { // Application data buffer with the binary bit unset. @@ -259,6 +141,7 @@ // unreliable delivery. struct SendDataParams { SendDataParams(); + SendDataParams(const SendDataParams&); DataMessageType type = DataMessageType::kText; @@ -305,7 +188,29 @@ // and receiving bandwidth estimate update from congestion control. class MediaTransportInterface { public: - virtual ~MediaTransportInterface() = default; + MediaTransportInterface(); + virtual ~MediaTransportInterface(); + + // Retrieves callers config (i.e. media transport offer) that should be passed + // to the callee, before the call is connected. Such config is opaque to SDP + // (sdp just passes it through). The config is a binary blob, so SDP may + // choose to use base64 to serialize it (or any other approach that guarantees + // that the binary blob goes through). This should only be called for the + // caller's perspective. + // + // This may return an unset optional, which means that the given media + // transport is not supported / disabled and shouldn't be reported in SDP. + // + // It may also return an empty string, in which case the media transport is + // supported, but without any extra settings. + // TODO(psla): Make abstract. + virtual absl::optional<std::string> GetTransportParametersOffer() const; + + // Connect the media transport to the ICE transport. + // The implementation must be able to ignore incoming packets that don't + // belong to it. + // TODO(psla): Make abstract. + virtual void Connect(rtc::PacketTransportInternal* packet_transport); // Start asynchronous send of audio frame. The status returned by this method // only pertains to the synchronous operations (e.g. @@ -321,6 +226,10 @@ uint64_t channel_id, const MediaTransportEncodedVideoFrame& frame) = 0; + // Used by video sender to be notified on key frame requests. + virtual void SetKeyFrameRequestCallback( + MediaTransportKeyFrameRequestCallback* callback); + // Requests a keyframe for the particular channel (stream). The caller should // check that the keyframe is not present in a jitter buffer already (i.e. // don't request a keyframe if there is one that you will get from the jitter @@ -341,12 +250,27 @@ // A newly registered observer will be called back with the latest recorded // target rate, if available. virtual void AddTargetTransferRateObserver( - webrtc::TargetTransferRateObserver* observer); + TargetTransferRateObserver* observer); // Removes an existing |observer| from observers. If observer was never // registered, an error is logged and method does nothing. virtual void RemoveTargetTransferRateObserver( - webrtc::TargetTransferRateObserver* observer); + TargetTransferRateObserver* observer); + + // Sets audio packets observer, which gets informed about incoming audio + // packets. Before destruction, the observer must be unregistered by setting + // nullptr. + // + // This method may be temporary, when the multiplexer is implemented (or + // multiplexer may use it to demultiplex channel ids). + virtual void SetFirstAudioPacketReceivedObserver( + AudioPacketReceivedObserver* observer); + + // Intended for receive side. AddRttObserver registers an observer to be + // called for each RTT measurement, typically once per ACK. Before media + // transport is destructed the observer must be unregistered. + virtual void AddRttObserver(MediaTransportRttObserver* observer); + virtual void RemoveRttObserver(MediaTransportRttObserver* observer); // Returns the last known target transfer rate as reported to the above // observers. @@ -358,12 +282,13 @@ // might not be a very accurate number. virtual size_t GetAudioPacketOverhead() const; - // Sets an observer for network change events. If the network route is already - // established when the callback is set, |callback| will be called immediately - // with the current network route. - // Before media transport is destroyed, the callback must be unregistered by - // setting it to nullptr. - virtual void SetNetworkChangeCallback( + // Registers an observer for network change events. If the network route is + // already established when the callback is added, |callback| will be called + // immediately with the current network route. Before media transport is + // destroyed, the callback must be removed. + virtual void AddNetworkChangeCallback( + MediaTransportNetworkChangeCallback* callback); + virtual void RemoveNetworkChangeCallback( MediaTransportNetworkChangeCallback* callback); // Sets a state observer callback. Before media transport is destroyed, the @@ -373,6 +298,15 @@ virtual void SetMediaTransportStateCallback( MediaTransportStateCallback* callback) = 0; + // Updates allocation limits. + // TODO(psla): Make abstract when downstream implementation implement it. + virtual void SetAllocatedBitrateLimits( + const MediaTransportAllocatedBitrateLimits& limits); + + // Opens a data |channel_id| for sending. May return an error if the + // specified |channel_id| is unusable. Must be called before |SendData|. + virtual RTCError OpenChannel(int channel_id) = 0; + // Sends a data buffer to the remote endpoint using the given send parameters. // |buffer| may not be larger than 256 KiB. Returns an error if the send // fails. @@ -408,21 +342,28 @@ // - Does not take ownership of packet_transport or network_thread. // - Does not support group calls, in 1:1 call one side must set // is_caller = true and another is_caller = false. - // TODO(bugs.webrtc.org/9938) This constructor will be removed and replaced - // with the one below. - virtual RTCErrorOr<std::unique_ptr<MediaTransportInterface>> - CreateMediaTransport(rtc::PacketTransportInternal* packet_transport, - rtc::Thread* network_thread, - bool is_caller); - - // Creates media transport. - // - Does not take ownership of packet_transport or network_thread. - // TODO(bugs.webrtc.org/9938): remove default implementation once all children - // override it. virtual RTCErrorOr<std::unique_ptr<MediaTransportInterface>> CreateMediaTransport(rtc::PacketTransportInternal* packet_transport, rtc::Thread* network_thread, const MediaTransportSettings& settings); + + // Creates a new Media Transport in a disconnected state. If the media + // transport for the caller is created, one can then call + // MediaTransportInterface::GetTransportParametersOffer on that new instance. + // TODO(psla): Make abstract. + virtual RTCErrorOr<std::unique_ptr<webrtc::MediaTransportInterface>> + CreateMediaTransport(rtc::Thread* network_thread, + const MediaTransportSettings& settings); + + // Gets a transport name which is supported by the implementation. + // Different factories should return different transport names, and at runtime + // it will be checked that different names were used. + // For example, "rtp" or "generic" may be returned by two different + // implementations. + // The value returned by this method must never change in the lifetime of the + // factory. + // TODO(psla): Make abstract. + virtual std::string GetTransportName() const; }; } // namespace webrtc
diff --git a/api/media_types.cc b/api/media_types.cc new file mode 100644 index 0000000..3359f1d --- /dev/null +++ b/api/media_types.cc
@@ -0,0 +1,49 @@ +/* + * Copyright 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/media_types.h" + +#include "api/media_stream_interface.h" +#include "rtc_base/checks.h" + +namespace { +static const char* kMediaTypeData = "data"; +} // namespace + +namespace cricket { + +std::string MediaTypeToString(MediaType type) { + switch (type) { + case MEDIA_TYPE_AUDIO: + return webrtc::MediaStreamTrackInterface::kAudioKind; + case MEDIA_TYPE_VIDEO: + return webrtc::MediaStreamTrackInterface::kVideoKind; + case MEDIA_TYPE_DATA: + return kMediaTypeData; + } + FATAL(); + // Not reachable; avoids compile warning. + return ""; +} + +MediaType MediaTypeFromString(const std::string& type_str) { + if (type_str == webrtc::MediaStreamTrackInterface::kAudioKind) { + return MEDIA_TYPE_AUDIO; + } else if (type_str == webrtc::MediaStreamTrackInterface::kVideoKind) { + return MEDIA_TYPE_VIDEO; + } else if (type_str == kMediaTypeData) { + return MEDIA_TYPE_DATA; + } + FATAL(); + // Not reachable; avoids compile warning. + return static_cast<MediaType>(-1); +} + +} // namespace cricket
diff --git a/api/media_types.h b/api/media_types.h new file mode 100644 index 0000000..64e2ebc --- /dev/null +++ b/api/media_types.h
@@ -0,0 +1,36 @@ +/* + * Copyright 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_MEDIA_TYPES_H_ +#define API_MEDIA_TYPES_H_ + +#include <string> + +// The cricket and webrtc have separate definitions for what a media type is. +// They're not compatible. Watch out for this. + +namespace cricket { + +enum MediaType { MEDIA_TYPE_AUDIO, MEDIA_TYPE_VIDEO, MEDIA_TYPE_DATA }; + +std::string MediaTypeToString(MediaType type); +// Aborts on invalid string. Only expected to be used on strings that are +// guaranteed to be valid, such as MediaStreamTrackInterface::kind(). +MediaType MediaTypeFromString(const std::string& type_str); + +} // namespace cricket + +namespace webrtc { + +enum class MediaType { ANY, AUDIO, VIDEO, DATA }; + +} // namespace webrtc + +#endif // API_MEDIA_TYPES_H_
diff --git a/api/notifier.h b/api/notifier.h index e5c61c9..c03b104 100644 --- a/api/notifier.h +++ b/api/notifier.h
@@ -13,7 +13,7 @@ #include <list> -#include "api/mediastreaminterface.h" +#include "api/media_stream_interface.h" #include "rtc_base/checks.h" namespace webrtc {
diff --git a/api/peer_connection_factory_proxy.h b/api/peer_connection_factory_proxy.h new file mode 100644 index 0000000..620f1ca --- /dev/null +++ b/api/peer_connection_factory_proxy.h
@@ -0,0 +1,65 @@ +/* + * Copyright 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_PEER_CONNECTION_FACTORY_PROXY_H_ +#define API_PEER_CONNECTION_FACTORY_PROXY_H_ + +#include <memory> +#include <string> +#include <utility> + +#include "api/peer_connection_interface.h" +#include "api/proxy.h" +#include "rtc_base/bind.h" + +namespace webrtc { + +// TODO(deadbeef): Move this to .cc file and out of api/. What threads methods +// are called on is an implementation detail. +BEGIN_SIGNALING_PROXY_MAP(PeerConnectionFactory) +PROXY_SIGNALING_THREAD_DESTRUCTOR() +PROXY_METHOD1(void, SetOptions, const Options&) +PROXY_METHOD4(rtc::scoped_refptr<PeerConnectionInterface>, + CreatePeerConnection, + const PeerConnectionInterface::RTCConfiguration&, + std::unique_ptr<cricket::PortAllocator>, + std::unique_ptr<rtc::RTCCertificateGeneratorInterface>, + PeerConnectionObserver*) +PROXY_METHOD2(rtc::scoped_refptr<PeerConnectionInterface>, + CreatePeerConnection, + const PeerConnectionInterface::RTCConfiguration&, + PeerConnectionDependencies) +PROXY_CONSTMETHOD1(webrtc::RtpCapabilities, + GetRtpSenderCapabilities, + cricket::MediaType) +PROXY_CONSTMETHOD1(webrtc::RtpCapabilities, + GetRtpReceiverCapabilities, + cricket::MediaType) +PROXY_METHOD1(rtc::scoped_refptr<MediaStreamInterface>, + CreateLocalMediaStream, + const std::string&) +PROXY_METHOD1(rtc::scoped_refptr<AudioSourceInterface>, + CreateAudioSource, + const cricket::AudioOptions&) +PROXY_METHOD2(rtc::scoped_refptr<VideoTrackInterface>, + CreateVideoTrack, + const std::string&, + VideoTrackSourceInterface*) +PROXY_METHOD2(rtc::scoped_refptr<AudioTrackInterface>, + CreateAudioTrack, + const std::string&, + AudioSourceInterface*) +PROXY_METHOD2(bool, StartAecDump, rtc::PlatformFile, int64_t) +PROXY_METHOD0(void, StopAecDump) +END_PROXY_MAP() + +} // namespace webrtc + +#endif // API_PEER_CONNECTION_FACTORY_PROXY_H_
diff --git a/api/peer_connection_interface.cc b/api/peer_connection_interface.cc new file mode 100644 index 0000000..244ee73 --- /dev/null +++ b/api/peer_connection_interface.cc
@@ -0,0 +1,245 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/peer_connection_interface.h" +#include "api/dtls_transport_interface.h" +#include "api/sctp_transport_interface.h" + +namespace webrtc { + +PeerConnectionInterface::IceServer::IceServer() = default; +PeerConnectionInterface::IceServer::IceServer(const IceServer& rhs) = default; +PeerConnectionInterface::IceServer::~IceServer() = default; + +PeerConnectionInterface::RTCConfiguration::RTCConfiguration() = default; + +PeerConnectionInterface::RTCConfiguration::RTCConfiguration( + const RTCConfiguration& rhs) = default; + +PeerConnectionInterface::RTCConfiguration::RTCConfiguration( + RTCConfigurationType type) { + if (type == RTCConfigurationType::kAggressive) { + // These parameters are also defined in Java and IOS configurations, + // so their values may be overwritten by the Java or IOS configuration. + bundle_policy = kBundlePolicyMaxBundle; + rtcp_mux_policy = kRtcpMuxPolicyRequire; + ice_connection_receiving_timeout = kAggressiveIceConnectionReceivingTimeout; + + // These parameters are not defined in Java or IOS configuration, + // so their values will not be overwritten. + enable_ice_renomination = true; + redetermine_role_on_ice_restart = false; + } +} + +PeerConnectionInterface::RTCConfiguration::~RTCConfiguration() = default; + +RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> +PeerConnectionInterface::AddTrack( + rtc::scoped_refptr<MediaStreamTrackInterface> track, + const std::vector<std::string>& stream_ids) { + return RTCError(RTCErrorType::UNSUPPORTED_OPERATION, "Not implemented"); +} + +bool PeerConnectionInterface::RemoveTrack(RtpSenderInterface* sender) { + return RemoveTrackNew(sender).ok(); +} + +RTCError PeerConnectionInterface::RemoveTrackNew( + rtc::scoped_refptr<RtpSenderInterface> sender) { + return RTCError(RemoveTrack(sender) ? RTCErrorType::NONE + : RTCErrorType::INTERNAL_ERROR); +} + +RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> +PeerConnectionInterface::AddTransceiver( + rtc::scoped_refptr<MediaStreamTrackInterface> track) { + return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented"); +} + +RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> +PeerConnectionInterface::AddTransceiver( + rtc::scoped_refptr<MediaStreamTrackInterface> track, + const RtpTransceiverInit& init) { + return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented"); +} + +RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> +PeerConnectionInterface::AddTransceiver(cricket::MediaType media_type) { + return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented"); +} + +RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> +PeerConnectionInterface::AddTransceiver(cricket::MediaType media_type, + const RtpTransceiverInit& init) { + return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented"); +} + +rtc::scoped_refptr<RtpSenderInterface> PeerConnectionInterface::CreateSender( + const std::string& kind, + const std::string& stream_id) { + return rtc::scoped_refptr<RtpSenderInterface>(); +} + +std::vector<rtc::scoped_refptr<RtpSenderInterface>> +PeerConnectionInterface::GetSenders() const { + return std::vector<rtc::scoped_refptr<RtpSenderInterface>>(); +} + +std::vector<rtc::scoped_refptr<RtpReceiverInterface>> +PeerConnectionInterface::GetReceivers() const { + return std::vector<rtc::scoped_refptr<RtpReceiverInterface>>(); +} + +std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> +PeerConnectionInterface::GetTransceivers() const { + return std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>(); +} + +const SessionDescriptionInterface* +PeerConnectionInterface::current_local_description() const { + return nullptr; +} + +const SessionDescriptionInterface* +PeerConnectionInterface::current_remote_description() const { + return nullptr; +} + +const SessionDescriptionInterface* +PeerConnectionInterface::pending_local_description() const { + return nullptr; +} + +const SessionDescriptionInterface* +PeerConnectionInterface::pending_remote_description() const { + return nullptr; +} + +PeerConnectionInterface::RTCConfiguration +PeerConnectionInterface::GetConfiguration() { + return PeerConnectionInterface::RTCConfiguration(); +} + +bool PeerConnectionInterface::SetConfiguration( + const PeerConnectionInterface::RTCConfiguration& config, + RTCError* error) { + return false; +} + +bool PeerConnectionInterface::SetConfiguration( + const PeerConnectionInterface::RTCConfiguration& config) { + return false; +} + +bool PeerConnectionInterface::RemoveIceCandidates( + const std::vector<cricket::Candidate>& candidates) { + return false; +} + +RTCError PeerConnectionInterface::SetBitrate(const BitrateSettings& bitrate) { + BitrateParameters bitrate_parameters; + bitrate_parameters.min_bitrate_bps = bitrate.min_bitrate_bps; + bitrate_parameters.current_bitrate_bps = bitrate.start_bitrate_bps; + bitrate_parameters.max_bitrate_bps = bitrate.max_bitrate_bps; + return SetBitrate(bitrate_parameters); +} + +RTCError PeerConnectionInterface::SetBitrate( + const BitrateParameters& bitrate_parameters) { + BitrateSettings bitrate; + bitrate.min_bitrate_bps = bitrate_parameters.min_bitrate_bps; + bitrate.start_bitrate_bps = bitrate_parameters.current_bitrate_bps; + bitrate.max_bitrate_bps = bitrate_parameters.max_bitrate_bps; + return SetBitrate(bitrate); +} + +PeerConnectionInterface::IceConnectionState +PeerConnectionInterface::standardized_ice_connection_state() { + return PeerConnectionInterface::IceConnectionState::kIceConnectionFailed; +} + +PeerConnectionInterface::PeerConnectionState +PeerConnectionInterface::peer_connection_state() { + return PeerConnectionInterface::PeerConnectionState::kFailed; +} + +bool PeerConnectionInterface::StartRtcEventLog(rtc::PlatformFile file, + int64_t max_size_bytes) { + return false; +} + +bool PeerConnectionInterface::StartRtcEventLog( + std::unique_ptr<RtcEventLogOutput> output, + int64_t output_period_ms) { + return false; +} + +rtc::scoped_refptr<DtlsTransportInterface> +PeerConnectionInterface::LookupDtlsTransportByMid(const std::string& mid) { + RTC_NOTREACHED(); + return nullptr; +} + +rtc::scoped_refptr<SctpTransportInterface> +PeerConnectionInterface::GetSctpTransport() const { + RTC_NOTREACHED(); + return nullptr; +} + +PeerConnectionInterface::BitrateParameters::BitrateParameters() = default; + +PeerConnectionInterface::BitrateParameters::~BitrateParameters() = default; + +PeerConnectionDependencies::PeerConnectionDependencies( + PeerConnectionObserver* observer_in) + : observer(observer_in) {} + +PeerConnectionDependencies::PeerConnectionDependencies( + PeerConnectionDependencies&&) = default; + +PeerConnectionDependencies::~PeerConnectionDependencies() = default; + +PeerConnectionFactoryDependencies::PeerConnectionFactoryDependencies() = + default; + +PeerConnectionFactoryDependencies::PeerConnectionFactoryDependencies( + PeerConnectionFactoryDependencies&&) = default; + +PeerConnectionFactoryDependencies::~PeerConnectionFactoryDependencies() = + default; + +rtc::scoped_refptr<PeerConnectionInterface> +PeerConnectionFactoryInterface::CreatePeerConnection( + const PeerConnectionInterface::RTCConfiguration& configuration, + std::unique_ptr<cricket::PortAllocator> allocator, + std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator, + PeerConnectionObserver* observer) { + return nullptr; +} + +rtc::scoped_refptr<PeerConnectionInterface> +PeerConnectionFactoryInterface::CreatePeerConnection( + const PeerConnectionInterface::RTCConfiguration& configuration, + PeerConnectionDependencies dependencies) { + return nullptr; +} + +RtpCapabilities PeerConnectionFactoryInterface::GetRtpSenderCapabilities( + cricket::MediaType kind) const { + return {}; +} + +RtpCapabilities PeerConnectionFactoryInterface::GetRtpReceiverCapabilities( + cricket::MediaType kind) const { + return {}; +} + +} // namespace webrtc
diff --git a/api/peer_connection_interface.h b/api/peer_connection_interface.h new file mode 100644 index 0000000..1d7f96f --- /dev/null +++ b/api/peer_connection_interface.h
@@ -0,0 +1,1437 @@ +/* + * Copyright 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This file contains the PeerConnection interface as defined in +// https://w3c.github.io/webrtc-pc/#peer-to-peer-connections +// +// The PeerConnectionFactory class provides factory methods to create +// PeerConnection, MediaStream and MediaStreamTrack objects. +// +// The following steps are needed to setup a typical call using WebRTC: +// +// 1. Create a PeerConnectionFactoryInterface. Check constructors for more +// information about input parameters. +// +// 2. Create a PeerConnection object. Provide a configuration struct which +// points to STUN and/or TURN servers used to generate ICE candidates, and +// provide an object that implements the PeerConnectionObserver interface, +// which is used to receive callbacks from the PeerConnection. +// +// 3. Create local MediaStreamTracks using the PeerConnectionFactory and add +// them to PeerConnection by calling AddTrack (or legacy method, AddStream). +// +// 4. Create an offer, call SetLocalDescription with it, serialize it, and send +// it to the remote peer +// +// 5. Once an ICE candidate has been gathered, the PeerConnection will call the +// observer function OnIceCandidate. The candidates must also be serialized and +// sent to the remote peer. +// +// 6. Once an answer is received from the remote peer, call +// SetRemoteDescription with the remote answer. +// +// 7. Once a remote candidate is received from the remote peer, provide it to +// the PeerConnection by calling AddIceCandidate. +// +// The receiver of a call (assuming the application is "call"-based) can decide +// to accept or reject the call; this decision will be taken by the application, +// not the PeerConnection. +// +// If the application decides to accept the call, it should: +// +// 1. Create PeerConnectionFactoryInterface if it doesn't exist. +// +// 2. Create a new PeerConnection. +// +// 3. Provide the remote offer to the new PeerConnection object by calling +// SetRemoteDescription. +// +// 4. Generate an answer to the remote offer by calling CreateAnswer and send it +// back to the remote peer. +// +// 5. Provide the local answer to the new PeerConnection by calling +// SetLocalDescription with the answer. +// +// 6. Provide the remote ICE candidates by calling AddIceCandidate. +// +// 7. Once a candidate has been gathered, the PeerConnection will call the +// observer function OnIceCandidate. Send these candidates to the remote peer. + +#ifndef API_PEER_CONNECTION_INTERFACE_H_ +#define API_PEER_CONNECTION_INTERFACE_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "api/async_resolver_factory.h" +#include "api/audio/audio_mixer.h" +#include "api/audio_codecs/audio_decoder_factory.h" +#include "api/audio_codecs/audio_encoder_factory.h" +#include "api/audio_options.h" +#include "api/call/call_factory_interface.h" +#include "api/crypto/crypto_options.h" +#include "api/data_channel_interface.h" +#include "api/fec_controller.h" +#include "api/jsep.h" +#include "api/media_stream_interface.h" +#include "api/media_transport_interface.h" +#include "api/rtc_error.h" +#include "api/rtc_event_log_output.h" +#include "api/rtp_receiver_interface.h" +#include "api/rtp_sender_interface.h" +#include "api/rtp_transceiver_interface.h" +#include "api/set_remote_description_observer_interface.h" +#include "api/stats/rtc_stats_collector_callback.h" +#include "api/stats_types.h" +#include "api/transport/bitrate_settings.h" +#include "api/transport/network_control.h" +#include "api/turn_customizer.h" +#include "logging/rtc_event_log/rtc_event_log_factory_interface.h" +#include "media/base/media_config.h" +// TODO(bugs.webrtc.org/7447): We plan to provide a way to let applications +// inject a PacketSocketFactory and/or NetworkManager, and not expose +// PortAllocator in the PeerConnection api. +#include "media/base/media_engine.h" // nogncheck +#include "p2p/base/port_allocator.h" // nogncheck +// TODO(nisse): The interface for bitrate allocation strategy belongs in api/. +#include "rtc_base/bitrate_allocation_strategy.h" +#include "rtc_base/network.h" +#include "rtc_base/platform_file.h" +#include "rtc_base/rtc_certificate.h" +#include "rtc_base/rtc_certificate_generator.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/ssl_certificate.h" +#include "rtc_base/ssl_stream_adapter.h" +#include "rtc_base/system/rtc_export.h" + +namespace rtc { +class SSLIdentity; +class Thread; +} // namespace rtc + +namespace webrtc { +class AudioDeviceModule; +class AudioMixer; +class AudioProcessing; +class DtlsTransportInterface; +class SctpTransportInterface; +class VideoDecoderFactory; +class VideoEncoderFactory; + +// MediaStream container interface. +class StreamCollectionInterface : public rtc::RefCountInterface { + public: + // TODO(ronghuawu): Update the function names to c++ style, e.g. find -> Find. + virtual size_t count() = 0; + virtual MediaStreamInterface* at(size_t index) = 0; + virtual MediaStreamInterface* find(const std::string& label) = 0; + virtual MediaStreamTrackInterface* FindAudioTrack(const std::string& id) = 0; + virtual MediaStreamTrackInterface* FindVideoTrack(const std::string& id) = 0; + + protected: + // Dtor protected as objects shouldn't be deleted via this interface. + ~StreamCollectionInterface() override = default; +}; + +class StatsObserver : public rtc::RefCountInterface { + public: + virtual void OnComplete(const StatsReports& reports) = 0; + + protected: + ~StatsObserver() override = default; +}; + +enum class SdpSemantics { kPlanB, kUnifiedPlan }; + +class PeerConnectionInterface : public rtc::RefCountInterface { + public: + // See https://w3c.github.io/webrtc-pc/#dom-rtcsignalingstate + enum SignalingState { + kStable, + kHaveLocalOffer, + kHaveLocalPrAnswer, + kHaveRemoteOffer, + kHaveRemotePrAnswer, + kClosed, + }; + + // See https://w3c.github.io/webrtc-pc/#dom-rtcicegatheringstate + enum IceGatheringState { + kIceGatheringNew, + kIceGatheringGathering, + kIceGatheringComplete + }; + + // See https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnectionstate + enum class PeerConnectionState { + kNew, + kConnecting, + kConnected, + kDisconnected, + kFailed, + kClosed, + }; + + // See https://w3c.github.io/webrtc-pc/#dom-rtciceconnectionstate + enum IceConnectionState { + kIceConnectionNew, + kIceConnectionChecking, + kIceConnectionConnected, + kIceConnectionCompleted, + kIceConnectionFailed, + kIceConnectionDisconnected, + kIceConnectionClosed, + kIceConnectionMax, + }; + + // TLS certificate policy. + enum TlsCertPolicy { + // For TLS based protocols, ensure the connection is secure by not + // circumventing certificate validation. + kTlsCertPolicySecure, + // For TLS based protocols, disregard security completely by skipping + // certificate validation. This is insecure and should never be used unless + // security is irrelevant in that particular context. + kTlsCertPolicyInsecureNoCheck, + }; + + struct IceServer { + IceServer(); + IceServer(const IceServer&); + ~IceServer(); + + // TODO(jbauch): Remove uri when all code using it has switched to urls. + // List of URIs associated with this server. Valid formats are described + // in RFC7064 and RFC7065, and more may be added in the future. The "host" + // part of the URI may contain either an IP address or a hostname. + std::string uri; + std::vector<std::string> urls; + std::string username; + std::string password; + TlsCertPolicy tls_cert_policy = kTlsCertPolicySecure; + // If the URIs in |urls| only contain IP addresses, this field can be used + // to indicate the hostname, which may be necessary for TLS (using the SNI + // extension). If |urls| itself contains the hostname, this isn't + // necessary. + std::string hostname; + // List of protocols to be used in the TLS ALPN extension. + std::vector<std::string> tls_alpn_protocols; + // List of elliptic curves to be used in the TLS elliptic curves extension. + std::vector<std::string> tls_elliptic_curves; + + bool operator==(const IceServer& o) const { + return uri == o.uri && urls == o.urls && username == o.username && + password == o.password && tls_cert_policy == o.tls_cert_policy && + hostname == o.hostname && + tls_alpn_protocols == o.tls_alpn_protocols && + tls_elliptic_curves == o.tls_elliptic_curves; + } + bool operator!=(const IceServer& o) const { return !(*this == o); } + }; + typedef std::vector<IceServer> IceServers; + + enum IceTransportsType { + // TODO(pthatcher): Rename these kTransporTypeXXX, but update + // Chromium at the same time. + kNone, + kRelay, + kNoHost, + kAll + }; + + // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-24#section-4.1.1 + enum BundlePolicy { + kBundlePolicyBalanced, + kBundlePolicyMaxBundle, + kBundlePolicyMaxCompat + }; + + // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-24#section-4.1.1 + enum RtcpMuxPolicy { + kRtcpMuxPolicyNegotiate, + kRtcpMuxPolicyRequire, + }; + + enum TcpCandidatePolicy { + kTcpCandidatePolicyEnabled, + kTcpCandidatePolicyDisabled + }; + + enum CandidateNetworkPolicy { + kCandidateNetworkPolicyAll, + kCandidateNetworkPolicyLowCost + }; + + enum ContinualGatheringPolicy { GATHER_ONCE, GATHER_CONTINUALLY }; + + enum class RTCConfigurationType { + // A configuration that is safer to use, despite not having the best + // performance. Currently this is the default configuration. + kSafe, + // An aggressive configuration that has better performance, although it + // may be riskier and may need extra support in the application. + kAggressive + }; + + // TODO(hbos): Change into class with private data and public getters. + // TODO(nisse): In particular, accessing fields directly from an + // application is brittle, since the organization mirrors the + // organization of the implementation, which isn't stable. So we + // need getters and setters at least for fields which applications + // are interested in. + struct RTC_EXPORT RTCConfiguration { + // This struct is subject to reorganization, both for naming + // consistency, and to group settings to match where they are used + // in the implementation. To do that, we need getter and setter + // methods for all settings which are of interest to applications, + // Chrome in particular. + + RTCConfiguration(); + RTCConfiguration(const RTCConfiguration&); + explicit RTCConfiguration(RTCConfigurationType type); + ~RTCConfiguration(); + + bool operator==(const RTCConfiguration& o) const; + bool operator!=(const RTCConfiguration& o) const; + + bool dscp() const { return media_config.enable_dscp; } + void set_dscp(bool enable) { media_config.enable_dscp = enable; } + + bool cpu_adaptation() const { + return media_config.video.enable_cpu_adaptation; + } + void set_cpu_adaptation(bool enable) { + media_config.video.enable_cpu_adaptation = enable; + } + + bool suspend_below_min_bitrate() const { + return media_config.video.suspend_below_min_bitrate; + } + void set_suspend_below_min_bitrate(bool enable) { + media_config.video.suspend_below_min_bitrate = enable; + } + + bool prerenderer_smoothing() const { + return media_config.video.enable_prerenderer_smoothing; + } + void set_prerenderer_smoothing(bool enable) { + media_config.video.enable_prerenderer_smoothing = enable; + } + + bool experiment_cpu_load_estimator() const { + return media_config.video.experiment_cpu_load_estimator; + } + void set_experiment_cpu_load_estimator(bool enable) { + media_config.video.experiment_cpu_load_estimator = enable; + } + + int audio_rtcp_report_interval_ms() const { + return media_config.audio.rtcp_report_interval_ms; + } + void set_audio_rtcp_report_interval_ms(int audio_rtcp_report_interval_ms) { + media_config.audio.rtcp_report_interval_ms = + audio_rtcp_report_interval_ms; + } + + int video_rtcp_report_interval_ms() const { + return media_config.video.rtcp_report_interval_ms; + } + void set_video_rtcp_report_interval_ms(int video_rtcp_report_interval_ms) { + media_config.video.rtcp_report_interval_ms = + video_rtcp_report_interval_ms; + } + + static const int kUndefined = -1; + // Default maximum number of packets in the audio jitter buffer. + static const int kAudioJitterBufferMaxPackets = 200; + // ICE connection receiving timeout for aggressive configuration. + static const int kAggressiveIceConnectionReceivingTimeout = 1000; + + //////////////////////////////////////////////////////////////////////// + // The below few fields mirror the standard RTCConfiguration dictionary: + // https://w3c.github.io/webrtc-pc/#rtcconfiguration-dictionary + //////////////////////////////////////////////////////////////////////// + + // TODO(pthatcher): Rename this ice_servers, but update Chromium + // at the same time. + IceServers servers; + // TODO(pthatcher): Rename this ice_transport_type, but update + // Chromium at the same time. + IceTransportsType type = kAll; + BundlePolicy bundle_policy = kBundlePolicyBalanced; + RtcpMuxPolicy rtcp_mux_policy = kRtcpMuxPolicyRequire; + std::vector<rtc::scoped_refptr<rtc::RTCCertificate>> certificates; + int ice_candidate_pool_size = 0; + + ////////////////////////////////////////////////////////////////////////// + // The below fields correspond to constraints from the deprecated + // constraints interface for constructing a PeerConnection. + // + // absl::optional fields can be "missing", in which case the implementation + // default will be used. + ////////////////////////////////////////////////////////////////////////// + + // If set to true, don't gather IPv6 ICE candidates. + // TODO(deadbeef): Remove this? IPv6 support has long stopped being + // experimental + bool disable_ipv6 = false; + + // If set to true, don't gather IPv6 ICE candidates on Wi-Fi. + // Only intended to be used on specific devices. Certain phones disable IPv6 + // when the screen is turned off and it would be better to just disable the + // IPv6 ICE candidates on Wi-Fi in those cases. + bool disable_ipv6_on_wifi = false; + + // By default, the PeerConnection will use a limited number of IPv6 network + // interfaces, in order to avoid too many ICE candidate pairs being created + // and delaying ICE completion. + // + // Can be set to INT_MAX to effectively disable the limit. + int max_ipv6_networks = cricket::kDefaultMaxIPv6Networks; + + // Exclude link-local network interfaces + // from considertaion for gathering ICE candidates. + bool disable_link_local_networks = false; + + // If set to true, use RTP data channels instead of SCTP. + // TODO(deadbeef): Remove this. We no longer commit to supporting RTP data + // channels, though some applications are still working on moving off of + // them. + bool enable_rtp_data_channel = false; + + // Minimum bitrate at which screencast video tracks will be encoded at. + // This means adding padding bits up to this bitrate, which can help + // when switching from a static scene to one with motion. + absl::optional<int> screencast_min_bitrate; + + // Use new combined audio/video bandwidth estimation? + absl::optional<bool> combined_audio_video_bwe; + + // TODO(bugs.webrtc.org/9891) - Move to crypto_options + // Can be used to disable DTLS-SRTP. This should never be done, but can be + // useful for testing purposes, for example in setting up a loopback call + // with a single PeerConnection. + absl::optional<bool> enable_dtls_srtp; + + ///////////////////////////////////////////////// + // The below fields are not part of the standard. + ///////////////////////////////////////////////// + + // Can be used to disable TCP candidate generation. + TcpCandidatePolicy tcp_candidate_policy = kTcpCandidatePolicyEnabled; + + // Can be used to avoid gathering candidates for a "higher cost" network, + // if a lower cost one exists. For example, if both Wi-Fi and cellular + // interfaces are available, this could be used to avoid using the cellular + // interface. + CandidateNetworkPolicy candidate_network_policy = + kCandidateNetworkPolicyAll; + + // The maximum number of packets that can be stored in the NetEq audio + // jitter buffer. Can be reduced to lower tolerated audio latency. + int audio_jitter_buffer_max_packets = kAudioJitterBufferMaxPackets; + + // Whether to use the NetEq "fast mode" which will accelerate audio quicker + // if it falls behind. + bool audio_jitter_buffer_fast_accelerate = false; + + // The minimum delay in milliseconds for the audio jitter buffer. + int audio_jitter_buffer_min_delay_ms = 0; + + // Whether the audio jitter buffer adapts the delay to retransmitted + // packets. + bool audio_jitter_buffer_enable_rtx_handling = false; + + // Timeout in milliseconds before an ICE candidate pair is considered to be + // "not receiving", after which a lower priority candidate pair may be + // selected. + int ice_connection_receiving_timeout = kUndefined; + + // Interval in milliseconds at which an ICE "backup" candidate pair will be + // pinged. This is a candidate pair which is not actively in use, but may + // be switched to if the active candidate pair becomes unusable. + // + // This is relevant mainly to Wi-Fi/cell handoff; the application may not + // want this backup cellular candidate pair pinged frequently, since it + // consumes data/battery. + int ice_backup_candidate_pair_ping_interval = kUndefined; + + // Can be used to enable continual gathering, which means new candidates + // will be gathered as network interfaces change. Note that if continual + // gathering is used, the candidate removal API should also be used, to + // avoid an ever-growing list of candidates. + ContinualGatheringPolicy continual_gathering_policy = GATHER_ONCE; + + // If set to true, candidate pairs will be pinged in order of most likely + // to work (which means using a TURN server, generally), rather than in + // standard priority order. + bool prioritize_most_likely_ice_candidate_pairs = false; + + // Implementation defined settings. A public member only for the benefit of + // the implementation. Applications must not access it directly, and should + // instead use provided accessor methods, e.g., set_cpu_adaptation. + struct cricket::MediaConfig media_config; + + // If set to true, only one preferred TURN allocation will be used per + // network interface. UDP is preferred over TCP and IPv6 over IPv4. This + // can be used to cut down on the number of candidate pairings. + bool prune_turn_ports = false; + + // If set to true, this means the ICE transport should presume TURN-to-TURN + // candidate pairs will succeed, even before a binding response is received. + // This can be used to optimize the initial connection time, since the DTLS + // handshake can begin immediately. + bool presume_writable_when_fully_relayed = false; + + // If true, "renomination" will be added to the ice options in the transport + // description. + // See: https://tools.ietf.org/html/draft-thatcher-ice-renomination-00 + bool enable_ice_renomination = false; + + // If true, the ICE role is re-determined when the PeerConnection sets a + // local transport description that indicates an ICE restart. + // + // This is standard RFC5245 ICE behavior, but causes unnecessary role + // thrashing, so an application may wish to avoid it. This role + // re-determining was removed in ICEbis (ICE v2). + bool redetermine_role_on_ice_restart = true; + + // The following fields define intervals in milliseconds at which ICE + // connectivity checks are sent. + // + // We consider ICE is "strongly connected" for an agent when there is at + // least one candidate pair that currently succeeds in connectivity check + // from its direction i.e. sending a STUN ping and receives a STUN ping + // response, AND all candidate pairs have sent a minimum number of pings for + // connectivity (this number is implementation-specific). Otherwise, ICE is + // considered in "weak connectivity". + // + // Note that the above notion of strong and weak connectivity is not defined + // in RFC 5245, and they apply to our current ICE implementation only. + // + // 1) ice_check_interval_strong_connectivity defines the interval applied to + // ALL candidate pairs when ICE is strongly connected, and it overrides the + // default value of this interval in the ICE implementation; + // 2) ice_check_interval_weak_connectivity defines the counterpart for ALL + // pairs when ICE is weakly connected, and it overrides the default value of + // this interval in the ICE implementation; + // 3) ice_check_min_interval defines the minimal interval (equivalently the + // maximum rate) that overrides the above two intervals when either of them + // is less. + absl::optional<int> ice_check_interval_strong_connectivity; + absl::optional<int> ice_check_interval_weak_connectivity; + absl::optional<int> ice_check_min_interval; + + // The min time period for which a candidate pair must wait for response to + // connectivity checks before it becomes unwritable. This parameter + // overrides the default value in the ICE implementation if set. + absl::optional<int> ice_unwritable_timeout; + + // The min number of connectivity checks that a candidate pair must sent + // without receiving response before it becomes unwritable. This parameter + // overrides the default value in the ICE implementation if set. + absl::optional<int> ice_unwritable_min_checks; + + // The min time period for which a candidate pair must wait for response to + // connectivity checks it becomes inactive. This parameter overrides the + // default value in the ICE implementation if set. + absl::optional<int> ice_inactive_timeout; + + // The interval in milliseconds at which STUN candidates will resend STUN + // binding requests to keep NAT bindings open. + absl::optional<int> stun_candidate_keepalive_interval; + + // ICE Periodic Regathering + // If set, WebRTC will periodically create and propose candidates without + // starting a new ICE generation. The regathering happens continuously with + // interval specified in milliseconds by the uniform distribution [a, b]. + absl::optional<rtc::IntervalRange> ice_regather_interval_range; + + // Optional TurnCustomizer. + // With this class one can modify outgoing TURN messages. + // The object passed in must remain valid until PeerConnection::Close() is + // called. + webrtc::TurnCustomizer* turn_customizer = nullptr; + + // Preferred network interface. + // A candidate pair on a preferred network has a higher precedence in ICE + // than one on an un-preferred network, regardless of priority or network + // cost. + absl::optional<rtc::AdapterType> network_preference; + + // Configure the SDP semantics used by this PeerConnection. Note that the + // WebRTC 1.0 specification requires kUnifiedPlan semantics. The + // RtpTransceiver API is only available with kUnifiedPlan semantics. + // + // kPlanB will cause PeerConnection to create offers and answers with at + // most one audio and one video m= section with multiple RtpSenders and + // RtpReceivers specified as multiple a=ssrc lines within the section. This + // will also cause PeerConnection to ignore all but the first m= section of + // the same media type. + // + // kUnifiedPlan will cause PeerConnection to create offers and answers with + // multiple m= sections where each m= section maps to one RtpSender and one + // RtpReceiver (an RtpTransceiver), either both audio or both video. This + // will also cause PeerConnection to ignore all but the first a=ssrc lines + // that form a Plan B stream. + // + // For users who wish to send multiple audio/video streams and need to stay + // interoperable with legacy WebRTC implementations or use legacy APIs, + // specify kPlanB. + // + // For all other users, specify kUnifiedPlan. + SdpSemantics sdp_semantics = SdpSemantics::kPlanB; + + // TODO(bugs.webrtc.org/9891) - Move to crypto_options or remove. + // Actively reset the SRTP parameters whenever the DTLS transports + // underneath are reset for every offer/answer negotiation. + // This is only intended to be a workaround for crbug.com/835958 + // WARNING: This would cause RTP/RTCP packets decryption failure if not used + // correctly. This flag will be deprecated soon. Do not rely on it. + bool active_reset_srtp_params = false; + + // If MediaTransportFactory is provided in PeerConnectionFactory, this flag + // informs PeerConnection that it should use the MediaTransportInterface for + // media (audio/video). It's invalid to set it to |true| if the + // MediaTransportFactory wasn't provided. + bool use_media_transport = false; + + // If MediaTransportFactory is provided in PeerConnectionFactory, this flag + // informs PeerConnection that it should use the MediaTransportInterface for + // data channels. It's invalid to set it to |true| if the + // MediaTransportFactory wasn't provided. Data channels over media + // transport are not compatible with RTP or SCTP data channels. Setting + // both |use_media_transport_for_data_channels| and + // |enable_rtp_data_channel| is invalid. + bool use_media_transport_for_data_channels = false; + + // Defines advanced optional cryptographic settings related to SRTP and + // frame encryption for native WebRTC. Setting this will overwrite any + // settings set in PeerConnectionFactory (which is deprecated). + absl::optional<CryptoOptions> crypto_options; + + // Configure if we should include the SDP attribute extmap-allow-mixed in + // our offer. Although we currently do support this, it's not included in + // our offer by default due to a previous bug that caused the SDP parser to + // abort parsing if this attribute was present. This is fixed in Chrome 71. + // TODO(webrtc:9985): Change default to true once sufficient time has + // passed. + bool offer_extmap_allow_mixed = false; + + // + // Don't forget to update operator== if adding something. + // + }; + + // See: https://www.w3.org/TR/webrtc/#idl-def-rtcofferansweroptions + struct RTCOfferAnswerOptions { + static const int kUndefined = -1; + static const int kMaxOfferToReceiveMedia = 1; + + // The default value for constraint offerToReceiveX:true. + static const int kOfferToReceiveMediaTrue = 1; + + // These options are left as backwards compatibility for clients who need + // "Plan B" semantics. Clients who have switched to "Unified Plan" semantics + // should use the RtpTransceiver API (AddTransceiver) instead. + // + // offer_to_receive_X set to 1 will cause a media description to be + // generated in the offer, even if no tracks of that type have been added. + // Values greater than 1 are treated the same. + // + // If set to 0, the generated directional attribute will not include the + // "recv" direction (meaning it will be "sendonly" or "inactive". + int offer_to_receive_video = kUndefined; + int offer_to_receive_audio = kUndefined; + + bool voice_activity_detection = true; + bool ice_restart = false; + + // If true, will offer to BUNDLE audio/video/data together. Not to be + // confused with RTCP mux (multiplexing RTP and RTCP together). + bool use_rtp_mux = true; + + // This will apply to all video tracks with a Plan B SDP offer/answer. + int num_simulcast_layers = 1; + + RTCOfferAnswerOptions() = default; + + RTCOfferAnswerOptions(int offer_to_receive_video, + int offer_to_receive_audio, + bool voice_activity_detection, + bool ice_restart, + bool use_rtp_mux) + : offer_to_receive_video(offer_to_receive_video), + offer_to_receive_audio(offer_to_receive_audio), + voice_activity_detection(voice_activity_detection), + ice_restart(ice_restart), + use_rtp_mux(use_rtp_mux) {} + }; + + // Used by GetStats to decide which stats to include in the stats reports. + // |kStatsOutputLevelStandard| includes the standard stats for Javascript API; + // |kStatsOutputLevelDebug| includes both the standard stats and additional + // stats for debugging purposes. + enum StatsOutputLevel { + kStatsOutputLevelStandard, + kStatsOutputLevelDebug, + }; + + // Accessor methods to active local streams. + // This method is not supported with kUnifiedPlan semantics. Please use + // GetSenders() instead. + virtual rtc::scoped_refptr<StreamCollectionInterface> local_streams() = 0; + + // Accessor methods to remote streams. + // This method is not supported with kUnifiedPlan semantics. Please use + // GetReceivers() instead. + virtual rtc::scoped_refptr<StreamCollectionInterface> remote_streams() = 0; + + // Add a new MediaStream to be sent on this PeerConnection. + // Note that a SessionDescription negotiation is needed before the + // remote peer can receive the stream. + // + // This has been removed from the standard in favor of a track-based API. So, + // this is equivalent to simply calling AddTrack for each track within the + // stream, with the one difference that if "stream->AddTrack(...)" is called + // later, the PeerConnection will automatically pick up the new track. Though + // this functionality will be deprecated in the future. + // + // This method is not supported with kUnifiedPlan semantics. Please use + // AddTrack instead. + virtual bool AddStream(MediaStreamInterface* stream) = 0; + + // Remove a MediaStream from this PeerConnection. + // Note that a SessionDescription negotiation is needed before the + // remote peer is notified. + // + // This method is not supported with kUnifiedPlan semantics. Please use + // RemoveTrack instead. + virtual void RemoveStream(MediaStreamInterface* stream) = 0; + + // Add a new MediaStreamTrack to be sent on this PeerConnection, and return + // the newly created RtpSender. The RtpSender will be associated with the + // streams specified in the |stream_ids| list. + // + // Errors: + // - INVALID_PARAMETER: |track| is null, has a kind other than audio or video, + // or a sender already exists for the track. + // - INVALID_STATE: The PeerConnection is closed. + virtual RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> AddTrack( + rtc::scoped_refptr<MediaStreamTrackInterface> track, + const std::vector<std::string>& stream_ids); + + // Remove an RtpSender from this PeerConnection. + // Returns true on success. + // TODO(steveanton): Replace with signature that returns RTCError. + virtual bool RemoveTrack(RtpSenderInterface* sender); + + // Plan B semantics: Removes the RtpSender from this PeerConnection. + // Unified Plan semantics: Stop sending on the RtpSender and mark the + // corresponding RtpTransceiver direction as no longer sending. + // + // Errors: + // - INVALID_PARAMETER: |sender| is null or (Plan B only) the sender is not + // associated with this PeerConnection. + // - INVALID_STATE: PeerConnection is closed. + // TODO(bugs.webrtc.org/9534): Rename to RemoveTrack once the other signature + // is removed. + virtual RTCError RemoveTrackNew( + rtc::scoped_refptr<RtpSenderInterface> sender); + + // AddTransceiver creates a new RtpTransceiver and adds it to the set of + // transceivers. Adding a transceiver will cause future calls to CreateOffer + // to add a media description for the corresponding transceiver. + // + // The initial value of |mid| in the returned transceiver is null. Setting a + // new session description may change it to a non-null value. + // + // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-addtransceiver + // + // Optionally, an RtpTransceiverInit structure can be specified to configure + // the transceiver from construction. If not specified, the transceiver will + // default to having a direction of kSendRecv and not be part of any streams. + // + // These methods are only available when Unified Plan is enabled (see + // RTCConfiguration). + // + // Common errors: + // - INTERNAL_ERROR: The configuration does not have Unified Plan enabled. + // TODO(steveanton): Make these pure virtual once downstream projects have + // updated. + + // Adds a transceiver with a sender set to transmit the given track. The kind + // of the transceiver (and sender/receiver) will be derived from the kind of + // the track. + // Errors: + // - INVALID_PARAMETER: |track| is null. + virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> + AddTransceiver(rtc::scoped_refptr<MediaStreamTrackInterface> track); + virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> + AddTransceiver(rtc::scoped_refptr<MediaStreamTrackInterface> track, + const RtpTransceiverInit& init); + + // Adds a transceiver with the given kind. Can either be MEDIA_TYPE_AUDIO or + // MEDIA_TYPE_VIDEO. + // Errors: + // - INVALID_PARAMETER: |media_type| is not MEDIA_TYPE_AUDIO or + // MEDIA_TYPE_VIDEO. + virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> + AddTransceiver(cricket::MediaType media_type); + virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> + AddTransceiver(cricket::MediaType media_type, const RtpTransceiverInit& init); + + // TODO(deadbeef): Make these pure virtual once all subclasses implement them. + + // Creates a sender without a track. Can be used for "early media"/"warmup" + // use cases, where the application may want to negotiate video attributes + // before a track is available to send. + // + // The standard way to do this would be through "addTransceiver", but we + // don't support that API yet. + // + // |kind| must be "audio" or "video". + // + // |stream_id| is used to populate the msid attribute; if empty, one will + // be generated automatically. + // + // This method is not supported with kUnifiedPlan semantics. Please use + // AddTransceiver instead. + virtual rtc::scoped_refptr<RtpSenderInterface> CreateSender( + const std::string& kind, + const std::string& stream_id); + + // If Plan B semantics are specified, gets all RtpSenders, created either + // through AddStream, AddTrack, or CreateSender. All senders of a specific + // media type share the same media description. + // + // If Unified Plan semantics are specified, gets the RtpSender for each + // RtpTransceiver. + virtual std::vector<rtc::scoped_refptr<RtpSenderInterface>> GetSenders() + const; + + // If Plan B semantics are specified, gets all RtpReceivers created when a + // remote description is applied. All receivers of a specific media type share + // the same media description. It is also possible to have a media description + // with no associated RtpReceivers, if the directional attribute does not + // indicate that the remote peer is sending any media. + // + // If Unified Plan semantics are specified, gets the RtpReceiver for each + // RtpTransceiver. + virtual std::vector<rtc::scoped_refptr<RtpReceiverInterface>> GetReceivers() + const; + + // Get all RtpTransceivers, created either through AddTransceiver, AddTrack or + // by a remote description applied with SetRemoteDescription. + // + // Note: This method is only available when Unified Plan is enabled (see + // RTCConfiguration). + virtual std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> + GetTransceivers() const; + + // The legacy non-compliant GetStats() API. This correspond to the + // callback-based version of getStats() in JavaScript. The returned metrics + // are UNDOCUMENTED and many of them rely on implementation-specific details. + // The goal is to DELETE THIS VERSION but we can't today because it is heavily + // relied upon by third parties. See https://crbug.com/822696. + // + // This version is wired up into Chrome. Any stats implemented are + // automatically exposed to the Web Platform. This has BYPASSED the Chrome + // release processes for years and lead to cross-browser incompatibility + // issues and web application reliance on Chrome-only behavior. + // + // This API is in "maintenance mode", serious regressions should be fixed but + // adding new stats is highly discouraged. + // + // TODO(hbos): Deprecate and remove this when third parties have migrated to + // the spec-compliant GetStats() API. https://crbug.com/822696 + virtual bool GetStats(StatsObserver* observer, + MediaStreamTrackInterface* track, // Optional + StatsOutputLevel level) = 0; + // The spec-compliant GetStats() API. This correspond to the promise-based + // version of getStats() in JavaScript. Implementation status is described in + // api/stats/rtcstats_objects.h. For more details on stats, see spec: + // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-getstats + // TODO(hbos): Takes shared ownership, use rtc::scoped_refptr<> instead. This + // requires stop overriding the current version in third party or making third + // party calls explicit to avoid ambiguity during switch. Make the future + // version abstract as soon as third party projects implement it. + virtual void GetStats(RTCStatsCollectorCallback* callback) {} + // Spec-compliant getStats() performing the stats selection algorithm with the + // sender. https://w3c.github.io/webrtc-pc/#dom-rtcrtpsender-getstats + // TODO(hbos): Make abstract as soon as third party projects implement it. + virtual void GetStats( + rtc::scoped_refptr<RtpSenderInterface> selector, + rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {} + // Spec-compliant getStats() performing the stats selection algorithm with the + // receiver. https://w3c.github.io/webrtc-pc/#dom-rtcrtpreceiver-getstats + // TODO(hbos): Make abstract as soon as third party projects implement it. + virtual void GetStats( + rtc::scoped_refptr<RtpReceiverInterface> selector, + rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {} + // Clear cached stats in the RTCStatsCollector. + // Exposed for testing while waiting for automatic cache clear to work. + // https://bugs.webrtc.org/8693 + virtual void ClearStatsCache() {} + + // Create a data channel with the provided config, or default config if none + // is provided. Note that an offer/answer negotiation is still necessary + // before the data channel can be used. + // + // Also, calling CreateDataChannel is the only way to get a data "m=" section + // in SDP, so it should be done before CreateOffer is called, if the + // application plans to use data channels. + virtual rtc::scoped_refptr<DataChannelInterface> CreateDataChannel( + const std::string& label, + const DataChannelInit* config) = 0; + + // Returns the more recently applied description; "pending" if it exists, and + // otherwise "current". See below. + virtual const SessionDescriptionInterface* local_description() const = 0; + virtual const SessionDescriptionInterface* remote_description() const = 0; + + // A "current" description the one currently negotiated from a complete + // offer/answer exchange. + virtual const SessionDescriptionInterface* current_local_description() const; + virtual const SessionDescriptionInterface* current_remote_description() const; + + // A "pending" description is one that's part of an incomplete offer/answer + // exchange (thus, either an offer or a pranswer). Once the offer/answer + // exchange is finished, the "pending" description will become "current". + virtual const SessionDescriptionInterface* pending_local_description() const; + virtual const SessionDescriptionInterface* pending_remote_description() const; + + // Create a new offer. + // The CreateSessionDescriptionObserver callback will be called when done. + virtual void CreateOffer(CreateSessionDescriptionObserver* observer, + const RTCOfferAnswerOptions& options) = 0; + + // Create an answer to an offer. + // The CreateSessionDescriptionObserver callback will be called when done. + virtual void CreateAnswer(CreateSessionDescriptionObserver* observer, + const RTCOfferAnswerOptions& options) = 0; + + // Sets the local session description. + // The PeerConnection takes the ownership of |desc| even if it fails. + // The |observer| callback will be called when done. + // TODO(deadbeef): Change |desc| to be a unique_ptr, to make it clear + // that this method always takes ownership of it. + virtual void SetLocalDescription(SetSessionDescriptionObserver* observer, + SessionDescriptionInterface* desc) = 0; + // Sets the remote session description. + // The PeerConnection takes the ownership of |desc| even if it fails. + // The |observer| callback will be called when done. + // TODO(hbos): Remove when Chrome implements the new signature. + virtual void SetRemoteDescription(SetSessionDescriptionObserver* observer, + SessionDescriptionInterface* desc) {} + // TODO(hbos): Make pure virtual when Chrome has updated its signature. + virtual void SetRemoteDescription( + std::unique_ptr<SessionDescriptionInterface> desc, + rtc::scoped_refptr<SetRemoteDescriptionObserverInterface> observer) {} + + // TODO(deadbeef): Make this pure virtual once all Chrome subclasses of + // PeerConnectionInterface implement it. + virtual PeerConnectionInterface::RTCConfiguration GetConfiguration(); + + // Sets the PeerConnection's global configuration to |config|. + // + // The members of |config| that may be changed are |type|, |servers|, + // |ice_candidate_pool_size| and |prune_turn_ports| (though the candidate + // pool size can't be changed after the first call to SetLocalDescription). + // Note that this means the BUNDLE and RTCP-multiplexing policies cannot be + // changed with this method. + // + // Any changes to STUN/TURN servers or ICE candidate policy will affect the + // next gathering phase, and cause the next call to createOffer to generate + // new ICE credentials, as described in JSEP. This also occurs when + // |prune_turn_ports| changes, for the same reasoning. + // + // If an error occurs, returns false and populates |error| if non-null: + // - INVALID_MODIFICATION if |config| contains a modified parameter other + // than one of the parameters listed above. + // - INVALID_RANGE if |ice_candidate_pool_size| is out of range. + // - SYNTAX_ERROR if parsing an ICE server URL failed. + // - INVALID_PARAMETER if a TURN server is missing |username| or |password|. + // - INTERNAL_ERROR if an unexpected error occurred. + // + // TODO(deadbeef): Make this pure virtual once all Chrome subclasses of + // PeerConnectionInterface implement it. + virtual bool SetConfiguration( + const PeerConnectionInterface::RTCConfiguration& config, + RTCError* error); + + // Version without error output param for backwards compatibility. + // TODO(deadbeef): Remove once chromium is updated. + virtual bool SetConfiguration( + const PeerConnectionInterface::RTCConfiguration& config); + + // Provides a remote candidate to the ICE Agent. + // A copy of the |candidate| will be created and added to the remote + // description. So the caller of this method still has the ownership of the + // |candidate|. + virtual bool AddIceCandidate(const IceCandidateInterface* candidate) = 0; + + // Removes a group of remote candidates from the ICE agent. Needed mainly for + // continual gathering, to avoid an ever-growing list of candidates as + // networks come and go. + virtual bool RemoveIceCandidates( + const std::vector<cricket::Candidate>& candidates); + + // 0 <= min <= current <= max should hold for set parameters. + struct BitrateParameters { + BitrateParameters(); + ~BitrateParameters(); + + absl::optional<int> min_bitrate_bps; + absl::optional<int> current_bitrate_bps; + absl::optional<int> max_bitrate_bps; + }; + + // SetBitrate limits the bandwidth allocated for all RTP streams sent by + // this PeerConnection. Other limitations might affect these limits and + // are respected (for example "b=AS" in SDP). + // + // Setting |current_bitrate_bps| will reset the current bitrate estimate + // to the provided value. + virtual RTCError SetBitrate(const BitrateSettings& bitrate); + + // TODO(nisse): Deprecated - use version above. These two default + // implementations require subclasses to implement one or the other + // of the methods. + virtual RTCError SetBitrate(const BitrateParameters& bitrate_parameters); + + // Sets current strategy. If not set default WebRTC allocator will be used. + // May be changed during an active session. The strategy + // ownership is passed with std::unique_ptr + // TODO(alexnarest): Make this pure virtual when tests will be updated + virtual void SetBitrateAllocationStrategy( + std::unique_ptr<rtc::BitrateAllocationStrategy> + bitrate_allocation_strategy) {} + + // Enable/disable playout of received audio streams. Enabled by default. Note + // that even if playout is enabled, streams will only be played out if the + // appropriate SDP is also applied. Setting |playout| to false will stop + // playout of the underlying audio device but starts a task which will poll + // for audio data every 10ms to ensure that audio processing happens and the + // audio statistics are updated. + // TODO(henrika): deprecate and remove this. + virtual void SetAudioPlayout(bool playout) {} + + // Enable/disable recording of transmitted audio streams. Enabled by default. + // Note that even if recording is enabled, streams will only be recorded if + // the appropriate SDP is also applied. + // TODO(henrika): deprecate and remove this. + virtual void SetAudioRecording(bool recording) {} + + // Looks up the DtlsTransport associated with a MID value. + // In the Javascript API, DtlsTransport is a property of a sender, but + // because the PeerConnection owns the DtlsTransport in this implementation, + // it is better to look them up on the PeerConnection. + // TODO(hta): Remove default implementation after updating Chrome. + virtual rtc::scoped_refptr<DtlsTransportInterface> LookupDtlsTransportByMid( + const std::string& mid); + + // Returns the SCTP transport, if any. + // TODO(hta): Remove default implementation after updating Chrome. + virtual rtc::scoped_refptr<SctpTransportInterface> GetSctpTransport() const; + + // Returns the current SignalingState. + virtual SignalingState signaling_state() = 0; + + // Returns an aggregate state of all ICE *and* DTLS transports. + // This is left in place to avoid breaking native clients who expect our old, + // nonstandard behavior. + // TODO(jonasolsson): deprecate and remove this. + virtual IceConnectionState ice_connection_state() = 0; + + // Returns an aggregated state of all ICE transports. + virtual IceConnectionState standardized_ice_connection_state(); + + // Returns an aggregated state of all ICE and DTLS transports. + virtual PeerConnectionState peer_connection_state(); + + virtual IceGatheringState ice_gathering_state() = 0; + + // Starts RtcEventLog using existing file. Takes ownership of |file| and + // passes it on to Call, which will take the ownership. If the + // operation fails the file will be closed. + // The logging will stop when |max_size_bytes| is reached or when the + // StopRtcEventLog function is called. + // TODO(eladalon): Deprecate and remove this. + virtual bool StartRtcEventLog(rtc::PlatformFile file, int64_t max_size_bytes); + + // Start RtcEventLog using an existing output-sink. Takes ownership of + // |output| and passes it on to Call, which will take the ownership. If the + // operation fails the output will be closed and deallocated. The event log + // will send serialized events to the output object every |output_period_ms|. + virtual bool StartRtcEventLog(std::unique_ptr<RtcEventLogOutput> output, + int64_t output_period_ms); + + // Stops logging the RtcEventLog. + // TODO(ivoc): Make this pure virtual when Chrome is updated. + virtual void StopRtcEventLog() {} + + // Terminates all media, closes the transports, and in general releases any + // resources used by the PeerConnection. This is an irreversible operation. + // + // Note that after this method completes, the PeerConnection will no longer + // use the PeerConnectionObserver interface passed in on construction, and + // thus the observer object can be safely destroyed. + virtual void Close() = 0; + + protected: + // Dtor protected as objects shouldn't be deleted via this interface. + ~PeerConnectionInterface() override = default; +}; + +// PeerConnection callback interface, used for RTCPeerConnection events. +// Application should implement these methods. +class PeerConnectionObserver { + public: + virtual ~PeerConnectionObserver() = default; + + // Triggered when the SignalingState changed. + virtual void OnSignalingChange( + PeerConnectionInterface::SignalingState new_state) = 0; + + // Triggered when media is received on a new stream from remote peer. + virtual void OnAddStream(rtc::scoped_refptr<MediaStreamInterface> stream) {} + + // Triggered when a remote peer closes a stream. + virtual void OnRemoveStream(rtc::scoped_refptr<MediaStreamInterface> stream) { + } + + // Triggered when a remote peer opens a data channel. + virtual void OnDataChannel( + rtc::scoped_refptr<DataChannelInterface> data_channel) = 0; + + // Triggered when renegotiation is needed. For example, an ICE restart + // has begun. + virtual void OnRenegotiationNeeded() = 0; + + // Called any time the legacy IceConnectionState changes. + // + // Note that our ICE states lag behind the standard slightly. The most + // notable differences include the fact that "failed" occurs after 15 + // seconds, not 30, and this actually represents a combination ICE + DTLS + // state, so it may be "failed" if DTLS fails while ICE succeeds. + // + // TODO(jonasolsson): deprecate and remove this. + virtual void OnIceConnectionChange( + PeerConnectionInterface::IceConnectionState new_state) = 0; + + // Called any time the standards-compliant IceConnectionState changes. + virtual void OnStandardizedIceConnectionChange( + PeerConnectionInterface::IceConnectionState new_state) {} + + // Called any time the PeerConnectionState changes. + virtual void OnConnectionChange( + PeerConnectionInterface::PeerConnectionState new_state) {} + + // Called any time the IceGatheringState changes. + virtual void OnIceGatheringChange( + PeerConnectionInterface::IceGatheringState new_state) = 0; + + // A new ICE candidate has been gathered. + virtual void OnIceCandidate(const IceCandidateInterface* candidate) = 0; + + // Ice candidates have been removed. + // TODO(honghaiz): Make this a pure virtual method when all its subclasses + // implement it. + virtual void OnIceCandidatesRemoved( + const std::vector<cricket::Candidate>& candidates) {} + + // Called when the ICE connection receiving status changes. + virtual void OnIceConnectionReceivingChange(bool receiving) {} + + // This is called when a receiver and its track are created. + // TODO(zhihuang): Make this pure virtual when all subclasses implement it. + // Note: This is called with both Plan B and Unified Plan semantics. Unified + // Plan users should prefer OnTrack, OnAddTrack is only called as backwards + // compatibility (and is called in the exact same situations as OnTrack). + virtual void OnAddTrack( + rtc::scoped_refptr<RtpReceiverInterface> receiver, + const std::vector<rtc::scoped_refptr<MediaStreamInterface>>& streams) {} + + // This is called when signaling indicates a transceiver will be receiving + // media from the remote endpoint. This is fired during a call to + // SetRemoteDescription. The receiving track can be accessed by: + // |transceiver->receiver()->track()| and its associated streams by + // |transceiver->receiver()->streams()|. + // Note: This will only be called if Unified Plan semantics are specified. + // This behavior is specified in section 2.2.8.2.5 of the "Set the + // RTCSessionDescription" algorithm: + // https://w3c.github.io/webrtc-pc/#set-description + virtual void OnTrack( + rtc::scoped_refptr<RtpTransceiverInterface> transceiver) {} + + // Called when signaling indicates that media will no longer be received on a + // track. + // With Plan B semantics, the given receiver will have been removed from the + // PeerConnection and the track muted. + // With Unified Plan semantics, the receiver will remain but the transceiver + // will have changed direction to either sendonly or inactive. + // https://w3c.github.io/webrtc-pc/#process-remote-track-removal + // TODO(hbos,deadbeef): Make pure virtual when all subclasses implement it. + virtual void OnRemoveTrack( + rtc::scoped_refptr<RtpReceiverInterface> receiver) {} + + // Called when an interesting usage is detected by WebRTC. + // An appropriate action is to add information about the context of the + // PeerConnection and write the event to some kind of "interesting events" + // log function. + // The heuristics for defining what constitutes "interesting" are + // implementation-defined. + virtual void OnInterestingUsage(int usage_pattern) {} +}; + +// PeerConnectionDependencies holds all of PeerConnections dependencies. +// A dependency is distinct from a configuration as it defines significant +// executable code that can be provided by a user of the API. +// +// All new dependencies should be added as a unique_ptr to allow the +// PeerConnection object to be the definitive owner of the dependencies +// lifetime making injection safer. +struct PeerConnectionDependencies final { + explicit PeerConnectionDependencies(PeerConnectionObserver* observer_in); + // This object is not copyable or assignable. + PeerConnectionDependencies(const PeerConnectionDependencies&) = delete; + PeerConnectionDependencies& operator=(const PeerConnectionDependencies&) = + delete; + // This object is only moveable. + PeerConnectionDependencies(PeerConnectionDependencies&&); + PeerConnectionDependencies& operator=(PeerConnectionDependencies&&) = default; + ~PeerConnectionDependencies(); + // Mandatory dependencies + PeerConnectionObserver* observer = nullptr; + // Optional dependencies + std::unique_ptr<cricket::PortAllocator> allocator; + std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory; + std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator; + std::unique_ptr<rtc::SSLCertificateVerifier> tls_cert_verifier; +}; + +// PeerConnectionFactoryDependencies holds all of the PeerConnectionFactory +// dependencies. All new dependencies should be added here instead of +// overloading the function. This simplifies dependency injection and makes it +// clear which are mandatory and optional. If possible please allow the peer +// connection factory to take ownership of the dependency by adding a unique_ptr +// to this structure. +struct PeerConnectionFactoryDependencies final { + PeerConnectionFactoryDependencies(); + // This object is not copyable or assignable. + PeerConnectionFactoryDependencies(const PeerConnectionFactoryDependencies&) = + delete; + PeerConnectionFactoryDependencies& operator=( + const PeerConnectionFactoryDependencies&) = delete; + // This object is only moveable. + PeerConnectionFactoryDependencies(PeerConnectionFactoryDependencies&&); + PeerConnectionFactoryDependencies& operator=( + PeerConnectionFactoryDependencies&&) = default; + ~PeerConnectionFactoryDependencies(); + + // Optional dependencies + rtc::Thread* network_thread = nullptr; + rtc::Thread* worker_thread = nullptr; + rtc::Thread* signaling_thread = nullptr; + std::unique_ptr<cricket::MediaEngineInterface> media_engine; + std::unique_ptr<CallFactoryInterface> call_factory; + std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory; + std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory; + std::unique_ptr<NetworkControllerFactoryInterface> network_controller_factory; + std::unique_ptr<MediaTransportFactory> media_transport_factory; +}; + +// PeerConnectionFactoryInterface is the factory interface used for creating +// PeerConnection, MediaStream and MediaStreamTrack objects. +// +// The simplest method for obtaiing one, CreatePeerConnectionFactory will +// create the required libjingle threads, socket and network manager factory +// classes for networking if none are provided, though it requires that the +// application runs a message loop on the thread that called the method (see +// explanation below) +// +// If an application decides to provide its own threads and/or implementation +// of networking classes, it should use the alternate +// CreatePeerConnectionFactory method which accepts threads as input, and use +// the CreatePeerConnection version that takes a PortAllocator as an argument. +class PeerConnectionFactoryInterface : public rtc::RefCountInterface { + public: + class Options { + public: + Options() {} + + // If set to true, created PeerConnections won't enforce any SRTP + // requirement, allowing unsecured media. Should only be used for + // testing/debugging. + bool disable_encryption = false; + + // Deprecated. The only effect of setting this to true is that + // CreateDataChannel will fail, which is not that useful. + bool disable_sctp_data_channels = false; + + // If set to true, any platform-supported network monitoring capability + // won't be used, and instead networks will only be updated via polling. + // + // This only has an effect if a PeerConnection is created with the default + // PortAllocator implementation. + bool disable_network_monitor = false; + + // Sets the network types to ignore. For instance, calling this with + // ADAPTER_TYPE_ETHERNET | ADAPTER_TYPE_LOOPBACK will ignore Ethernet and + // loopback interfaces. + int network_ignore_mask = rtc::kDefaultNetworkIgnoreMask; + + // Sets the maximum supported protocol version. The highest version + // supported by both ends will be used for the connection, i.e. if one + // party supports DTLS 1.0 and the other DTLS 1.2, DTLS 1.0 will be used. + rtc::SSLProtocolVersion ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12; + + // Sets crypto related options, e.g. enabled cipher suites. + CryptoOptions crypto_options = CryptoOptions::NoGcm(); + }; + + // Set the options to be used for subsequently created PeerConnections. + virtual void SetOptions(const Options& options) = 0; + + // The preferred way to create a new peer connection. Simply provide the + // configuration and a PeerConnectionDependencies structure. + // TODO(benwright): Make pure virtual once downstream mock PC factory classes + // are updated. + virtual rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection( + const PeerConnectionInterface::RTCConfiguration& configuration, + PeerConnectionDependencies dependencies); + + // Deprecated; |allocator| and |cert_generator| may be null, in which case + // default implementations will be used. + // + // |observer| must not be null. + // + // Note that this method does not take ownership of |observer|; it's the + // responsibility of the caller to delete it. It can be safely deleted after + // Close has been called on the returned PeerConnection, which ensures no + // more observer callbacks will be invoked. + virtual rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection( + const PeerConnectionInterface::RTCConfiguration& configuration, + std::unique_ptr<cricket::PortAllocator> allocator, + std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator, + PeerConnectionObserver* observer); + + // Returns the capabilities of an RTP sender of type |kind|. + // If for some reason you pass in MEDIA_TYPE_DATA, returns an empty structure. + // TODO(orphis): Make pure virtual when all subclasses implement it. + virtual RtpCapabilities GetRtpSenderCapabilities( + cricket::MediaType kind) const; + + // Returns the capabilities of an RTP receiver of type |kind|. + // If for some reason you pass in MEDIA_TYPE_DATA, returns an empty structure. + // TODO(orphis): Make pure virtual when all subclasses implement it. + virtual RtpCapabilities GetRtpReceiverCapabilities( + cricket::MediaType kind) const; + + virtual rtc::scoped_refptr<MediaStreamInterface> CreateLocalMediaStream( + const std::string& stream_id) = 0; + + // Creates an AudioSourceInterface. + // |options| decides audio processing settings. + virtual rtc::scoped_refptr<AudioSourceInterface> CreateAudioSource( + const cricket::AudioOptions& options) = 0; + + // Creates a new local VideoTrack. The same |source| can be used in several + // tracks. + virtual rtc::scoped_refptr<VideoTrackInterface> CreateVideoTrack( + const std::string& label, + VideoTrackSourceInterface* source) = 0; + + // Creates an new AudioTrack. At the moment |source| can be null. + virtual rtc::scoped_refptr<AudioTrackInterface> CreateAudioTrack( + const std::string& label, + AudioSourceInterface* source) = 0; + + // Starts AEC dump using existing file. Takes ownership of |file| and passes + // it on to VoiceEngine (via other objects) immediately, which will take + // the ownerhip. If the operation fails, the file will be closed. + // A maximum file size in bytes can be specified. When the file size limit is + // reached, logging is stopped automatically. If max_size_bytes is set to a + // value <= 0, no limit will be used, and logging will continue until the + // StopAecDump function is called. + virtual bool StartAecDump(rtc::PlatformFile file, int64_t max_size_bytes) = 0; + + // Stops logging the AEC dump. + virtual void StopAecDump() = 0; + + protected: + // Dtor and ctor protected as objects shouldn't be created or deleted via + // this interface. + PeerConnectionFactoryInterface() {} + ~PeerConnectionFactoryInterface() override = default; +}; + +// This is a lower-level version of the CreatePeerConnectionFactory functions +// above. It's implemented in the "peerconnection" build target, whereas the +// above methods are only implemented in the broader "libjingle_peerconnection" +// build target, which pulls in the implementations of every module webrtc may +// use. +// +// If an application knows it will only require certain modules, it can reduce +// webrtc's impact on its binary size by depending only on the "peerconnection" +// target and the modules the application requires, using +// CreateModularPeerConnectionFactory instead of one of the +// CreatePeerConnectionFactory methods above. For example, if an application +// only uses WebRTC for audio, it can pass in null pointers for the +// video-specific interfaces, and omit the corresponding modules from its +// build. +// +// If |network_thread| or |worker_thread| are null, the PeerConnectionFactory +// will create the necessary thread internally. If |signaling_thread| is null, +// the PeerConnectionFactory will use the thread on which this method is called +// as the signaling thread, wrapping it in an rtc::Thread object if needed. +// +// If non-null, a reference is added to |default_adm|, and ownership of +// |video_encoder_factory| and |video_decoder_factory| is transferred to the +// returned factory. +// +// If |audio_mixer| is null, an internal audio mixer will be created and used. +// +// TODO(deadbeef): Use rtc::scoped_refptr<> and std::unique_ptr<> to make this +// ownership transfer and ref counting more obvious. +// +// TODO(deadbeef): Encapsulate these modules in a struct, so that when a new +// module is inevitably exposed, we can just add a field to the struct instead +// of adding a whole new CreateModularPeerConnectionFactory overload. +rtc::scoped_refptr<PeerConnectionFactoryInterface> +CreateModularPeerConnectionFactory( + rtc::Thread* network_thread, + rtc::Thread* worker_thread, + rtc::Thread* signaling_thread, + std::unique_ptr<cricket::MediaEngineInterface> media_engine, + std::unique_ptr<CallFactoryInterface> call_factory, + std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory); + +rtc::scoped_refptr<PeerConnectionFactoryInterface> +CreateModularPeerConnectionFactory( + rtc::Thread* network_thread, + rtc::Thread* worker_thread, + rtc::Thread* signaling_thread, + std::unique_ptr<cricket::MediaEngineInterface> media_engine, + std::unique_ptr<CallFactoryInterface> call_factory, + std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory, + std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory, + std::unique_ptr<NetworkControllerFactoryInterface> + network_controller_factory = nullptr); + +rtc::scoped_refptr<PeerConnectionFactoryInterface> +CreateModularPeerConnectionFactory( + PeerConnectionFactoryDependencies dependencies); + +} // namespace webrtc + +#endif // API_PEER_CONNECTION_INTERFACE_H_
diff --git a/api/peer_connection_proxy.h b/api/peer_connection_proxy.h new file mode 100644 index 0000000..61058b5 --- /dev/null +++ b/api/peer_connection_proxy.h
@@ -0,0 +1,145 @@ +/* + * Copyright 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_PEER_CONNECTION_PROXY_H_ +#define API_PEER_CONNECTION_PROXY_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "api/peer_connection_interface.h" +#include "api/proxy.h" + +namespace webrtc { + +// TODO(deadbeef): Move this to .cc file and out of api/. What threads methods +// are called on is an implementation detail. +BEGIN_SIGNALING_PROXY_MAP(PeerConnection) +PROXY_SIGNALING_THREAD_DESTRUCTOR() +PROXY_METHOD0(rtc::scoped_refptr<StreamCollectionInterface>, local_streams) +PROXY_METHOD0(rtc::scoped_refptr<StreamCollectionInterface>, remote_streams) +PROXY_METHOD1(bool, AddStream, MediaStreamInterface*) +PROXY_METHOD1(void, RemoveStream, MediaStreamInterface*) +PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>, + AddTrack, + rtc::scoped_refptr<MediaStreamTrackInterface>, + const std::vector<std::string>&) +PROXY_METHOD1(bool, RemoveTrack, RtpSenderInterface*) +PROXY_METHOD1(RTCError, RemoveTrackNew, rtc::scoped_refptr<RtpSenderInterface>) +PROXY_METHOD1(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>, + AddTransceiver, + rtc::scoped_refptr<MediaStreamTrackInterface>) +PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>, + AddTransceiver, + rtc::scoped_refptr<MediaStreamTrackInterface>, + const RtpTransceiverInit&) +PROXY_METHOD1(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>, + AddTransceiver, + cricket::MediaType) +PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>, + AddTransceiver, + cricket::MediaType, + const RtpTransceiverInit&) +PROXY_METHOD2(rtc::scoped_refptr<RtpSenderInterface>, + CreateSender, + const std::string&, + const std::string&) +PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpSenderInterface>>, + GetSenders) +PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpReceiverInterface>>, + GetReceivers) +PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>, + GetTransceivers) +PROXY_METHOD3(bool, + GetStats, + StatsObserver*, + MediaStreamTrackInterface*, + StatsOutputLevel) +PROXY_METHOD1(void, GetStats, RTCStatsCollectorCallback*) +PROXY_METHOD2(void, + GetStats, + rtc::scoped_refptr<RtpSenderInterface>, + rtc::scoped_refptr<RTCStatsCollectorCallback>) +PROXY_METHOD2(void, + GetStats, + rtc::scoped_refptr<RtpReceiverInterface>, + rtc::scoped_refptr<RTCStatsCollectorCallback>) +PROXY_METHOD2(rtc::scoped_refptr<DataChannelInterface>, + CreateDataChannel, + const std::string&, + const DataChannelInit*) +PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, local_description) +PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, remote_description) +PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, + current_local_description) +PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, + current_remote_description) +PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, + pending_local_description) +PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, + pending_remote_description) +PROXY_METHOD2(void, + CreateOffer, + CreateSessionDescriptionObserver*, + const RTCOfferAnswerOptions&) +PROXY_METHOD2(void, + CreateAnswer, + CreateSessionDescriptionObserver*, + const RTCOfferAnswerOptions&) +PROXY_METHOD2(void, + SetLocalDescription, + SetSessionDescriptionObserver*, + SessionDescriptionInterface*) +PROXY_METHOD2(void, + SetRemoteDescription, + SetSessionDescriptionObserver*, + SessionDescriptionInterface*) +PROXY_METHOD2(void, + SetRemoteDescription, + std::unique_ptr<SessionDescriptionInterface>, + rtc::scoped_refptr<SetRemoteDescriptionObserverInterface>) +PROXY_METHOD0(PeerConnectionInterface::RTCConfiguration, GetConfiguration) +PROXY_METHOD2(bool, + SetConfiguration, + const PeerConnectionInterface::RTCConfiguration&, + RTCError*) +PROXY_METHOD1(bool, + SetConfiguration, + const PeerConnectionInterface::RTCConfiguration&) +PROXY_METHOD1(bool, AddIceCandidate, const IceCandidateInterface*) +PROXY_METHOD1(bool, RemoveIceCandidates, const std::vector<cricket::Candidate>&) +PROXY_METHOD1(RTCError, SetBitrate, const BitrateSettings&) +PROXY_METHOD1(void, + SetBitrateAllocationStrategy, + std::unique_ptr<rtc::BitrateAllocationStrategy>) +PROXY_METHOD1(void, SetAudioPlayout, bool) +PROXY_METHOD1(void, SetAudioRecording, bool) +PROXY_METHOD1(rtc::scoped_refptr<DtlsTransportInterface>, + LookupDtlsTransportByMid, + const std::string&) +PROXY_CONSTMETHOD0(rtc::scoped_refptr<SctpTransportInterface>, GetSctpTransport) +PROXY_METHOD0(SignalingState, signaling_state) +PROXY_METHOD0(IceConnectionState, ice_connection_state) +PROXY_METHOD0(IceConnectionState, standardized_ice_connection_state) +PROXY_METHOD0(PeerConnectionState, peer_connection_state) +PROXY_METHOD0(IceGatheringState, ice_gathering_state) +PROXY_METHOD2(bool, StartRtcEventLog, rtc::PlatformFile, int64_t) +PROXY_METHOD2(bool, + StartRtcEventLog, + std::unique_ptr<RtcEventLogOutput>, + int64_t) +PROXY_METHOD0(void, StopRtcEventLog) +PROXY_METHOD0(void, Close) +END_PROXY_MAP() + +} // namespace webrtc + +#endif // API_PEER_CONNECTION_PROXY_H_
diff --git a/api/proxy.h b/api/proxy.h index 9916051..6627aac 100644 --- a/api/proxy.h +++ b/api/proxy.h
@@ -53,12 +53,20 @@ #define API_PROXY_H_ #include <memory> +#include <string> #include <utility> +#include "api/scoped_refptr.h" #include "rtc_base/event.h" -#include "rtc_base/refcountedobject.h" +#include "rtc_base/message_handler.h" +#include "rtc_base/message_queue.h" +#include "rtc_base/ref_counted_object.h" #include "rtc_base/thread.h" +namespace rtc { +class Location; +} + namespace webrtc { template <typename R>
diff --git a/api/ref_counted_base.h b/api/ref_counted_base.h new file mode 100644 index 0000000..a1761db --- /dev/null +++ b/api/ref_counted_base.h
@@ -0,0 +1,43 @@ +/* + * Copyright 2017 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef API_REF_COUNTED_BASE_H_ +#define API_REF_COUNTED_BASE_H_ + +#include "rtc_base/constructor_magic.h" +#include "rtc_base/ref_count.h" +#include "rtc_base/ref_counter.h" + +namespace rtc { + +class RefCountedBase { + public: + RefCountedBase() = default; + + void AddRef() const { ref_count_.IncRef(); } + RefCountReleaseStatus Release() const { + const auto status = ref_count_.DecRef(); + if (status == RefCountReleaseStatus::kDroppedLastRef) { + delete this; + } + return status; + } + + protected: + virtual ~RefCountedBase() = default; + + private: + mutable webrtc::webrtc_impl::RefCounter ref_count_{0}; + + RTC_DISALLOW_COPY_AND_ASSIGN(RefCountedBase); +}; + +} // namespace rtc + +#endif // API_REF_COUNTED_BASE_H_
diff --git a/api/rtc_error.cc b/api/rtc_error.cc new file mode 100644 index 0000000..51fd07f --- /dev/null +++ b/api/rtc_error.cc
@@ -0,0 +1,61 @@ +/* + * Copyright 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/rtc_error.h" + +#include "absl/strings/string_view.h" +#include "rtc_base/arraysize.h" + +namespace { + +const absl::string_view kRTCErrorTypeNames[] = { + "NONE", + "UNSUPPORTED_OPERATION", + "UNSUPPORTED_PARAMETER", + "INVALID_PARAMETER", + "INVALID_RANGE", + "SYNTAX_ERROR", + "INVALID_STATE", + "INVALID_MODIFICATION", + "NETWORK_ERROR", + "RESOURCE_EXHAUSTED", + "INTERNAL_ERROR", +}; +static_assert(static_cast<int>(webrtc::RTCErrorType::INTERNAL_ERROR) == + (arraysize(kRTCErrorTypeNames) - 1), + "kRTCErrorTypeNames must have as many strings as RTCErrorType " + "has values."); + +} // namespace + +namespace webrtc { + +RTCError::RTCError(RTCError&& other) = default; +RTCError& RTCError::operator=(RTCError&& other) = default; + +// static +RTCError RTCError::OK() { + return RTCError(); +} + +const char* RTCError::message() const { + return message_.c_str(); +} + +void RTCError::set_message(std::string message) { + message_ = std::move(message); +} + +absl::string_view ToString(RTCErrorType error) { + int index = static_cast<int>(error); + return kRTCErrorTypeNames[index]; +} + +} // namespace webrtc
diff --git a/api/rtc_error.h b/api/rtc_error.h new file mode 100644 index 0000000..904a619 --- /dev/null +++ b/api/rtc_error.h
@@ -0,0 +1,297 @@ +/* + * Copyright 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_RTC_ERROR_H_ +#define API_RTC_ERROR_H_ + +#ifdef UNIT_TEST +#include <ostream> +#endif // UNIT_TEST +#include <string> +#include <utility> // For std::move. + +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { + +// Enumeration to represent distinct classes of errors that an application +// may wish to act upon differently. These roughly map to DOMExceptions or +// RTCError "errorDetailEnum" values in the web API, as described in the +// comments below. +enum class RTCErrorType { + // No error. + NONE, + + // An operation is valid, but currently unsupported. + // Maps to OperationError DOMException. + UNSUPPORTED_OPERATION, + + // A supplied parameter is valid, but currently unsupported. + // Maps to OperationError DOMException. + UNSUPPORTED_PARAMETER, + + // General error indicating that a supplied parameter is invalid. + // Maps to InvalidAccessError or TypeError DOMException depending on context. + INVALID_PARAMETER, + + // Slightly more specific than INVALID_PARAMETER; a parameter's value was + // outside the allowed range. + // Maps to RangeError DOMException. + INVALID_RANGE, + + // Slightly more specific than INVALID_PARAMETER; an error occurred while + // parsing string input. + // Maps to SyntaxError DOMException. + SYNTAX_ERROR, + + // The object does not support this operation in its current state. + // Maps to InvalidStateError DOMException. + INVALID_STATE, + + // An attempt was made to modify the object in an invalid way. + // Maps to InvalidModificationError DOMException. + INVALID_MODIFICATION, + + // An error occurred within an underlying network protocol. + // Maps to NetworkError DOMException. + NETWORK_ERROR, + + // Some resource has been exhausted; file handles, hardware resources, ports, + // etc. + // Maps to OperationError DOMException. + RESOURCE_EXHAUSTED, + + // The operation failed due to an internal error. + // Maps to OperationError DOMException. + INTERNAL_ERROR, +}; + +// Roughly corresponds to RTCError in the web api. Holds an error type, a +// message, and possibly additional information specific to that error. +// +// Doesn't contain anything beyond a type and message now, but will in the +// future as more errors are implemented. +class RTCError { + public: + // Constructors. + + // Creates a "no error" error. + RTCError() {} + explicit RTCError(RTCErrorType type) : type_(type) {} + + RTCError(RTCErrorType type, std::string message) + : type_(type), message_(std::move(message)) {} + + // Delete the copy constructor and assignment operator; there aren't any use + // cases where you should need to copy an RTCError, as opposed to moving it. + // Can revisit this decision if use cases arise in the future. + RTCError(const RTCError& other) = delete; + RTCError& operator=(const RTCError& other) = delete; + + // Move constructor and move-assignment operator. + RTCError(RTCError&& other); + RTCError& operator=(RTCError&& other); + + // Identical to default constructed error. + // + // Preferred over the default constructor for code readability. + static RTCError OK(); + + // Error type. + RTCErrorType type() const { return type_; } + void set_type(RTCErrorType type) { type_ = type; } + + // Human-readable message describing the error. Shouldn't be used for + // anything but logging/diagnostics, since messages are not guaranteed to be + // stable. + const char* message() const; + + void set_message(std::string message); + + // Convenience method for situations where you only care whether or not an + // error occurred. + bool ok() const { return type_ == RTCErrorType::NONE; } + + private: + RTCErrorType type_ = RTCErrorType::NONE; + std::string message_; +}; + +// Outputs the error as a friendly string. Update this method when adding a new +// error type. +// +// Only intended to be used for logging/diagnostics. The string_view points +// to literal string that lives for the whole duration of the program. +absl::string_view ToString(RTCErrorType error); + +#ifdef UNIT_TEST +inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982) + std::ostream& stream, // no-presubmit-check TODO(webrtc:8982) + RTCErrorType error) { + return stream << ToString(error); +} +#endif // UNIT_TEST + +// Helper macro that can be used by implementations to create an error with a +// message and log it. |message| should be a string literal or movable +// std::string. +#define LOG_AND_RETURN_ERROR_EX(type, message, severity) \ + { \ + RTC_DCHECK(type != RTCErrorType::NONE); \ + RTC_LOG(severity) << message << " (" << ToString(type) << ")"; \ + return webrtc::RTCError(type, message); \ + } + +#define LOG_AND_RETURN_ERROR(type, message) \ + LOG_AND_RETURN_ERROR_EX(type, message, LS_ERROR) + +// RTCErrorOr<T> is the union of an RTCError object and a T object. RTCErrorOr +// models the concept of an object that is either a usable value, or an error +// Status explaining why such a value is not present. To this end RTCErrorOr<T> +// does not allow its RTCErrorType value to be RTCErrorType::NONE. This is +// enforced by a debug check in most cases. +// +// The primary use-case for RTCErrorOr<T> is as the return value of a function +// which may fail. For example, CreateRtpSender will fail if the parameters +// could not be successfully applied at the media engine level, but if +// successful will return a unique_ptr to an RtpSender. +// +// Example client usage for a RTCErrorOr<std::unique_ptr<T>>: +// +// RTCErrorOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg); +// if (result.ok()) { +// std::unique_ptr<Foo> foo = result.ConsumeValue(); +// foo->DoSomethingCool(); +// } else { +// RTC_LOG(LS_ERROR) << result.error(); +// } +// +// Example factory implementation returning RTCErrorOr<std::unique_ptr<T>>: +// +// RTCErrorOr<std::unique_ptr<Foo>> FooFactory::MakeNewFoo(int arg) { +// if (arg <= 0) { +// return RTCError(RTCErrorType::INVALID_RANGE, "Arg must be positive"); +// } else { +// return std::unique_ptr<Foo>(new Foo(arg)); +// } +// } +// +template <typename T> +class RTCErrorOr { + // Used to convert between RTCErrorOr<Foo>/RtcErrorOr<Bar>, when an implicit + // conversion from Foo to Bar exists. + template <typename U> + friend class RTCErrorOr; + + public: + typedef T element_type; + + // Constructs a new RTCErrorOr with RTCErrorType::INTERNAL_ERROR error. This + // is marked 'explicit' to try to catch cases like 'return {};', where people + // think RTCErrorOr<std::vector<int>> will be initialized with an empty + // vector, instead of a RTCErrorType::INTERNAL_ERROR error. + RTCErrorOr() : error_(RTCErrorType::INTERNAL_ERROR) {} + + // Constructs a new RTCErrorOr with the given non-ok error. After calling + // this constructor, calls to value() will DCHECK-fail. + // + // NOTE: Not explicit - we want to use RTCErrorOr<T> as a return + // value, so it is convenient and sensible to be able to do 'return + // RTCError(...)' when the return type is RTCErrorOr<T>. + // + // REQUIRES: !error.ok(). This requirement is DCHECKed. + RTCErrorOr(RTCError&& error) : error_(std::move(error)) { // NOLINT + RTC_DCHECK(!error.ok()); + } + + // Constructs a new RTCErrorOr with the given value. After calling this + // constructor, calls to value() will succeed, and calls to error() will + // return a default-constructed RTCError. + // + // NOTE: Not explicit - we want to use RTCErrorOr<T> as a return type + // so it is convenient and sensible to be able to do 'return T()' + // when the return type is RTCErrorOr<T>. + RTCErrorOr(const T& value) : value_(value) {} // NOLINT + RTCErrorOr(T&& value) : value_(std::move(value)) {} // NOLINT + + // Delete the copy constructor and assignment operator; there aren't any use + // cases where you should need to copy an RTCErrorOr, as opposed to moving + // it. Can revisit this decision if use cases arise in the future. + RTCErrorOr(const RTCErrorOr& other) = delete; + RTCErrorOr& operator=(const RTCErrorOr& other) = delete; + + // Move constructor and move-assignment operator. + // + // Visual Studio doesn't support "= default" with move constructors or + // assignment operators (even though they compile, they segfault), so define + // them explicitly. + RTCErrorOr(RTCErrorOr&& other) + : error_(std::move(other.error_)), value_(std::move(other.value_)) {} + RTCErrorOr& operator=(RTCErrorOr&& other) { + error_ = std::move(other.error_); + value_ = std::move(other.value_); + return *this; + } + + // Conversion constructor and assignment operator; T must be copy or move + // constructible from U. + template <typename U> + RTCErrorOr(RTCErrorOr<U> other) // NOLINT + : error_(std::move(other.error_)), value_(std::move(other.value_)) {} + template <typename U> + RTCErrorOr& operator=(RTCErrorOr<U> other) { + error_ = std::move(other.error_); + value_ = std::move(other.value_); + return *this; + } + + // Returns a reference to our error. If this contains a T, then returns + // default-constructed RTCError. + const RTCError& error() const { return error_; } + + // Moves the error. Can be useful if, say "CreateFoo" returns an + // RTCErrorOr<Foo>, and internally calls "CreateBar" which returns an + // RTCErrorOr<Bar>, and wants to forward the error up the stack. + RTCError MoveError() { return std::move(error_); } + + // Returns this->error().ok() + bool ok() const { return error_.ok(); } + + // Returns a reference to our current value, or DCHECK-fails if !this->ok(). + // + // Can be convenient for the implementation; for example, a method may want + // to access the value in some way before returning it to the next method on + // the stack. + const T& value() const { + RTC_DCHECK(ok()); + return value_; + } + T& value() { + RTC_DCHECK(ok()); + return value_; + } + + // Moves our current value out of this object and returns it, or DCHECK-fails + // if !this->ok(). + T MoveValue() { + RTC_DCHECK(ok()); + return std::move(value_); + } + + private: + RTCError error_; + T value_; +}; + +} // namespace webrtc + +#endif // API_RTC_ERROR_H_
diff --git a/api/rtc_error_unittest.cc b/api/rtc_error_unittest.cc new file mode 100644 index 0000000..e9beb00 --- /dev/null +++ b/api/rtc_error_unittest.cc
@@ -0,0 +1,241 @@ +/* + * Copyright 2017 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <utility> + +#include "api/rtc_error.h" +#include "test/gtest.h" + +namespace { + +const int kDefaultMoveOnlyIntValue = 0xbadf00d; + +// Class that has no copy constructor, ensuring that RTCErrorOr can +struct MoveOnlyInt { + MoveOnlyInt() {} + explicit MoveOnlyInt(int value) : value(value) {} + MoveOnlyInt(const MoveOnlyInt& other) = delete; + MoveOnlyInt& operator=(const MoveOnlyInt& other) = delete; + MoveOnlyInt(MoveOnlyInt&& other) : value(other.value) {} + MoveOnlyInt& operator=(MoveOnlyInt&& other) { + value = other.value; + return *this; + } + + int value = kDefaultMoveOnlyIntValue; +}; + +// Same as above. Used to test conversion from RTCErrorOr<A> to RTCErrorOr<B> +// when A can be converted to B. +struct MoveOnlyInt2 { + MoveOnlyInt2() {} + explicit MoveOnlyInt2(int value) : value(value) {} + MoveOnlyInt2(const MoveOnlyInt2& other) = delete; + MoveOnlyInt2& operator=(const MoveOnlyInt2& other) = delete; + MoveOnlyInt2(MoveOnlyInt2&& other) : value(other.value) {} + MoveOnlyInt2& operator=(MoveOnlyInt2&& other) { + value = other.value; + return *this; + } + + explicit MoveOnlyInt2(MoveOnlyInt&& other) : value(other.value) {} + MoveOnlyInt2& operator=(MoveOnlyInt&& other) { + value = other.value; + return *this; + } + + int value = kDefaultMoveOnlyIntValue; +}; + +} // namespace + +namespace webrtc { + +// Test that the default constructor creates a "no error" error. +TEST(RTCErrorTest, DefaultConstructor) { + RTCError e; + EXPECT_EQ(RTCErrorType::NONE, e.type()); + EXPECT_EQ(std::string(), e.message()); + EXPECT_TRUE(e.ok()); +} + +TEST(RTCErrorTest, NormalConstructors) { + RTCError a(RTCErrorType::INVALID_PARAMETER); + EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, a.type()); + EXPECT_EQ(std::string(), a.message()); + + // Constructor that takes const char* message. + RTCError b(RTCErrorType::UNSUPPORTED_PARAMETER, "foobar"); + EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, b.type()); + EXPECT_EQ(std::string("foobar"), b.message()); + + // Constructor that takes std::string message. + RTCError c(RTCErrorType::INVALID_RANGE, std::string("new")); + EXPECT_EQ(RTCErrorType::INVALID_RANGE, c.type()); + EXPECT_EQ(std::string("new"), c.message()); +} + +TEST(RTCErrorTest, MoveConstructor) { + // Static string. + RTCError a(RTCErrorType::INVALID_PARAMETER, "foo"); + RTCError b(std::move(a)); + EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, b.type()); + EXPECT_EQ(std::string("foo"), b.message()); + + // Non-static string. + RTCError c(RTCErrorType::UNSUPPORTED_PARAMETER, std::string("bar")); + RTCError d(std::move(c)); + EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, d.type()); + EXPECT_EQ(std::string("bar"), d.message()); +} + +TEST(RTCErrorTest, MoveAssignment) { + // Try all combinations of "is static string"/"is non-static string" moves. + RTCError e(RTCErrorType::INVALID_PARAMETER, "foo"); + + e = RTCError(RTCErrorType::UNSUPPORTED_PARAMETER, "bar"); + EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, e.type()); + EXPECT_EQ(std::string("bar"), e.message()); + + e = RTCError(RTCErrorType::SYNTAX_ERROR, std::string("baz")); + EXPECT_EQ(std::string("baz"), e.message()); + + e = RTCError(RTCErrorType::SYNTAX_ERROR, std::string("another")); + EXPECT_EQ(std::string("another"), e.message()); + + e = RTCError(RTCErrorType::SYNTAX_ERROR, "last"); + EXPECT_EQ(std::string("last"), e.message()); +} + +// Test that the error returned by RTCError::OK() is a "no error" error. +TEST(RTCErrorTest, OKConstant) { + RTCError ok = RTCError::OK(); + EXPECT_EQ(RTCErrorType::NONE, ok.type()); + EXPECT_EQ(std::string(), ok.message()); + EXPECT_TRUE(ok.ok()); +} + +// Test that "error.ok()" behaves as expected. +TEST(RTCErrorTest, OkMethod) { + RTCError success; + RTCError failure(RTCErrorType::INTERNAL_ERROR); + EXPECT_TRUE(success.ok()); + EXPECT_FALSE(failure.ok()); +} + +// Test that a message can be set using either static const strings or +// std::strings. +TEST(RTCErrorTest, SetMessage) { + RTCError e; + // Try all combinations of "is static string"/"is non-static string" calls. + e.set_message("foo"); + EXPECT_EQ(std::string("foo"), e.message()); + + e.set_message("bar"); + EXPECT_EQ(std::string("bar"), e.message()); + + e.set_message(std::string("string")); + EXPECT_EQ(std::string("string"), e.message()); + + e.set_message(std::string("more")); + EXPECT_EQ(std::string("more"), e.message()); + + e.set_message("love to test"); + EXPECT_EQ(std::string("love to test"), e.message()); +} + +// Test that the default constructor creates an "INTERNAL_ERROR". +TEST(RTCErrorOrTest, DefaultConstructor) { + RTCErrorOr<MoveOnlyInt> e; + EXPECT_EQ(RTCErrorType::INTERNAL_ERROR, e.error().type()); +} + +// Test that an RTCErrorOr can be implicitly constructed from a value. +TEST(RTCErrorOrTest, ImplicitValueConstructor) { + RTCErrorOr<MoveOnlyInt> e = [] { return MoveOnlyInt(100); }(); + EXPECT_EQ(100, e.value().value); +} + +// Test that an RTCErrorOr can be implicitly constructed from an RTCError. +TEST(RTCErrorOrTest, ImplicitErrorConstructor) { + RTCErrorOr<MoveOnlyInt> e = [] { + return RTCError(RTCErrorType::SYNTAX_ERROR); + }(); + EXPECT_EQ(RTCErrorType::SYNTAX_ERROR, e.error().type()); +} + +TEST(RTCErrorOrTest, MoveConstructor) { + RTCErrorOr<MoveOnlyInt> a(MoveOnlyInt(5)); + RTCErrorOr<MoveOnlyInt> b(std::move(a)); + EXPECT_EQ(5, b.value().value); +} + +TEST(RTCErrorOrTest, MoveAssignment) { + RTCErrorOr<MoveOnlyInt> a(MoveOnlyInt(5)); + RTCErrorOr<MoveOnlyInt> b(MoveOnlyInt(10)); + a = std::move(b); + EXPECT_EQ(10, a.value().value); +} + +TEST(RTCErrorOrTest, ConversionConstructor) { + RTCErrorOr<MoveOnlyInt> a(MoveOnlyInt(1)); + RTCErrorOr<MoveOnlyInt2> b(std::move(a)); +} + +TEST(RTCErrorOrTest, ConversionAssignment) { + RTCErrorOr<MoveOnlyInt> a(MoveOnlyInt(5)); + RTCErrorOr<MoveOnlyInt2> b(MoveOnlyInt2(10)); + b = std::move(a); + EXPECT_EQ(5, b.value().value); +} + +TEST(RTCErrorOrTest, OkMethod) { + RTCErrorOr<int> success(1337); + RTCErrorOr<int> error = RTCError(RTCErrorType::INTERNAL_ERROR); + EXPECT_TRUE(success.ok()); + EXPECT_FALSE(error.ok()); +} + +TEST(RTCErrorOrTest, MoveError) { + RTCErrorOr<int> e({RTCErrorType::SYNTAX_ERROR, "message"}); + RTCError err = e.MoveError(); + EXPECT_EQ(RTCErrorType::SYNTAX_ERROR, err.type()); + EXPECT_EQ(std::string("message"), err.message()); +} + +TEST(RTCErrorOrTest, MoveValue) { + RTCErrorOr<MoveOnlyInt> e(MoveOnlyInt(88)); + MoveOnlyInt value = e.MoveValue(); + EXPECT_EQ(88, value.value); +} + +// Death tests. +// Disabled on Android because death tests misbehave on Android, see +// base/test/gtest_util.h. +#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) + +TEST(RTCErrorOrDeathTest, ConstructWithOkError) { + RTCErrorOr<int> err; + EXPECT_DEATH(err = RTCError::OK(), ""); +} + +TEST(RTCErrorOrDeathTest, DereferenceErrorValue) { + RTCErrorOr<int> error = RTCError(RTCErrorType::INTERNAL_ERROR); + EXPECT_DEATH(error.value(), ""); +} + +TEST(RTCErrorOrDeathTest, MoveErrorValue) { + RTCErrorOr<int> error = RTCError(RTCErrorType::INTERNAL_ERROR); + EXPECT_DEATH(error.MoveValue(), ""); +} + +#endif // RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) + +} // namespace webrtc
diff --git a/api/rtc_event_log_output.h b/api/rtc_event_log_output.h new file mode 100644 index 0000000..92fb9e8 --- /dev/null +++ b/api/rtc_event_log_output.h
@@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_RTC_EVENT_LOG_OUTPUT_H_ +#define API_RTC_EVENT_LOG_OUTPUT_H_ + +#include <string> + +namespace webrtc { + +// NOTE: This class is still under development and may change without notice. +class RtcEventLogOutput { + public: + virtual ~RtcEventLogOutput() = default; + + // An output normally starts out active, though that might not always be + // the case (e.g. failed to open a file for writing). + // Once an output has become inactive (e.g. maximum file size reached), it can + // never become active again. + virtual bool IsActive() const = 0; + + // Write encoded events to an output. Returns true if the output was + // successfully written in its entirety. Otherwise, no guarantee is given + // about how much data was written, if any. The output sink becomes inactive + // after the first time |false| is returned. Write() may not be called on + // an inactive output sink. + virtual bool Write(const std::string& output) = 0; + + // Indicates that buffers should be written to disk if applicable. + virtual void Flush() {} +}; + +} // namespace webrtc + +#endif // API_RTC_EVENT_LOG_OUTPUT_H_
diff --git a/api/rtp_headers.h b/api/rtp_headers.h index c766899..8ab560c 100644 --- a/api/rtp_headers.h +++ b/api/rtp_headers.h
@@ -82,6 +82,17 @@ // Mid represents RtpMid which is a string. typedef StringRtpHeaderExtension Mid; +struct FeedbackRequest { + // Determines whether the recv delta as specified in + // https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01 + // should be included. + bool include_timestamps; + // Include feedback of received packets in the range [sequence_number - + // sequence_count + 1, sequence_number]. That is, no feedback will be sent if + // sequence_count is zero. + int sequence_count; +}; + struct RTPHeaderExtension { RTPHeaderExtension(); RTPHeaderExtension(const RTPHeaderExtension& other); @@ -93,6 +104,7 @@ uint32_t absoluteSendTime; bool hasTransportSequenceNumber; uint16_t transportSequenceNumber; + absl::optional<FeedbackRequest> feedback_request; // Audio Level includes both level in dBov and voiced/unvoiced bit. See: // https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
diff --git a/api/rtp_parameters.cc b/api/rtp_parameters.cc new file mode 100644 index 0000000..9ba2423 --- /dev/null +++ b/api/rtp_parameters.cc
@@ -0,0 +1,238 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "api/rtp_parameters.h" + +#include <algorithm> +#include <string> + +#include "api/array_view.h" +#include "rtc_base/strings/string_builder.h" + +namespace webrtc { + +const double kDefaultBitratePriority = 1.0; + +RtcpFeedback::RtcpFeedback() = default; +RtcpFeedback::RtcpFeedback(RtcpFeedbackType type) : type(type) {} +RtcpFeedback::RtcpFeedback(RtcpFeedbackType type, + RtcpFeedbackMessageType message_type) + : type(type), message_type(message_type) {} +RtcpFeedback::RtcpFeedback(const RtcpFeedback& rhs) = default; +RtcpFeedback::~RtcpFeedback() = default; + +RtpCodecCapability::RtpCodecCapability() = default; +RtpCodecCapability::~RtpCodecCapability() = default; + +RtpHeaderExtensionCapability::RtpHeaderExtensionCapability() = default; +RtpHeaderExtensionCapability::RtpHeaderExtensionCapability( + const std::string& uri) + : uri(uri) {} +RtpHeaderExtensionCapability::RtpHeaderExtensionCapability( + const std::string& uri, + int preferred_id) + : uri(uri), preferred_id(preferred_id) {} +RtpHeaderExtensionCapability::~RtpHeaderExtensionCapability() = default; + +RtpExtension::RtpExtension() = default; +RtpExtension::RtpExtension(const std::string& uri, int id) : uri(uri), id(id) {} +RtpExtension::RtpExtension(const std::string& uri, int id, bool encrypt) + : uri(uri), id(id), encrypt(encrypt) {} +RtpExtension::~RtpExtension() = default; + +RtpFecParameters::RtpFecParameters() = default; +RtpFecParameters::RtpFecParameters(FecMechanism mechanism) + : mechanism(mechanism) {} +RtpFecParameters::RtpFecParameters(FecMechanism mechanism, uint32_t ssrc) + : ssrc(ssrc), mechanism(mechanism) {} +RtpFecParameters::RtpFecParameters(const RtpFecParameters& rhs) = default; +RtpFecParameters::~RtpFecParameters() = default; + +RtpRtxParameters::RtpRtxParameters() = default; +RtpRtxParameters::RtpRtxParameters(uint32_t ssrc) : ssrc(ssrc) {} +RtpRtxParameters::RtpRtxParameters(const RtpRtxParameters& rhs) = default; +RtpRtxParameters::~RtpRtxParameters() = default; + +RtpEncodingParameters::RtpEncodingParameters() = default; +RtpEncodingParameters::RtpEncodingParameters(const RtpEncodingParameters& rhs) = + default; +RtpEncodingParameters::~RtpEncodingParameters() = default; + +RtpCodecParameters::RtpCodecParameters() = default; +RtpCodecParameters::RtpCodecParameters(const RtpCodecParameters& rhs) = default; +RtpCodecParameters::~RtpCodecParameters() = default; + +RtpCapabilities::RtpCapabilities() = default; +RtpCapabilities::~RtpCapabilities() = default; + +RtcpParameters::RtcpParameters() = default; +RtcpParameters::RtcpParameters(const RtcpParameters& rhs) = default; +RtcpParameters::~RtcpParameters() = default; + +RtpParameters::RtpParameters() = default; +RtpParameters::RtpParameters(const RtpParameters& rhs) = default; +RtpParameters::~RtpParameters() = default; + +std::string RtpExtension::ToString() const { + char buf[256]; + rtc::SimpleStringBuilder sb(buf); + sb << "{uri: " << uri; + sb << ", id: " << id; + if (encrypt) { + sb << ", encrypt"; + } + sb << '}'; + return sb.str(); +} + +const char RtpExtension::kAudioLevelUri[] = + "urn:ietf:params:rtp-hdrext:ssrc-audio-level"; + +const char RtpExtension::kTimestampOffsetUri[] = + "urn:ietf:params:rtp-hdrext:toffset"; + +const char RtpExtension::kAbsSendTimeUri[] = + "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"; + +const char RtpExtension::kVideoRotationUri[] = "urn:3gpp:video-orientation"; + +const char RtpExtension::kTransportSequenceNumberUri[] = + "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"; +const char RtpExtension::kTransportSequenceNumberV2Uri[] = + "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02"; + +// This extension allows applications to adaptively limit the playout delay +// on frames as per the current needs. For example, a gaming application +// has very different needs on end-to-end delay compared to a video-conference +// application. +const char RtpExtension::kPlayoutDelayUri[] = + "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay"; + +const char RtpExtension::kVideoContentTypeUri[] = + "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type"; + +const char RtpExtension::kVideoTimingUri[] = + "http://www.webrtc.org/experiments/rtp-hdrext/video-timing"; + +const char RtpExtension::kMidUri[] = "urn:ietf:params:rtp-hdrext:sdes:mid"; + +const char RtpExtension::kFrameMarkingUri[] = + "http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07"; + +const char RtpExtension::kGenericFrameDescriptorUri00[] = + "http://www.webrtc.org/experiments/rtp-hdrext/generic-frame-descriptor-00"; +const char RtpExtension::kGenericFrameDescriptorUri01[] = + "http://www.webrtc.org/experiments/rtp-hdrext/generic-frame-descriptor-01"; +const char RtpExtension::kGenericFrameDescriptorUri[] = + "http://www.webrtc.org/experiments/rtp-hdrext/generic-frame-descriptor-00"; + +const char RtpExtension::kEncryptHeaderExtensionsUri[] = + "urn:ietf:params:rtp-hdrext:encrypt"; + +const char RtpExtension::kColorSpaceUri[] = + "http://www.webrtc.org/experiments/rtp-hdrext/color-space"; + +const char RtpExtension::kRidUri[] = + "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id"; + +const char RtpExtension::kRepairedRidUri[] = + "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id"; + +constexpr int RtpExtension::kMinId; +constexpr int RtpExtension::kMaxId; +constexpr int RtpExtension::kMaxValueSize; +constexpr int RtpExtension::kOneByteHeaderExtensionMaxId; +constexpr int RtpExtension::kOneByteHeaderExtensionMaxValueSize; + +bool RtpExtension::IsSupportedForAudio(const std::string& uri) { + return uri == webrtc::RtpExtension::kAudioLevelUri || + uri == webrtc::RtpExtension::kTransportSequenceNumberUri || + uri == webrtc::RtpExtension::kTransportSequenceNumberV2Uri || + uri == webrtc::RtpExtension::kMidUri || + uri == webrtc::RtpExtension::kRidUri || + uri == webrtc::RtpExtension::kRepairedRidUri; +} + +bool RtpExtension::IsSupportedForVideo(const std::string& uri) { + return uri == webrtc::RtpExtension::kTimestampOffsetUri || + uri == webrtc::RtpExtension::kAbsSendTimeUri || + uri == webrtc::RtpExtension::kVideoRotationUri || + uri == webrtc::RtpExtension::kTransportSequenceNumberUri || + uri == webrtc::RtpExtension::kTransportSequenceNumberV2Uri || + uri == webrtc::RtpExtension::kPlayoutDelayUri || + uri == webrtc::RtpExtension::kVideoContentTypeUri || + uri == webrtc::RtpExtension::kVideoTimingUri || + uri == webrtc::RtpExtension::kMidUri || + uri == webrtc::RtpExtension::kFrameMarkingUri || + uri == webrtc::RtpExtension::kGenericFrameDescriptorUri00 || + uri == webrtc::RtpExtension::kGenericFrameDescriptorUri01 || + uri == webrtc::RtpExtension::kColorSpaceUri || + uri == webrtc::RtpExtension::kRidUri || + uri == webrtc::RtpExtension::kRepairedRidUri; +} + +bool RtpExtension::IsEncryptionSupported(const std::string& uri) { + return uri == webrtc::RtpExtension::kAudioLevelUri || + uri == webrtc::RtpExtension::kTimestampOffsetUri || +#if !defined(ENABLE_EXTERNAL_AUTH) + // TODO(jbauch): Figure out a way to always allow "kAbsSendTimeUri" + // here and filter out later if external auth is really used in + // srtpfilter. External auth is used by Chromium and replaces the + // extension header value of "kAbsSendTimeUri", so it must not be + // encrypted (which can't be done by Chromium). + uri == webrtc::RtpExtension::kAbsSendTimeUri || +#endif + uri == webrtc::RtpExtension::kVideoRotationUri || + uri == webrtc::RtpExtension::kTransportSequenceNumberUri || + uri == webrtc::RtpExtension::kTransportSequenceNumberV2Uri || + uri == webrtc::RtpExtension::kPlayoutDelayUri || + uri == webrtc::RtpExtension::kVideoContentTypeUri || + uri == webrtc::RtpExtension::kMidUri || + uri == webrtc::RtpExtension::kRidUri || + uri == webrtc::RtpExtension::kRepairedRidUri; +} + +const RtpExtension* RtpExtension::FindHeaderExtensionByUri( + const std::vector<RtpExtension>& extensions, + const std::string& uri) { + for (const auto& extension : extensions) { + if (extension.uri == uri) { + return &extension; + } + } + return nullptr; +} + +std::vector<RtpExtension> RtpExtension::FilterDuplicateNonEncrypted( + const std::vector<RtpExtension>& extensions) { + std::vector<RtpExtension> filtered; + for (auto extension = extensions.begin(); extension != extensions.end(); + ++extension) { + if (extension->encrypt) { + filtered.push_back(*extension); + continue; + } + + // Only add non-encrypted extension if no encrypted with the same URI + // is also present... + if (std::find_if(extension + 1, extensions.end(), + [extension](const RtpExtension& check) { + return extension->uri == check.uri; + }) != extensions.end()) { + continue; + } + + // ...and has not been added before. + if (!FindHeaderExtensionByUri(filtered, extension->uri)) { + filtered.push_back(*extension); + } + } + return filtered; +} +} // namespace webrtc
diff --git a/api/rtp_parameters.h b/api/rtp_parameters.h new file mode 100644 index 0000000..b7d7702 --- /dev/null +++ b/api/rtp_parameters.h
@@ -0,0 +1,664 @@ +/* + * Copyright 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_RTP_PARAMETERS_H_ +#define API_RTP_PARAMETERS_H_ + +#include <stdint.h> +#include <string> +#include <unordered_map> +#include <vector> + +#include "absl/types/optional.h" +#include "api/media_types.h" +#include "rtc_base/system/rtc_export.h" + +namespace webrtc { + +// These structures are intended to mirror those defined by: +// http://draft.ortc.org/#rtcrtpdictionaries* +// Contains everything specified as of 2017 Jan 24. +// +// They are used when retrieving or modifying the parameters of an +// RtpSender/RtpReceiver, or retrieving capabilities. +// +// Note on conventions: Where ORTC may use "octet", "short" and "unsigned" +// types, we typically use "int", in keeping with our style guidelines. The +// parameter's actual valid range will be enforced when the parameters are set, +// rather than when the parameters struct is built. An exception is made for +// SSRCs, since they use the full unsigned 32-bit range, and aren't expected to +// be used for any numeric comparisons/operations. +// +// Additionally, where ORTC uses strings, we may use enums for things that have +// a fixed number of supported values. However, for things that can be extended +// (such as codecs, by providing an external encoder factory), a string +// identifier is used. + +enum class FecMechanism { + RED, + RED_AND_ULPFEC, + FLEXFEC, +}; + +// Used in RtcpFeedback struct. +enum class RtcpFeedbackType { + CCM, + NACK, + REMB, // "goog-remb" + TRANSPORT_CC, +}; + +// Used in RtcpFeedback struct when type is NACK or CCM. +enum class RtcpFeedbackMessageType { + // Equivalent to {type: "nack", parameter: undefined} in ORTC. + GENERIC_NACK, + PLI, // Usable with NACK. + FIR, // Usable with CCM. +}; + +enum class DtxStatus { + DISABLED, + ENABLED, +}; + +// Based on the spec in +// https://w3c.github.io/webrtc-pc/#idl-def-rtcdegradationpreference. +// These options are enforced on a best-effort basis. For instance, all of +// these options may suffer some frame drops in order to avoid queuing. +// TODO(sprang): Look into possibility of more strictly enforcing the +// maintain-framerate option. +// TODO(deadbeef): Default to "balanced", as the spec indicates? +enum class DegradationPreference { + // Don't take any actions based on over-utilization signals. Not part of the + // web API. + DISABLED, + // On over-use, request lower frame rate, possibly causing frame drops. + MAINTAIN_FRAMERATE, + // On over-use, request lower resolution, possibly causing down-scaling. + MAINTAIN_RESOLUTION, + // Try to strike a "pleasing" balance between frame rate or resolution. + BALANCED, +}; + +extern const double kDefaultBitratePriority; + +struct RtcpFeedback { + RtcpFeedbackType type = RtcpFeedbackType::CCM; + + // Equivalent to ORTC "parameter" field with slight differences: + // 1. It's an enum instead of a string. + // 2. Generic NACK feedback is represented by a GENERIC_NACK message type, + // rather than an unset "parameter" value. + absl::optional<RtcpFeedbackMessageType> message_type; + + // Constructors for convenience. + RtcpFeedback(); + explicit RtcpFeedback(RtcpFeedbackType type); + RtcpFeedback(RtcpFeedbackType type, RtcpFeedbackMessageType message_type); + RtcpFeedback(const RtcpFeedback&); + ~RtcpFeedback(); + + bool operator==(const RtcpFeedback& o) const { + return type == o.type && message_type == o.message_type; + } + bool operator!=(const RtcpFeedback& o) const { return !(*this == o); } +}; + +// RtpCodecCapability is to RtpCodecParameters as RtpCapabilities is to +// RtpParameters. This represents the static capabilities of an endpoint's +// implementation of a codec. +struct RtpCodecCapability { + RtpCodecCapability(); + ~RtpCodecCapability(); + + // Build MIME "type/subtype" string from |name| and |kind|. + std::string mime_type() const { return MediaTypeToString(kind) + "/" + name; } + + // Used to identify the codec. Equivalent to MIME subtype. + std::string name; + + // The media type of this codec. Equivalent to MIME top-level type. + cricket::MediaType kind = cricket::MEDIA_TYPE_AUDIO; + + // Clock rate in Hertz. If unset, the codec is applicable to any clock rate. + absl::optional<int> clock_rate; + + // Default payload type for this codec. Mainly needed for codecs that use + // that have statically assigned payload types. + absl::optional<int> preferred_payload_type; + + // Maximum packetization time supported by an RtpReceiver for this codec. + // TODO(deadbeef): Not implemented. + absl::optional<int> max_ptime; + + // Preferred packetization time for an RtpReceiver or RtpSender of this + // codec. + // TODO(deadbeef): Not implemented. + absl::optional<int> ptime; + + // The number of audio channels supported. Unused for video codecs. + absl::optional<int> num_channels; + + // Feedback mechanisms supported for this codec. + std::vector<RtcpFeedback> rtcp_feedback; + + // Codec-specific parameters that must be signaled to the remote party. + // + // Corresponds to "a=fmtp" parameters in SDP. + // + // Contrary to ORTC, these parameters are named using all lowercase strings. + // This helps make the mapping to SDP simpler, if an application is using + // SDP. Boolean values are represented by the string "1". + std::unordered_map<std::string, std::string> parameters; + + // Codec-specific parameters that may optionally be signaled to the remote + // party. + // TODO(deadbeef): Not implemented. + std::unordered_map<std::string, std::string> options; + + // Maximum number of temporal layer extensions supported by this codec. + // For example, a value of 1 indicates that 2 total layers are supported. + // TODO(deadbeef): Not implemented. + int max_temporal_layer_extensions = 0; + + // Maximum number of spatial layer extensions supported by this codec. + // For example, a value of 1 indicates that 2 total layers are supported. + // TODO(deadbeef): Not implemented. + int max_spatial_layer_extensions = 0; + + // Whether the implementation can send/receive SVC layers with distinct + // SSRCs. Always false for audio codecs. True for video codecs that support + // scalable video coding with MRST. + // TODO(deadbeef): Not implemented. + bool svc_multi_stream_support = false; + + bool operator==(const RtpCodecCapability& o) const { + return name == o.name && kind == o.kind && clock_rate == o.clock_rate && + preferred_payload_type == o.preferred_payload_type && + max_ptime == o.max_ptime && ptime == o.ptime && + num_channels == o.num_channels && rtcp_feedback == o.rtcp_feedback && + parameters == o.parameters && options == o.options && + max_temporal_layer_extensions == o.max_temporal_layer_extensions && + max_spatial_layer_extensions == o.max_spatial_layer_extensions && + svc_multi_stream_support == o.svc_multi_stream_support; + } + bool operator!=(const RtpCodecCapability& o) const { return !(*this == o); } +}; + +// Used in RtpCapabilities; represents the capabilities/preferences of an +// implementation for a header extension. +// +// Just called "RtpHeaderExtension" in ORTC, but the "Capability" suffix was +// added here for consistency and to avoid confusion with +// RtpHeaderExtensionParameters. +// +// Note that ORTC includes a "kind" field, but we omit this because it's +// redundant; if you call "RtpReceiver::GetCapabilities(MEDIA_TYPE_AUDIO)", +// you know you're getting audio capabilities. +struct RtpHeaderExtensionCapability { + // URI of this extension, as defined in RFC8285. + std::string uri; + + // Preferred value of ID that goes in the packet. + absl::optional<int> preferred_id; + + // If true, it's preferred that the value in the header is encrypted. + // TODO(deadbeef): Not implemented. + bool preferred_encrypt = false; + + // Constructors for convenience. + RtpHeaderExtensionCapability(); + explicit RtpHeaderExtensionCapability(const std::string& uri); + RtpHeaderExtensionCapability(const std::string& uri, int preferred_id); + ~RtpHeaderExtensionCapability(); + + bool operator==(const RtpHeaderExtensionCapability& o) const { + return uri == o.uri && preferred_id == o.preferred_id && + preferred_encrypt == o.preferred_encrypt; + } + bool operator!=(const RtpHeaderExtensionCapability& o) const { + return !(*this == o); + } +}; + +// RTP header extension, see RFC8285. +struct RtpExtension { + RtpExtension(); + RtpExtension(const std::string& uri, int id); + RtpExtension(const std::string& uri, int id, bool encrypt); + ~RtpExtension(); + std::string ToString() const; + bool operator==(const RtpExtension& rhs) const { + return uri == rhs.uri && id == rhs.id && encrypt == rhs.encrypt; + } + static bool IsSupportedForAudio(const std::string& uri); + static bool IsSupportedForVideo(const std::string& uri); + // Return "true" if the given RTP header extension URI may be encrypted. + static bool IsEncryptionSupported(const std::string& uri); + + // Returns the named header extension if found among all extensions, + // nullptr otherwise. + static const RtpExtension* FindHeaderExtensionByUri( + const std::vector<RtpExtension>& extensions, + const std::string& uri); + + // Return a list of RTP header extensions with the non-encrypted extensions + // removed if both the encrypted and non-encrypted extension is present for + // the same URI. + static std::vector<RtpExtension> FilterDuplicateNonEncrypted( + const std::vector<RtpExtension>& extensions); + + // Header extension for audio levels, as defined in: + // http://tools.ietf.org/html/draft-ietf-avtext-client-to-mixer-audio-level-03 + static const char kAudioLevelUri[]; + + // Header extension for RTP timestamp offset, see RFC 5450 for details: + // http://tools.ietf.org/html/rfc5450 + static const char kTimestampOffsetUri[]; + + // Header extension for absolute send time, see url for details: + // http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time + static const char kAbsSendTimeUri[]; + + // Header extension for coordination of video orientation, see url for + // details: + // http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/12.07.00_60/ts_126114v120700p.pdf + static const char kVideoRotationUri[]; + + // Header extension for video content type. E.g. default or screenshare. + static const char kVideoContentTypeUri[]; + + // Header extension for video timing. + static const char kVideoTimingUri[]; + + // Header extension for video frame marking. + static const char kFrameMarkingUri[]; + + // Experimental codec agnostic frame descriptor. + static const char kGenericFrameDescriptorUri00[]; + static const char kGenericFrameDescriptorUri01[]; + // TODO(bugs.webrtc.org/10243): Remove once dependencies have been updated. + static const char kGenericFrameDescriptorUri[]; + + // Header extension for transport sequence number, see url for details: + // http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions + static const char kTransportSequenceNumberUri[]; + static const char kTransportSequenceNumberV2Uri[]; + + static const char kPlayoutDelayUri[]; + + // Header extension for identifying media section within a transport. + // https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-49#section-15 + static const char kMidUri[]; + + // Encryption of Header Extensions, see RFC 6904 for details: + // https://tools.ietf.org/html/rfc6904 + static const char kEncryptHeaderExtensionsUri[]; + + // Header extension for color space information. + static const char kColorSpaceUri[]; + + // Header extension for RIDs and Repaired RIDs + // https://tools.ietf.org/html/draft-ietf-avtext-rid-09 + // https://tools.ietf.org/html/draft-ietf-mmusic-rid-15 + static const char kRidUri[]; + static const char kRepairedRidUri[]; + + // Inclusive min and max IDs for two-byte header extensions and one-byte + // header extensions, per RFC8285 Section 4.2-4.3. + static constexpr int kMinId = 1; + static constexpr int kMaxId = 255; + static constexpr int kMaxValueSize = 255; + static constexpr int kOneByteHeaderExtensionMaxId = 14; + static constexpr int kOneByteHeaderExtensionMaxValueSize = 16; + + std::string uri; + int id = 0; + bool encrypt = false; +}; + +// TODO(deadbeef): This is missing the "encrypt" flag, which is unimplemented. +typedef RtpExtension RtpHeaderExtensionParameters; + +struct RtpFecParameters { + // If unset, a value is chosen by the implementation. + // Works just like RtpEncodingParameters::ssrc. + absl::optional<uint32_t> ssrc; + + FecMechanism mechanism = FecMechanism::RED; + + // Constructors for convenience. + RtpFecParameters(); + explicit RtpFecParameters(FecMechanism mechanism); + RtpFecParameters(FecMechanism mechanism, uint32_t ssrc); + RtpFecParameters(const RtpFecParameters&); + ~RtpFecParameters(); + + bool operator==(const RtpFecParameters& o) const { + return ssrc == o.ssrc && mechanism == o.mechanism; + } + bool operator!=(const RtpFecParameters& o) const { return !(*this == o); } +}; + +struct RtpRtxParameters { + // If unset, a value is chosen by the implementation. + // Works just like RtpEncodingParameters::ssrc. + absl::optional<uint32_t> ssrc; + + // Constructors for convenience. + RtpRtxParameters(); + explicit RtpRtxParameters(uint32_t ssrc); + RtpRtxParameters(const RtpRtxParameters&); + ~RtpRtxParameters(); + + bool operator==(const RtpRtxParameters& o) const { return ssrc == o.ssrc; } + bool operator!=(const RtpRtxParameters& o) const { return !(*this == o); } +}; + +struct RtpEncodingParameters { + RtpEncodingParameters(); + RtpEncodingParameters(const RtpEncodingParameters&); + ~RtpEncodingParameters(); + + // If unset, a value is chosen by the implementation. + // + // Note that the chosen value is NOT returned by GetParameters, because it + // may change due to an SSRC conflict, in which case the conflict is handled + // internally without any event. Another way of looking at this is that an + // unset SSRC acts as a "wildcard" SSRC. + absl::optional<uint32_t> ssrc; + + // Can be used to reference a codec in the |codecs| member of the + // RtpParameters that contains this RtpEncodingParameters. If unset, the + // implementation will choose the first possible codec (if a sender), or + // prepare to receive any codec (for a receiver). + // TODO(deadbeef): Not implemented. Implementation of RtpSender will always + // choose the first codec from the list. + absl::optional<int> codec_payload_type; + + // Specifies the FEC mechanism, if set. + // TODO(deadbeef): Not implemented. Current implementation will use whatever + // FEC codecs are available, including red+ulpfec. + absl::optional<RtpFecParameters> fec; + + // Specifies the RTX parameters, if set. + // TODO(deadbeef): Not implemented with PeerConnection senders/receivers. + absl::optional<RtpRtxParameters> rtx; + + // Only used for audio. If set, determines whether or not discontinuous + // transmission will be used, if an available codec supports it. If not + // set, the implementation default setting will be used. + // TODO(deadbeef): Not implemented. Current implementation will use a CN + // codec as long as it's present. + absl::optional<DtxStatus> dtx; + + // The relative bitrate priority of this encoding. Currently this is + // implemented for the entire rtp sender by using the value of the first + // encoding parameter. + // TODO(webrtc.bugs.org/8630): Implement this per encoding parameter. + // Currently there is logic for how bitrate is distributed per simulcast layer + // in the VideoBitrateAllocator. This must be updated to incorporate relative + // bitrate priority. + double bitrate_priority = kDefaultBitratePriority; + + // The relative DiffServ Code Point priority for this encoding, allowing + // packets to be marked relatively higher or lower without affecting + // bandwidth allocations. See https://w3c.github.io/webrtc-dscp-exp/ . NB + // we follow chromium's translation of the allowed string enum values for + // this field to 1.0, 0.5, et cetera, similar to bitrate_priority above. + // TODO(http://crbug.com/webrtc/8630): Implement this per encoding parameter. + double network_priority = kDefaultBitratePriority; + + // Indicates the preferred duration of media represented by a packet in + // milliseconds for this encoding. If set, this will take precedence over the + // ptime set in the RtpCodecParameters. This could happen if SDP negotiation + // creates a ptime for a specific codec, which is later changed in the + // RtpEncodingParameters by the application. + // TODO(bugs.webrtc.org/8819): Not implemented. + absl::optional<int> ptime; + + // If set, this represents the Transport Independent Application Specific + // maximum bandwidth defined in RFC3890. If unset, there is no maximum + // bitrate. Currently this is implemented for the entire rtp sender by using + // the value of the first encoding parameter. + // + // Just called "maxBitrate" in ORTC spec. + // + // TODO(deadbeef): With ORTC RtpSenders, this currently sets the total + // bandwidth for the entire bandwidth estimator (audio and video). This is + // just always how "b=AS" was handled, but it's not correct and should be + // fixed. + absl::optional<int> max_bitrate_bps; + + // Specifies the minimum bitrate in bps for video. + // TODO(asapersson): Not implemented for ORTC API. + absl::optional<int> min_bitrate_bps; + + // Specifies the maximum framerate in fps for video. + // TODO(asapersson): Different framerates are not supported per simulcast + // layer. If set, the maximum |max_framerate| is currently used. + // Not supported for screencast. + absl::optional<int> max_framerate; + + // Specifies the number of temporal layers for video (if the feature is + // supported by the codec implementation). + // TODO(asapersson): Different number of temporal layers are not supported + // per simulcast layer. + // Screencast support is experimental. + absl::optional<int> num_temporal_layers; + + // For video, scale the resolution down by this factor. + absl::optional<double> scale_resolution_down_by; + + // Scale the framerate down by this factor. + // TODO(deadbeef): Not implemented. + absl::optional<double> scale_framerate_down_by; + + // For an RtpSender, set to true to cause this encoding to be encoded and + // sent, and false for it not to be encoded and sent. This allows control + // across multiple encodings of a sender for turning simulcast layers on and + // off. + // TODO(webrtc.bugs.org/8807): Updating this parameter will trigger an encoder + // reset, but this isn't necessarily required. + bool active = true; + + // Value to use for RID RTP header extension. + // Called "encodingId" in ORTC. + std::string rid; + + // RIDs of encodings on which this layer depends. + // Called "dependencyEncodingIds" in ORTC spec. + // TODO(deadbeef): Not implemented. + std::vector<std::string> dependency_rids; + + bool operator==(const RtpEncodingParameters& o) const { + return ssrc == o.ssrc && codec_payload_type == o.codec_payload_type && + fec == o.fec && rtx == o.rtx && dtx == o.dtx && + bitrate_priority == o.bitrate_priority && + network_priority == o.network_priority && ptime == o.ptime && + max_bitrate_bps == o.max_bitrate_bps && + min_bitrate_bps == o.min_bitrate_bps && + max_framerate == o.max_framerate && + num_temporal_layers == o.num_temporal_layers && + scale_resolution_down_by == o.scale_resolution_down_by && + scale_framerate_down_by == o.scale_framerate_down_by && + active == o.active && rid == o.rid && + dependency_rids == o.dependency_rids; + } + bool operator!=(const RtpEncodingParameters& o) const { + return !(*this == o); + } +}; + +struct RtpCodecParameters { + RtpCodecParameters(); + RtpCodecParameters(const RtpCodecParameters&); + ~RtpCodecParameters(); + + // Build MIME "type/subtype" string from |name| and |kind|. + std::string mime_type() const { return MediaTypeToString(kind) + "/" + name; } + + // Used to identify the codec. Equivalent to MIME subtype. + std::string name; + + // The media type of this codec. Equivalent to MIME top-level type. + cricket::MediaType kind = cricket::MEDIA_TYPE_AUDIO; + + // Payload type used to identify this codec in RTP packets. + // This must always be present, and must be unique across all codecs using + // the same transport. + int payload_type = 0; + + // If unset, the implementation default is used. + absl::optional<int> clock_rate; + + // The number of audio channels used. Unset for video codecs. If unset for + // audio, the implementation default is used. + // TODO(deadbeef): The "implementation default" part isn't fully implemented. + // Only defaults to 1, even though some codecs (such as opus) should really + // default to 2. + absl::optional<int> num_channels; + + // The maximum packetization time to be used by an RtpSender. + // If |ptime| is also set, this will be ignored. + // TODO(deadbeef): Not implemented. + absl::optional<int> max_ptime; + + // The packetization time to be used by an RtpSender. + // If unset, will use any time up to max_ptime. + // TODO(deadbeef): Not implemented. + absl::optional<int> ptime; + + // Feedback mechanisms to be used for this codec. + // TODO(deadbeef): Not implemented with PeerConnection senders/receivers. + std::vector<RtcpFeedback> rtcp_feedback; + + // Codec-specific parameters that must be signaled to the remote party. + // + // Corresponds to "a=fmtp" parameters in SDP. + // + // Contrary to ORTC, these parameters are named using all lowercase strings. + // This helps make the mapping to SDP simpler, if an application is using + // SDP. Boolean values are represented by the string "1". + std::unordered_map<std::string, std::string> parameters; + + bool operator==(const RtpCodecParameters& o) const { + return name == o.name && kind == o.kind && payload_type == o.payload_type && + clock_rate == o.clock_rate && num_channels == o.num_channels && + max_ptime == o.max_ptime && ptime == o.ptime && + rtcp_feedback == o.rtcp_feedback && parameters == o.parameters; + } + bool operator!=(const RtpCodecParameters& o) const { return !(*this == o); } +}; + +// RtpCapabilities is used to represent the static capabilities of an +// endpoint. An application can use these capabilities to construct an +// RtpParameters. +struct RtpCapabilities { + RtpCapabilities(); + ~RtpCapabilities(); + + // Supported codecs. + std::vector<RtpCodecCapability> codecs; + + // Supported RTP header extensions. + std::vector<RtpHeaderExtensionCapability> header_extensions; + + // Supported Forward Error Correction (FEC) mechanisms. Note that the RED, + // ulpfec and flexfec codecs used by these mechanisms will still appear in + // |codecs|. + std::vector<FecMechanism> fec; + + bool operator==(const RtpCapabilities& o) const { + return codecs == o.codecs && header_extensions == o.header_extensions && + fec == o.fec; + } + bool operator!=(const RtpCapabilities& o) const { return !(*this == o); } +}; + +struct RtcpParameters final { + RtcpParameters(); + RtcpParameters(const RtcpParameters&); + ~RtcpParameters(); + + // The SSRC to be used in the "SSRC of packet sender" field. If not set, one + // will be chosen by the implementation. + // TODO(deadbeef): Not implemented. + absl::optional<uint32_t> ssrc; + + // The Canonical Name (CNAME) used by RTCP (e.g. in SDES messages). + // + // If empty in the construction of the RtpTransport, one will be generated by + // the implementation, and returned in GetRtcpParameters. Multiple + // RtpTransports created by the same OrtcFactory will use the same generated + // CNAME. + // + // If empty when passed into SetParameters, the CNAME simply won't be + // modified. + std::string cname; + + // Send reduced-size RTCP? + bool reduced_size = false; + + // Send RTCP multiplexed on the RTP transport? + // Not used with PeerConnection senders/receivers + bool mux = true; + + bool operator==(const RtcpParameters& o) const { + return ssrc == o.ssrc && cname == o.cname && + reduced_size == o.reduced_size && mux == o.mux; + } + bool operator!=(const RtcpParameters& o) const { return !(*this == o); } +}; + +struct RTC_EXPORT RtpParameters { + RtpParameters(); + RtpParameters(const RtpParameters&); + ~RtpParameters(); + + // Used when calling getParameters/setParameters with a PeerConnection + // RtpSender, to ensure that outdated parameters are not unintentionally + // applied successfully. + std::string transaction_id; + + // Value to use for MID RTP header extension. + // Called "muxId" in ORTC. + // TODO(deadbeef): Not implemented. + std::string mid; + + std::vector<RtpCodecParameters> codecs; + + std::vector<RtpHeaderExtensionParameters> header_extensions; + + std::vector<RtpEncodingParameters> encodings; + + // Only available with a Peerconnection RtpSender. + // In ORTC, our API includes an additional "RtpTransport" + // abstraction on which RTCP parameters are set. + RtcpParameters rtcp; + + // When bandwidth is constrained and the RtpSender needs to choose between + // degrading resolution or degrading framerate, degradationPreference + // indicates which is preferred. Only for video tracks. + DegradationPreference degradation_preference = + DegradationPreference::BALANCED; + + bool operator==(const RtpParameters& o) const { + return mid == o.mid && codecs == o.codecs && + header_extensions == o.header_extensions && + encodings == o.encodings && rtcp == o.rtcp && + degradation_preference == o.degradation_preference; + } + bool operator!=(const RtpParameters& o) const { return !(*this == o); } +}; + +} // namespace webrtc + +#endif // API_RTP_PARAMETERS_H_
diff --git a/api/rtp_parameters_unittest.cc b/api/rtp_parameters_unittest.cc new file mode 100644 index 0000000..b6f2482 --- /dev/null +++ b/api/rtp_parameters_unittest.cc
@@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/rtp_parameters.h" +#include "test/gtest.h" + +namespace webrtc { + +using webrtc::RtpExtension; + +static const char kExtensionUri1[] = "extension-uri1"; +static const char kExtensionUri2[] = "extension-uri2"; + +static const RtpExtension kExtension1(kExtensionUri1, 1); +static const RtpExtension kExtension1Encrypted(kExtensionUri1, 10, true); +static const RtpExtension kExtension2(kExtensionUri2, 2); + +TEST(RtpExtensionTest, FilterDuplicateNonEncrypted) { + std::vector<RtpExtension> extensions; + std::vector<RtpExtension> filtered; + + extensions.push_back(kExtension1); + extensions.push_back(kExtension1Encrypted); + filtered = RtpExtension::FilterDuplicateNonEncrypted(extensions); + EXPECT_EQ(1u, filtered.size()); + EXPECT_EQ(std::vector<RtpExtension>{kExtension1Encrypted}, filtered); + + extensions.clear(); + extensions.push_back(kExtension1Encrypted); + extensions.push_back(kExtension1); + filtered = RtpExtension::FilterDuplicateNonEncrypted(extensions); + EXPECT_EQ(1u, filtered.size()); + EXPECT_EQ(std::vector<RtpExtension>{kExtension1Encrypted}, filtered); + + extensions.clear(); + extensions.push_back(kExtension1); + extensions.push_back(kExtension2); + filtered = RtpExtension::FilterDuplicateNonEncrypted(extensions); + EXPECT_EQ(2u, filtered.size()); + EXPECT_EQ(extensions, filtered); +} +} // namespace webrtc
diff --git a/api/rtp_receiver_interface.cc b/api/rtp_receiver_interface.cc new file mode 100644 index 0000000..52f72df --- /dev/null +++ b/api/rtp_receiver_interface.cc
@@ -0,0 +1,61 @@ +/* + * Copyright 2018 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/rtp_receiver_interface.h" + +namespace webrtc { + +RtpSource::RtpSource(int64_t timestamp_ms, + uint32_t source_id, + RtpSourceType source_type) + : timestamp_ms_(timestamp_ms), + source_id_(source_id), + source_type_(source_type) {} + +RtpSource::RtpSource(int64_t timestamp_ms, + uint32_t source_id, + RtpSourceType source_type, + uint8_t audio_level) + : timestamp_ms_(timestamp_ms), + source_id_(source_id), + source_type_(source_type), + audio_level_(audio_level) {} + +RtpSource::RtpSource(const RtpSource&) = default; +RtpSource& RtpSource::operator=(const RtpSource&) = default; +RtpSource::~RtpSource() = default; + +std::vector<std::string> RtpReceiverInterface::stream_ids() const { + return {}; +} + +std::vector<rtc::scoped_refptr<MediaStreamInterface>> +RtpReceiverInterface::streams() const { + return {}; +} + +std::vector<RtpSource> RtpReceiverInterface::GetSources() const { + return {}; +} + +void RtpReceiverInterface::SetFrameDecryptor( + rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor) {} + +rtc::scoped_refptr<FrameDecryptorInterface> +RtpReceiverInterface::GetFrameDecryptor() const { + return nullptr; +} + +rtc::scoped_refptr<DtlsTransportInterface> +RtpReceiverInterface::dtls_transport() const { + return nullptr; +} + +} // namespace webrtc
diff --git a/api/rtp_receiver_interface.h b/api/rtp_receiver_interface.h new file mode 100644 index 0000000..7d9870b --- /dev/null +++ b/api/rtp_receiver_interface.h
@@ -0,0 +1,176 @@ +/* + * Copyright 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This file contains interfaces for RtpReceivers +// http://w3c.github.io/webrtc-pc/#rtcrtpreceiver-interface + +#ifndef API_RTP_RECEIVER_INTERFACE_H_ +#define API_RTP_RECEIVER_INTERFACE_H_ + +#include <string> +#include <vector> + +#include "api/crypto/frame_decryptor_interface.h" +#include "api/dtls_transport_interface.h" +#include "api/media_stream_interface.h" +#include "api/media_types.h" +#include "api/proxy.h" +#include "api/rtp_parameters.h" +#include "api/scoped_refptr.h" +#include "rtc_base/ref_count.h" + +namespace webrtc { + +enum class RtpSourceType { + SSRC, + CSRC, +}; + +class RtpSource { + public: + RtpSource() = delete; + RtpSource(int64_t timestamp_ms, + uint32_t source_id, + RtpSourceType source_type); + RtpSource(int64_t timestamp_ms, + uint32_t source_id, + RtpSourceType source_type, + uint8_t audio_level); + RtpSource(const RtpSource&); + RtpSource& operator=(const RtpSource&); + ~RtpSource(); + + int64_t timestamp_ms() const { return timestamp_ms_; } + void update_timestamp_ms(int64_t timestamp_ms) { + RTC_DCHECK_LE(timestamp_ms_, timestamp_ms); + timestamp_ms_ = timestamp_ms; + } + + // The identifier of the source can be the CSRC or the SSRC. + uint32_t source_id() const { return source_id_; } + + // The source can be either a contributing source or a synchronization source. + RtpSourceType source_type() const { return source_type_; } + + absl::optional<uint8_t> audio_level() const { return audio_level_; } + void set_audio_level(const absl::optional<uint8_t>& level) { + audio_level_ = level; + } + + bool operator==(const RtpSource& o) const { + return timestamp_ms_ == o.timestamp_ms() && source_id_ == o.source_id() && + source_type_ == o.source_type() && audio_level_ == o.audio_level_; + } + + private: + int64_t timestamp_ms_; + uint32_t source_id_; + RtpSourceType source_type_; + absl::optional<uint8_t> audio_level_; +}; + +class RtpReceiverObserverInterface { + public: + // Note: Currently if there are multiple RtpReceivers of the same media type, + // they will all call OnFirstPacketReceived at once. + // + // In the future, it's likely that an RtpReceiver will only call + // OnFirstPacketReceived when a packet is received specifically for its + // SSRC/mid. + virtual void OnFirstPacketReceived(cricket::MediaType media_type) = 0; + + protected: + virtual ~RtpReceiverObserverInterface() {} +}; + +class RtpReceiverInterface : public rtc::RefCountInterface { + public: + virtual rtc::scoped_refptr<MediaStreamTrackInterface> track() const = 0; + + // The dtlsTransport attribute exposes the DTLS transport on which the + // media is received. It may be null. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtpreceiver-transport + // TODO(https://bugs.webrtc.org/907849) remove default implementation + virtual rtc::scoped_refptr<DtlsTransportInterface> dtls_transport() const; + + // The list of streams that |track| is associated with. This is the same as + // the [[AssociatedRemoteMediaStreams]] internal slot in the spec. + // https://w3c.github.io/webrtc-pc/#dfn-associatedremotemediastreams + // TODO(hbos): Make pure virtual as soon as Chromium's mock implements this. + // TODO(https://crbug.com/webrtc/9480): Remove streams() in favor of + // stream_ids() as soon as downstream projects are no longer dependent on + // stream objects. + virtual std::vector<std::string> stream_ids() const; + virtual std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams() const; + + // Audio or video receiver? + virtual cricket::MediaType media_type() const = 0; + + // Not to be confused with "mid", this is a field we can temporarily use + // to uniquely identify a receiver until we implement Unified Plan SDP. + virtual std::string id() const = 0; + + // The WebRTC specification only defines RTCRtpParameters in terms of senders, + // but this API also applies them to receivers, similar to ORTC: + // http://ortc.org/wp-content/uploads/2016/03/ortc.html#rtcrtpparameters*. + virtual RtpParameters GetParameters() const = 0; + // Currently, doesn't support changing any parameters, but may in the future. + virtual bool SetParameters(const RtpParameters& parameters) = 0; + + // Does not take ownership of observer. + // Must call SetObserver(nullptr) before the observer is destroyed. + virtual void SetObserver(RtpReceiverObserverInterface* observer) = 0; + + // TODO(zhihuang): Remove the default implementation once the subclasses + // implement this. Currently, the only relevant subclass is the + // content::FakeRtpReceiver in Chromium. + virtual std::vector<RtpSource> GetSources() const; + + // Sets a user defined frame decryptor that will decrypt the entire frame + // before it is sent across the network. This will decrypt the entire frame + // using the user provided decryption mechanism regardless of whether SRTP is + // enabled or not. + virtual void SetFrameDecryptor( + rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor); + + // Returns a pointer to the frame decryptor set previously by the + // user. This can be used to update the state of the object. + virtual rtc::scoped_refptr<FrameDecryptorInterface> GetFrameDecryptor() const; + + protected: + ~RtpReceiverInterface() override = default; +}; + +// Define proxy for RtpReceiverInterface. +// TODO(deadbeef): Move this to .cc file and out of api/. What threads methods +// are called on is an implementation detail. +BEGIN_SIGNALING_PROXY_MAP(RtpReceiver) +PROXY_SIGNALING_THREAD_DESTRUCTOR() +PROXY_CONSTMETHOD0(rtc::scoped_refptr<MediaStreamTrackInterface>, track) +PROXY_CONSTMETHOD0(rtc::scoped_refptr<DtlsTransportInterface>, dtls_transport) +PROXY_CONSTMETHOD0(std::vector<std::string>, stream_ids) +PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<MediaStreamInterface>>, + streams) +PROXY_CONSTMETHOD0(cricket::MediaType, media_type) +PROXY_CONSTMETHOD0(std::string, id) +PROXY_CONSTMETHOD0(RtpParameters, GetParameters) +PROXY_METHOD1(bool, SetParameters, const RtpParameters&) +PROXY_METHOD1(void, SetObserver, RtpReceiverObserverInterface*) +PROXY_CONSTMETHOD0(std::vector<RtpSource>, GetSources) +PROXY_METHOD1(void, + SetFrameDecryptor, + rtc::scoped_refptr<FrameDecryptorInterface>) +PROXY_CONSTMETHOD0(rtc::scoped_refptr<FrameDecryptorInterface>, + GetFrameDecryptor) +END_PROXY_MAP() + +} // namespace webrtc + +#endif // API_RTP_RECEIVER_INTERFACE_H_
diff --git a/api/rtp_sender_interface.cc b/api/rtp_sender_interface.cc new file mode 100644 index 0000000..d23fd18 --- /dev/null +++ b/api/rtp_sender_interface.cc
@@ -0,0 +1,33 @@ +/* + * Copyright 2018 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/rtp_sender_interface.h" + +namespace webrtc { + +void RtpSenderInterface::SetFrameEncryptor( + rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor) {} + +rtc::scoped_refptr<FrameEncryptorInterface> +RtpSenderInterface::GetFrameEncryptor() const { + return nullptr; +} + +std::vector<RtpEncodingParameters> RtpSenderInterface::init_send_encodings() + const { + return {}; +} + +rtc::scoped_refptr<DtlsTransportInterface> RtpSenderInterface::dtls_transport() + const { + return nullptr; +} + +} // namespace webrtc
diff --git a/api/rtp_sender_interface.h b/api/rtp_sender_interface.h new file mode 100644 index 0000000..e0a29a3 --- /dev/null +++ b/api/rtp_sender_interface.h
@@ -0,0 +1,119 @@ +/* + * Copyright 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This file contains interfaces for RtpSenders +// http://w3c.github.io/webrtc-pc/#rtcrtpsender-interface + +#ifndef API_RTP_SENDER_INTERFACE_H_ +#define API_RTP_SENDER_INTERFACE_H_ + +#include <string> +#include <vector> + +#include "api/crypto/frame_encryptor_interface.h" +#include "api/dtls_transport_interface.h" +#include "api/dtmf_sender_interface.h" +#include "api/media_stream_interface.h" +#include "api/media_types.h" +#include "api/proxy.h" +#include "api/rtc_error.h" +#include "api/rtp_parameters.h" +#include "api/scoped_refptr.h" +#include "rtc_base/ref_count.h" + +namespace webrtc { + +class RtpSenderInterface : public rtc::RefCountInterface { + public: + // Returns true if successful in setting the track. + // Fails if an audio track is set on a video RtpSender, or vice-versa. + virtual bool SetTrack(MediaStreamTrackInterface* track) = 0; + virtual rtc::scoped_refptr<MediaStreamTrackInterface> track() const = 0; + + // The dtlsTransport attribute exposes the DTLS transport on which the + // media is sent. It may be null. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtpsender-transport + // TODO(https://bugs.webrtc.org/907849) remove default implementation + virtual rtc::scoped_refptr<DtlsTransportInterface> dtls_transport() const; + + // Returns primary SSRC used by this sender for sending media. + // Returns 0 if not yet determined. + // TODO(deadbeef): Change to absl::optional. + // TODO(deadbeef): Remove? With GetParameters this should be redundant. + virtual uint32_t ssrc() const = 0; + + // Audio or video sender? + virtual cricket::MediaType media_type() const = 0; + + // Not to be confused with "mid", this is a field we can temporarily use + // to uniquely identify a receiver until we implement Unified Plan SDP. + virtual std::string id() const = 0; + + // Returns a list of media stream ids associated with this sender's track. + // These are signalled in the SDP so that the remote side can associate + // tracks. + virtual std::vector<std::string> stream_ids() const = 0; + + // Returns the list of encoding parameters that will be applied when the SDP + // local description is set. These initial encoding parameters can be set by + // PeerConnection::AddTransceiver, and later updated with Get/SetParameters. + // TODO(orphis): Make it pure virtual once Chrome has updated + virtual std::vector<RtpEncodingParameters> init_send_encodings() const; + + virtual RtpParameters GetParameters() const = 0; + // Note that only a subset of the parameters can currently be changed. See + // rtpparameters.h + // The encodings are in increasing quality order for simulcast. + virtual RTCError SetParameters(const RtpParameters& parameters) = 0; + + // Returns null for a video sender. + virtual rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const = 0; + + // Sets a user defined frame encryptor that will encrypt the entire frame + // before it is sent across the network. This will encrypt the entire frame + // using the user provided encryption mechanism regardless of whether SRTP is + // enabled or not. + virtual void SetFrameEncryptor( + rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor); + + // Returns a pointer to the frame encryptor set previously by the + // user. This can be used to update the state of the object. + virtual rtc::scoped_refptr<FrameEncryptorInterface> GetFrameEncryptor() const; + + protected: + ~RtpSenderInterface() override = default; +}; + +// Define proxy for RtpSenderInterface. +// TODO(deadbeef): Move this to .cc file and out of api/. What threads methods +// are called on is an implementation detail. +BEGIN_SIGNALING_PROXY_MAP(RtpSender) +PROXY_SIGNALING_THREAD_DESTRUCTOR() +PROXY_METHOD1(bool, SetTrack, MediaStreamTrackInterface*) +PROXY_CONSTMETHOD0(rtc::scoped_refptr<MediaStreamTrackInterface>, track) +PROXY_CONSTMETHOD0(rtc::scoped_refptr<DtlsTransportInterface>, dtls_transport) +PROXY_CONSTMETHOD0(uint32_t, ssrc) +PROXY_CONSTMETHOD0(cricket::MediaType, media_type) +PROXY_CONSTMETHOD0(std::string, id) +PROXY_CONSTMETHOD0(std::vector<std::string>, stream_ids) +PROXY_CONSTMETHOD0(std::vector<RtpEncodingParameters>, init_send_encodings) +PROXY_CONSTMETHOD0(RtpParameters, GetParameters) +PROXY_METHOD1(RTCError, SetParameters, const RtpParameters&) +PROXY_CONSTMETHOD0(rtc::scoped_refptr<DtmfSenderInterface>, GetDtmfSender) +PROXY_METHOD1(void, + SetFrameEncryptor, + rtc::scoped_refptr<FrameEncryptorInterface>) +PROXY_CONSTMETHOD0(rtc::scoped_refptr<FrameEncryptorInterface>, + GetFrameEncryptor) +END_PROXY_MAP() + +} // namespace webrtc + +#endif // API_RTP_SENDER_INTERFACE_H_
diff --git a/api/rtp_transceiver_interface.cc b/api/rtp_transceiver_interface.cc new file mode 100644 index 0000000..0504331 --- /dev/null +++ b/api/rtp_transceiver_interface.cc
@@ -0,0 +1,33 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/rtp_transceiver_interface.h" + +#include "rtc_base/checks.h" + +namespace webrtc { + +RtpTransceiverInit::RtpTransceiverInit() = default; + +RtpTransceiverInit::RtpTransceiverInit(const RtpTransceiverInit& rhs) = default; + +RtpTransceiverInit::~RtpTransceiverInit() = default; + +absl::optional<RtpTransceiverDirection> +RtpTransceiverInterface::fired_direction() const { + return absl::nullopt; +} + +void RtpTransceiverInterface::SetCodecPreferences( + rtc::ArrayView<RtpCodecCapability>) { + RTC_NOTREACHED() << "Not implemented"; +} + +} // namespace webrtc
diff --git a/api/rtp_transceiver_interface.h b/api/rtp_transceiver_interface.h new file mode 100644 index 0000000..aec0d15 --- /dev/null +++ b/api/rtp_transceiver_interface.h
@@ -0,0 +1,140 @@ +/* + * Copyright 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_RTP_TRANSCEIVER_INTERFACE_H_ +#define API_RTP_TRANSCEIVER_INTERFACE_H_ + +#include <string> +#include <vector> + +#include "absl/types/optional.h" +#include "api/array_view.h" +#include "api/media_types.h" +#include "api/rtp_parameters.h" +#include "api/rtp_receiver_interface.h" +#include "api/rtp_sender_interface.h" +#include "api/scoped_refptr.h" +#include "rtc_base/ref_count.h" + +namespace webrtc { + +// https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiverdirection +enum class RtpTransceiverDirection { + kSendRecv, + kSendOnly, + kRecvOnly, + kInactive +}; + +// Structure for initializing an RtpTransceiver in a call to +// PeerConnectionInterface::AddTransceiver. +// https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiverinit +struct RtpTransceiverInit final { + RtpTransceiverInit(); + RtpTransceiverInit(const RtpTransceiverInit&); + ~RtpTransceiverInit(); + // Direction of the RtpTransceiver. See RtpTransceiverInterface::direction(). + RtpTransceiverDirection direction = RtpTransceiverDirection::kSendRecv; + + // The added RtpTransceiver will be added to these streams. + std::vector<std::string> stream_ids; + + // TODO(bugs.webrtc.org/7600): Not implemented. + std::vector<RtpEncodingParameters> send_encodings; +}; + +// The RtpTransceiverInterface maps to the RTCRtpTransceiver defined by the +// WebRTC specification. A transceiver represents a combination of an RtpSender +// and an RtpReceiver than share a common mid. As defined in JSEP, an +// RtpTransceiver is said to be associated with a media description if its mid +// property is non-null; otherwise, it is said to be disassociated. +// JSEP: https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-24 +// +// Note that RtpTransceivers are only supported when using PeerConnection with +// Unified Plan SDP. +// +// This class is thread-safe. +// +// WebRTC specification for RTCRtpTransceiver, the JavaScript analog: +// https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver +class RtpTransceiverInterface : public rtc::RefCountInterface { + public: + // Media type of the transceiver. Any sender(s)/receiver(s) will have this + // type as well. + virtual cricket::MediaType media_type() const = 0; + + // The mid attribute is the mid negotiated and present in the local and + // remote descriptions. Before negotiation is complete, the mid value may be + // null. After rollbacks, the value may change from a non-null value to null. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-mid + virtual absl::optional<std::string> mid() const = 0; + + // The sender attribute exposes the RtpSender corresponding to the RTP media + // that may be sent with the transceiver's mid. The sender is always present, + // regardless of the direction of media. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-sender + virtual rtc::scoped_refptr<RtpSenderInterface> sender() const = 0; + + // The receiver attribute exposes the RtpReceiver corresponding to the RTP + // media that may be received with the transceiver's mid. The receiver is + // always present, regardless of the direction of media. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-receiver + virtual rtc::scoped_refptr<RtpReceiverInterface> receiver() const = 0; + + // The stopped attribute indicates that the sender of this transceiver will no + // longer send, and that the receiver will no longer receive. It is true if + // either stop has been called or if setting the local or remote description + // has caused the RtpTransceiver to be stopped. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stopped + virtual bool stopped() const = 0; + + // The direction attribute indicates the preferred direction of this + // transceiver, which will be used in calls to CreateOffer and CreateAnswer. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction + virtual RtpTransceiverDirection direction() const = 0; + + // Sets the preferred direction of this transceiver. An update of + // directionality does not take effect immediately. Instead, future calls to + // CreateOffer and CreateAnswer mark the corresponding media descriptions as + // sendrecv, sendonly, recvonly, or inactive. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction + virtual void SetDirection(RtpTransceiverDirection new_direction) = 0; + + // The current_direction attribute indicates the current direction negotiated + // for this transceiver. If this transceiver has never been represented in an + // offer/answer exchange, or if the transceiver is stopped, the value is null. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-currentdirection + virtual absl::optional<RtpTransceiverDirection> current_direction() const = 0; + + // An internal slot designating for which direction the relevant + // PeerConnection events have been fired. This is to ensure that events like + // OnAddTrack only get fired once even if the same session description is + // applied again. + // Exposed in the public interface for use by Chromium. + virtual absl::optional<RtpTransceiverDirection> fired_direction() const; + + // The Stop method irreversibly stops the RtpTransceiver. The sender of this + // transceiver will no longer send, the receiver will no longer receive. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stop + virtual void Stop() = 0; + + // The SetCodecPreferences method overrides the default codec preferences used + // by WebRTC for this transceiver. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-setcodecpreferences + // TODO(steveanton): Not implemented. + virtual void SetCodecPreferences(rtc::ArrayView<RtpCodecCapability> codecs); + + protected: + ~RtpTransceiverInterface() override = default; +}; + +} // namespace webrtc + +#endif // API_RTP_TRANSCEIVER_INTERFACE_H_
diff --git a/api/scoped_refptr.h b/api/scoped_refptr.h index 0993e03..67d179f 100644 --- a/api/scoped_refptr.h +++ b/api/scoped_refptr.h
@@ -71,6 +71,8 @@ template <class T> class scoped_refptr { public: + typedef T element_type; + scoped_refptr() : ptr_(nullptr) {} scoped_refptr(T* p) : ptr_(p) { // NOLINT(runtime/explicit)
diff --git a/api/sctp_transport_interface.cc b/api/sctp_transport_interface.cc new file mode 100644 index 0000000..c6c1fbe --- /dev/null +++ b/api/sctp_transport_interface.cc
@@ -0,0 +1,32 @@ +/* + * Copyright 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <utility> + +#include "api/sctp_transport_interface.h" + +namespace webrtc { + +SctpTransportInformation::SctpTransportInformation(SctpTransportState state) + : state_(state) {} + +SctpTransportInformation::SctpTransportInformation( + SctpTransportState state, + rtc::scoped_refptr<DtlsTransportInterface> dtls_transport, + absl::optional<double> max_message_size, + absl::optional<int> max_channels) + : state_(state), + dtls_transport_(std::move(dtls_transport)), + max_message_size_(max_message_size), + max_channels_(max_channels) {} + +SctpTransportInformation::~SctpTransportInformation() {} + +} // namespace webrtc
diff --git a/api/sctp_transport_interface.h b/api/sctp_transport_interface.h new file mode 100644 index 0000000..3698fc2 --- /dev/null +++ b/api/sctp_transport_interface.h
@@ -0,0 +1,90 @@ +/* + * Copyright 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_SCTP_TRANSPORT_INTERFACE_H_ +#define API_SCTP_TRANSPORT_INTERFACE_H_ + +#include "absl/types/optional.h" +#include "api/dtls_transport_interface.h" +#include "api/rtc_error.h" +#include "api/scoped_refptr.h" +#include "rtc_base/ref_count.h" + +namespace webrtc { + +// States of a SCTP transport, corresponding to the JS API specification. +// http://w3c.github.io/webrtc-pc/#dom-rtcsctptransportstate +enum class SctpTransportState { + kNew, // Has not started negotiating yet. Non-standard state. + kConnecting, // In the process of negotiating an association. + kConnected, // Completed negotiation of an association. + kClosed, // Closed by local or remote party. + kNumValues +}; + +// This object gives snapshot information about the changeable state of a +// SctpTransport. +// It reflects the readonly attributes of the object in the specification. +// http://w3c.github.io/webrtc-pc/#rtcsctptransport-interface +class SctpTransportInformation { + public: + explicit SctpTransportInformation(SctpTransportState state); + SctpTransportInformation( + SctpTransportState state, + rtc::scoped_refptr<DtlsTransportInterface> dtls_transport, + absl::optional<double> max_message_size, + absl::optional<int> max_channels); + ~SctpTransportInformation(); + // The DTLS transport that supports this SCTP transport. + rtc::scoped_refptr<DtlsTransportInterface> dtls_transport() const { + return dtls_transport_; + } + SctpTransportState state() const { return state_; } + absl::optional<double> MaxMessageSize() const { return max_message_size_; } + absl::optional<int> MaxChannels() const { return max_channels_; } + + private: + SctpTransportState state_; + rtc::scoped_refptr<DtlsTransportInterface> dtls_transport_; + absl::optional<double> max_message_size_; + absl::optional<int> max_channels_; +}; + +class SctpTransportObserverInterface { + public: + // This callback carries information about the state of the transport. + // The argument is a pass-by-value snapshot of the state. + // The callback will be called on the network thread. + virtual void OnStateChange(SctpTransportInformation info) = 0; + + protected: + virtual ~SctpTransportObserverInterface() = default; +}; + +// A SCTP transport, as represented to the outside world. +// This object is created on the network thread, and can only be +// accessed on that thread, except for functions explicitly marked otherwise. +// References can be held by other threads, and destruction can therefore +// be initiated by other threads. +class SctpTransportInterface : public rtc::RefCountInterface { + public: + // This function can be called from other threads. + virtual rtc::scoped_refptr<DtlsTransportInterface> dtls_transport() const = 0; + // Returns information on the state of the SctpTransport. + // This function can be called from other threads. + virtual SctpTransportInformation Information() const = 0; + // Observer management. + virtual void RegisterObserver(SctpTransportObserverInterface* observer) = 0; + virtual void UnregisterObserver() = 0; +}; + +} // namespace webrtc + +#endif // API_SCTP_TRANSPORT_INTERFACE_H_
diff --git a/api/set_remote_description_observer_interface.h b/api/set_remote_description_observer_interface.h new file mode 100644 index 0000000..1782555 --- /dev/null +++ b/api/set_remote_description_observer_interface.h
@@ -0,0 +1,31 @@ +/* + * Copyright 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_SET_REMOTE_DESCRIPTION_OBSERVER_INTERFACE_H_ +#define API_SET_REMOTE_DESCRIPTION_OBSERVER_INTERFACE_H_ + +#include "api/rtc_error.h" +#include "rtc_base/ref_count.h" + +namespace webrtc { + +// An observer for PeerConnectionInterface::SetRemoteDescription(). The +// callback is invoked such that the state of the peer connection can be +// examined to accurately reflect the effects of the SetRemoteDescription +// operation. +class SetRemoteDescriptionObserverInterface : public rtc::RefCountInterface { + public: + // On success, |error.ok()| is true. + virtual void OnSetRemoteDescriptionComplete(RTCError error) = 0; +}; + +} // namespace webrtc + +#endif // API_SET_REMOTE_DESCRIPTION_OBSERVER_INTERFACE_H_
diff --git a/api/stats_types.cc b/api/stats_types.cc new file mode 100644 index 0000000..71b1f86 --- /dev/null +++ b/api/stats_types.cc
@@ -0,0 +1,842 @@ +/* + * Copyright 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/stats_types.h" + +#include <string.h> + +#include "rtc_base/checks.h" +#include "rtc_base/ref_counted_object.h" + +// TODO(tommi): Could we have a static map of value name -> expected type +// and use this to RTC_DCHECK on correct usage (somewhat strongly typed values)? +// Alternatively, we could define the names+type in a separate document and +// generate strongly typed inline C++ code that forces the correct type to be +// used for a given name at compile time. + +using rtc::RefCountedObject; + +namespace webrtc { +namespace { + +// The id of StatsReport of type kStatsReportTypeBwe. +const char kStatsReportVideoBweId[] = "bweforvideo"; + +// NOTE: These names need to be consistent with an external +// specification (W3C Stats Identifiers). +const char* InternalTypeToString(StatsReport::StatsType type) { + switch (type) { + case StatsReport::kStatsReportTypeSession: + return "googLibjingleSession"; + case StatsReport::kStatsReportTypeBwe: + return "VideoBwe"; + case StatsReport::kStatsReportTypeRemoteSsrc: + return "remoteSsrc"; + case StatsReport::kStatsReportTypeSsrc: + return "ssrc"; + case StatsReport::kStatsReportTypeTrack: + return "googTrack"; + case StatsReport::kStatsReportTypeIceLocalCandidate: + return "localcandidate"; + case StatsReport::kStatsReportTypeIceRemoteCandidate: + return "remotecandidate"; + case StatsReport::kStatsReportTypeTransport: + return "transport"; + case StatsReport::kStatsReportTypeComponent: + return "googComponent"; + case StatsReport::kStatsReportTypeCandidatePair: + return "googCandidatePair"; + case StatsReport::kStatsReportTypeCertificate: + return "googCertificate"; + case StatsReport::kStatsReportTypeDataChannel: + return "datachannel"; + } + RTC_NOTREACHED(); + return nullptr; +} + +class BandwidthEstimationId : public StatsReport::IdBase { + public: + BandwidthEstimationId() + : StatsReport::IdBase(StatsReport::kStatsReportTypeBwe) {} + std::string ToString() const override { return kStatsReportVideoBweId; } +}; + +class TypedId : public StatsReport::IdBase { + public: + TypedId(StatsReport::StatsType type, const std::string& id) + : StatsReport::IdBase(type), id_(id) {} + + bool Equals(const IdBase& other) const override { + return IdBase::Equals(other) && + static_cast<const TypedId&>(other).id_ == id_; + } + + std::string ToString() const override { + return std::string(InternalTypeToString(type_)) + kSeparator + id_; + } + + protected: + const std::string id_; +}; + +class TypedIntId : public StatsReport::IdBase { + public: + TypedIntId(StatsReport::StatsType type, int id) + : StatsReport::IdBase(type), id_(id) {} + + bool Equals(const IdBase& other) const override { + return IdBase::Equals(other) && + static_cast<const TypedIntId&>(other).id_ == id_; + } + + std::string ToString() const override { + return std::string(InternalTypeToString(type_)) + kSeparator + + rtc::ToString(id_); + } + + protected: + const int id_; +}; + +class IdWithDirection : public TypedId { + public: + IdWithDirection(StatsReport::StatsType type, + const std::string& id, + StatsReport::Direction direction) + : TypedId(type, id), direction_(direction) {} + + bool Equals(const IdBase& other) const override { + return TypedId::Equals(other) && + static_cast<const IdWithDirection&>(other).direction_ == direction_; + } + + std::string ToString() const override { + std::string ret(TypedId::ToString()); + ret += kSeparator; + ret += direction_ == StatsReport::kSend ? "send" : "recv"; + return ret; + } + + private: + const StatsReport::Direction direction_; +}; + +class CandidateId : public TypedId { + public: + CandidateId(bool local, const std::string& id) + : TypedId(local ? StatsReport::kStatsReportTypeIceLocalCandidate + : StatsReport::kStatsReportTypeIceRemoteCandidate, + id) {} + + std::string ToString() const override { return "Cand-" + id_; } +}; + +class ComponentId : public StatsReport::IdBase { + public: + ComponentId(const std::string& content_name, int component) + : ComponentId(StatsReport::kStatsReportTypeComponent, + content_name, + component) {} + + bool Equals(const IdBase& other) const override { + return IdBase::Equals(other) && + static_cast<const ComponentId&>(other).component_ == component_ && + static_cast<const ComponentId&>(other).content_name_ == + content_name_; + } + + std::string ToString() const override { return ToString("Channel-"); } + + protected: + ComponentId(StatsReport::StatsType type, + const std::string& content_name, + int component) + : IdBase(type), content_name_(content_name), component_(component) {} + + std::string ToString(const char* prefix) const { + std::string ret(prefix); + ret += content_name_; + ret += '-'; + ret += rtc::ToString(component_); + return ret; + } + + private: + const std::string content_name_; + const int component_; +}; + +class CandidatePairId : public ComponentId { + public: + CandidatePairId(const std::string& content_name, int component, int index) + : ComponentId(StatsReport::kStatsReportTypeCandidatePair, + content_name, + component), + index_(index) {} + + bool Equals(const IdBase& other) const override { + return ComponentId::Equals(other) && + static_cast<const CandidatePairId&>(other).index_ == index_; + } + + std::string ToString() const override { + std::string ret(ComponentId::ToString("Conn-")); + ret += '-'; + ret += rtc::ToString(index_); + return ret; + } + + private: + const int index_; +}; + +} // namespace + +StatsReport::IdBase::IdBase(StatsType type) : type_(type) {} +StatsReport::IdBase::~IdBase() {} + +StatsReport::StatsType StatsReport::IdBase::type() const { + return type_; +} + +bool StatsReport::IdBase::Equals(const IdBase& other) const { + return other.type_ == type_; +} + +StatsReport::Value::Value(StatsValueName name, int64_t value, Type int_type) + : name(name), type_(int_type) { + RTC_DCHECK(type_ == kInt || type_ == kInt64); + type_ == kInt ? value_.int_ = static_cast<int>(value) : value_.int64_ = value; +} + +StatsReport::Value::Value(StatsValueName name, float f) + : name(name), type_(kFloat) { + value_.float_ = f; +} + +StatsReport::Value::Value(StatsValueName name, const std::string& value) + : name(name), type_(kString) { + value_.string_ = new std::string(value); +} + +StatsReport::Value::Value(StatsValueName name, const char* value) + : name(name), type_(kStaticString) { + value_.static_string_ = value; +} + +StatsReport::Value::Value(StatsValueName name, bool b) + : name(name), type_(kBool) { + value_.bool_ = b; +} + +StatsReport::Value::Value(StatsValueName name, const Id& value) + : name(name), type_(kId) { + value_.id_ = new Id(value); +} + +StatsReport::Value::~Value() { + switch (type_) { + case kInt: + case kInt64: + case kFloat: + case kBool: + case kStaticString: + break; + case kString: + delete value_.string_; + break; + case kId: + delete value_.id_; + break; + } +} + +bool StatsReport::Value::Equals(const Value& other) const { + if (name != other.name) + return false; + + // There's a 1:1 relation between a name and a type, so we don't have to + // check that. + RTC_DCHECK_EQ(type_, other.type_); + + switch (type_) { + case kInt: + return value_.int_ == other.value_.int_; + case kInt64: + return value_.int64_ == other.value_.int64_; + case kFloat: + return value_.float_ == other.value_.float_; + case kStaticString: { +#if RTC_DCHECK_IS_ON + if (value_.static_string_ != other.value_.static_string_) { + RTC_DCHECK(strcmp(value_.static_string_, other.value_.static_string_) != + 0) + << "Duplicate global?"; + } +#endif + return value_.static_string_ == other.value_.static_string_; + } + case kString: + return *value_.string_ == *other.value_.string_; + case kBool: + return value_.bool_ == other.value_.bool_; + case kId: + return (*value_.id_)->Equals(*other.value_.id_); + } + RTC_NOTREACHED(); + return false; +} + +bool StatsReport::Value::operator==(const std::string& value) const { + return (type_ == kString && value_.string_->compare(value) == 0) || + (type_ == kStaticString && value.compare(value_.static_string_) == 0); +} + +bool StatsReport::Value::operator==(const char* value) const { + if (type_ == kString) + return value_.string_->compare(value) == 0; + if (type_ != kStaticString) + return false; +#if RTC_DCHECK_IS_ON + if (value_.static_string_ != value) + RTC_DCHECK(strcmp(value_.static_string_, value) != 0) + << "Duplicate global?"; +#endif + return value == value_.static_string_; +} + +bool StatsReport::Value::operator==(int64_t value) const { + return type_ == kInt ? value_.int_ == static_cast<int>(value) + : (type_ == kInt64 ? value_.int64_ == value : false); +} + +bool StatsReport::Value::operator==(bool value) const { + return type_ == kBool && value_.bool_ == value; +} + +bool StatsReport::Value::operator==(float value) const { + return type_ == kFloat && value_.float_ == value; +} + +bool StatsReport::Value::operator==(const Id& value) const { + return type_ == kId && (*value_.id_)->Equals(value); +} + +int StatsReport::Value::int_val() const { + RTC_DCHECK(type_ == kInt); + return value_.int_; +} + +int64_t StatsReport::Value::int64_val() const { + RTC_DCHECK(type_ == kInt64); + return value_.int64_; +} + +float StatsReport::Value::float_val() const { + RTC_DCHECK(type_ == kFloat); + return value_.float_; +} + +const char* StatsReport::Value::static_string_val() const { + RTC_DCHECK(type_ == kStaticString); + return value_.static_string_; +} + +const std::string& StatsReport::Value::string_val() const { + RTC_DCHECK(type_ == kString); + return *value_.string_; +} + +bool StatsReport::Value::bool_val() const { + RTC_DCHECK(type_ == kBool); + return value_.bool_; +} + +const char* StatsReport::Value::display_name() const { + switch (name) { + case kStatsValueNameAecDivergentFilterFraction: + return "aecDivergentFilterFraction"; + case kStatsValueNameAudioOutputLevel: + return "audioOutputLevel"; + case kStatsValueNameAudioInputLevel: + return "audioInputLevel"; + case kStatsValueNameBytesSent: + return "bytesSent"; + case kStatsValueNameConcealedSamples: + return "concealedSamples"; + case kStatsValueNameConcealmentEvents: + return "concealmentEvents"; + case kStatsValueNamePacketsSent: + return "packetsSent"; + case kStatsValueNameBytesReceived: + return "bytesReceived"; + case kStatsValueNameLabel: + return "label"; + case kStatsValueNamePacketsReceived: + return "packetsReceived"; + case kStatsValueNamePacketsLost: + return "packetsLost"; + case kStatsValueNameProtocol: + return "protocol"; + case kStatsValueNameTotalSamplesReceived: + return "totalSamplesReceived"; + case kStatsValueNameTransportId: + return "transportId"; + case kStatsValueNameSelectedCandidatePairId: + return "selectedCandidatePairId"; + case kStatsValueNameSsrc: + return "ssrc"; + case kStatsValueNameState: + return "state"; + case kStatsValueNameDataChannelId: + return "datachannelid"; + case kStatsValueNameFramesDecoded: + return "framesDecoded"; + case kStatsValueNameFramesEncoded: + return "framesEncoded"; + case kStatsValueNameJitterBufferDelay: + return "jitterBufferDelay"; + case kStatsValueNameCodecImplementationName: + return "codecImplementationName"; + case kStatsValueNameMediaType: + return "mediaType"; + case kStatsValueNameQpSum: + return "qpSum"; + // 'goog' prefixed constants. + case kStatsValueNameAccelerateRate: + return "googAccelerateRate"; + case kStatsValueNameActiveConnection: + return "googActiveConnection"; + case kStatsValueNameActualEncBitrate: + return "googActualEncBitrate"; + case kStatsValueNameAvailableReceiveBandwidth: + return "googAvailableReceiveBandwidth"; + case kStatsValueNameAvailableSendBandwidth: + return "googAvailableSendBandwidth"; + case kStatsValueNameAvgEncodeMs: + return "googAvgEncodeMs"; + case kStatsValueNameBucketDelay: + return "googBucketDelay"; + case kStatsValueNameBandwidthLimitedResolution: + return "googBandwidthLimitedResolution"; + // STUN ping related attributes. + // + // TODO(zhihuang) Rename these stats to follow the standards. + // Connectivity checks. + case kStatsValueNameSentPingRequestsTotal: + return "requestsSent"; + case kStatsValueNameSentPingRequestsBeforeFirstResponse: + return "consentRequestsSent"; + case kStatsValueNameSentPingResponses: + return "responsesSent"; + case kStatsValueNameRecvPingRequests: + return "requestsReceived"; + case kStatsValueNameRecvPingResponses: + return "responsesReceived"; + // STUN Keepalive pings. + case kStatsValueNameSentStunKeepaliveRequests: + return "stunKeepaliveRequestsSent"; + case kStatsValueNameRecvStunKeepaliveResponses: + return "stunKeepaliveResponsesReceived"; + case kStatsValueNameStunKeepaliveRttTotal: + return "stunKeepaliveRttTotal"; + case kStatsValueNameStunKeepaliveRttSquaredTotal: + return "stunKeepaliveRttSquaredTotal"; + + // Candidate related attributes. Values are taken from + // http://w3c.github.io/webrtc-stats/#rtcstatstype-enum*. + case kStatsValueNameCandidateIPAddress: + return "ipAddress"; + case kStatsValueNameCandidateNetworkType: + return "networkType"; + case kStatsValueNameCandidatePortNumber: + return "portNumber"; + case kStatsValueNameCandidatePriority: + return "priority"; + case kStatsValueNameCandidateTransportType: + return "transport"; + case kStatsValueNameCandidateType: + return "candidateType"; + + case kStatsValueNameChannelId: + return "googChannelId"; + case kStatsValueNameCodecName: + return "googCodecName"; + case kStatsValueNameComponent: + return "googComponent"; + case kStatsValueNameContentName: + return "googContentName"; + case kStatsValueNameContentType: + return "googContentType"; + case kStatsValueNameCpuLimitedResolution: + return "googCpuLimitedResolution"; + case kStatsValueNameDecodingCTSG: + return "googDecodingCTSG"; + case kStatsValueNameDecodingCTN: + return "googDecodingCTN"; + case kStatsValueNameDecodingMutedOutput: + return "googDecodingMuted"; + case kStatsValueNameDecodingNormal: + return "googDecodingNormal"; + case kStatsValueNameDecodingPLC: + return "googDecodingPLC"; + case kStatsValueNameDecodingCNG: + return "googDecodingCNG"; + case kStatsValueNameDecodingPLCCNG: + return "googDecodingPLCCNG"; + case kStatsValueNameDer: + return "googDerBase64"; + case kStatsValueNameDtlsCipher: + return "dtlsCipher"; + case kStatsValueNameEchoDelayMedian: + return "googEchoCancellationEchoDelayMedian"; + case kStatsValueNameEchoDelayStdDev: + return "googEchoCancellationEchoDelayStdDev"; + case kStatsValueNameEchoReturnLoss: + return "googEchoCancellationReturnLoss"; + case kStatsValueNameEchoReturnLossEnhancement: + return "googEchoCancellationReturnLossEnhancement"; + case kStatsValueNameEncodeUsagePercent: + return "googEncodeUsagePercent"; + case kStatsValueNameExpandRate: + return "googExpandRate"; + case kStatsValueNameFingerprint: + return "googFingerprint"; + case kStatsValueNameFingerprintAlgorithm: + return "googFingerprintAlgorithm"; + case kStatsValueNameFirsReceived: + return "googFirsReceived"; + case kStatsValueNameFirsSent: + return "googFirsSent"; + case kStatsValueNameFirstFrameReceivedToDecodedMs: + return "googFirstFrameReceivedToDecodedMs"; + case kStatsValueNameFrameHeightInput: + return "googFrameHeightInput"; + case kStatsValueNameFrameHeightReceived: + return "googFrameHeightReceived"; + case kStatsValueNameFrameHeightSent: + return "googFrameHeightSent"; + case kStatsValueNameFrameRateReceived: + return "googFrameRateReceived"; + case kStatsValueNameFrameRateDecoded: + return "googFrameRateDecoded"; + case kStatsValueNameFrameRateOutput: + return "googFrameRateOutput"; + case kStatsValueNameDecodeMs: + return "googDecodeMs"; + case kStatsValueNameMaxDecodeMs: + return "googMaxDecodeMs"; + case kStatsValueNameCurrentDelayMs: + return "googCurrentDelayMs"; + case kStatsValueNameTargetDelayMs: + return "googTargetDelayMs"; + case kStatsValueNameJitterBufferMs: + return "googJitterBufferMs"; + case kStatsValueNameMinPlayoutDelayMs: + return "googMinPlayoutDelayMs"; + case kStatsValueNameRenderDelayMs: + return "googRenderDelayMs"; + case kStatsValueNameCaptureStartNtpTimeMs: + return "googCaptureStartNtpTimeMs"; + case kStatsValueNameFrameRateInput: + return "googFrameRateInput"; + case kStatsValueNameFrameRateSent: + return "googFrameRateSent"; + case kStatsValueNameFrameWidthInput: + return "googFrameWidthInput"; + case kStatsValueNameFrameWidthReceived: + return "googFrameWidthReceived"; + case kStatsValueNameFrameWidthSent: + return "googFrameWidthSent"; + case kStatsValueNameHasEnteredLowResolution: + return "googHasEnteredLowResolution"; + case kStatsValueNameHugeFramesSent: + return "hugeFramesSent"; + case kStatsValueNameInitiator: + return "googInitiator"; + case kStatsValueNameInterframeDelayMaxMs: + return "googInterframeDelayMax"; + case kStatsValueNameIssuerId: + return "googIssuerId"; + case kStatsValueNameJitterReceived: + return "googJitterReceived"; + case kStatsValueNameLocalAddress: + return "googLocalAddress"; + case kStatsValueNameLocalCandidateId: + return "localCandidateId"; + case kStatsValueNameLocalCandidateType: + return "googLocalCandidateType"; + case kStatsValueNameLocalCertificateId: + return "localCertificateId"; + case kStatsValueNameAdaptationChanges: + return "googAdaptationChanges"; + case kStatsValueNameNacksReceived: + return "googNacksReceived"; + case kStatsValueNameNacksSent: + return "googNacksSent"; + case kStatsValueNamePreemptiveExpandRate: + return "googPreemptiveExpandRate"; + case kStatsValueNamePlisReceived: + return "googPlisReceived"; + case kStatsValueNamePlisSent: + return "googPlisSent"; + case kStatsValueNamePreferredJitterBufferMs: + return "googPreferredJitterBufferMs"; + case kStatsValueNameReceiving: + return "googReadable"; + case kStatsValueNameRemoteAddress: + return "googRemoteAddress"; + case kStatsValueNameRemoteCandidateId: + return "remoteCandidateId"; + case kStatsValueNameRemoteCandidateType: + return "googRemoteCandidateType"; + case kStatsValueNameRemoteCertificateId: + return "remoteCertificateId"; + case kStatsValueNameResidualEchoLikelihood: + return "googResidualEchoLikelihood"; + case kStatsValueNameResidualEchoLikelihoodRecentMax: + return "googResidualEchoLikelihoodRecentMax"; + case kStatsValueNameAnaBitrateActionCounter: + return "googAnaBitrateActionCounter"; + case kStatsValueNameAnaChannelActionCounter: + return "googAnaChannelActionCounter"; + case kStatsValueNameAnaDtxActionCounter: + return "googAnaDtxActionCounter"; + case kStatsValueNameAnaFecActionCounter: + return "googAnaFecActionCounter"; + case kStatsValueNameAnaFrameLengthIncreaseCounter: + return "googAnaFrameLengthIncreaseCounter"; + case kStatsValueNameAnaFrameLengthDecreaseCounter: + return "googAnaFrameLengthDecreaseCounter"; + case kStatsValueNameAnaUplinkPacketLossFraction: + return "googAnaUplinkPacketLossFraction"; + case kStatsValueNameRetransmitBitrate: + return "googRetransmitBitrate"; + case kStatsValueNameRtt: + return "googRtt"; + case kStatsValueNameSecondaryDecodedRate: + return "googSecondaryDecodedRate"; + case kStatsValueNameSecondaryDiscardedRate: + return "googSecondaryDiscardedRate"; + case kStatsValueNameSendPacketsDiscarded: + return "packetsDiscardedOnSend"; + case kStatsValueNameSpeechExpandRate: + return "googSpeechExpandRate"; + case kStatsValueNameSrtpCipher: + return "srtpCipher"; + case kStatsValueNameTargetEncBitrate: + return "googTargetEncBitrate"; + case kStatsValueNameTotalAudioEnergy: + return "totalAudioEnergy"; + case kStatsValueNameTotalSamplesDuration: + return "totalSamplesDuration"; + case kStatsValueNameTransmitBitrate: + return "googTransmitBitrate"; + case kStatsValueNameTransportType: + return "googTransportType"; + case kStatsValueNameTrackId: + return "googTrackId"; + case kStatsValueNameTimingFrameInfo: + return "googTimingFrameInfo"; + case kStatsValueNameTypingNoiseState: + return "googTypingNoiseState"; + case kStatsValueNameWritable: + return "googWritable"; + } + + return nullptr; +} + +std::string StatsReport::Value::ToString() const { + switch (type_) { + case kInt: + return rtc::ToString(value_.int_); + case kInt64: + return rtc::ToString(value_.int64_); + case kFloat: + return rtc::ToString(value_.float_); + case kStaticString: + return std::string(value_.static_string_); + case kString: + return *value_.string_; + case kBool: + return value_.bool_ ? "true" : "false"; + case kId: + return (*value_.id_)->ToString(); + } + RTC_NOTREACHED(); + return std::string(); +} + +StatsReport::StatsReport(const Id& id) : id_(id), timestamp_(0.0) { + RTC_DCHECK(id_.get()); +} + +StatsReport::~StatsReport() = default; + +// static +StatsReport::Id StatsReport::NewBandwidthEstimationId() { + return Id(new RefCountedObject<BandwidthEstimationId>()); +} + +// static +StatsReport::Id StatsReport::NewTypedId(StatsType type, const std::string& id) { + return Id(new RefCountedObject<TypedId>(type, id)); +} + +// static +StatsReport::Id StatsReport::NewTypedIntId(StatsType type, int id) { + return Id(new RefCountedObject<TypedIntId>(type, id)); +} + +// static +StatsReport::Id StatsReport::NewIdWithDirection( + StatsType type, + const std::string& id, + StatsReport::Direction direction) { + return Id(new RefCountedObject<IdWithDirection>(type, id, direction)); +} + +// static +StatsReport::Id StatsReport::NewCandidateId(bool local, const std::string& id) { + return Id(new RefCountedObject<CandidateId>(local, id)); +} + +// static +StatsReport::Id StatsReport::NewComponentId(const std::string& content_name, + int component) { + return Id(new RefCountedObject<ComponentId>(content_name, component)); +} + +// static +StatsReport::Id StatsReport::NewCandidatePairId(const std::string& content_name, + int component, + int index) { + return Id( + new RefCountedObject<CandidatePairId>(content_name, component, index)); +} + +const char* StatsReport::TypeToString() const { + return InternalTypeToString(id_->type()); +} + +void StatsReport::AddString(StatsReport::StatsValueName name, + const std::string& value) { + const Value* found = FindValue(name); + if (!found || !(*found == value)) + values_[name] = ValuePtr(new Value(name, value)); +} + +void StatsReport::AddString(StatsReport::StatsValueName name, + const char* value) { + const Value* found = FindValue(name); + if (!found || !(*found == value)) + values_[name] = ValuePtr(new Value(name, value)); +} + +void StatsReport::AddInt64(StatsReport::StatsValueName name, int64_t value) { + const Value* found = FindValue(name); + if (!found || !(*found == value)) + values_[name] = ValuePtr(new Value(name, value, Value::kInt64)); +} + +void StatsReport::AddInt(StatsReport::StatsValueName name, int value) { + const Value* found = FindValue(name); + if (!found || !(*found == static_cast<int64_t>(value))) + values_[name] = ValuePtr(new Value(name, value, Value::kInt)); +} + +void StatsReport::AddFloat(StatsReport::StatsValueName name, float value) { + const Value* found = FindValue(name); + if (!found || !(*found == value)) + values_[name] = ValuePtr(new Value(name, value)); +} + +void StatsReport::AddBoolean(StatsReport::StatsValueName name, bool value) { + const Value* found = FindValue(name); + if (!found || !(*found == value)) + values_[name] = ValuePtr(new Value(name, value)); +} + +void StatsReport::AddId(StatsReport::StatsValueName name, const Id& value) { + const Value* found = FindValue(name); + if (!found || !(*found == value)) + values_[name] = ValuePtr(new Value(name, value)); +} + +const StatsReport::Value* StatsReport::FindValue(StatsValueName name) const { + Values::const_iterator it = values_.find(name); + return it == values_.end() ? nullptr : it->second.get(); +} + +StatsCollection::StatsCollection() {} + +StatsCollection::~StatsCollection() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + for (auto* r : list_) + delete r; +} + +StatsCollection::const_iterator StatsCollection::begin() const { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + return list_.begin(); +} + +StatsCollection::const_iterator StatsCollection::end() const { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + return list_.end(); +} + +size_t StatsCollection::size() const { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + return list_.size(); +} + +StatsReport* StatsCollection::InsertNew(const StatsReport::Id& id) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(Find(id) == nullptr); + StatsReport* report = new StatsReport(id); + list_.push_back(report); + return report; +} + +StatsReport* StatsCollection::FindOrAddNew(const StatsReport::Id& id) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + StatsReport* ret = Find(id); + return ret ? ret : InsertNew(id); +} + +StatsReport* StatsCollection::ReplaceOrAddNew(const StatsReport::Id& id) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(id.get()); + Container::iterator it = std::find_if( + list_.begin(), list_.end(), + [&id](const StatsReport* r) -> bool { return r->id()->Equals(id); }); + if (it != end()) { + StatsReport* report = new StatsReport((*it)->id()); + delete *it; + *it = report; + return report; + } + return InsertNew(id); +} + +// Looks for a report with the given |id|. If one is not found, null +// will be returned. +StatsReport* StatsCollection::Find(const StatsReport::Id& id) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + Container::iterator it = std::find_if( + list_.begin(), list_.end(), + [&id](const StatsReport* r) -> bool { return r->id()->Equals(id); }); + return it == list_.end() ? nullptr : *it; +} + +} // namespace webrtc
diff --git a/api/stats_types.h b/api/stats_types.h new file mode 100644 index 0000000..0e97eaf --- /dev/null +++ b/api/stats_types.h
@@ -0,0 +1,452 @@ +/* + * Copyright 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This file contains structures used for retrieving statistics from an ongoing +// libjingle session. + +#ifndef API_STATS_TYPES_H_ +#define API_STATS_TYPES_H_ + +#include <algorithm> +#include <list> +#include <map> +#include <string> +#include <vector> + +#include "api/scoped_refptr.h" +#include "rtc_base/constructor_magic.h" +#include "rtc_base/ref_count.h" +#include "rtc_base/string_encode.h" +#include "rtc_base/thread_checker.h" + +namespace webrtc { + +class StatsReport { + public: + // Indicates whether a track is for sending or receiving. + // Used in reports for audio/video tracks. + enum Direction { + kSend = 0, + kReceive, + }; + + enum StatsType { + // StatsReport types. + // A StatsReport of |type| = "googSession" contains overall information + // about the thing libjingle calls a session (which may contain one + // or more RTP sessions. + kStatsReportTypeSession, + + // A StatsReport of |type| = "googTransport" contains information + // about a libjingle "transport". + kStatsReportTypeTransport, + + // A StatsReport of |type| = "googComponent" contains information + // about a libjingle "channel" (typically, RTP or RTCP for a transport). + // This is intended to be the same thing as an ICE "Component". + kStatsReportTypeComponent, + + // A StatsReport of |type| = "googCandidatePair" contains information + // about a libjingle "connection" - a single source/destination port pair. + // This is intended to be the same thing as an ICE "candidate pair". + kStatsReportTypeCandidatePair, + + // A StatsReport of |type| = "VideoBWE" is statistics for video Bandwidth + // Estimation, which is global per-session. The |id| field is "bweforvideo" + // (will probably change in the future). + kStatsReportTypeBwe, + + // A StatsReport of |type| = "ssrc" is statistics for a specific rtp stream. + // The |id| field is the SSRC in decimal form of the rtp stream. + kStatsReportTypeSsrc, + + // A StatsReport of |type| = "remoteSsrc" is statistics for a specific + // rtp stream, generated by the remote end of the connection. + kStatsReportTypeRemoteSsrc, + + // A StatsReport of |type| = "googTrack" is statistics for a specific media + // track. The |id| field is the track id. + kStatsReportTypeTrack, + + // A StatsReport of |type| = "localcandidate" or "remotecandidate" is + // attributes on a specific ICE Candidate. It links to its connection pair + // by candidate id. The string value is taken from + // http://w3c.github.io/webrtc-stats/#rtcstatstype-enum*. + kStatsReportTypeIceLocalCandidate, + kStatsReportTypeIceRemoteCandidate, + + // A StatsReport of |type| = "googCertificate" contains an SSL certificate + // transmitted by one of the endpoints of this connection. The |id| is + // controlled by the fingerprint, and is used to identify the certificate in + // the Channel stats (as "googLocalCertificateId" or + // "googRemoteCertificateId") and in any child certificates (as + // "googIssuerId"). + kStatsReportTypeCertificate, + + // A StatsReport of |type| = "datachannel" with statistics for a + // particular DataChannel. + kStatsReportTypeDataChannel, + }; + + enum StatsValueName { + kStatsValueNameActiveConnection, + kStatsValueNameAecDivergentFilterFraction, + kStatsValueNameAudioInputLevel, + kStatsValueNameAudioOutputLevel, + kStatsValueNameBytesReceived, + kStatsValueNameBytesSent, + kStatsValueNameCodecImplementationName, + kStatsValueNameConcealedSamples, + kStatsValueNameConcealmentEvents, + kStatsValueNameDataChannelId, + kStatsValueNameFramesDecoded, + kStatsValueNameFramesEncoded, + kStatsValueNameJitterBufferDelay, + kStatsValueNameMediaType, + kStatsValueNamePacketsLost, + kStatsValueNamePacketsReceived, + kStatsValueNamePacketsSent, + kStatsValueNameProtocol, + kStatsValueNameQpSum, + kStatsValueNameReceiving, + kStatsValueNameSelectedCandidatePairId, + kStatsValueNameSsrc, + kStatsValueNameState, + kStatsValueNameTotalAudioEnergy, + kStatsValueNameTotalSamplesDuration, + kStatsValueNameTotalSamplesReceived, + kStatsValueNameTransportId, + kStatsValueNameSentPingRequestsTotal, + kStatsValueNameSentPingRequestsBeforeFirstResponse, + kStatsValueNameSentPingResponses, + kStatsValueNameRecvPingRequests, + kStatsValueNameRecvPingResponses, + kStatsValueNameSentStunKeepaliveRequests, + kStatsValueNameRecvStunKeepaliveResponses, + kStatsValueNameStunKeepaliveRttTotal, + kStatsValueNameStunKeepaliveRttSquaredTotal, + + // Internal StatsValue names. + kStatsValueNameAccelerateRate, + kStatsValueNameActualEncBitrate, + kStatsValueNameAdaptationChanges, + kStatsValueNameAvailableReceiveBandwidth, + kStatsValueNameAvailableSendBandwidth, + kStatsValueNameAvgEncodeMs, + kStatsValueNameBandwidthLimitedResolution, + kStatsValueNameBucketDelay, + kStatsValueNameCaptureStartNtpTimeMs, + kStatsValueNameCandidateIPAddress, + kStatsValueNameCandidateNetworkType, + kStatsValueNameCandidatePortNumber, + kStatsValueNameCandidatePriority, + kStatsValueNameCandidateTransportType, + kStatsValueNameCandidateType, + kStatsValueNameChannelId, + kStatsValueNameCodecName, + kStatsValueNameComponent, + kStatsValueNameContentName, + kStatsValueNameContentType, + kStatsValueNameCpuLimitedResolution, + kStatsValueNameCurrentDelayMs, + kStatsValueNameDecodeMs, + kStatsValueNameDecodingCNG, + kStatsValueNameDecodingCTN, + kStatsValueNameDecodingCTSG, + kStatsValueNameDecodingMutedOutput, + kStatsValueNameDecodingNormal, + kStatsValueNameDecodingPLC, + kStatsValueNameDecodingPLCCNG, + kStatsValueNameDer, + kStatsValueNameDtlsCipher, + kStatsValueNameEchoDelayMedian, + kStatsValueNameEchoDelayStdDev, + kStatsValueNameEchoReturnLoss, + kStatsValueNameEchoReturnLossEnhancement, + kStatsValueNameEncodeUsagePercent, + kStatsValueNameExpandRate, + kStatsValueNameFingerprint, + kStatsValueNameFingerprintAlgorithm, + kStatsValueNameFirsReceived, + kStatsValueNameFirsSent, + kStatsValueNameFirstFrameReceivedToDecodedMs, + kStatsValueNameFrameHeightInput, + kStatsValueNameFrameHeightReceived, + kStatsValueNameFrameHeightSent, + kStatsValueNameFrameRateDecoded, + kStatsValueNameFrameRateInput, + kStatsValueNameFrameRateOutput, + kStatsValueNameFrameRateReceived, + kStatsValueNameFrameRateSent, + kStatsValueNameFrameWidthInput, + kStatsValueNameFrameWidthReceived, + kStatsValueNameFrameWidthSent, + kStatsValueNameHasEnteredLowResolution, + kStatsValueNameHugeFramesSent, + kStatsValueNameInitiator, + kStatsValueNameInterframeDelayMaxMs, // Max over last 10 seconds. + kStatsValueNameIssuerId, + kStatsValueNameJitterBufferMs, + kStatsValueNameJitterReceived, + kStatsValueNameLabel, + kStatsValueNameLocalAddress, + kStatsValueNameLocalCandidateId, + kStatsValueNameLocalCandidateType, + kStatsValueNameLocalCertificateId, + kStatsValueNameMaxDecodeMs, + kStatsValueNameMinPlayoutDelayMs, + kStatsValueNameNacksReceived, + kStatsValueNameNacksSent, + kStatsValueNamePlisReceived, + kStatsValueNamePlisSent, + kStatsValueNamePreemptiveExpandRate, + kStatsValueNamePreferredJitterBufferMs, + kStatsValueNameRemoteAddress, + kStatsValueNameRemoteCandidateId, + kStatsValueNameRemoteCandidateType, + kStatsValueNameRemoteCertificateId, + kStatsValueNameRenderDelayMs, + kStatsValueNameResidualEchoLikelihood, + kStatsValueNameResidualEchoLikelihoodRecentMax, + kStatsValueNameAnaBitrateActionCounter, + kStatsValueNameAnaChannelActionCounter, + kStatsValueNameAnaDtxActionCounter, + kStatsValueNameAnaFecActionCounter, + kStatsValueNameAnaFrameLengthIncreaseCounter, + kStatsValueNameAnaFrameLengthDecreaseCounter, + kStatsValueNameAnaUplinkPacketLossFraction, + kStatsValueNameRetransmitBitrate, + kStatsValueNameRtt, + kStatsValueNameSecondaryDecodedRate, + kStatsValueNameSecondaryDiscardedRate, + kStatsValueNameSendPacketsDiscarded, + kStatsValueNameSpeechExpandRate, + kStatsValueNameSrtpCipher, + kStatsValueNameTargetDelayMs, + kStatsValueNameTargetEncBitrate, + kStatsValueNameTimingFrameInfo, // Result of |TimingFrameInfo::ToString| + kStatsValueNameTrackId, + kStatsValueNameTransmitBitrate, + kStatsValueNameTransportType, + kStatsValueNameTypingNoiseState, + kStatsValueNameWritable, + }; + + class IdBase : public rtc::RefCountInterface { + public: + ~IdBase() override; + StatsType type() const; + + // Users of IdBase will be using the Id typedef, which is compatible with + // this Equals() function. It simply calls the protected (and overridden) + // Equals() method. + bool Equals(const rtc::scoped_refptr<IdBase>& other) const { + return Equals(*other.get()); + } + + virtual std::string ToString() const = 0; + + protected: + // Protected since users of the IdBase type will be using the Id typedef. + virtual bool Equals(const IdBase& other) const; + + explicit IdBase(StatsType type); // Only meant for derived classes. + const StatsType type_; + + static const char kSeparator = '_'; + }; + + typedef rtc::scoped_refptr<IdBase> Id; + + struct Value { + enum Type { + kInt, // int. + kInt64, // int64_t. + kFloat, // float. + kString, // std::string + kStaticString, // const char*. + kBool, // bool. + kId, // Id. + }; + + Value(StatsValueName name, int64_t value, Type int_type); + Value(StatsValueName name, float f); + Value(StatsValueName name, const std::string& value); + Value(StatsValueName name, const char* value); + Value(StatsValueName name, bool b); + Value(StatsValueName name, const Id& value); + + ~Value(); + + // Support ref counting. Note that for performance reasons, we + // don't use thread safe operations. Therefore, all operations + // affecting the ref count (in practice, creation and copying of + // the Values mapping) must occur on webrtc's signalling thread. + int AddRef() const { + RTC_DCHECK_RUN_ON(&thread_checker_); + return ++ref_count_; + } + int Release() const { + RTC_DCHECK_RUN_ON(&thread_checker_); + int count = --ref_count_; + if (!count) + delete this; + return count; + } + + // TODO(tommi): This compares name as well as value... + // I think we should only need to compare the value part and + // move the name part into a hash map. + bool Equals(const Value& other) const; + + // Comparison operators. Return true iff the current instance is of the + // correct type and holds the same value. No conversion is performed so + // a string value of "123" is not equal to an int value of 123 and an int + // value of 123 is not equal to a float value of 123.0f. + // One exception to this is that types kInt and kInt64 can be compared and + // kString and kStaticString too. + bool operator==(const std::string& value) const; + bool operator==(const char* value) const; + bool operator==(int64_t value) const; + bool operator==(bool value) const; + bool operator==(float value) const; + bool operator==(const Id& value) const; + + // Getters that allow getting the native value directly. + // The caller must know the type beforehand or else hit a check. + int int_val() const; + int64_t int64_val() const; + float float_val() const; + const char* static_string_val() const; + const std::string& string_val() const; + bool bool_val() const; + const Id& id_val() const; + + // Returns the string representation of |name|. + const char* display_name() const; + + // Converts the native value to a string representation of the value. + std::string ToString() const; + + Type type() const { return type_; } + + // TODO(tommi): Move |name| and |display_name| out of the Value struct. + const StatsValueName name; + + private: + rtc::ThreadChecker thread_checker_; + mutable int ref_count_ RTC_GUARDED_BY(thread_checker_) = 0; + + const Type type_; + // TODO(tommi): Use C++ 11 union and make value_ const. + union InternalType { + int int_; + int64_t int64_; + float float_; + bool bool_; + std::string* string_; + const char* static_string_; + Id* id_; + } value_; + + RTC_DISALLOW_COPY_AND_ASSIGN(Value); + }; + + typedef rtc::scoped_refptr<Value> ValuePtr; + typedef std::map<StatsValueName, ValuePtr> Values; + + // Ownership of |id| is passed to |this|. + explicit StatsReport(const Id& id); + ~StatsReport(); + + // Factory functions for various types of stats IDs. + static Id NewBandwidthEstimationId(); + static Id NewTypedId(StatsType type, const std::string& id); + static Id NewTypedIntId(StatsType type, int id); + static Id NewIdWithDirection(StatsType type, + const std::string& id, + Direction direction); + static Id NewCandidateId(bool local, const std::string& id); + static Id NewComponentId(const std::string& content_name, int component); + static Id NewCandidatePairId(const std::string& content_name, + int component, + int index); + + const Id& id() const { return id_; } + StatsType type() const { return id_->type(); } + double timestamp() const { return timestamp_; } + void set_timestamp(double t) { timestamp_ = t; } + bool empty() const { return values_.empty(); } + const Values& values() const { return values_; } + + const char* TypeToString() const; + + void AddString(StatsValueName name, const std::string& value); + void AddString(StatsValueName name, const char* value); + void AddInt64(StatsValueName name, int64_t value); + void AddInt(StatsValueName name, int value); + void AddFloat(StatsValueName name, float value); + void AddBoolean(StatsValueName name, bool value); + void AddId(StatsValueName name, const Id& value); + + const Value* FindValue(StatsValueName name) const; + + private: + // The unique identifier for this object. + // This is used as a key for this report in ordered containers, + // so it must never be changed. + const Id id_; + double timestamp_; // Time since 1970-01-01T00:00:00Z in milliseconds. + Values values_; + + RTC_DISALLOW_COPY_AND_ASSIGN(StatsReport); +}; + +// Typedef for an array of const StatsReport pointers. +// Ownership of the pointers held by this implementation is assumed to lie +// elsewhere and lifetime guarantees are made by the implementation that uses +// this type. In the StatsCollector, object ownership lies with the +// StatsCollection class. +typedef std::vector<const StatsReport*> StatsReports; + +// A map from the report id to the report. +// This class wraps an STL container and provides a limited set of +// functionality in order to keep things simple. +class StatsCollection { + public: + StatsCollection(); + ~StatsCollection(); + + typedef std::list<StatsReport*> Container; + typedef Container::iterator iterator; + typedef Container::const_iterator const_iterator; + + const_iterator begin() const; + const_iterator end() const; + size_t size() const; + + // Creates a new report object with |id| that does not already + // exist in the list of reports. + StatsReport* InsertNew(const StatsReport::Id& id); + StatsReport* FindOrAddNew(const StatsReport::Id& id); + StatsReport* ReplaceOrAddNew(const StatsReport::Id& id); + + // Looks for a report with the given |id|. If one is not found, null + // will be returned. + StatsReport* Find(const StatsReport::Id& id); + + private: + Container list_; + rtc::ThreadChecker thread_checker_; +}; + +} // namespace webrtc + +#endif // API_STATS_TYPES_H_
diff --git a/api/task_queue/default_task_queue_factory.h b/api/task_queue/default_task_queue_factory.h new file mode 100644 index 0000000..ccdd1eb --- /dev/null +++ b/api/task_queue/default_task_queue_factory.h
@@ -0,0 +1,23 @@ +/* + * Copyright 2019 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef API_TASK_QUEUE_DEFAULT_TASK_QUEUE_FACTORY_H_ +#define API_TASK_QUEUE_DEFAULT_TASK_QUEUE_FACTORY_H_ + +#include <memory> + +#include "api/task_queue/task_queue_factory.h" + +namespace webrtc { + +std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory(); + +} // namespace webrtc + +#endif // API_TASK_QUEUE_DEFAULT_TASK_QUEUE_FACTORY_H_
diff --git a/api/task_queue/default_task_queue_factory_gcd.cc b/api/task_queue/default_task_queue_factory_gcd.cc new file mode 100644 index 0000000..7e17b48 --- /dev/null +++ b/api/task_queue/default_task_queue_factory_gcd.cc
@@ -0,0 +1,21 @@ +/* + * Copyright 2019 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include <memory> + +#include "api/task_queue/task_queue_factory.h" +#include "rtc_base/task_queue_gcd.h" + +namespace webrtc { + +std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory() { + return CreateTaskQueueGcdFactory(); +} + +} // namespace webrtc
diff --git a/api/task_queue/default_task_queue_factory_libevent.cc b/api/task_queue/default_task_queue_factory_libevent.cc new file mode 100644 index 0000000..f2fb418 --- /dev/null +++ b/api/task_queue/default_task_queue_factory_libevent.cc
@@ -0,0 +1,21 @@ +/* + * Copyright 2019 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include <memory> + +#include "api/task_queue/task_queue_factory.h" +#include "rtc_base/task_queue_libevent.h" + +namespace webrtc { + +std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory() { + return CreateTaskQueueLibeventFactory(); +} + +} // namespace webrtc
diff --git a/api/task_queue/default_task_queue_factory_stdlib.cc b/api/task_queue/default_task_queue_factory_stdlib.cc new file mode 100644 index 0000000..ca7d720 --- /dev/null +++ b/api/task_queue/default_task_queue_factory_stdlib.cc
@@ -0,0 +1,21 @@ +/* + * Copyright 2019 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include <memory> + +#include "api/task_queue/task_queue_factory.h" +#include "rtc_base/task_queue_stdlib.h" + +namespace webrtc { + +std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory() { + return CreateTaskQueueStdlibFactory(); +} + +} // namespace webrtc
diff --git a/api/task_queue/default_task_queue_factory_unittest.cc b/api/task_queue/default_task_queue_factory_unittest.cc new file mode 100644 index 0000000..92c17d8 --- /dev/null +++ b/api/task_queue/default_task_queue_factory_unittest.cc
@@ -0,0 +1,24 @@ +/* + * Copyright 2019 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/task_queue/default_task_queue_factory.h" + +#include "api/task_queue/task_queue_test.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +INSTANTIATE_TEST_SUITE_P(Default, + TaskQueueTest, + ::testing::Values(CreateDefaultTaskQueueFactory)); + +} // namespace +} // namespace webrtc
diff --git a/api/task_queue/default_task_queue_factory_win.cc b/api/task_queue/default_task_queue_factory_win.cc new file mode 100644 index 0000000..493ea66 --- /dev/null +++ b/api/task_queue/default_task_queue_factory_win.cc
@@ -0,0 +1,21 @@ +/* + * Copyright 2019 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include <memory> + +#include "api/task_queue/task_queue_factory.h" +#include "rtc_base/task_queue_win.h" + +namespace webrtc { + +std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory() { + return CreateTaskQueueWinFactory(); +} + +} // namespace webrtc
diff --git a/api/task_queue/global_task_queue_factory.cc b/api/task_queue/global_task_queue_factory.cc new file mode 100644 index 0000000..528d14d --- /dev/null +++ b/api/task_queue/global_task_queue_factory.cc
@@ -0,0 +1,40 @@ +/* + * Copyright 2019 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "api/task_queue/global_task_queue_factory.h" + +#include "api/task_queue/default_task_queue_factory.h" +#include "rtc_base/checks.h" + +namespace webrtc { +namespace { + +TaskQueueFactory* GlobalOrDefault(TaskQueueFactory* global) { + static TaskQueueFactory* const factory = + global ? global : CreateDefaultTaskQueueFactory().release(); + return factory; +} + +} // namespace + +void SetGlobalTaskQueueFactory(std::unique_ptr<TaskQueueFactory> factory) { + RTC_CHECK(factory) << "Can't set nullptr TaskQueueFactory"; + // Own, but never delete the global factory. + TaskQueueFactory* global = factory.release(); + RTC_CHECK(GlobalOrDefault(global) == global) + << "Task queue factory set after another SetFactory or after a task " + "queue was created"; +} + +TaskQueueFactory& GlobalTaskQueueFactory() { + return *GlobalOrDefault(nullptr); +} + +} // namespace webrtc
diff --git a/api/task_queue/global_task_queue_factory.h b/api/task_queue/global_task_queue_factory.h new file mode 100644 index 0000000..a580833 --- /dev/null +++ b/api/task_queue/global_task_queue_factory.h
@@ -0,0 +1,27 @@ +/* + * Copyright 2019 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef API_TASK_QUEUE_GLOBAL_TASK_QUEUE_FACTORY_H_ +#define API_TASK_QUEUE_GLOBAL_TASK_QUEUE_FACTORY_H_ + +#include <memory> + +#include "api/task_queue/task_queue_factory.h" + +namespace webrtc { + +// May be called at most once, and before any TaskQueue is created. +void SetGlobalTaskQueueFactory(std::unique_ptr<TaskQueueFactory> factory); + +// Returns TaskQueue factory. Always returns the same factory. +TaskQueueFactory& GlobalTaskQueueFactory(); + +} // namespace webrtc + +#endif // API_TASK_QUEUE_GLOBAL_TASK_QUEUE_FACTORY_H_
diff --git a/api/task_queue/module.mk b/api/task_queue/module.mk new file mode 100644 index 0000000..37c23f4 --- /dev/null +++ b/api/task_queue/module.mk
@@ -0,0 +1,5 @@ +# Copyright 2018 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +include common.mk
diff --git a/api/task_queue/queued_task.h b/api/task_queue/queued_task.h new file mode 100644 index 0000000..5748628 --- /dev/null +++ b/api/task_queue/queued_task.h
@@ -0,0 +1,32 @@ +/* + * Copyright 2018 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef API_TASK_QUEUE_QUEUED_TASK_H_ +#define API_TASK_QUEUE_QUEUED_TASK_H_ + +namespace webrtc { + +// Base interface for asynchronously executed tasks. +// The interface basically consists of a single function, Run(), that executes +// on the target queue. For more details see the Run() method and TaskQueue. +class QueuedTask { + public: + virtual ~QueuedTask() = default; + + // Main routine that will run when the task is executed on the desired queue. + // The task should return |true| to indicate that it should be deleted or + // |false| to indicate that the queue should consider ownership of the task + // having been transferred. Returning |false| can be useful if a task has + // re-posted itself to a different queue or is otherwise being re-used. + virtual bool Run() = 0; +}; + +} // namespace webrtc + +#endif // API_TASK_QUEUE_QUEUED_TASK_H_
diff --git a/api/task_queue/task_queue_base.cc b/api/task_queue/task_queue_base.cc new file mode 100644 index 0000000..7d3539a --- /dev/null +++ b/api/task_queue/task_queue_base.cc
@@ -0,0 +1,79 @@ +/* + * Copyright 2019 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "api/task_queue/task_queue_base.h" + +#include "absl/base/attributes.h" +#include "absl/base/config.h" +#include "rtc_base/checks.h" + +#if defined(ABSL_HAVE_THREAD_LOCAL) + +namespace webrtc { +namespace { + +ABSL_CONST_INIT thread_local TaskQueueBase* current = nullptr; + +} // namespace + +TaskQueueBase* TaskQueueBase::Current() { + return current; +} + +TaskQueueBase::CurrentTaskQueueSetter::CurrentTaskQueueSetter( + TaskQueueBase* task_queue) + : previous_(current) { + current = task_queue; +} + +TaskQueueBase::CurrentTaskQueueSetter::~CurrentTaskQueueSetter() { + current = previous_; +} +} // namespace webrtc + +#elif defined(WEBRTC_POSIX) + +#include <pthread.h> + +namespace webrtc { +namespace { + +ABSL_CONST_INIT pthread_key_t g_queue_ptr_tls = 0; + +void InitializeTls() { + RTC_CHECK(pthread_key_create(&g_queue_ptr_tls, nullptr) == 0); +} + +pthread_key_t GetQueuePtrTls() { + static pthread_once_t init_once = PTHREAD_ONCE_INIT; + RTC_CHECK(pthread_once(&init_once, &InitializeTls) == 0); + return g_queue_ptr_tls; +} + +} // namespace + +TaskQueueBase* TaskQueueBase::Current() { + return static_cast<TaskQueueBase*>(pthread_getspecific(GetQueuePtrTls())); +} + +TaskQueueBase::CurrentTaskQueueSetter::CurrentTaskQueueSetter( + TaskQueueBase* task_queue) + : previous_(TaskQueueBase::Current()) { + pthread_setspecific(GetQueuePtrTls(), task_queue); +} + +TaskQueueBase::CurrentTaskQueueSetter::~CurrentTaskQueueSetter() { + pthread_setspecific(GetQueuePtrTls(), previous_); +} + +} // namespace webrtc + +#else +#error Unsupported platform +#endif
diff --git a/api/task_queue/task_queue_base.h b/api/task_queue/task_queue_base.h new file mode 100644 index 0000000..b1b5cc7 --- /dev/null +++ b/api/task_queue/task_queue_base.h
@@ -0,0 +1,91 @@ +/* + * Copyright 2019 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef API_TASK_QUEUE_TASK_QUEUE_BASE_H_ +#define API_TASK_QUEUE_TASK_QUEUE_BASE_H_ + +#include <memory> + +#include "api/task_queue/queued_task.h" + +// TODO(bugs.webrtc.org/10191): Remove when +// rtc::TaskQueue* rtc::TaskQueue::Current() is unused. +namespace rtc { +class TaskQueue; +} // namespace rtc + +namespace webrtc { + +// Asynchronously executes tasks in a way that guarantees that they're executed +// in FIFO order and that tasks never overlap. Tasks may always execute on the +// same worker thread and they may not. To DCHECK that tasks are executing on a +// known task queue, use IsCurrent(). +class TaskQueueBase { + public: + // Starts destruction of the task queue. + // On return ensures no task are running and no new tasks are able to start + // on the task queue. + // Responsible for deallocation. Deallocation may happen syncrhoniously during + // Delete or asynchronously after Delete returns. + // Code not running on the TaskQueue should not make any assumption when + // TaskQueue is deallocated and thus should not call any methods after Delete. + // Code running on the TaskQueue should not call Delete, but can assume + // TaskQueue still exists and may call other methods, e.g. PostTask. + virtual void Delete() = 0; + + // Schedules a task to execute. Tasks are executed in FIFO order. + // If |task->Run()| returns true, task is deleted on the task queue + // before next QueuedTask starts executing. + // When a TaskQueue is deleted, pending tasks will not be executed but they + // will be deleted. The deletion of tasks may happen synchronously on the + // TaskQueue or it may happen asynchronously after TaskQueue is deleted. + // This may vary from one implementation to the next so assumptions about + // lifetimes of pending tasks should not be made. + virtual void PostTask(std::unique_ptr<QueuedTask> task) = 0; + + // Schedules a task to execute a specified number of milliseconds from when + // the call is made. The precision should be considered as "best effort" + // and in some cases, such as on Windows when all high precision timers have + // been used up, can be off by as much as 15 millseconds. + virtual void PostDelayedTask(std::unique_ptr<QueuedTask> task, + uint32_t milliseconds) = 0; + + // Returns the task queue that is running the current thread. + // Returns nullptr if this thread is not associated with any task queue. + static TaskQueueBase* Current(); + bool IsCurrent() const { return Current() == this; } + + protected: + class CurrentTaskQueueSetter { + public: + explicit CurrentTaskQueueSetter(TaskQueueBase* task_queue); + CurrentTaskQueueSetter(const CurrentTaskQueueSetter&) = delete; + CurrentTaskQueueSetter& operator=(const CurrentTaskQueueSetter&) = delete; + ~CurrentTaskQueueSetter(); + + private: + TaskQueueBase* const previous_; + }; + + // Users of the TaskQueue should call Delete instead of directly deleting + // this object. + virtual ~TaskQueueBase() = default; + + private: + friend class rtc::TaskQueue; + rtc::TaskQueue* task_queue_ = nullptr; +}; + +struct TaskQueueDeleter { + void operator()(TaskQueueBase* task_queue) const { task_queue->Delete(); } +}; + +} // namespace webrtc + +#endif // API_TASK_QUEUE_TASK_QUEUE_BASE_H_
diff --git a/api/task_queue/task_queue_factory.h b/api/task_queue/task_queue_factory.h new file mode 100644 index 0000000..b68ab33 --- /dev/null +++ b/api/task_queue/task_queue_factory.h
@@ -0,0 +1,35 @@ +/* + * Copyright 2019 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef API_TASK_QUEUE_TASK_QUEUE_FACTORY_H_ +#define API_TASK_QUEUE_TASK_QUEUE_FACTORY_H_ + +#include <memory> + +#include "absl/strings/string_view.h" +#include "api/task_queue/task_queue_base.h" + +namespace webrtc { + +// The implementation of this interface must be thread-safe. +class TaskQueueFactory { + public: + // TaskQueue priority levels. On some platforms these will map to thread + // priorities, on others such as Mac and iOS, GCD queue priorities. + enum class Priority { NORMAL = 0, HIGH, LOW }; + + virtual ~TaskQueueFactory() = default; + virtual std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue( + absl::string_view name, + Priority priority) const = 0; +}; + +} // namespace webrtc + +#endif // API_TASK_QUEUE_TASK_QUEUE_FACTORY_H_
diff --git a/api/task_queue/task_queue_test.cc b/api/task_queue/task_queue_test.cc new file mode 100644 index 0000000..e78dbd2 --- /dev/null +++ b/api/task_queue/task_queue_test.cc
@@ -0,0 +1,254 @@ +/* + * Copyright 2019 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "api/task_queue/task_queue_test.h" + +#include "absl/memory/memory.h" +#include "absl/strings/string_view.h" +#include "rtc_base/event.h" +#include "rtc_base/task_utils/to_queued_task.h" +#include "rtc_base/time_utils.h" + +namespace webrtc { +namespace { + +std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue( + const std::unique_ptr<webrtc::TaskQueueFactory>& factory, + absl::string_view task_queue_name, + TaskQueueFactory::Priority priority = TaskQueueFactory::Priority::NORMAL) { + return factory->CreateTaskQueue(task_queue_name, priority); +} + +TEST_P(TaskQueueTest, Construct) { + std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(); + auto queue = CreateTaskQueue(factory, "Construct"); + EXPECT_FALSE(queue->IsCurrent()); +} + +TEST_P(TaskQueueTest, PostAndCheckCurrent) { + std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(); + rtc::Event event; + auto queue = CreateTaskQueue(factory, "PostAndCheckCurrent"); + + // We're not running a task, so there shouldn't be a current queue. + EXPECT_FALSE(queue->IsCurrent()); + EXPECT_FALSE(TaskQueueBase::Current()); + + queue->PostTask(ToQueuedTask([&event, &queue] { + EXPECT_TRUE(queue->IsCurrent()); + event.Set(); + })); + EXPECT_TRUE(event.Wait(1000)); +} + +TEST_P(TaskQueueTest, PostCustomTask) { + std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(); + rtc::Event ran; + auto queue = CreateTaskQueue(factory, "PostCustomImplementation"); + + class CustomTask : public QueuedTask { + public: + explicit CustomTask(rtc::Event* ran) : ran_(ran) {} + + private: + bool Run() override { + ran_->Set(); + return false; // Do not allow the task to be deleted by the queue. + } + + rtc::Event* const ran_; + } my_task(&ran); + + queue->PostTask(absl::WrapUnique(&my_task)); + EXPECT_TRUE(ran.Wait(1000)); +} + +TEST_P(TaskQueueTest, PostDelayedZero) { + std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(); + rtc::Event event; + auto queue = CreateTaskQueue(factory, "PostDelayedZero"); + + queue->PostDelayedTask(ToQueuedTask([&event] { event.Set(); }), 0); + EXPECT_TRUE(event.Wait(1000)); +} + +TEST_P(TaskQueueTest, PostFromQueue) { + std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(); + rtc::Event event; + auto queue = CreateTaskQueue(factory, "PostFromQueue"); + + queue->PostTask(ToQueuedTask([&event, &queue] { + queue->PostTask(ToQueuedTask([&event] { event.Set(); })); + })); + EXPECT_TRUE(event.Wait(1000)); +} + +TEST_P(TaskQueueTest, PostDelayed) { + std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(); + rtc::Event event; + auto queue = + CreateTaskQueue(factory, "PostDelayed", TaskQueueFactory::Priority::HIGH); + + int64_t start = rtc::TimeMillis(); + queue->PostDelayedTask(ToQueuedTask([&event, &queue] { + EXPECT_TRUE(queue->IsCurrent()); + event.Set(); + }), + 100); + EXPECT_TRUE(event.Wait(1000)); + int64_t end = rtc::TimeMillis(); + // These tests are a little relaxed due to how "powerful" our test bots can + // be. Most recently we've seen windows bots fire the callback after 94-99ms, + // which is why we have a little bit of leeway backwards as well. + EXPECT_GE(end - start, 90u); + EXPECT_NEAR(end - start, 190u, 100u); // Accept 90-290. +} + +TEST_P(TaskQueueTest, PostMultipleDelayed) { + std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(); + auto queue = CreateTaskQueue(factory, "PostMultipleDelayed"); + + std::vector<rtc::Event> events(100); + for (int i = 0; i < 100; ++i) { + rtc::Event* event = &events[i]; + queue->PostDelayedTask(ToQueuedTask([event, &queue] { + EXPECT_TRUE(queue->IsCurrent()); + event->Set(); + }), + i); + } + + for (rtc::Event& e : events) + EXPECT_TRUE(e.Wait(1000)); +} + +TEST_P(TaskQueueTest, PostDelayedAfterDestruct) { + std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(); + rtc::Event run; + rtc::Event deleted; + auto queue = CreateTaskQueue(factory, "PostDelayedAfterDestruct"); + queue->PostDelayedTask( + ToQueuedTask([&run] { run.Set(); }, [&deleted] { deleted.Set(); }), 100); + // Destroy the queue. + queue = nullptr; + // Task might outlive the TaskQueue, but still should be deleted. + EXPECT_TRUE(deleted.Wait(200)); + EXPECT_FALSE(run.Wait(0)); // and should not run. +} + +TEST_P(TaskQueueTest, PostAndReuse) { + std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(); + rtc::Event event; + auto post_queue = CreateTaskQueue(factory, "PostQueue"); + auto reply_queue = CreateTaskQueue(factory, "ReplyQueue"); + + int call_count = 0; + + class ReusedTask : public QueuedTask { + public: + ReusedTask(int* counter, TaskQueueBase* reply_queue, rtc::Event* event) + : counter_(*counter), reply_queue_(reply_queue), event_(*event) { + EXPECT_EQ(counter_, 0); + } + + private: + bool Run() override { + if (++counter_ == 1) { + reply_queue_->PostTask(absl::WrapUnique(this)); + // At this point, the object is owned by reply_queue_ and it's + // theoratically possible that the object has been deleted (e.g. if + // posting wasn't possible). So, don't touch any member variables here. + + // Indicate to the current queue that ownership has been transferred. + return false; + } else { + EXPECT_EQ(counter_, 2); + EXPECT_TRUE(reply_queue_->IsCurrent()); + event_.Set(); + return true; // Indicate that the object should be deleted. + } + } + + int& counter_; + TaskQueueBase* const reply_queue_; + rtc::Event& event_; + }; + + auto task = + absl::make_unique<ReusedTask>(&call_count, reply_queue.get(), &event); + post_queue->PostTask(std::move(task)); + EXPECT_TRUE(event.Wait(1000)); +} + +// Tests posting more messages than a queue can queue up. +// In situations like that, tasks will get dropped. +TEST_P(TaskQueueTest, PostALot) { + std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(); + // To destruct the event after the queue has gone out of scope. + rtc::Event event; + + int tasks_executed = 0; + int tasks_cleaned_up = 0; + static const int kTaskCount = 0xffff; + + { + auto queue = CreateTaskQueue(factory, "PostALot"); + + // On linux, the limit of pending bytes in the pipe buffer is 0xffff. + // So here we post a total of 0xffff+1 messages, which triggers a failure + // case inside of the libevent queue implementation. + + queue->PostTask( + ToQueuedTask([&event] { event.Wait(rtc::Event::kForever); })); + for (int i = 0; i < kTaskCount; ++i) + queue->PostTask( + ToQueuedTask([&tasks_executed] { ++tasks_executed; }, + [&tasks_cleaned_up] { ++tasks_cleaned_up; })); + event.Set(); // Unblock the first task. + } + + EXPECT_GE(tasks_cleaned_up, tasks_executed); + EXPECT_EQ(tasks_cleaned_up, kTaskCount); +} + +// Test posting two tasks that have shared state not protected by a +// lock. The TaskQueue should guarantee memory read-write order and +// FIFO task execution order, so the second task should always see the +// changes that were made by the first task. +// +// If the TaskQueue doesn't properly synchronize the execution of +// tasks, there will be a data race, which is undefined behavior. The +// EXPECT calls may randomly catch this, but to make the most of this +// unit test, run it under TSan or some other tool that is able to +// directly detect data races. +TEST_P(TaskQueueTest, PostTwoWithSharedUnprotectedState) { + std::unique_ptr<webrtc::TaskQueueFactory> factory = GetParam()(); + struct SharedState { + // First task will set this value to 1 and second will assert it. + int state = 0; + } state; + + auto queue = CreateTaskQueue(factory, "PostTwoWithSharedUnprotectedState"); + rtc::Event done; + queue->PostTask(ToQueuedTask([&state, &queue, &done] { + // Post tasks from queue to guarantee, that 1st task won't be + // executed before the second one will be posted. + queue->PostTask(ToQueuedTask([&state] { state.state = 1; })); + queue->PostTask(ToQueuedTask([&state, &done] { + EXPECT_EQ(state.state, 1); + done.Set(); + })); + // Check, that state changing tasks didn't start yet. + EXPECT_EQ(state.state, 0); + })); + EXPECT_TRUE(done.Wait(1000)); +} + +} // namespace +} // namespace webrtc
diff --git a/api/task_queue/task_queue_test.h b/api/task_queue/task_queue_test.h new file mode 100644 index 0000000..e2e4730 --- /dev/null +++ b/api/task_queue/task_queue_test.h
@@ -0,0 +1,40 @@ +/* + * Copyright 2019 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef API_TASK_QUEUE_TASK_QUEUE_TEST_H_ +#define API_TASK_QUEUE_TASK_QUEUE_TEST_H_ + +#include <functional> +#include <memory> + +#include "api/task_queue/task_queue_factory.h" +#include "test/gtest.h" + +namespace webrtc { + +// Suite of tests to verify TaskQueue implementation with. +// Example usage: +// +// namespace { +// +// using ::testing::Values; +// using ::webrtc::TaskQueueTest; +// +// std::unique_ptr<webrtc::TaskQueueFactory> CreateMyFactory(); +// +// INSTANTIATE_TEST_SUITE_P(My, TaskQueueTest, Values(CreateMyFactory)); +// +// } // namespace +class TaskQueueTest : public ::testing::TestWithParam< + std::function<std::unique_ptr<TaskQueueFactory>()>> { +}; + +} // namespace webrtc + +#endif // API_TASK_QUEUE_TASK_QUEUE_TEST_H_
diff --git a/api/transport/field_trial_based_config.cc b/api/transport/field_trial_based_config.cc new file mode 100644 index 0000000..7e6764f --- /dev/null +++ b/api/transport/field_trial_based_config.cc
@@ -0,0 +1,17 @@ +/* + * Copyright 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "api/transport/field_trial_based_config.h" +#include "system_wrappers/include/field_trial.h" + +namespace webrtc { +std::string FieldTrialBasedConfig::Lookup(absl::string_view key) const { + return webrtc::field_trial::FindFullName(std::string(key)); +} +} // namespace webrtc
diff --git a/api/transport/field_trial_based_config.h b/api/transport/field_trial_based_config.h new file mode 100644 index 0000000..e0989db --- /dev/null +++ b/api/transport/field_trial_based_config.h
@@ -0,0 +1,25 @@ +/* + * Copyright 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef API_TRANSPORT_FIELD_TRIAL_BASED_CONFIG_H_ +#define API_TRANSPORT_FIELD_TRIAL_BASED_CONFIG_H_ + +#include <string> +#include "absl/strings/string_view.h" +#include "api/transport/webrtc_key_value_config.h" + +namespace webrtc { +// Implementation using the field trial API fo the key value lookup. +class FieldTrialBasedConfig : public WebRtcKeyValueConfig { + public: + std::string Lookup(absl::string_view key) const override; +}; +} // namespace webrtc + +#endif // API_TRANSPORT_FIELD_TRIAL_BASED_CONFIG_H_
diff --git a/api/transport/goog_cc_factory.cc b/api/transport/goog_cc_factory.cc index 119e2dc..92fd4d1 100644 --- a/api/transport/goog_cc_factory.cc +++ b/api/transport/goog_cc_factory.cc
@@ -10,8 +10,11 @@ #include "api/transport/goog_cc_factory.h" +#include <stdint.h> + #include "absl/memory/memory.h" #include "modules/congestion_controller/goog_cc/goog_cc_network_control.h" + namespace webrtc { GoogCcNetworkControllerFactory::GoogCcNetworkControllerFactory( RtcEventLog* event_log)
diff --git a/api/transport/network_control.h b/api/transport/network_control.h index 9086260..53ac10e 100644 --- a/api/transport/network_control.h +++ b/api/transport/network_control.h
@@ -14,6 +14,7 @@ #include <memory> #include "api/transport/network_types.h" +#include "api/transport/webrtc_key_value_config.h" namespace webrtc { @@ -23,6 +24,9 @@ // Called to indicate target transfer rate as well as giving information about // the current estimate of network parameters. virtual void OnTargetTransferRate(TargetTransferRate) = 0; + // Called to provide updates to the expected target rate in case it changes + // before the first call to OnTargetTransferRate. + virtual void OnStartRateUpdate(DataRate) {} }; // Configuration sent to factory create function. The parameters here are @@ -36,6 +40,10 @@ // Initial stream specific configuration, these are changed at any later time // by calls to OnStreamsConfig. StreamsConfig stream_based_config; + + // Optional override of configuration of WebRTC internals. Using nullptr here + // indicates that the field trial API will be used. + const WebRtcKeyValueConfig* key_value_config = nullptr; }; // NetworkControllerInterface is implemented by network controllers. A network
diff --git a/api/transport/network_types.cc b/api/transport/network_types.cc index 80214de..acc9c2b 100644 --- a/api/transport/network_types.cc +++ b/api/transport/network_types.cc
@@ -81,4 +81,8 @@ probe_cluster_min_bytes == rhs.probe_cluster_min_bytes; } +ProcessInterval::ProcessInterval() = default; +ProcessInterval::ProcessInterval(const ProcessInterval&) = default; +ProcessInterval::~ProcessInterval() = default; + } // namespace webrtc
diff --git a/api/transport/network_types.h b/api/transport/network_types.h index 0f1d7ab..e26561a 100644 --- a/api/transport/network_types.h +++ b/api/transport/network_types.h
@@ -31,13 +31,11 @@ StreamsConfig(const StreamsConfig&); ~StreamsConfig(); Timestamp at_time = Timestamp::PlusInfinity(); - bool requests_alr_probing = false; + absl::optional<bool> requests_alr_probing; absl::optional<double> pacing_factor; absl::optional<DataRate> min_pacing_rate; absl::optional<DataRate> max_padding_rate; absl::optional<DataRate> max_total_allocated_bitrate; - // The send rate of traffic for which feedback is not received. - DataRate unacknowledged_rate_allocation = DataRate::Zero(); }; struct TargetRateConstraints { @@ -136,6 +134,7 @@ ~TransportPacketsFeedback(); Timestamp feedback_time = Timestamp::PlusInfinity(); + Timestamp first_unacked_send_time = Timestamp::PlusInfinity(); DataSize data_in_flight = DataSize::Zero(); DataSize prior_in_flight = DataSize::Zero(); std::vector<PacketResult> packet_feedbacks; @@ -177,6 +176,7 @@ DataRate target_data_rate = DataRate::Zero(); TimeDelta target_duration = TimeDelta::Zero(); int32_t target_probe_count = 0; + int32_t id = 0; }; struct TargetTransferRate { @@ -201,7 +201,11 @@ // Process control struct ProcessInterval { + ProcessInterval(); + ProcessInterval(const ProcessInterval&); + ~ProcessInterval(); Timestamp at_time = Timestamp::PlusInfinity(); + absl::optional<DataSize> pacer_queue; }; } // namespace webrtc
diff --git a/api/transport/webrtc_key_value_config.h b/api/transport/webrtc_key_value_config.h new file mode 100644 index 0000000..c6376a9 --- /dev/null +++ b/api/transport/webrtc_key_value_config.h
@@ -0,0 +1,31 @@ +/* + * Copyright 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef API_TRANSPORT_WEBRTC_KEY_VALUE_CONFIG_H_ +#define API_TRANSPORT_WEBRTC_KEY_VALUE_CONFIG_H_ + +#include <string> +#include "absl/strings/string_view.h" + +namespace webrtc { + +// An interface that provides a key-value mapping for configuring internal +// details of WebRTC. Note that there's no guarantess that the meaning of a +// particular key value mapping will be preserved over time and no announcements +// will be made if they are changed. It's up to the library user to ensure that +// the behavior does not break. +class WebRtcKeyValueConfig { + public: + virtual ~WebRtcKeyValueConfig() = default; + // The configured value for the given key. Defaults to an empty string. + virtual std::string Lookup(absl::string_view key) const = 0; +}; +} // namespace webrtc + +#endif // API_TRANSPORT_WEBRTC_KEY_VALUE_CONFIG_H_
diff --git a/api/turn_customizer.h b/api/turn_customizer.h new file mode 100644 index 0000000..f0bf0d9 --- /dev/null +++ b/api/turn_customizer.h
@@ -0,0 +1,45 @@ +/* + * Copyright 2017 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_TURN_CUSTOMIZER_H_ +#define API_TURN_CUSTOMIZER_H_ + +#include <stdlib.h> + +namespace cricket { +class PortInterface; +class StunMessage; +} // namespace cricket + +namespace webrtc { + +class TurnCustomizer { + public: + // This is called before a TURN message is sent. + // This could be used to add implementation specific attributes to a request. + virtual void MaybeModifyOutgoingStunMessage( + cricket::PortInterface* port, + cricket::StunMessage* message) = 0; + + // TURN can send data using channel data messages or Send indication. + // This method should return false if |data| should be sent using + // a Send indication instead of a ChannelData message, even if a + // channel is bound. + virtual bool AllowChannelData(cricket::PortInterface* port, + const void* data, + size_t size, + bool payload) = 0; + + virtual ~TurnCustomizer() {} +}; + +} // namespace webrtc + +#endif // API_TURN_CUSTOMIZER_H_
diff --git a/api/uma_metrics.h b/api/uma_metrics.h new file mode 100644 index 0000000..51b0ff0 --- /dev/null +++ b/api/uma_metrics.h
@@ -0,0 +1,168 @@ +/* + * Copyright 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This file contains enums related to IPv4/IPv6 metrics. + +#ifndef API_UMA_METRICS_H_ +#define API_UMA_METRICS_H_ + +#include "rtc_base/ref_count.h" + +namespace webrtc { + +// Currently this contains information related to WebRTC network/transport +// information. + +// The difference between PeerConnectionEnumCounter and +// PeerConnectionMetricsName is that the "EnumCounter" is only counting the +// occurrences of events, while "Name" has a value associated with it which is +// used to form a histogram. + +// This enum is backed by Chromium's histograms.xml, +// chromium/src/tools/metrics/histograms/histograms.xml +// Existing values cannot be re-ordered and new enums must be added +// before kBoundary. +enum PeerConnectionAddressFamilyCounter { + kPeerConnection_IPv4, + kPeerConnection_IPv6, + kBestConnections_IPv4, + kBestConnections_IPv6, + kPeerConnectionAddressFamilyCounter_Max, +}; + +// TODO(guoweis): Keep previous name here until all references are renamed. +#define kBoundary kPeerConnectionAddressFamilyCounter_Max + +// TODO(guoweis): Keep previous name here until all references are renamed. +typedef PeerConnectionAddressFamilyCounter PeerConnectionUMAMetricsCounter; + +// This enum defines types for UMA samples, which will have a range. +enum PeerConnectionMetricsName { + kNetworkInterfaces_IPv4, // Number of IPv4 interfaces. + kNetworkInterfaces_IPv6, // Number of IPv6 interfaces. + kTimeToConnect, // In milliseconds. + kLocalCandidates_IPv4, // Number of IPv4 local candidates. + kLocalCandidates_IPv6, // Number of IPv6 local candidates. + kPeerConnectionMetricsName_Max +}; + +// TODO(guoweis): Keep previous name here until all references are renamed. +typedef PeerConnectionMetricsName PeerConnectionUMAMetricsName; + +// The IceCandidatePairType has the format of +// <local_candidate_type>_<remote_candidate_type>. It is recorded based on the +// type of candidate pair used when the PeerConnection first goes to a completed +// state. When BUNDLE is enabled, only the first transport gets recorded. +enum IceCandidatePairType { + // HostHost is deprecated. It was replaced with the set of types at the bottom + // to report private or public host IP address. + kIceCandidatePairHostHost, + kIceCandidatePairHostSrflx, + kIceCandidatePairHostRelay, + kIceCandidatePairHostPrflx, + kIceCandidatePairSrflxHost, + kIceCandidatePairSrflxSrflx, + kIceCandidatePairSrflxRelay, + kIceCandidatePairSrflxPrflx, + kIceCandidatePairRelayHost, + kIceCandidatePairRelaySrflx, + kIceCandidatePairRelayRelay, + kIceCandidatePairRelayPrflx, + kIceCandidatePairPrflxHost, + kIceCandidatePairPrflxSrflx, + kIceCandidatePairPrflxRelay, + + // The following 9 types tell whether local and remote hosts have hostname, + // private or public IP addresses. + kIceCandidatePairHostPrivateHostPrivate, + kIceCandidatePairHostPrivateHostPublic, + kIceCandidatePairHostPublicHostPrivate, + kIceCandidatePairHostPublicHostPublic, + kIceCandidatePairHostNameHostName, + kIceCandidatePairHostNameHostPrivate, + kIceCandidatePairHostNameHostPublic, + kIceCandidatePairHostPrivateHostName, + kIceCandidatePairHostPublicHostName, + kIceCandidatePairMax +}; + +enum KeyExchangeProtocolType { + kEnumCounterKeyProtocolDtls, + kEnumCounterKeyProtocolSdes, + kEnumCounterKeyProtocolMax +}; + +enum KeyExchangeProtocolMedia { + kEnumCounterKeyProtocolMediaTypeDtlsAudio, + kEnumCounterKeyProtocolMediaTypeDtlsVideo, + kEnumCounterKeyProtocolMediaTypeDtlsData, + kEnumCounterKeyProtocolMediaTypeSdesAudio, + kEnumCounterKeyProtocolMediaTypeSdesVideo, + kEnumCounterKeyProtocolMediaTypeSdesData, + kEnumCounterKeyProtocolMediaTypeMax +}; + +enum SdpSemanticRequested { + kSdpSemanticRequestDefault, + kSdpSemanticRequestPlanB, + kSdpSemanticRequestUnifiedPlan, + kSdpSemanticRequestMax +}; + +enum SdpSemanticNegotiated { + kSdpSemanticNegotiatedNone, + kSdpSemanticNegotiatedPlanB, + kSdpSemanticNegotiatedUnifiedPlan, + kSdpSemanticNegotiatedMixed, + kSdpSemanticNegotiatedMax +}; + +// Metric which records the format of the received SDP for tracking how much the +// difference between Plan B and Unified Plan affect users. +enum SdpFormatReceived { + // No audio or video tracks. This is worth special casing since it seems to be + // the most common scenario (data-channel only). + kSdpFormatReceivedNoTracks, + // No more than one audio and one video track. Should be compatible with both + // Plan B and Unified Plan endpoints. + kSdpFormatReceivedSimple, + // More than one audio track or more than one video track in the Plan B format + // (e.g., one audio media section with multiple streams). + kSdpFormatReceivedComplexPlanB, + // More than one audio track or more than one video track in the Unified Plan + // format (e.g., two audio media sections). + kSdpFormatReceivedComplexUnifiedPlan, + kSdpFormatReceivedMax +}; + +// Metric for counting the outcome of adding an ICE candidate +enum AddIceCandidateResult { + kAddIceCandidateSuccess, + kAddIceCandidateFailClosed, + kAddIceCandidateFailNoRemoteDescription, + kAddIceCandidateFailNullCandidate, + kAddIceCandidateFailNotValid, + kAddIceCandidateFailNotReady, + kAddIceCandidateFailInAddition, + kAddIceCandidateFailNotUsable, + kAddIceCandidateMax +}; + +// Metric for recording which api surface was used to enable simulcast. +enum SimulcastApiVersion { + kSimulcastApiVersionNone, + kSimulcastApiVersionLegacy, + kSimulcastApiVersionSpecCompliant, + kSimulcastApiVersionMax, +}; + +} // namespace webrtc + +#endif // API_UMA_METRICS_H_
diff --git a/api/units/data_rate.cc b/api/units/data_rate.cc index d72d958..f9586c5 100644 --- a/api/units/data_rate.cc +++ b/api/units/data_rate.cc
@@ -10,6 +10,7 @@ #include "api/units/data_rate.h" +#include "api/array_view.h" #include "rtc_base/strings/string_builder.h" namespace webrtc { @@ -17,8 +18,10 @@ std::string ToString(DataRate value) { char buf[64]; rtc::SimpleStringBuilder sb(buf); - if (value.IsInfinite()) { - sb << "inf bps"; + if (value.IsPlusInfinity()) { + sb << "+inf bps"; + } else if (value.IsMinusInfinity()) { + sb << "-inf bps"; } else { if (value.bps() == 0 || value.bps() % 1000 != 0) { sb << value.bps() << " bps";
diff --git a/api/units/data_rate.h b/api/units/data_rate.h index 7119284..9b09aa9 100644 --- a/api/units/data_rate.h +++ b/api/units/data_rate.h
@@ -52,10 +52,17 @@ } template <typename T> static constexpr DataRate bps(T bits_per_second) { + static_assert(std::is_arithmetic<T>::value, ""); return FromValue(bits_per_second); } template <typename T> + static constexpr DataRate bytes_per_sec(T bytes_per_second) { + static_assert(std::is_arithmetic<T>::value, ""); + return FromFraction<8>(bytes_per_second); + } + template <typename T> static constexpr DataRate kbps(T kilobits_per_sec) { + static_assert(std::is_arithmetic<T>::value, ""); return FromFraction<1000>(kilobits_per_sec); } template <typename T = int64_t> @@ -63,6 +70,10 @@ return ToValue<T>(); } template <typename T = int64_t> + constexpr T bytes_per_sec() const { + return ToFraction<8, T>(); + } + template <typename T = int64_t> T kbps() const { return ToFraction<1000, T>(); }
diff --git a/api/units/data_size.cc b/api/units/data_size.cc index 8a87786..45487df 100644 --- a/api/units/data_size.cc +++ b/api/units/data_size.cc
@@ -10,6 +10,7 @@ #include "api/units/data_size.h" +#include "api/array_view.h" #include "rtc_base/strings/string_builder.h" namespace webrtc { @@ -17,8 +18,10 @@ std::string ToString(DataSize value) { char buf[64]; rtc::SimpleStringBuilder sb(buf); - if (value.IsInfinite()) { - sb << "inf bytes"; + if (value.IsPlusInfinity()) { + sb << "+inf bytes"; + } else if (value.IsMinusInfinity()) { + sb << "-inf bytes"; } else { sb << value.bytes() << " bytes"; }
diff --git a/api/units/data_size.h b/api/units/data_size.h index b4cbb65..90ef00d 100644 --- a/api/units/data_size.h +++ b/api/units/data_size.h
@@ -31,14 +31,13 @@ return FromStaticValue<bytes>(); } - template < - typename T, - typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr> + template <typename T> static DataSize bytes(T bytes) { + static_assert(std::is_arithmetic<T>::value, ""); return FromValue(bytes); } template <typename T = int64_t> - typename std::enable_if<std::is_arithmetic<T>::value, T>::type bytes() const { + T bytes() const { return ToValue<T>(); }
diff --git a/api/units/time_delta.cc b/api/units/time_delta.cc index f90451b..9fe1308 100644 --- a/api/units/time_delta.cc +++ b/api/units/time_delta.cc
@@ -10,6 +10,7 @@ #include "api/units/time_delta.h" +#include "api/array_view.h" #include "rtc_base/strings/string_builder.h" namespace webrtc {
diff --git a/api/units/time_delta.h b/api/units/time_delta.h index 6458369..e5172f4 100644 --- a/api/units/time_delta.h +++ b/api/units/time_delta.h
@@ -46,14 +46,17 @@ } template <typename T> static TimeDelta seconds(T seconds) { + static_assert(std::is_arithmetic<T>::value, ""); return FromFraction<1000000>(seconds); } template <typename T> static TimeDelta ms(T milliseconds) { + static_assert(std::is_arithmetic<T>::value, ""); return FromFraction<1000>(milliseconds); } template <typename T> static TimeDelta us(T microseconds) { + static_assert(std::is_arithmetic<T>::value, ""); return FromValue(microseconds); } template <typename T = int64_t>
diff --git a/api/units/timestamp.cc b/api/units/timestamp.cc index d3417cf..0b9cdd9 100644 --- a/api/units/timestamp.cc +++ b/api/units/timestamp.cc
@@ -10,14 +10,17 @@ #include "api/units/timestamp.h" +#include "api/array_view.h" #include "rtc_base/strings/string_builder.h" namespace webrtc { std::string ToString(Timestamp value) { char buf[64]; rtc::SimpleStringBuilder sb(buf); - if (value.IsInfinite()) { - sb << "inf ms"; + if (value.IsPlusInfinity()) { + sb << "+inf ms"; + } else if (value.IsMinusInfinity()) { + sb << "-inf ms"; } else { if (value.ms() % 1000 == 0) sb << value.seconds() << " s";
diff --git a/api/units/timestamp.h b/api/units/timestamp.h index a6e450f..370a091 100644 --- a/api/units/timestamp.h +++ b/api/units/timestamp.h
@@ -45,14 +45,17 @@ template <typename T> static Timestamp seconds(T seconds) { + static_assert(std::is_arithmetic<T>::value, ""); return FromFraction<1000000>(seconds); } template <typename T> static Timestamp ms(T milliseconds) { + static_assert(std::is_arithmetic<T>::value, ""); return FromFraction<1000>(milliseconds); } template <typename T> static Timestamp us(T microseconds) { + static_assert(std::is_arithmetic<T>::value, ""); return FromValue(microseconds); } template <typename T = int64_t>
diff --git a/api/video/builtin_video_bitrate_allocator_factory.cc b/api/video/builtin_video_bitrate_allocator_factory.cc index 70f6ad0..b01e5c2 100644 --- a/api/video/builtin_video_bitrate_allocator_factory.cc +++ b/api/video/builtin_video_bitrate_allocator_factory.cc
@@ -11,7 +11,9 @@ #include "api/video/builtin_video_bitrate_allocator_factory.h" #include "absl/memory/memory.h" -#include "media/base/codec.h" +#include "api/video/video_bitrate_allocator.h" +#include "api/video_codecs/video_codec.h" +#include "common_types.h" // NOLINT(build/include) #include "modules/video_coding/codecs/vp9/svc_rate_allocator.h" #include "modules/video_coding/utility/default_video_bitrate_allocator.h" #include "modules/video_coding/utility/simulcast_rate_allocator.h"
diff --git a/api/video/color_space.cc b/api/video/color_space.cc index ad138ab..710bb43 100644 --- a/api/video/color_space.cc +++ b/api/video/color_space.cc
@@ -10,6 +10,7 @@ #include "api/video/color_space.h" +namespace webrtc { namespace { // Try to convert |enum_value| into the enum class T. |enum_bitmask| is created // by the funciton below. Returns true if conversion was successful, false @@ -50,9 +51,17 @@ return MakeMask(0, N, values); } -} // namespace +bool SetChromaSitingFromUint8(uint8_t enum_value, + ColorSpace::ChromaSiting* chroma_siting) { + constexpr ColorSpace::ChromaSiting kChromaSitings[] = { + ColorSpace::ChromaSiting::kUnspecified, + ColorSpace::ChromaSiting::kCollocated, ColorSpace::ChromaSiting::kHalf}; + constexpr uint64_t enum_bitmask = CreateEnumBitmask(kChromaSitings); -namespace webrtc { + return SetFromUint8(enum_value, enum_bitmask, chroma_siting); +} + +} // namespace ColorSpace::ColorSpace() = default; ColorSpace::ColorSpace(const ColorSpace& other) = default; @@ -63,17 +72,27 @@ TransferID transfer, MatrixID matrix, RangeID range) - : ColorSpace(primaries, transfer, matrix, range, nullptr) {} + : ColorSpace(primaries, + transfer, + matrix, + range, + ChromaSiting::kUnspecified, + ChromaSiting::kUnspecified, + nullptr) {} ColorSpace::ColorSpace(PrimaryID primaries, TransferID transfer, MatrixID matrix, RangeID range, + ChromaSiting chroma_siting_horz, + ChromaSiting chroma_siting_vert, const HdrMetadata* hdr_metadata) : primaries_(primaries), transfer_(transfer), matrix_(matrix), range_(range), + chroma_siting_horizontal_(chroma_siting_horz), + chroma_siting_vertical_(chroma_siting_vert), hdr_metadata_(hdr_metadata ? absl::make_optional(*hdr_metadata) : absl::nullopt) {} @@ -93,17 +112,24 @@ return range_; } +ColorSpace::ChromaSiting ColorSpace::chroma_siting_horizontal() const { + return chroma_siting_horizontal_; +} + +ColorSpace::ChromaSiting ColorSpace::chroma_siting_vertical() const { + return chroma_siting_vertical_; +} + const HdrMetadata* ColorSpace::hdr_metadata() const { return hdr_metadata_ ? &*hdr_metadata_ : nullptr; } bool ColorSpace::set_primaries_from_uint8(uint8_t enum_value) { constexpr PrimaryID kPrimaryIds[] = { - PrimaryID::kInvalid, PrimaryID::kBT709, PrimaryID::kUNSPECIFIED, - PrimaryID::kBT470M, PrimaryID::kBT470BG, PrimaryID::kSMPTE170M, - PrimaryID::kSMPTE240M, PrimaryID::kFILM, PrimaryID::kBT2020, - PrimaryID::kSMPTEST428, PrimaryID::kSMPTEST431, PrimaryID::kSMPTEST432, - PrimaryID::kJEDECP22}; + PrimaryID::kBT709, PrimaryID::kUnspecified, PrimaryID::kBT470M, + PrimaryID::kBT470BG, PrimaryID::kSMPTE170M, PrimaryID::kSMPTE240M, + PrimaryID::kFILM, PrimaryID::kBT2020, PrimaryID::kSMPTEST428, + PrimaryID::kSMPTEST431, PrimaryID::kSMPTEST432, PrimaryID::kJEDECP22}; constexpr uint64_t enum_bitmask = CreateEnumBitmask(kPrimaryIds); return SetFromUint8(enum_value, enum_bitmask, &primaries_); @@ -111,15 +137,15 @@ bool ColorSpace::set_transfer_from_uint8(uint8_t enum_value) { constexpr TransferID kTransferIds[] = { - TransferID::kInvalid, TransferID::kBT709, - TransferID::kUNSPECIFIED, TransferID::kGAMMA22, - TransferID::kGAMMA28, TransferID::kSMPTE170M, - TransferID::kSMPTE240M, TransferID::kLINEAR, - TransferID::kLOG, TransferID::kLOG_SQRT, - TransferID::kIEC61966_2_4, TransferID::kBT1361_ECG, - TransferID::kIEC61966_2_1, TransferID::kBT2020_10, - TransferID::kBT2020_12, TransferID::kSMPTEST2084, - TransferID::kSMPTEST428, TransferID::kARIB_STD_B67}; + TransferID::kBT709, TransferID::kUnspecified, + TransferID::kGAMMA22, TransferID::kGAMMA28, + TransferID::kSMPTE170M, TransferID::kSMPTE240M, + TransferID::kLINEAR, TransferID::kLOG, + TransferID::kLOG_SQRT, TransferID::kIEC61966_2_4, + TransferID::kBT1361_ECG, TransferID::kIEC61966_2_1, + TransferID::kBT2020_10, TransferID::kBT2020_12, + TransferID::kSMPTEST2084, TransferID::kSMPTEST428, + TransferID::kARIB_STD_B67}; constexpr uint64_t enum_bitmask = CreateEnumBitmask(kTransferIds); return SetFromUint8(enum_value, enum_bitmask, &transfer_); @@ -127,11 +153,11 @@ bool ColorSpace::set_matrix_from_uint8(uint8_t enum_value) { constexpr MatrixID kMatrixIds[] = { - MatrixID::kRGB, MatrixID::kBT709, MatrixID::kUNSPECIFIED, - MatrixID::kFCC, MatrixID::kBT470BG, MatrixID::kSMPTE170M, - MatrixID::kSMPTE240M, MatrixID::kYCOCG, MatrixID::kBT2020_NCL, - MatrixID::kBT2020_CL, MatrixID::kSMPTE2085, MatrixID::kCDNCLS, - MatrixID::kCDCLS, MatrixID::kBT2100_ICTCP, MatrixID::kInvalid}; + MatrixID::kRGB, MatrixID::kBT709, MatrixID::kUnspecified, + MatrixID::kFCC, MatrixID::kBT470BG, MatrixID::kSMPTE170M, + MatrixID::kSMPTE240M, MatrixID::kYCOCG, MatrixID::kBT2020_NCL, + MatrixID::kBT2020_CL, MatrixID::kSMPTE2085, MatrixID::kCDNCLS, + MatrixID::kCDCLS, MatrixID::kBT2100_ICTCP}; constexpr uint64_t enum_bitmask = CreateEnumBitmask(kMatrixIds); return SetFromUint8(enum_value, enum_bitmask, &matrix_); @@ -145,6 +171,14 @@ return SetFromUint8(enum_value, enum_bitmask, &range_); } +bool ColorSpace::set_chroma_siting_horizontal_from_uint8(uint8_t enum_value) { + return SetChromaSitingFromUint8(enum_value, &chroma_siting_horizontal_); +} + +bool ColorSpace::set_chroma_siting_vertical_from_uint8(uint8_t enum_value) { + return SetChromaSitingFromUint8(enum_value, &chroma_siting_vertical_); +} + void ColorSpace::set_hdr_metadata(const HdrMetadata* hdr_metadata) { hdr_metadata_ = hdr_metadata ? absl::make_optional(*hdr_metadata) : absl::nullopt;
diff --git a/api/video/color_space.h b/api/video/color_space.h index 79a15f5..91b4e17 100644 --- a/api/video/color_space.h +++ b/api/video/color_space.h
@@ -35,9 +35,8 @@ public: enum class PrimaryID : uint8_t { // The indices are equal to the values specified in T-REC H.273 Table 2. - kInvalid = 0, kBT709 = 1, - kUNSPECIFIED = 2, + kUnspecified = 2, kBT470M = 4, kBT470BG = 5, kSMPTE170M = 6, // Identical to BT601 @@ -54,9 +53,8 @@ enum class TransferID : uint8_t { // The indices are equal to the values specified in T-REC H.273 Table 3. - kInvalid = 0, kBT709 = 1, - kUNSPECIFIED = 2, + kUnspecified = 2, kGAMMA22 = 4, kGAMMA28 = 5, kSMPTE170M = 6, @@ -80,7 +78,7 @@ // The indices are equal to the values specified in T-REC H.273 Table 4. kRGB = 0, kBT709 = 1, - kUNSPECIFIED = 2, + kUnspecified = 2, kFCC = 4, kBT470BG = 5, kSMPTE170M = 6, @@ -92,7 +90,6 @@ kCDNCLS = 12, kCDCLS = 13, kBT2100_ICTCP = 14, - kInvalid = 63, // When adding/removing entries here, please make sure to do the // corresponding change to kMatrixIds. }; @@ -111,6 +108,19 @@ // corresponding change to kRangeIds. }; + enum class ChromaSiting { + // Chroma siting specifies how chroma is subsampled relative to the luma + // samples in a YUV video frame. + // The indices are equal to the values specified at + // https://www.webmproject.org/docs/container/#colour for the element + // ChromaSitingVert and ChromaSitingHorz. + kUnspecified = 0, + kCollocated = 1, + kHalf = 2, + // When adding/removing entries here, please make sure to do the + // corresponding change to kChromaSitings. + }; + ColorSpace(); ColorSpace(const ColorSpace& other); ColorSpace(ColorSpace&& other); @@ -118,40 +128,50 @@ ColorSpace(PrimaryID primaries, TransferID transfer, MatrixID matrix, - RangeID full_range); + RangeID range); ColorSpace(PrimaryID primaries, TransferID transfer, MatrixID matrix, RangeID range, + ChromaSiting chroma_siting_horizontal, + ChromaSiting chroma_siting_vertical, const HdrMetadata* hdr_metadata); - bool operator==(const ColorSpace& other) const { - return primaries_ == other.primaries() && transfer_ == other.transfer() && - matrix_ == other.matrix() && range_ == other.range() && - ((hdr_metadata_.has_value() && other.hdr_metadata() && - *hdr_metadata_ == *other.hdr_metadata()) || - (!hdr_metadata_.has_value() && other.hdr_metadata() == nullptr)); + friend bool operator==(const ColorSpace& lhs, const ColorSpace& rhs) { + return lhs.primaries_ == rhs.primaries_ && lhs.transfer_ == rhs.transfer_ && + lhs.matrix_ == rhs.matrix_ && lhs.range_ == rhs.range_ && + lhs.chroma_siting_horizontal_ == rhs.chroma_siting_horizontal_ && + lhs.chroma_siting_vertical_ == rhs.chroma_siting_vertical_ && + lhs.hdr_metadata_ == rhs.hdr_metadata_; + } + friend bool operator!=(const ColorSpace& lhs, const ColorSpace& rhs) { + return !(lhs == rhs); } PrimaryID primaries() const; TransferID transfer() const; MatrixID matrix() const; RangeID range() const; + ChromaSiting chroma_siting_horizontal() const; + ChromaSiting chroma_siting_vertical() const; const HdrMetadata* hdr_metadata() const; bool set_primaries_from_uint8(uint8_t enum_value); bool set_transfer_from_uint8(uint8_t enum_value); bool set_matrix_from_uint8(uint8_t enum_value); bool set_range_from_uint8(uint8_t enum_value); + bool set_chroma_siting_horizontal_from_uint8(uint8_t enum_value); + bool set_chroma_siting_vertical_from_uint8(uint8_t enum_value); void set_hdr_metadata(const HdrMetadata* hdr_metadata); private: - PrimaryID primaries_ = PrimaryID::kInvalid; - TransferID transfer_ = TransferID::kInvalid; - MatrixID matrix_ = MatrixID::kInvalid; + PrimaryID primaries_ = PrimaryID::kUnspecified; + TransferID transfer_ = TransferID::kUnspecified; + MatrixID matrix_ = MatrixID::kUnspecified; RangeID range_ = RangeID::kInvalid; + ChromaSiting chroma_siting_horizontal_ = ChromaSiting::kUnspecified; + ChromaSiting chroma_siting_vertical_ = ChromaSiting::kUnspecified; absl::optional<HdrMetadata> hdr_metadata_; }; } // namespace webrtc - #endif // API_VIDEO_COLOR_SPACE_H_
diff --git a/api/video/encoded_frame.h b/api/video/encoded_frame.h index b8462c6..fa06568 100644 --- a/api/video/encoded_frame.h +++ b/api/video/encoded_frame.h
@@ -13,6 +13,9 @@ #include "modules/video_coding/encoded_frame.h" +#include <stddef.h> +#include <stdint.h> + namespace webrtc { namespace video_coding { @@ -56,8 +59,6 @@ EncodedFrame() = default; virtual ~EncodedFrame() {} - virtual bool GetBitstream(uint8_t* destination) const = 0; - // When this frame was received. virtual int64_t ReceivedTime() const = 0; @@ -69,8 +70,6 @@ // been implemented. virtual bool delayed_by_retransmission() const; - size_t size() const { return _length; } - bool is_keyframe() const { return num_references == 0; } VideoLayerFrameId id; @@ -80,6 +79,9 @@ size_t num_references = 0; int64_t references[kMaxFrameReferences]; bool inter_layer_predicted = false; + // Is this subframe the last one in the superframe (In RTP stream that would + // mean that the last packet has a marker bit set). + bool is_last_spatial_layer = true; }; } // namespace video_coding
diff --git a/api/video/encoded_image.cc b/api/video/encoded_image.cc index e7c6fad..d1fa046 100644 --- a/api/video/encoded_image.cc +++ b/api/video/encoded_image.cc
@@ -29,10 +29,23 @@ EncodedImage::EncodedImage() : EncodedImage(nullptr, 0, 0) {} +EncodedImage::EncodedImage(EncodedImage&&) = default; EncodedImage::EncodedImage(const EncodedImage&) = default; -EncodedImage::EncodedImage(uint8_t* buffer, size_t length, size_t size) - : _buffer(buffer), _length(length), _size(size) {} +EncodedImage::EncodedImage(uint8_t* buffer, size_t size, size_t capacity) + : size_(size), buffer_(buffer), capacity_(capacity) {} + +EncodedImage::~EncodedImage() = default; + +EncodedImage& EncodedImage::operator=(EncodedImage&&) = default; +EncodedImage& EncodedImage::operator=(const EncodedImage&) = default; + +void EncodedImage::Retain() { + if (buffer_) { + encoded_data_.SetData(buffer_, size_); + buffer_ = nullptr; + } +} void EncodedImage::SetEncodeTime(int64_t encode_start_ms, int64_t encode_finish_ms) {
diff --git a/api/video/encoded_image.h b/api/video/encoded_image.h index a7c719c..1d3bd46 100644 --- a/api/video/encoded_image.h +++ b/api/video/encoded_image.h
@@ -15,13 +15,14 @@ #include "absl/types/optional.h" #include "api/video/color_space.h" -#include "api/video/video_bitrate_allocation.h" +#include "api/video/video_codec_constants.h" #include "api/video/video_codec_type.h" #include "api/video/video_content_type.h" #include "api/video/video_rotation.h" #include "api/video/video_timing.h" #include "common_types.h" // NOLINT(build/include) #include "rtc_base/checks.h" +#include "rtc_base/copy_on_write_buffer.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -37,8 +38,16 @@ static size_t GetBufferPaddingBytes(VideoCodecType codec_type); EncodedImage(); + EncodedImage(EncodedImage&&); + // Discouraged: potentially expensive. EncodedImage(const EncodedImage&); - EncodedImage(uint8_t* buffer, size_t length, size_t size); + EncodedImage(uint8_t* buffer, size_t length, size_t capacity); + + ~EncodedImage(); + + EncodedImage& operator=(EncodedImage&&); + // Discouraged: potentially expensive. + EncodedImage& operator=(const EncodedImage&); // TODO(nisse): Change style to timestamp(), set_timestamp(), for consistency // with the VideoFrame class. @@ -62,20 +71,51 @@ const webrtc::ColorSpace* ColorSpace() const { return color_space_ ? &*color_space_ : nullptr; } - void SetColorSpace(const webrtc::ColorSpace* color_space) { - color_space_ = - color_space ? absl::make_optional(*color_space) : absl::nullopt; + void SetColorSpace(const absl::optional<webrtc::ColorSpace>& color_space) { + color_space_ = color_space; } + size_t size() const { return size_; } + void set_size(size_t new_size) { + RTC_DCHECK_LE(new_size, capacity()); + size_ = new_size; + } + size_t capacity() const { return buffer_ ? capacity_ : encoded_data_.size(); } + + void set_buffer(uint8_t* buffer, size_t capacity) { + buffer_ = buffer; + capacity_ = capacity; + } + + void Allocate(size_t capacity) { + encoded_data_.SetSize(capacity); + buffer_ = nullptr; + } + + uint8_t* data() { return buffer_ ? buffer_ : encoded_data_.data(); } + const uint8_t* data() const { + return buffer_ ? buffer_ : encoded_data_.cdata(); + } + // TODO(nisse): At some places, code accepts a const ref EncodedImage, but + // still writes to it, to clear padding at the end of the encoded data. + // Padding is required by ffmpeg; the best way to deal with that is likely to + // make this class ensure that buffers always have a few zero padding bytes. + uint8_t* mutable_data() const { return const_cast<uint8_t*>(data()); } + + // TODO(bugs.webrtc.org/9378): Delete. Used by code that wants to modify a + // buffer corresponding to a const EncodedImage. Requires an un-owned buffer. + uint8_t* buffer() const { return buffer_; } + + // Hack to workaround lack of ownership of the encoded data. If we don't + // already own the underlying data, make an owned copy. + void Retain(); + uint32_t _encodedWidth = 0; uint32_t _encodedHeight = 0; // NTP time of the capture time in local timebase in milliseconds. int64_t ntp_time_ms_ = 0; int64_t capture_time_ms_ = 0; FrameType _frameType = kVideoFrameDelta; - uint8_t* _buffer; - size_t _length; - size_t _size; VideoRotation rotation_ = kVideoRotation_0; VideoContentType content_type_ = VideoContentType::UNSPECIFIED; bool _completeFrame = false; @@ -99,6 +139,14 @@ } timing_; private: + // TODO(bugs.webrtc.org/9378): We're transitioning to always owning the + // encoded data. + rtc::CopyOnWriteBuffer encoded_data_; + size_t size_; // Size of encoded frame data. + // Non-null when used with an un-owned buffer. + uint8_t* buffer_; + // Allocated size of _buffer; relevant only if it's non-null. + size_t capacity_; uint32_t timestamp_rtp_ = 0; absl::optional<int> spatial_index_; absl::optional<webrtc::ColorSpace> color_space_;
diff --git a/api/video/hdr_metadata.h b/api/video/hdr_metadata.h index 676a900..e9001a2 100644 --- a/api/video/hdr_metadata.h +++ b/api/video/hdr_metadata.h
@@ -11,27 +11,47 @@ #ifndef API_VIDEO_HDR_METADATA_H_ #define API_VIDEO_HDR_METADATA_H_ -#include <stdint.h> - namespace webrtc { // SMPTE ST 2086 mastering metadata, // see https://ieeexplore.ieee.org/document/8353899. struct HdrMasteringMetadata { struct Chromaticity { - // xy chromaticity coordinates must be calculated as specified in ISO - // 11664-3:2012 Section 7, and must be specified with four decimal places. - // The x coordinate must be in the range [0.0001, 0.7400] and the y - // coordinate must be in the range [0.0001, 0.8400]. - float x = 0.0f; - float y = 0.0f; + Chromaticity(); + bool operator==(const Chromaticity& rhs) const { return x == rhs.x && y == rhs.y; } - Chromaticity(); + bool Validate() const { + return x >= 0.0 && x <= 1.0 && y >= 0.0 && y <= 1.0; + } + + // xy chromaticity coordinates must be calculated as specified in ISO + // 11664-3:2012 Section 7, and must be specified with four decimal places. + // The x coordinate should be in the range [0.0001, 0.7400] and the y + // coordinate should be in the range [0.0001, 0.8400]. Valid range [0.0000, + // 1.0000]. + float x = 0.0f; + float y = 0.0f; }; + HdrMasteringMetadata(); + + bool operator==(const HdrMasteringMetadata& rhs) const { + return ((primary_r == rhs.primary_r) && (primary_g == rhs.primary_g) && + (primary_b == rhs.primary_b) && (white_point == rhs.white_point) && + (luminance_max == rhs.luminance_max) && + (luminance_min == rhs.luminance_min)); + } + + bool Validate() const { + return luminance_max >= 0.0 && luminance_max <= 20000.0 && + luminance_min >= 0.0 && luminance_min <= 5.0 && + primary_r.Validate() && primary_g.Validate() && + primary_b.Validate() && white_point.Validate(); + } + // The nominal primaries of the mastering display. Chromaticity primary_r; Chromaticity primary_g; @@ -41,37 +61,20 @@ Chromaticity white_point; // The nominal maximum display luminance of the mastering display. Specified - // in the unit candela/m2. The value must be in the range [5, 10000] with zero - // decimal places. + // in the unit candela/m2. The value should be in the range [5, 10000] with + // zero decimal places. Valid range [0, 20000]. float luminance_max = 0.0f; // The nominal minimum display luminance of the mastering display. Specified - // in the unit candela/m2. The value must be in the range [0.0001, 5.0000] - // with four decimal places. + // in the unit candela/m2. The value should be in the range [0.0001, 5.0000] + // with four decimal places. Valid range [0.0000, 5.0000]. float luminance_min = 0.0f; - - HdrMasteringMetadata(); - - bool operator==(const HdrMasteringMetadata& rhs) const { - return ((primary_r == rhs.primary_r) && (primary_g == rhs.primary_g) && - (primary_b == rhs.primary_b) && (white_point == rhs.white_point) && - (luminance_max == rhs.luminance_max) && - (luminance_min == rhs.luminance_min)); - } }; // High dynamic range (HDR) metadata common for HDR10 and WebM/VP9-based HDR // formats. This struct replicates the HDRMetadata struct defined in // https://cs.chromium.org/chromium/src/media/base/hdr_metadata.h struct HdrMetadata { - HdrMasteringMetadata mastering_metadata; - // Max content light level (CLL), i.e. maximum brightness level present in the - // stream, in nits. 1 nit = 1 candela/m2. - uint32_t max_content_light_level = 0; - // Max frame-average light level (FALL), i.e. maximum average brightness of - // the brightest frame in the stream, in nits. - uint32_t max_frame_average_light_level = 0; - HdrMetadata(); bool operator==(const HdrMetadata& rhs) const { @@ -80,6 +83,21 @@ (max_frame_average_light_level == rhs.max_frame_average_light_level) && (mastering_metadata == rhs.mastering_metadata)); } + + bool Validate() const { + return max_content_light_level >= 0 && max_content_light_level <= 20000 && + max_frame_average_light_level >= 0 && + max_frame_average_light_level <= 20000 && + mastering_metadata.Validate(); + } + + HdrMasteringMetadata mastering_metadata; + // Max content light level (CLL), i.e. maximum brightness level present in the + // stream, in nits. 1 nit = 1 candela/m2. Valid range [0, 20000]. + int max_content_light_level = 0; + // Max frame-average light level (FALL), i.e. maximum average brightness of + // the brightest frame in the stream, in nits. Valid range [0, 20000]. + int max_frame_average_light_level = 0; }; } // namespace webrtc
diff --git a/api/video/i010_buffer.cc b/api/video/i010_buffer.cc index adb5a5e..7286676 100644 --- a/api/video/i010_buffer.cc +++ b/api/video/i010_buffer.cc
@@ -9,14 +9,12 @@ */ #include "api/video/i010_buffer.h" -#include <algorithm> #include <utility> #include "api/video/i420_buffer.h" #include "rtc_base/checks.h" -#include "rtc_base/refcountedobject.h" +#include "rtc_base/ref_counted_object.h" #include "third_party/libyuv/include/libyuv/convert.h" -#include "third_party/libyuv/include/libyuv/planar_functions.h" #include "third_party/libyuv/include/libyuv/scale.h" // Aligning pointer to 64 bytes for improved performance, e.g. use SIMD. @@ -234,4 +232,35 @@ CropAndScaleFrom(src, 0, 0, src.width(), src.height()); } +void I010Buffer::PasteFrom(const I010BufferInterface& picture, + int offset_col, + int offset_row) { + RTC_CHECK_LE(picture.width() + offset_col, width()); + RTC_CHECK_LE(picture.height() + offset_row, height()); + RTC_CHECK_GE(offset_col, 0); + RTC_CHECK_GE(offset_row, 0); + + // Pasted picture has to be aligned so subsumpled UV plane isn't corrupted. + RTC_CHECK(offset_col % 2 == 0); + RTC_CHECK(offset_row % 2 == 0); + RTC_CHECK(picture.width() % 2 == 0 || + picture.width() + offset_col == width()); + RTC_CHECK(picture.height() % 2 == 0 || + picture.height() + offset_row == height()); + + libyuv::CopyPlane_16(picture.DataY(), picture.StrideY(), + MutableDataY() + StrideY() * offset_row + offset_col, + StrideY(), picture.width(), picture.height()); + + libyuv::CopyPlane_16( + picture.DataU(), picture.StrideU(), + MutableDataU() + StrideU() * offset_row / 2 + offset_col / 2, StrideU(), + picture.width() / 2, picture.height() / 2); + + libyuv::CopyPlane_16( + picture.DataV(), picture.StrideV(), + MutableDataV() + StrideV() * offset_row / 2 + offset_col / 2, StrideV(), + picture.width() / 2, picture.height() / 2); +} + } // namespace webrtc
diff --git a/api/video/i010_buffer.h b/api/video/i010_buffer.h index 1208b31..4b35ca3 100644 --- a/api/video/i010_buffer.h +++ b/api/video/i010_buffer.h
@@ -11,8 +11,10 @@ #ifndef API_VIDEO_I010_BUFFER_H_ #define API_VIDEO_I010_BUFFER_H_ +#include <stdint.h> #include <memory> +#include "api/scoped_refptr.h" #include "api/video/video_frame_buffer.h" #include "api/video/video_rotation.h" #include "rtc_base/memory/aligned_malloc.h" @@ -63,6 +65,12 @@ // Scale all of |src| to the size of |this| buffer, with no cropping. void ScaleFrom(const I010BufferInterface& src); + // Pastes whole picture to canvas at (offset_row, offset_col). + // Offsets and picture dimensions must be even. + void PasteFrom(const I010BufferInterface& picture, + int offset_col, + int offset_row); + protected: I010Buffer(int width, int height, int stride_y, int stride_u, int stride_v); ~I010Buffer() override;
diff --git a/api/video/i420_buffer.cc b/api/video/i420_buffer.cc index 8d239f3..46de581 100644 --- a/api/video/i420_buffer.cc +++ b/api/video/i420_buffer.cc
@@ -10,12 +10,11 @@ #include "api/video/i420_buffer.h" #include <string.h> - #include <algorithm> #include <utility> #include "rtc_base/checks.h" -#include "rtc_base/keep_ref_until_done.h" +#include "rtc_base/ref_counted_object.h" #include "third_party/libyuv/include/libyuv/convert.h" #include "third_party/libyuv/include/libyuv/planar_functions.h" #include "third_party/libyuv/include/libyuv/scale.h" @@ -227,4 +226,35 @@ CropAndScaleFrom(src, 0, 0, src.width(), src.height()); } +void I420Buffer::PasteFrom(const I420BufferInterface& picture, + int offset_col, + int offset_row) { + RTC_CHECK_LE(picture.width() + offset_col, width()); + RTC_CHECK_LE(picture.height() + offset_row, height()); + RTC_CHECK_GE(offset_col, 0); + RTC_CHECK_GE(offset_row, 0); + + // Pasted picture has to be aligned so subsumpled UV plane isn't corrupted. + RTC_CHECK(offset_col % 2 == 0); + RTC_CHECK(offset_row % 2 == 0); + RTC_CHECK(picture.width() % 2 == 0 || + picture.width() + offset_col == width()); + RTC_CHECK(picture.height() % 2 == 0 || + picture.height() + offset_row == height()); + + libyuv::CopyPlane(picture.DataY(), picture.StrideY(), + MutableDataY() + StrideY() * offset_row + offset_col, + StrideY(), picture.width(), picture.height()); + + libyuv::CopyPlane( + picture.DataU(), picture.StrideU(), + MutableDataU() + StrideU() * offset_row / 2 + offset_col / 2, StrideU(), + picture.width() / 2, picture.height() / 2); + + libyuv::CopyPlane( + picture.DataV(), picture.StrideV(), + MutableDataV() + StrideV() * offset_row / 2 + offset_col / 2, StrideV(), + picture.width() / 2, picture.height() / 2); +} + } // namespace webrtc
diff --git a/api/video/i420_buffer.h b/api/video/i420_buffer.h index 631e394..b76a507 100644 --- a/api/video/i420_buffer.h +++ b/api/video/i420_buffer.h
@@ -14,10 +14,10 @@ #include <stdint.h> #include <memory> +#include "api/scoped_refptr.h" #include "api/video/video_frame_buffer.h" #include "api/video/video_rotation.h" #include "rtc_base/memory/aligned_malloc.h" -#include "rtc_base/scoped_ref_ptr.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { @@ -97,6 +97,12 @@ // Scale all of |src| to the size of |this| buffer, with no cropping. void ScaleFrom(const I420BufferInterface& src); + // Pastes whole picture to canvas at (offset_row, offset_col). + // Offsets and picture dimensions must be even. + void PasteFrom(const I420BufferInterface& picture, + int offset_col, + int offset_row); + protected: I420Buffer(int width, int height); I420Buffer(int width, int height, int stride_y, int stride_u, int stride_v);
diff --git a/api/video/video_bitrate_allocation.h b/api/video/video_bitrate_allocation.h index d1771b4..ef64226 100644 --- a/api/video/video_bitrate_allocation.h +++ b/api/video/video_bitrate_allocation.h
@@ -18,14 +18,10 @@ #include <vector> #include "absl/types/optional.h" +#include "api/video/video_codec_constants.h" namespace webrtc { -// TODO(sprang): Move back to common_types when include of this is removed. -enum : int { kMaxSimulcastStreams = 4 }; -enum : int { kMaxSpatialLayers = 5 }; -enum : int { kMaxTemporalStreams = 4 }; - // Class that describes how video bitrate, in bps, is allocated across temporal // and spatial layers. Not that bitrates are NOT cumulative. Depending on if // layers are dependent or not, it is up to the user to aggregate.
diff --git a/api/video/video_codec_constants.h b/api/video/video_codec_constants.h new file mode 100644 index 0000000..a3f7cd2 --- /dev/null +++ b/api/video/video_codec_constants.h
@@ -0,0 +1,22 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_VIDEO_VIDEO_CODEC_CONSTANTS_H_ +#define API_VIDEO_VIDEO_CODEC_CONSTANTS_H_ + +namespace webrtc { + +enum : int { kMaxSimulcastStreams = 4 }; +enum : int { kMaxSpatialLayers = 5 }; +enum : int { kMaxTemporalStreams = 4 }; + +} // namespace webrtc + +#endif // API_VIDEO_VIDEO_CODEC_CONSTANTS_H_
diff --git a/api/video/video_codec_type.h b/api/video/video_codec_type.h index 447723c..2e406c0 100644 --- a/api/video/video_codec_type.h +++ b/api/video/video_codec_type.h
@@ -21,7 +21,6 @@ kVideoCodecVP8, kVideoCodecVP9, kVideoCodecH264, - kVideoCodecI420, kVideoCodecMultiplex, };
diff --git a/api/video/video_frame.cc b/api/video/video_frame.cc index eaae33b..7a71f43 100644 --- a/api/video/video_frame.cc +++ b/api/video/video_frame.cc
@@ -10,18 +10,63 @@ #include "api/video/video_frame.h" +#include <algorithm> + #include "rtc_base/checks.h" -#include "rtc_base/timeutils.h" +#include "rtc_base/time_utils.h" namespace webrtc { +void VideoFrame::UpdateRect::Union(const UpdateRect& other) { + if (other.IsEmpty()) + return; + if (IsEmpty()) { + *this = other; + return; + } + int right = std::max(offset_x + width, other.offset_x + other.width); + int bottom = std::max(offset_y + height, other.offset_y + other.height); + offset_x = std::min(offset_x, other.offset_x); + offset_y = std::min(offset_y, other.offset_y); + width = right - offset_x; + height = bottom - offset_y; + RTC_DCHECK_GT(width, 0); + RTC_DCHECK_GT(height, 0); +} + +void VideoFrame::UpdateRect::Intersect(const UpdateRect& other) { + if (other.IsEmpty() || IsEmpty()) { + MakeEmptyUpdate(); + return; + } + + int right = std::min(offset_x + width, other.offset_x + other.width); + int bottom = std::min(offset_y + height, other.offset_y + other.height); + offset_x = std::max(offset_x, other.offset_x); + offset_y = std::max(offset_y, other.offset_y); + width = right - offset_x; + height = bottom - offset_y; + if (width <= 0 || height <= 0) { + MakeEmptyUpdate(); + } +} + +void VideoFrame::UpdateRect::MakeEmptyUpdate() { + width = height = offset_x = offset_y = 0; +} + +bool VideoFrame::UpdateRect::IsEmpty() const { + return width == 0 && height == 0; +} + VideoFrame::Builder::Builder() = default; VideoFrame::Builder::~Builder() = default; VideoFrame VideoFrame::Builder::build() { - return VideoFrame(video_frame_buffer_, timestamp_us_, timestamp_rtp_, - ntp_time_ms_, rotation_, color_space_); + RTC_CHECK(video_frame_buffer_ != nullptr); + return VideoFrame(id_, video_frame_buffer_, timestamp_us_, timestamp_rtp_, + ntp_time_ms_, rotation_, color_space_, update_rect_); } VideoFrame::Builder& VideoFrame::Builder::set_video_frame_buffer( @@ -59,7 +104,7 @@ } VideoFrame::Builder& VideoFrame::Builder::set_color_space( - const ColorSpace& color_space) { + const absl::optional<ColorSpace>& color_space) { color_space_ = color_space; return *this; } @@ -71,6 +116,17 @@ return *this; } +VideoFrame::Builder& VideoFrame::Builder::set_id(uint16_t id) { + id_ = id; + return *this; +} + +VideoFrame::Builder& VideoFrame::Builder::set_update_rect( + const VideoFrame::UpdateRect& update_rect) { + update_rect_ = update_rect; + return *this; +} + VideoFrame::VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer, webrtc::VideoRotation rotation, int64_t timestamp_us) @@ -78,7 +134,8 @@ timestamp_rtp_(0), ntp_time_ms_(0), timestamp_us_(timestamp_us), - rotation_(rotation) {} + rotation_(rotation), + update_rect_{0, 0, buffer->width(), buffer->height()} {} VideoFrame::VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer, uint32_t timestamp_rtp, @@ -88,22 +145,33 @@ timestamp_rtp_(timestamp_rtp), ntp_time_ms_(0), timestamp_us_(render_time_ms * rtc::kNumMicrosecsPerMillisec), - rotation_(rotation) { + rotation_(rotation), + update_rect_{0, 0, buffer->width(), buffer->height()} { RTC_DCHECK(buffer); } -VideoFrame::VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer, +VideoFrame::VideoFrame(uint16_t id, + const rtc::scoped_refptr<VideoFrameBuffer>& buffer, int64_t timestamp_us, uint32_t timestamp_rtp, int64_t ntp_time_ms, VideoRotation rotation, - const absl::optional<ColorSpace>& color_space) - : video_frame_buffer_(buffer), + const absl::optional<ColorSpace>& color_space, + const absl::optional<UpdateRect>& update_rect) + : id_(id), + video_frame_buffer_(buffer), timestamp_rtp_(timestamp_rtp), ntp_time_ms_(ntp_time_ms), timestamp_us_(timestamp_us), rotation_(rotation), - color_space_(color_space) {} + color_space_(color_space), + update_rect_(update_rect.value_or(UpdateRect{ + 0, 0, video_frame_buffer_->width(), video_frame_buffer_->height()})) { + RTC_DCHECK_GE(update_rect_.offset_x, 0); + RTC_DCHECK_GE(update_rect_.offset_y, 0); + RTC_DCHECK_LE(update_rect_.offset_x + update_rect_.width, width()); + RTC_DCHECK_LE(update_rect_.offset_y + update_rect_.height, height()); +} VideoFrame::~VideoFrame() = default;
diff --git a/api/video/video_frame.h b/api/video/video_frame.h index 2c5d081..c7dd02a 100644 --- a/api/video/video_frame.h +++ b/api/video/video_frame.h
@@ -14,17 +14,36 @@ #include <stdint.h> #include "absl/types/optional.h" +#include "api/scoped_refptr.h" #include "api/video/color_space.h" #include "api/video/hdr_metadata.h" #include "api/video/video_frame_buffer.h" #include "api/video/video_rotation.h" -#include "rtc_base/scoped_ref_ptr.h" +#include "rtc_base/checks.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { class RTC_EXPORT VideoFrame { public: + struct UpdateRect { + int offset_x; + int offset_y; + int width; + int height; + + // Makes this UpdateRect a bounding box of this and other rect. + void Union(const UpdateRect& other); + + // Makes this UpdateRect an intersection of this and other rect. + void Intersect(const UpdateRect& other); + + // Sets everything to 0, making this UpdateRect a zero-size (empty) update. + void MakeEmptyUpdate(); + + bool IsEmpty() const; + }; + // Preferred way of building VideoFrame objects. class Builder { public: @@ -39,16 +58,20 @@ Builder& set_timestamp_rtp(uint32_t timestamp_rtp); Builder& set_ntp_time_ms(int64_t ntp_time_ms); Builder& set_rotation(VideoRotation rotation); - Builder& set_color_space(const ColorSpace& color_space); + Builder& set_color_space(const absl::optional<ColorSpace>& color_space); Builder& set_color_space(const ColorSpace* color_space); + Builder& set_id(uint16_t id); + Builder& set_update_rect(const UpdateRect& update_rect); private: + uint16_t id_ = 0; rtc::scoped_refptr<webrtc::VideoFrameBuffer> video_frame_buffer_; int64_t timestamp_us_ = 0; uint32_t timestamp_rtp_ = 0; int64_t ntp_time_ms_ = 0; VideoRotation rotation_ = kVideoRotation_0; absl::optional<ColorSpace> color_space_; + absl::optional<UpdateRect> update_rect_; }; // To be deprecated. Migrate all use to Builder. @@ -75,6 +98,15 @@ // Get frame size in pixels. uint32_t size() const; + // Get frame ID. Returns 0 if ID is not set. Not guarantee to be transferred + // from the sender to the receiver, but preserved on single side. The id + // should be propagated between all frame modifications during its lifetime + // from capturing to sending as encoded image. It is intended to be unique + // over a time window of a few minutes for peer connection, to which + // corresponding video stream belongs to. + uint16_t id() const { return id_; } + void set_id(uint16_t id) { id_ = id; } + // System monotonic clock, same timebase as rtc::TimeMicros(). int64_t timestamp_us() const { return timestamp_us_; } void set_timestamp_us(int64_t timestamp_us) { timestamp_us_ = timestamp_us; } @@ -115,8 +147,9 @@ void set_rotation(VideoRotation rotation) { rotation_ = rotation; } // Get color space when available. - const ColorSpace* color_space() const { - return color_space_ ? &*color_space_ : nullptr; + const absl::optional<ColorSpace>& color_space() const { return color_space_; } + void set_color_space(const absl::optional<ColorSpace>& color_space) { + color_space_ = color_space; } // Get render time in milliseconds. @@ -133,14 +166,29 @@ return video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative; } + // Always initialized to whole frame update, can be set by Builder or manually + // by |set_update_rect|. + UpdateRect update_rect() const { return update_rect_; } + // Rectangle must be within the frame dimensions. + void set_update_rect(const VideoFrame::UpdateRect& update_rect) { + RTC_DCHECK_GE(update_rect.offset_x, 0); + RTC_DCHECK_GE(update_rect.offset_y, 0); + RTC_DCHECK_LE(update_rect.offset_x + update_rect.width, width()); + RTC_DCHECK_LE(update_rect.offset_y + update_rect.height, height()); + update_rect_ = update_rect; + } + private: - VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer, + VideoFrame(uint16_t id, + const rtc::scoped_refptr<VideoFrameBuffer>& buffer, int64_t timestamp_us, uint32_t timestamp_rtp, int64_t ntp_time_ms, VideoRotation rotation, - const absl::optional<ColorSpace>& color_space); + const absl::optional<ColorSpace>& color_space, + const absl::optional<UpdateRect>& update_rect); + uint16_t id_; // An opaque reference counted handle that stores the pixel data. rtc::scoped_refptr<webrtc::VideoFrameBuffer> video_frame_buffer_; uint32_t timestamp_rtp_; @@ -148,6 +196,9 @@ int64_t timestamp_us_; VideoRotation rotation_; absl::optional<ColorSpace> color_space_; + // Updated since the last frame area. Unless set explicitly, will always be + // a full frame rectangle. + UpdateRect update_rect_; }; } // namespace webrtc
diff --git a/api/video/video_frame_buffer.h b/api/video/video_frame_buffer.h index 1e8169a..7fb603e 100644 --- a/api/video/video_frame_buffer.h +++ b/api/video/video_frame_buffer.h
@@ -13,8 +13,8 @@ #include <stdint.h> -#include "rtc_base/refcount.h" -#include "rtc_base/scoped_ref_ptr.h" +#include "api/scoped_refptr.h" +#include "rtc_base/ref_count.h" namespace webrtc {
diff --git a/api/video/video_source_interface.h b/api/video/video_source_interface.h index 2bf7370..9d1641c 100644 --- a/api/video/video_source_interface.h +++ b/api/video/video_source_interface.h
@@ -47,15 +47,13 @@ template <typename VideoFrameT> class VideoSourceInterface { public: + virtual ~VideoSourceInterface() = default; + virtual void AddOrUpdateSink(VideoSinkInterface<VideoFrameT>* sink, const VideoSinkWants& wants) = 0; // RemoveSink must guarantee that at the time the method returns, // there is no current and no future calls to VideoSinkInterface::OnFrame. virtual void RemoveSink(VideoSinkInterface<VideoFrameT>* sink) = 0; - - protected: - // Non-public, since one shouldn't own sources via this interface. - virtual ~VideoSourceInterface() {} }; } // namespace rtc
diff --git a/api/video/video_stream_encoder_create.cc b/api/video/video_stream_encoder_create.cc index 3147d34..875edd9 100644 --- a/api/video/video_stream_encoder_create.cc +++ b/api/video/video_stream_encoder_create.cc
@@ -11,17 +11,30 @@ #include "api/video/video_stream_encoder_create.h" #include "absl/memory/memory.h" +#include "api/task_queue/global_task_queue_factory.h" +#include "video/overuse_frame_detector.h" #include "video/video_stream_encoder.h" namespace webrtc { std::unique_ptr<VideoStreamEncoderInterface> CreateVideoStreamEncoder( uint32_t number_of_cores, VideoStreamEncoderObserver* encoder_stats_observer, - const VideoStreamEncoderSettings& settings, - // Deprecated, used for tests only. - rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback) { - return absl::make_unique<VideoStreamEncoder>( - number_of_cores, encoder_stats_observer, settings, pre_encode_callback, - absl::make_unique<OveruseFrameDetector>(encoder_stats_observer)); + const VideoStreamEncoderSettings& settings) { + return CreateVideoStreamEncoder(Clock::GetRealTimeClock(), + &GlobalTaskQueueFactory(), number_of_cores, + encoder_stats_observer, settings); } + +std::unique_ptr<VideoStreamEncoderInterface> CreateVideoStreamEncoder( + Clock* clock, + TaskQueueFactory* task_queue_factory, + uint32_t number_of_cores, + VideoStreamEncoderObserver* encoder_stats_observer, + const VideoStreamEncoderSettings& settings) { + return absl::make_unique<VideoStreamEncoder>( + clock, number_of_cores, encoder_stats_observer, settings, + absl::make_unique<OveruseFrameDetector>(encoder_stats_observer), + task_queue_factory); +} + } // namespace webrtc
diff --git a/api/video/video_stream_encoder_create.h b/api/video/video_stream_encoder_create.h index 9117273..4241626 100644 --- a/api/video/video_stream_encoder_create.h +++ b/api/video/video_stream_encoder_create.h
@@ -11,31 +11,31 @@ #ifndef API_VIDEO_VIDEO_STREAM_ENCODER_CREATE_H_ #define API_VIDEO_VIDEO_STREAM_ENCODER_CREATE_H_ -#include <map> +#include <stdint.h> #include <memory> -#include <utility> +#include "api/task_queue/task_queue_factory.h" +#include "api/video/video_frame.h" +#include "api/video/video_sink_interface.h" #include "api/video/video_stream_encoder_interface.h" #include "api/video/video_stream_encoder_observer.h" #include "api/video/video_stream_encoder_settings.h" namespace webrtc { +// TODO(srte): Find a way to avoid this forward declaration. +class Clock; std::unique_ptr<VideoStreamEncoderInterface> CreateVideoStreamEncoder( uint32_t number_of_cores, VideoStreamEncoderObserver* encoder_stats_observer, - const VideoStreamEncoderSettings& settings, - // Deprecated, used for tests only. - rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback); + const VideoStreamEncoderSettings& settings); -inline std::unique_ptr<VideoStreamEncoderInterface> CreateVideoStreamEncoder( +std::unique_ptr<VideoStreamEncoderInterface> CreateVideoStreamEncoder( + Clock* clock, + TaskQueueFactory* task_queue_factory, uint32_t number_of_cores, VideoStreamEncoderObserver* encoder_stats_observer, - const VideoStreamEncoderSettings& settings) { - return CreateVideoStreamEncoder(number_of_cores, encoder_stats_observer, - settings, nullptr); -} - + const VideoStreamEncoderSettings& settings); } // namespace webrtc #endif // API_VIDEO_VIDEO_STREAM_ENCODER_CREATE_H_
diff --git a/api/video/video_stream_encoder_interface.h b/api/video/video_stream_encoder_interface.h index 2f95e58..7181143 100644 --- a/api/video/video_stream_encoder_interface.h +++ b/api/video/video_stream_encoder_interface.h
@@ -13,7 +13,8 @@ #include <vector> -#include "api/rtpparameters.h" // For DegradationPreference. +#include "api/rtp_parameters.h" // For DegradationPreference. +#include "api/video/video_bitrate_allocator.h" #include "api/video/video_sink_interface.h" #include "api/video/video_source_interface.h" #include "api/video_codecs/video_encoder.h" @@ -21,9 +22,6 @@ namespace webrtc { -// TODO(nisse): Move full declaration to api/. -class VideoBitrateAllocationObserver; - // This interface represents a class responsible for creating and driving the // encoder(s) for a single video stream. It is also responsible for adaptation // decisions related to video quality, requesting reduced frame rate or @@ -44,6 +42,7 @@ public: virtual void OnEncoderConfigurationChanged( std::vector<VideoStream> streams, + VideoEncoderConfig::ContentType content_type, int min_transmit_bitrate_bps) = 0; };
diff --git a/api/video/video_timing.cc b/api/video/video_timing.cc index 40de011..df1bc48 100644 --- a/api/video/video_timing.cc +++ b/api/video/video_timing.cc
@@ -10,10 +10,21 @@ #include "api/video/video_timing.h" +#include "api/array_view.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/strings/string_builder.h" namespace webrtc { +uint16_t VideoSendTiming::GetDeltaCappedMs(int64_t base_ms, int64_t time_ms) { + if (time_ms < base_ms) { + RTC_DLOG(LS_ERROR) << "Delta " << (time_ms - base_ms) + << "ms expected to be positive"; + } + return rtc::saturated_cast<uint16_t>(time_ms - base_ms); +} + TimingFrameInfo::TimingFrameInfo() : rtp_timestamp(0), capture_time_ms(-1),
diff --git a/api/video/video_timing.h b/api/video/video_timing.h index e787a45..745afbc 100644 --- a/api/video/video_timing.h +++ b/api/video/video_timing.h
@@ -16,9 +16,6 @@ #include <limits> #include <string> -#include "rtc_base/checks.h" -#include "rtc_base/numerics/safe_conversions.h" - namespace webrtc { // Video timing timestamps in ms counted from capture_time_ms of a frame. @@ -46,10 +43,7 @@ // Used to fill this data structure as per // https://webrtc.org/experiments/rtp-hdrext/video-timing/ extension stores // 16-bit deltas of timestamps from packet capture time. - static uint16_t GetDeltaCappedMs(int64_t base_ms, int64_t time_ms) { - RTC_DCHECK_GE(time_ms, base_ms); - return rtc::saturated_cast<uint16_t>(time_ms - base_ms); - } + static uint16_t GetDeltaCappedMs(int64_t base_ms, int64_t time_ms); uint16_t encode_start_delta_ms; uint16_t encode_finish_delta_ms;
diff --git a/api/video_track_source_proxy.h b/api/video_track_source_proxy.h new file mode 100644 index 0000000..eb11bef --- /dev/null +++ b/api/video_track_source_proxy.h
@@ -0,0 +1,43 @@ +/* + * Copyright 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef API_VIDEO_TRACK_SOURCE_PROXY_H_ +#define API_VIDEO_TRACK_SOURCE_PROXY_H_ + +#include "api/media_stream_interface.h" +#include "api/proxy.h" + +namespace webrtc { + +// Makes sure the real VideoTrackSourceInterface implementation is destroyed on +// the signaling thread and marshals all method calls to the signaling thread. +// TODO(deadbeef): Move this to .cc file and out of api/. What threads methods +// are called on is an implementation detail. +BEGIN_PROXY_MAP(VideoTrackSource) +PROXY_SIGNALING_THREAD_DESTRUCTOR() +PROXY_CONSTMETHOD0(SourceState, state) +PROXY_CONSTMETHOD0(bool, remote) +PROXY_CONSTMETHOD0(bool, is_screencast) +PROXY_CONSTMETHOD0(absl::optional<bool>, needs_denoising) +PROXY_METHOD1(bool, GetStats, Stats*) +PROXY_WORKER_METHOD2(void, + AddOrUpdateSink, + rtc::VideoSinkInterface<VideoFrame>*, + const rtc::VideoSinkWants&) +PROXY_WORKER_METHOD1(void, RemoveSink, rtc::VideoSinkInterface<VideoFrame>*) +PROXY_WORKER_METHOD1(void, SetLatency, double) +PROXY_WORKER_CONSTMETHOD0(double, GetLatency) +PROXY_METHOD1(void, RegisterObserver, ObserverInterface*) +PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*) +END_PROXY_MAP() + +} // namespace webrtc + +#endif // API_VIDEO_TRACK_SOURCE_PROXY_H_
diff --git a/audio/BUILD.gn b/audio/BUILD.gn index c045af6..3a1d123 100644 --- a/audio/BUILD.gn +++ b/audio/BUILD.gn
@@ -37,15 +37,11 @@ "transport_feedback_packet_loss_tracker.h", ] - if (!build_with_chromium && is_clang) { - # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). - suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] - } - deps = [ "../api:array_view", "../api:call_api", "../api:libjingle_peerconnection_api", + "../api:scoped_refptr", "../api:transport_api", "../api/audio:aec3_factory", "../api/audio:audio_frame_api", @@ -61,7 +57,6 @@ "../logging:rtc_stream_config", "../modules/audio_coding", "../modules/audio_coding:audio_encoder_cng", - "../modules/audio_coding:audio_format_conversion", "../modules/audio_coding:audio_network_adaptor_config", "../modules/audio_device", "../modules/audio_processing", @@ -79,7 +74,7 @@ "../rtc_base:rtc_base_approved", "../rtc_base:rtc_task_queue", "../rtc_base:safe_minmax", - "../rtc_base:stringutils", + "../rtc_base/experiments:audio_allocation_settings", "../system_wrappers", "../system_wrappers:field_trial", "../system_wrappers:metrics", @@ -104,12 +99,8 @@ "../system_wrappers:system_wrappers", "../test:test_common", "../test:test_support", + "//third_party/abseil-cpp/absl/memory", ] - - if (!build_with_chromium && is_clang) { - # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). - suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] - } } rtc_source_set("audio_tests") { @@ -148,6 +139,7 @@ "../logging:rtc_event_log_api", "../modules/audio_device:mock_audio_device", "../rtc_base:rtc_base_tests_utils", + "../test:field_trial", # For TestAudioDeviceModule "../modules/audio_device:audio_device_impl", @@ -163,6 +155,7 @@ "../rtc_base:rtc_base_approved", "../rtc_base:rtc_task_queue", "../rtc_base:safe_compare", + "../rtc_base:timeutils", "../system_wrappers:system_wrappers", "../test:audio_codec_mocks", "../test:rtp_test_utils", @@ -172,11 +165,6 @@ "//testing/gtest", "//third_party/abseil-cpp/absl/memory", ] - - if (!build_with_chromium && is_clang) { - # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). - suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] - } } if (rtc_enable_protobuf) { @@ -206,11 +194,6 @@ "../resources/voice_engine/audio_tiny16.wav", "../resources/voice_engine/audio_tiny48.wav", ] - - if (!build_with_chromium && is_clang) { - # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163) - suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] - } } group("low_bandwidth_audio_perf_test") { @@ -280,10 +263,5 @@ data = [ "//resources/voice_engine/audio_dtx16.wav", ] - - if (!build_with_chromium && is_clang) { - # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). - suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] - } } }
diff --git a/audio/audio_level.h b/audio/audio_level.h index 3bbe5fd..bb04cc0 100644 --- a/audio/audio_level.h +++ b/audio/audio_level.h
@@ -11,7 +11,7 @@ #ifndef AUDIO_AUDIO_LEVEL_H_ #define AUDIO_AUDIO_LEVEL_H_ -#include "rtc_base/criticalsection.h" +#include "rtc_base/critical_section.h" #include "rtc_base/thread_annotations.h" namespace webrtc {
diff --git a/audio/audio_receive_stream.cc b/audio/audio_receive_stream.cc index 8d4afe0..b7b68d0 100644 --- a/audio/audio_receive_stream.cc +++ b/audio/audio_receive_stream.cc
@@ -17,7 +17,7 @@ #include "api/array_view.h" #include "api/audio_codecs/audio_format.h" #include "api/call/audio_sink.h" -#include "api/rtpparameters.h" +#include "api/rtp_parameters.h" #include "audio/audio_send_stream.h" #include "audio/audio_state.h" #include "audio/channel_receive.h" @@ -27,7 +27,7 @@ #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/strings/string_builder.h" -#include "rtc_base/timeutils.h" +#include "rtc_base/time_utils.h" namespace webrtc { @@ -67,6 +67,7 @@ namespace internal { namespace { std::unique_ptr<voe::ChannelReceiveInterface> CreateChannelReceive( + Clock* clock, webrtc::AudioState* audio_state, ProcessThread* module_process_thread, const webrtc::AudioReceiveStream::Config& config, @@ -75,33 +76,37 @@ internal::AudioState* internal_audio_state = static_cast<internal::AudioState*>(audio_state); return voe::CreateChannelReceive( - module_process_thread, internal_audio_state->audio_device_module(), + clock, module_process_thread, internal_audio_state->audio_device_module(), config.media_transport, config.rtcp_send_transport, event_log, config.rtp.remote_ssrc, config.jitter_buffer_max_packets, config.jitter_buffer_fast_accelerate, config.jitter_buffer_min_delay_ms, - config.decoder_factory, config.codec_pair_id, config.frame_decryptor, - config.crypto_options); + config.jitter_buffer_enable_rtx_handling, config.decoder_factory, + config.codec_pair_id, config.frame_decryptor, config.crypto_options); } } // namespace AudioReceiveStream::AudioReceiveStream( + Clock* clock, RtpStreamReceiverControllerInterface* receiver_controller, PacketRouter* packet_router, ProcessThread* module_process_thread, const webrtc::AudioReceiveStream::Config& config, const rtc::scoped_refptr<webrtc::AudioState>& audio_state, webrtc::RtcEventLog* event_log) - : AudioReceiveStream(receiver_controller, + : AudioReceiveStream(clock, + receiver_controller, packet_router, config, audio_state, event_log, - CreateChannelReceive(audio_state.get(), + CreateChannelReceive(clock, + audio_state.get(), module_process_thread, config, event_log)) {} AudioReceiveStream::AudioReceiveStream( + Clock* clock, RtpStreamReceiverControllerInterface* receiver_controller, PacketRouter* packet_router, const webrtc::AudioReceiveStream::Config& config, @@ -175,8 +180,8 @@ channel_receive_->GetRTCPStatistics(); // TODO(solenberg): Don't return here if we can't get the codec - return the // stats we *can* get. - webrtc::CodecInst codec_inst = {0}; - if (!channel_receive_->GetRecCodec(&codec_inst)) { + auto receive_codec = channel_receive_->GetReceiveCodec(); + if (!receive_codec) { return stats; } @@ -185,13 +190,12 @@ stats.packets_lost = call_stats.cumulativeLost; stats.fraction_lost = Q8ToFloat(call_stats.fractionLost); stats.capture_start_ntp_time_ms = call_stats.capture_start_ntp_time_ms_; - if (codec_inst.pltype != -1) { - stats.codec_name = codec_inst.plname; - stats.codec_payload_type = codec_inst.pltype; - } + stats.codec_name = receive_codec->second.name; + stats.codec_payload_type = receive_codec->first; stats.ext_seqnum = call_stats.extendedMax; - if (codec_inst.plfreq / 1000 > 0) { - stats.jitter_ms = call_stats.jitterSamples / (codec_inst.plfreq / 1000); + int clockrate_khz = receive_codec->second.clockrate_hz / 1000; + if (clockrate_khz > 0) { + stats.jitter_ms = call_stats.jitterSamples / clockrate_khz; } stats.delay_estimate_ms = channel_receive_->GetDelayEstimate(); stats.audio_level = channel_receive_->GetSpeechOutputLevelFullRange(); @@ -208,6 +212,7 @@ stats.jitter_buffer_delay_seconds = static_cast<double>(ns.jitterBufferDelayMs) / static_cast<double>(rtc::kNumMillisecsPerSec); + stats.jitter_buffer_emitted_count = ns.jitterBufferEmittedCount; stats.expand_rate = Q14ToFloat(ns.currentExpandRate); stats.speech_expand_rate = Q14ToFloat(ns.currentSpeechExpandRate); stats.secondary_decoded_rate = Q14ToFloat(ns.currentSecondaryDecodedRate); @@ -216,6 +221,9 @@ stats.preemptive_expand_rate = Q14ToFloat(ns.currentPreemptiveRate); stats.jitter_buffer_flushes = ns.packetBufferFlushes; stats.delayed_packet_outage_samples = ns.delayedPacketOutageSamples; + stats.relative_packet_arrival_delay_seconds = + static_cast<double>(ns.relativePacketArrivalDelayMs) / + static_cast<double>(rtc::kNumMillisecsPerSec); auto ds = channel_receive_->GetDecodingCallStatistics(); stats.decoding_calls_to_silence_generator = ds.calls_to_silence_generator; @@ -239,6 +247,16 @@ channel_receive_->SetChannelOutputVolumeScaling(gain); } +bool AudioReceiveStream::SetBaseMinimumPlayoutDelayMs(int delay_ms) { + RTC_DCHECK_RUN_ON(&worker_thread_checker_); + return channel_receive_->SetBaseMinimumPlayoutDelayMs(delay_ms); +} + +int AudioReceiveStream::GetBaseMinimumPlayoutDelayMs() const { + RTC_DCHECK_RUN_ON(&worker_thread_checker_); + return channel_receive_->GetBaseMinimumPlayoutDelayMs(); +} + std::vector<RtpSource> AudioReceiveStream::GetSources() const { RTC_DCHECK_RUN_ON(&worker_thread_checker_); return channel_receive_->GetSources();
diff --git a/audio/audio_receive_stream.h b/audio/audio_receive_stream.h index 86bcb1c..1745c0f 100644 --- a/audio/audio_receive_stream.h +++ b/audio/audio_receive_stream.h
@@ -19,8 +19,9 @@ #include "audio/audio_state.h" #include "call/audio_receive_stream.h" #include "call/syncable.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" #include "rtc_base/thread_checker.h" +#include "system_wrappers/include/clock.h" namespace webrtc { class PacketRouter; @@ -41,7 +42,8 @@ public AudioMixer::Source, public Syncable { public: - AudioReceiveStream(RtpStreamReceiverControllerInterface* receiver_controller, + AudioReceiveStream(Clock* clock, + RtpStreamReceiverControllerInterface* receiver_controller, PacketRouter* packet_router, ProcessThread* module_process_thread, const webrtc::AudioReceiveStream::Config& config, @@ -49,6 +51,7 @@ webrtc::RtcEventLog* event_log); // For unit tests, which need to supply a mock channel receive. AudioReceiveStream( + Clock* clock, RtpStreamReceiverControllerInterface* receiver_controller, PacketRouter* packet_router, const webrtc::AudioReceiveStream::Config& config, @@ -64,6 +67,8 @@ webrtc::AudioReceiveStream::Stats GetStats() const override; void SetSink(AudioSinkInterface* sink) override; void SetGain(float gain) override; + bool SetBaseMinimumPlayoutDelayMs(int delay_ms) override; + int GetBaseMinimumPlayoutDelayMs() const override; std::vector<webrtc::RtpSource> GetSources() const override; // TODO(nisse): We don't formally implement RtpPacketSinkInterface, and this
diff --git a/audio/audio_receive_stream_unittest.cc b/audio/audio_receive_stream_unittest.cc index 7422810..4594e56 100644 --- a/audio/audio_receive_stream_unittest.cc +++ b/audio/audio_receive_stream_unittest.cc
@@ -10,6 +10,7 @@ #include <map> #include <string> +#include <utility> #include <vector> #include "api/test/mock_audio_mixer.h" @@ -24,6 +25,7 @@ #include "modules/bitrate_controller/include/mock/mock_bitrate_controller.h" #include "modules/pacing/packet_router.h" #include "modules/rtp_rtcp/source/byte_io.h" +#include "rtc_base/time_utils.h" #include "test/gtest.h" #include "test/mock_audio_decoder_factory.h" #include "test/mock_transport.h" @@ -63,10 +65,11 @@ const CallReceiveStatistics kCallStats = {345, 678, 901, 234, -12, 567, 890, 123}; -const CodecInst kCodecInst = {123, "codec_name_recv", 96000, -187, 0, -103}; +const std::pair<int, SdpAudioFormat> kReceiveCodec = + {123, {"codec_name_recv", 96000, 0}}; const NetworkStatistics kNetworkStats = { - 123, 456, false, 789012, 3456, 123, 456, 0, {}, 789, 12, - 345, 678, 901, 0, -1, -1, -1, -1, -1, 0}; + 123, 456, false, 789012, 3456, 123, 456, 789, 0, {}, 789, + 12, 345, 678, 901, 0, -1, -1, -1, -1, -1, 0}; const AudioDecodingCallStats kAudioDecodeStats = MakeAudioDecodeStatsForTest(); struct ConfigHelper { @@ -112,8 +115,8 @@ std::unique_ptr<internal::AudioReceiveStream> CreateAudioReceiveStream() { return std::unique_ptr<internal::AudioReceiveStream>( new internal::AudioReceiveStream( - &rtp_stream_receiver_controller_, &packet_router_, stream_config_, - audio_state_, &event_log_, + Clock::GetRealTimeClock(), &rtp_stream_receiver_controller_, + &packet_router_, stream_config_, audio_state_, &event_log_, std::unique_ptr<voe::ChannelReceiveInterface>(channel_receive_))); } @@ -140,8 +143,8 @@ .WillOnce(Return(kNetworkStats)); EXPECT_CALL(*channel_receive_, GetDecodingCallStatistics()) .WillOnce(Return(kAudioDecodeStats)); - EXPECT_CALL(*channel_receive_, GetRecCodec(_)) - .WillOnce(DoAll(SetArgPointee<0>(kCodecInst), Return(true))); + EXPECT_CALL(*channel_receive_, GetReceiveCodec()) + .WillOnce(Return(kReceiveCodec)); } private: @@ -267,10 +270,11 @@ stats.packets_rcvd); EXPECT_EQ(kCallStats.cumulativeLost, stats.packets_lost); EXPECT_EQ(Q8ToFloat(kCallStats.fractionLost), stats.fraction_lost); - EXPECT_EQ(std::string(kCodecInst.plname), stats.codec_name); + EXPECT_EQ(kReceiveCodec.second.name, stats.codec_name); EXPECT_EQ(kCallStats.extendedMax, stats.ext_seqnum); - EXPECT_EQ(kCallStats.jitterSamples / (kCodecInst.plfreq / 1000), - stats.jitter_ms); + EXPECT_EQ( + kCallStats.jitterSamples / (kReceiveCodec.second.clockrate_hz / 1000), + stats.jitter_ms); EXPECT_EQ(kNetworkStats.currentBufferSize, stats.jitter_buffer_ms); EXPECT_EQ(kNetworkStats.preferredBufferSize, stats.jitter_buffer_preferred_ms); @@ -285,6 +289,8 @@ EXPECT_EQ(static_cast<double>(kNetworkStats.jitterBufferDelayMs) / static_cast<double>(rtc::kNumMillisecsPerSec), stats.jitter_buffer_delay_seconds); + EXPECT_EQ(kNetworkStats.jitterBufferEmittedCount, + stats.jitter_buffer_emitted_count); EXPECT_EQ(Q14ToFloat(kNetworkStats.currentExpandRate), stats.expand_rate); EXPECT_EQ(Q14ToFloat(kNetworkStats.currentSpeechExpandRate), stats.speech_expand_rate);
diff --git a/audio/audio_send_stream.cc b/audio/audio_send_stream.cc index 75e6efb..bb79149 100644 --- a/audio/audio_send_stream.cc +++ b/audio/audio_send_stream.cc
@@ -19,7 +19,7 @@ #include "api/audio_codecs/audio_encoder_factory.h" #include "api/audio_codecs/audio_format.h" #include "api/call/transport.h" -#include "api/crypto/frameencryptorinterface.h" +#include "api/crypto/frame_encryptor_interface.h" #include "audio/audio_state.h" #include "audio/channel_send.h" #include "audio/conversion.h" @@ -37,7 +37,6 @@ #include "rtc_base/logging.h" #include "rtc_base/strings/audio_format_to_string.h" #include "rtc_base/task_queue.h" -#include "rtc_base/timeutils.h" #include "system_wrappers/include/field_trial.h" namespace webrtc { @@ -48,14 +47,6 @@ constexpr size_t kPacketLossRateMinNumAckedPackets = 50; constexpr size_t kRecoverablePacketLossRateMinNumAckedPairs = 40; -void CallEncoder(const std::unique_ptr<voe::ChannelSendInterface>& channel_send, - rtc::FunctionView<void(AudioEncoder*)> lambda) { - channel_send->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder_ptr) { - RTC_DCHECK(encoder_ptr); - lambda(encoder_ptr->get()); - }); -} - void UpdateEventLogStreamConfig(RtcEventLog* event_log, const AudioSendStream::Config& config, const AudioSendStream::Config* old_config) { @@ -91,6 +82,7 @@ } // namespace AudioSendStream::AudioSendStream( + Clock* clock, const webrtc::AudioSendStream::Config& config, const rtc::scoped_refptr<webrtc::AudioState>& audio_state, rtc::TaskQueue* worker_queue, @@ -100,7 +92,8 @@ RtcEventLog* event_log, RtcpRttStats* rtcp_rtt_stats, const absl::optional<RtpState>& suspended_rtp_state) - : AudioSendStream(config, + : AudioSendStream(clock, + config, audio_state, worker_queue, rtp_transport, @@ -108,9 +101,11 @@ event_log, rtcp_rtt_stats, suspended_rtp_state, - voe::CreateChannelSend(worker_queue, + voe::CreateChannelSend(clock, + worker_queue, module_process_thread, config.media_transport, + /*overhead_observer=*/this, config.send_transport, rtcp_rtt_stats, event_log, @@ -120,6 +115,7 @@ config.rtcp_report_interval_ms)) {} AudioSendStream::AudioSendStream( + Clock* clock, const webrtc::AudioSendStream::Config& config, const rtc::scoped_refptr<webrtc::AudioState>& audio_state, rtc::TaskQueue* worker_queue, @@ -129,7 +125,8 @@ RtcpRttStats* rtcp_rtt_stats, const absl::optional<RtpState>& suspended_rtp_state, std::unique_ptr<voe::ChannelSendInterface> channel_send) - : worker_queue_(worker_queue), + : clock_(clock), + worker_queue_(worker_queue), config_(Config(/*send_transport=*/nullptr, /*media_transport=*/nullptr)), audio_state_(audio_state), @@ -152,7 +149,15 @@ // should be no rtp_transport, and below check should be strengthened to XOR // (either rtp_transport or media_transport but not both). RTC_DCHECK(rtp_transport || config.media_transport); - + if (config.media_transport) { + // TODO(sukhanov): Currently media transport audio overhead is considered + // constant, we will not get overhead_observer calls when using + // media_transport. In the future when we introduce RTP media transport we + // should make audio overhead interface consistent and work for both RTP and + // non-RTP implementations. + audio_overhead_per_packet_bytes_ = + config.media_transport->GetAudioPacketOverhead(); + } rtp_rtcp_module_ = channel_send_->GetRtpRtcp(); RTC_DCHECK(rtp_rtcp_module_); @@ -197,11 +202,19 @@ ids.transport_sequence_number = extension.id; } else if (extension.uri == RtpExtension::kMidUri) { ids.mid = extension.id; + } else if (extension.uri == RtpExtension::kRidUri) { + ids.rid = extension.id; + } else if (extension.uri == RtpExtension::kRepairedRidUri) { + ids.repaired_rid = extension.id; } } return ids; } +int AudioSendStream::TransportSeqNumId(const AudioSendStream::Config& config) { + return FindExtensionIds(config.rtp.extensions).transport_sequence_number; +} + void AudioSendStream::ConfigureStream( webrtc::internal::AudioSendStream* stream, const webrtc::AudioSendStream::Config& new_config, @@ -247,18 +260,16 @@ } bool transport_seq_num_id_changed = new_ids.transport_sequence_number != old_ids.transport_sequence_number; - if (first_time || - (transport_seq_num_id_changed && - !webrtc::field_trial::IsEnabled("WebRTC-Audio-ForceNoTWCC"))) { + if (first_time || (transport_seq_num_id_changed && + !stream->allocation_settings_.ForceNoAudioFeedback())) { if (!first_time) { channel_send->ResetSenderCongestionControlObjects(); } RtcpBandwidthObserver* bandwidth_observer = nullptr; - bool has_transport_sequence_number = - new_ids.transport_sequence_number != 0 && - !webrtc::field_trial::IsEnabled("WebRTC-Audio-ForceNoTWCC"); - if (has_transport_sequence_number) { + + if (stream->allocation_settings_.ShouldSendTransportSequenceNumber( + new_ids.transport_sequence_number)) { channel_send->EnableSendTransportSequenceNumber( new_ids.transport_sequence_number); // Probing in application limited region is only used in combination with @@ -281,6 +292,13 @@ channel_send->SetMid(new_config.rtp.mid, new_ids.mid); } + // RID RTP header extension + if ((first_time || new_ids.rid != old_ids.rid || + new_ids.repaired_rid != old_ids.repaired_rid || + new_config.rtp.rid != old_config.rtp.rid)) { + channel_send->SetRid(new_config.rtp.rid, new_ids.rid, new_ids.repaired_rid); + } + if (!ReconfigureSendCodec(stream, new_config)) { RTC_LOG(LS_ERROR) << "Failed to set up send codec state."; } @@ -297,20 +315,13 @@ return; } - bool has_transport_sequence_number = - FindExtensionIds(config_.rtp.extensions).transport_sequence_number != 0 && - !webrtc::field_trial::IsEnabled("WebRTC-Audio-ForceNoTWCC"); - if (config_.min_bitrate_bps != -1 && config_.max_bitrate_bps != -1 && - !config_.has_dscp && - (has_transport_sequence_number || - !webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe") || - webrtc::field_trial::IsEnabled("WebRTC-Audio-ABWENoTWCC"))) { - // Audio BWE is enabled. + if (allocation_settings_.IncludeAudioInAllocationOnStart( + config_.min_bitrate_bps, config_.max_bitrate_bps, config_.has_dscp, + TransportSeqNumId(config_))) { rtp_transport_->packet_sender()->SetAccountForAudioPackets(true); rtp_rtcp_module_->SetAsPartOfAllocation(true); ConfigureBitrateObserver(config_.min_bitrate_bps, config_.max_bitrate_bps, - config_.bitrate_priority, - has_transport_sequence_number); + config_.bitrate_priority); } else { rtp_rtcp_module_->SetAsPartOfAllocation(false); } @@ -448,7 +459,7 @@ // TODO(eladalon): This function call could potentially reset the window, // setting both PLR and RPLR to unknown. Consider (during upcoming // refactoring) passing an indication of such an event. - packet_loss_tracker_.OnPacketAdded(seq_num, rtc::TimeMillis()); + packet_loss_tracker_.OnPacketAdded(seq_num, clock_->TimeInMilliseconds()); } } @@ -474,9 +485,36 @@ } } -void AudioSendStream::SetTransportOverhead(int transport_overhead_per_packet) { +void AudioSendStream::SetTransportOverhead( + int transport_overhead_per_packet_bytes) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); - channel_send_->SetTransportOverhead(transport_overhead_per_packet); + rtc::CritScope cs(&overhead_per_packet_lock_); + transport_overhead_per_packet_bytes_ = transport_overhead_per_packet_bytes; + UpdateOverheadForEncoder(); +} + +void AudioSendStream::OnOverheadChanged( + size_t overhead_bytes_per_packet_bytes) { + rtc::CritScope cs(&overhead_per_packet_lock_); + audio_overhead_per_packet_bytes_ = overhead_bytes_per_packet_bytes; + UpdateOverheadForEncoder(); +} + +void AudioSendStream::UpdateOverheadForEncoder() { + const size_t overhead_per_packet_bytes = GetPerPacketOverheadBytes(); + channel_send_->CallEncoder([&](AudioEncoder* encoder) { + encoder->OnReceivedOverhead(overhead_per_packet_bytes); + }); +} + +size_t AudioSendStream::TestOnlyGetPerPacketOverheadBytes() const { + rtc::CritScope cs(&overhead_per_packet_lock_); + return GetPerPacketOverheadBytes(); +} + +size_t AudioSendStream::GetPerPacketOverheadBytes() const { + return transport_overhead_per_packet_bytes_ + + audio_overhead_per_packet_bytes_; } RtpState AudioSendStream::GetRtpState() const { @@ -529,16 +567,11 @@ return false; } - // If other side does not support audio TWCC and WebRTC-Audio-ABWENoTWCC is - // not enabled, do not update target audio bitrate if we are in - // WebRTC-Audio-SendSideBwe-For-Video experiment - const bool do_not_update_target_bitrate = - !webrtc::field_trial::IsEnabled("WebRTC-Audio-ABWENoTWCC") && - webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe-For-Video") && - !FindExtensionIds(new_config.rtp.extensions).transport_sequence_number; // If a bitrate has been specified for the codec, use it over the // codec's default. - if (!do_not_update_target_bitrate && spec.target_bitrate_bps) { + if (stream->allocation_settings_.UpdateAudioTargetBitrate( + TransportSeqNumId(new_config)) && + spec.target_bitrate_bps) { encoder->OnReceivedTargetAudioBitrate(*spec.target_bitrate_bps); } @@ -567,10 +600,18 @@ new_config.send_codec_spec->format.clockrate_hz); } + // Set currently known overhead (used in ANA, opus only). + // If overhead changes later, it will be updated in UpdateOverheadForEncoder. + { + rtc::CritScope cs(&stream->overhead_per_packet_lock_); + encoder->OnReceivedOverhead(stream->GetPerPacketOverheadBytes()); + } + stream->StoreEncoderProperties(encoder->SampleRateHz(), encoder->NumChannels()); stream->channel_send_->SetEncoder(new_config.send_codec_spec->payload_type, std::move(encoder)); + return true; } @@ -601,22 +642,16 @@ return SetupSendCodec(stream, new_config); } - // If other side does not support audio TWCC and WebRTC-Audio-ABWENoTWCC is - // not enabled, do not update target audio bitrate if we are in - // WebRTC-Audio-SendSideBwe-For-Video experiment - const bool do_not_update_target_bitrate = - !webrtc::field_trial::IsEnabled("WebRTC-Audio-ABWENoTWCC") && - webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe-For-Video") && - !FindExtensionIds(new_config.rtp.extensions).transport_sequence_number; - const absl::optional<int>& new_target_bitrate_bps = new_config.send_codec_spec->target_bitrate_bps; // If a bitrate has been specified for the codec, use it over the // codec's default. - if (!do_not_update_target_bitrate && new_target_bitrate_bps && + if (stream->allocation_settings_.UpdateAudioTargetBitrate( + TransportSeqNumId(new_config)) && + new_target_bitrate_bps && new_target_bitrate_bps != old_config.send_codec_spec->target_bitrate_bps) { - CallEncoder(stream->channel_send_, [&](AudioEncoder* encoder) { + stream->channel_send_->CallEncoder([&](AudioEncoder* encoder) { encoder->OnReceivedTargetAudioBitrate(*new_target_bitrate_bps); }); } @@ -624,6 +659,12 @@ ReconfigureANA(stream, new_config); ReconfigureCNG(stream, new_config); + // Set currently known overhead (used in ANA, opus only). + { + rtc::CritScope cs(&stream->overhead_per_packet_lock_); + stream->UpdateOverheadForEncoder(); + } + return true; } @@ -634,7 +675,7 @@ return; } if (new_config.audio_network_adaptor_config) { - CallEncoder(stream->channel_send_, [&](AudioEncoder* encoder) { + stream->channel_send_->CallEncoder([&](AudioEncoder* encoder) { if (encoder->EnableAudioNetworkAdaptor( *new_config.audio_network_adaptor_config, stream->event_log_)) { RTC_DLOG(LS_INFO) << "Audio network adaptor enabled on SSRC " @@ -644,9 +685,8 @@ } }); } else { - CallEncoder(stream->channel_send_, [&](AudioEncoder* encoder) { - encoder->DisableAudioNetworkAdaptor(); - }); + stream->channel_send_->CallEncoder( + [&](AudioEncoder* encoder) { encoder->DisableAudioNetworkAdaptor(); }); RTC_DLOG(LS_INFO) << "Audio network adaptor disabled on SSRC " << new_config.rtp.ssrc; } @@ -701,26 +741,21 @@ // allow us to configure the bitrate observer if the new config has bitrate // limits set, but would only have us call RemoveBitrateObserver if we were // previously configured with bitrate limits. - int new_transport_seq_num_id = - FindExtensionIds(new_config.rtp.extensions).transport_sequence_number; if (stream->config_.min_bitrate_bps == new_config.min_bitrate_bps && stream->config_.max_bitrate_bps == new_config.max_bitrate_bps && stream->config_.bitrate_priority == new_config.bitrate_priority && - (FindExtensionIds(stream->config_.rtp.extensions) - .transport_sequence_number == new_transport_seq_num_id || - !webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe"))) { + (TransportSeqNumId(stream->config_) == TransportSeqNumId(new_config) || + stream->allocation_settings_.IgnoreSeqNumIdChange())) { return; } - bool has_transport_sequence_number = new_transport_seq_num_id != 0; - if (new_config.min_bitrate_bps != -1 && new_config.max_bitrate_bps != -1 && - !new_config.has_dscp && - (has_transport_sequence_number || - !webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe"))) { + if (stream->allocation_settings_.IncludeAudioInAllocationOnReconfigure( + new_config.min_bitrate_bps, new_config.max_bitrate_bps, + new_config.has_dscp, TransportSeqNumId(new_config))) { stream->rtp_transport_->packet_sender()->SetAccountForAudioPackets(true); - stream->ConfigureBitrateObserver( - new_config.min_bitrate_bps, new_config.max_bitrate_bps, - new_config.bitrate_priority, has_transport_sequence_number); + stream->ConfigureBitrateObserver(new_config.min_bitrate_bps, + new_config.max_bitrate_bps, + new_config.bitrate_priority); stream->rtp_rtcp_module_->SetAsPartOfAllocation(true); } else { stream->rtp_transport_->packet_sender()->SetAccountForAudioPackets(false); @@ -731,8 +766,7 @@ void AudioSendStream::ConfigureBitrateObserver(int min_bitrate_bps, int max_bitrate_bps, - double bitrate_priority, - bool has_packet_feedback) { + double bitrate_priority) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); RTC_DCHECK_GE(max_bitrate_bps, min_bitrate_bps); rtc::Event thread_sync_event; @@ -746,8 +780,9 @@ bitrate_allocator_->AddObserver( this, MediaStreamAllocationConfig{ static_cast<uint32_t>(min_bitrate_bps), - static_cast<uint32_t>(max_bitrate_bps), 0, true, - config_.track_id, bitrate_priority, has_packet_feedback}); + static_cast<uint32_t>(max_bitrate_bps), 0, + allocation_settings_.DefaultPriorityBitrate().bps(), true, + config_.track_id, bitrate_priority}); thread_sync_event.Set(); }); thread_sync_event.Wait(rtc::Event::kForever); @@ -765,14 +800,8 @@ void AudioSendStream::RegisterCngPayloadType(int payload_type, int clockrate_hz) { - const CodecInst codec = {payload_type, "CN", clockrate_hz, 0, 1, 0}; - if (rtp_rtcp_module_->RegisterSendPayload(codec) != 0) { - rtp_rtcp_module_->DeRegisterSendPayload(codec.pltype); - if (rtp_rtcp_module_->RegisterSendPayload(codec) != 0) { - RTC_DLOG(LS_ERROR) << "RegisterCngPayloadType() failed to register CN to " - "RTP/RTCP module"; - } - } + rtp_rtcp_module_->RegisterAudioSendPayload(payload_type, "CN", clockrate_hz, + 1, 0); } } // namespace internal } // namespace webrtc
diff --git a/audio/audio_send_stream.h b/audio/audio_send_stream.h index bf94901..c227e61 100644 --- a/audio/audio_send_stream.h +++ b/audio/audio_send_stream.h
@@ -20,7 +20,8 @@ #include "call/audio_state.h" #include "call/bitrate_allocator.h" #include "modules/rtp_rtcp/include/rtp_rtcp.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" +#include "rtc_base/experiments/audio_allocation_settings.h" #include "rtc_base/race_checker.h" #include "rtc_base/thread_checker.h" @@ -35,9 +36,11 @@ class AudioSendStream final : public webrtc::AudioSendStream, public webrtc::BitrateAllocatorObserver, - public webrtc::PacketFeedbackObserver { + public webrtc::PacketFeedbackObserver, + public webrtc::OverheadObserver { public: - AudioSendStream(const webrtc::AudioSendStream::Config& config, + AudioSendStream(Clock* clock, + const webrtc::AudioSendStream::Config& config, const rtc::scoped_refptr<webrtc::AudioState>& audio_state, rtc::TaskQueue* worker_queue, ProcessThread* module_process_thread, @@ -47,7 +50,8 @@ RtcpRttStats* rtcp_rtt_stats, const absl::optional<RtpState>& suspended_rtp_state); // For unit tests, which need to supply a mock ChannelSend. - AudioSendStream(const webrtc::AudioSendStream::Config& config, + AudioSendStream(Clock* clock, + const webrtc::AudioSendStream::Config& config, const rtc::scoped_refptr<webrtc::AudioState>& audio_state, rtc::TaskQueue* worker_queue, RtpTransportControllerSendInterface* rtp_transport, @@ -84,11 +88,19 @@ void OnPacketFeedbackVector( const std::vector<PacketFeedback>& packet_feedback_vector) override; - void SetTransportOverhead(int transport_overhead_per_packet); + void SetTransportOverhead(int transport_overhead_per_packet_bytes); + + // OverheadObserver override reports audio packetization overhead from + // RTP/RTCP module or Media Transport. + void OnOverheadChanged(size_t overhead_bytes_per_packet_bytes) override; RtpState GetRtpState() const; const voe::ChannelSendInterface* GetChannel() const; + // Returns combined per-packet overhead. + size_t TestOnlyGetPerPacketOverheadBytes() const + RTC_LOCKS_EXCLUDED(overhead_per_packet_lock_); + private: class TimedTransport; @@ -112,16 +124,26 @@ void ConfigureBitrateObserver(int min_bitrate_bps, int max_bitrate_bps, - double bitrate_priority, - bool has_packet_feedback); + double bitrate_priority); void RemoveBitrateObserver(); + // Sets per-packet overhead on encoded (for ANA) based on current known values + // of transport and packetization overheads. + void UpdateOverheadForEncoder() + RTC_EXCLUSIVE_LOCKS_REQUIRED(overhead_per_packet_lock_); + + // Returns combined per-packet overhead. + size_t GetPerPacketOverheadBytes() const + RTC_EXCLUSIVE_LOCKS_REQUIRED(overhead_per_packet_lock_); + void RegisterCngPayloadType(int payload_type, int clockrate_hz); + Clock* clock_; rtc::ThreadChecker worker_thread_checker_; rtc::ThreadChecker pacer_thread_checker_; rtc::RaceChecker audio_capture_race_checker_; rtc::TaskQueue* worker_queue_; + const AudioAllocationSettings allocation_settings_; webrtc::AudioSendStream::Config config_; rtc::scoped_refptr<webrtc::AudioState> audio_state_; const std::unique_ptr<voe::ChannelSendInterface> channel_send_; @@ -148,9 +170,22 @@ int audio_level = 0; int transport_sequence_number = 0; int mid = 0; + int rid = 0; + int repaired_rid = 0; }; static ExtensionIds FindExtensionIds( const std::vector<RtpExtension>& extensions); + static int TransportSeqNumId(const Config& config); + + rtc::CriticalSection overhead_per_packet_lock_; + + // Current transport overhead (ICE, TURN, etc.) + size_t transport_overhead_per_packet_bytes_ + RTC_GUARDED_BY(overhead_per_packet_lock_) = 0; + + // Current audio packetization overhead (RTP or Media Transport). + size_t audio_overhead_per_packet_bytes_ + RTC_GUARDED_BY(overhead_per_packet_lock_) = 0; RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AudioSendStream); };
diff --git a/audio/audio_send_stream_tests.cc b/audio/audio_send_stream_tests.cc index 7deeff3..8a83554 100644 --- a/audio/audio_send_stream_tests.cc +++ b/audio/audio_send_stream_tests.cc
@@ -8,7 +8,12 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include <string> +#include <utility> +#include <vector> + #include "test/call_test.h" +#include "test/field_trial.h" #include "test/gtest.h" #include "test/rtcp_packet_parser.h" @@ -16,6 +21,11 @@ namespace test { namespace { +enum : int { // The first valid value is 1. + kAudioLevelExtensionId = 1, + kTransportSequenceNumberExtensionId, +}; + class AudioSendTest : public SendTest { public: AudioSendTest() : SendTest(CallTest::kDefaultTimeoutMs) {} @@ -101,8 +111,8 @@ class AudioLevelObserver : public AudioSendTest { public: AudioLevelObserver() : AudioSendTest() { - EXPECT_TRUE(parser_->RegisterRtpHeaderExtension( - kRtpExtensionAudioLevel, test::kAudioLevelExtensionId)); + EXPECT_TRUE(parser_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel, + kAudioLevelExtensionId)); } Action OnSendRtp(const uint8_t* packet, size_t length) override { @@ -125,8 +135,8 @@ AudioSendStream::Config* send_config, std::vector<AudioReceiveStream::Config>* receive_configs) override { send_config->rtp.extensions.clear(); - send_config->rtp.extensions.push_back(RtpExtension( - RtpExtension::kAudioLevelUri, test::kAudioLevelExtensionId)); + send_config->rtp.extensions.push_back( + RtpExtension(RtpExtension::kAudioLevelUri, kAudioLevelExtensionId)); } void PerformTest() override { @@ -137,42 +147,54 @@ RunBaseTest(&test); } -TEST_F(AudioSendStreamCallTest, SupportsTransportWideSequenceNumbers) { - static const uint8_t kExtensionId = test::kTransportSequenceNumberExtensionId; - class TransportWideSequenceNumberObserver : public AudioSendTest { - public: - TransportWideSequenceNumberObserver() : AudioSendTest() { - EXPECT_TRUE(parser_->RegisterRtpHeaderExtension( - kRtpExtensionTransportSequenceNumber, kExtensionId)); - } +class TransportWideSequenceNumberObserver : public AudioSendTest { + public: + explicit TransportWideSequenceNumberObserver(bool expect_sequence_number) + : AudioSendTest(), expect_sequence_number_(expect_sequence_number) { + EXPECT_TRUE(parser_->RegisterRtpHeaderExtension( + kRtpExtensionTransportSequenceNumber, + kTransportSequenceNumberExtensionId)); + } - private: - Action OnSendRtp(const uint8_t* packet, size_t length) override { - RTPHeader header; - EXPECT_TRUE(parser_->Parse(packet, length, &header)); + private: + Action OnSendRtp(const uint8_t* packet, size_t length) override { + RTPHeader header; + EXPECT_TRUE(parser_->Parse(packet, length, &header)); - EXPECT_TRUE(header.extension.hasTransportSequenceNumber); - EXPECT_FALSE(header.extension.hasTransmissionTimeOffset); - EXPECT_FALSE(header.extension.hasAbsoluteSendTime); + EXPECT_EQ(header.extension.hasTransportSequenceNumber, + expect_sequence_number_); + EXPECT_FALSE(header.extension.hasTransmissionTimeOffset); + EXPECT_FALSE(header.extension.hasAbsoluteSendTime); - observation_complete_.Set(); + observation_complete_.Set(); - return SEND_PACKET; - } + return SEND_PACKET; + } - void ModifyAudioConfigs( - AudioSendStream::Config* send_config, - std::vector<AudioReceiveStream::Config>* receive_configs) override { - send_config->rtp.extensions.clear(); - send_config->rtp.extensions.push_back(RtpExtension( - RtpExtension::kTransportSequenceNumberUri, kExtensionId)); - } + void ModifyAudioConfigs( + AudioSendStream::Config* send_config, + std::vector<AudioReceiveStream::Config>* receive_configs) override { + send_config->rtp.extensions.clear(); + send_config->rtp.extensions.push_back( + RtpExtension(RtpExtension::kTransportSequenceNumberUri, + kTransportSequenceNumberExtensionId)); + } - void PerformTest() override { - EXPECT_TRUE(Wait()) << "Timed out while waiting for a single RTP packet."; - } - } test; + void PerformTest() override { + EXPECT_TRUE(Wait()) << "Timed out while waiting for a single RTP packet."; + } + const bool expect_sequence_number_; +}; +TEST_F(AudioSendStreamCallTest, SendsTransportWideSequenceNumbersInFieldTrial) { + ScopedFieldTrials field_trials("WebRTC-Audio-SendSideBwe/Enabled/"); + TransportWideSequenceNumberObserver test(/*expect_sequence_number=*/true); + RunBaseTest(&test); +} + +TEST_F(AudioSendStreamCallTest, + DoesNotSendTransportWideSequenceNumbersPerDefault) { + TransportWideSequenceNumberObserver test(/*expect_sequence_number=*/false); RunBaseTest(&test); }
diff --git a/audio/audio_send_stream_unittest.cc b/audio/audio_send_stream_unittest.cc index e400ada..ddd8137 100644 --- a/audio/audio_send_stream_unittest.cc +++ b/audio/audio_send_stream_unittest.cc
@@ -28,6 +28,8 @@ #include "modules/rtp_rtcp/mocks/mock_rtcp_rtt_stats.h" #include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h" #include "rtc_base/task_queue.h" +#include "system_wrappers/include/clock.h" +#include "test/field_trial.h" #include "test/gtest.h" #include "test/mock_audio_encoder.h" #include "test/mock_audio_encoder_factory.h" @@ -61,7 +63,6 @@ const int kTelephoneEventPayloadFrequency = 65432; const int kTelephoneEventCode = 45; const int kTelephoneEventDuration = 6789; -const CodecInst kIsacCodec = {103, "isac", 16000, 320, 1, 32000}; constexpr int kIsacPayloadType = 103; const SdpAudioFormat kIsacFormat = {"isac", 16000, 1}; const SdpAudioFormat kOpusFormat = {"opus", 48000, 2}; @@ -73,12 +74,10 @@ class MockLimitObserver : public BitrateAllocator::LimitObserver { public: - MOCK_METHOD5(OnAllocationLimitsChanged, + MOCK_METHOD3(OnAllocationLimitsChanged, void(uint32_t min_send_bitrate_bps, uint32_t max_padding_bitrate_bps, - uint32_t total_bitrate_bps, - uint32_t allocated_without_feedback_bps, - bool has_packet_feedback)); + uint32_t total_bitrate_bps)); }; std::unique_ptr<MockAudioEncoder> SetupAudioEncoderMock( @@ -127,9 +126,10 @@ struct ConfigHelper { ConfigHelper(bool audio_bwe_enabled, bool expect_set_encoder_call) - : stream_config_(/*send_transport=*/nullptr, /*media_transport=*/nullptr), + : clock_(1000000), + stream_config_(/*send_transport=*/nullptr, /*media_transport=*/nullptr), audio_processing_(new rtc::RefCountedObject<MockAudioProcessing>()), - bitrate_allocator_(&limit_observer_), + bitrate_allocator_(&clock_, &limit_observer_), worker_queue_("ConfigHelper_worker_queue"), audio_encoder_(nullptr) { using testing::Invoke; @@ -163,8 +163,9 @@ std::unique_ptr<internal::AudioSendStream> CreateAudioSendStream() { return std::unique_ptr<internal::AudioSendStream>( new internal::AudioSendStream( - stream_config_, audio_state_, &worker_queue_, &rtp_transport_, - &bitrate_allocator_, &event_log_, &rtcp_rtt_stats_, absl::nullopt, + Clock::GetRealTimeClock(), stream_config_, audio_state_, + &worker_queue_, &rtp_transport_, &bitrate_allocator_, &event_log_, + &rtcp_rtt_stats_, absl::nullopt, std::unique_ptr<voe::ChannelSendInterface>(channel_send_))); } @@ -211,6 +212,7 @@ .Times(1); } EXPECT_CALL(*channel_send_, ResetSenderCongestionControlObjects()).Times(1); + EXPECT_CALL(*channel_send_, SetRid(std::string(), 0, 0)).Times(1); } void SetupMockForSetupSendCodec(bool expect_set_encoder_call) { @@ -224,15 +226,14 @@ } } - void SetupMockForModifyEncoder() { + void SetupMockForCallEncoder() { // Let ModifyEncoder to invoke mock audio encoder. - EXPECT_CALL(*channel_send_, ModifyEncoder(_)) - .WillRepeatedly(Invoke( - [this](rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> - modifier) { + EXPECT_CALL(*channel_send_, CallEncoder(_)) + .WillRepeatedly( + [this](rtc::FunctionView<void(AudioEncoder*)> modifier) { if (this->audio_encoder_) - modifier(&this->audio_encoder_); - })); + modifier(this->audio_encoder_.get()); + }); } void SetupMockForSendTelephoneEvent() { @@ -285,6 +286,7 @@ } private: + SimulatedClock clock_; rtc::scoped_refptr<AudioState> audio_state_; AudioSendStream::Config stream_config_; testing::StrictMock<MockChannelSend>* channel_send_ = nullptr; @@ -356,6 +358,7 @@ } TEST(AudioSendStreamTest, AudioBweCorrectObjectsOnChannelProxy) { + ScopedFieldTrials field_trials("WebRTC-Audio-SendSideBwe/Enabled/"); ConfigHelper helper(true, true); auto send_stream = helper.CreateAudioSendStream(); } @@ -375,11 +378,11 @@ EXPECT_EQ(kCallStats.packetsSent, stats.packets_sent); EXPECT_EQ(kReportBlock.cumulative_num_packets_lost, stats.packets_lost); EXPECT_EQ(Q8ToFloat(kReportBlock.fraction_lost), stats.fraction_lost); - EXPECT_EQ(std::string(kIsacCodec.plname), stats.codec_name); + EXPECT_EQ(kIsacFormat.name, stats.codec_name); EXPECT_EQ(static_cast<int32_t>(kReportBlock.extended_highest_sequence_number), stats.ext_seqnum); EXPECT_EQ(static_cast<int32_t>(kReportBlock.interarrival_jitter / - (kIsacCodec.plfreq / 1000)), + (kIsacFormat.clockrate_hz / 1000)), stats.jitter_ms); EXPECT_EQ(kCallStats.rttMs, stats.rtt_ms); EXPECT_EQ(0, stats.audio_level); @@ -428,7 +431,7 @@ auto stream_config = helper.config(); stream_config.audio_network_adaptor_config = kAnaReconfigString; - helper.SetupMockForModifyEncoder(); + helper.SetupMockForCallEncoder(); send_stream->Reconfigure(stream_config); } @@ -507,6 +510,7 @@ } TEST(AudioSendStreamTest, ReconfigureTransportCcResetsFirst) { + ScopedFieldTrials field_trials("WebRTC-Audio-SendSideBwe/Enabled/"); ConfigHelper helper(false, true); auto send_stream = helper.CreateAudioSendStream(); auto new_config = helper.config(); @@ -522,9 +526,61 @@ helper.transport(), Ne(nullptr))) .Times(1); } + + // CallEncoder will be called to re-set overhead. + EXPECT_CALL(*helper.channel_send(), CallEncoder(testing::_)).Times(1); + send_stream->Reconfigure(new_config); } +TEST(AudioSendStreamTest, OnTransportOverheadChanged) { + ConfigHelper helper(false, true); + auto send_stream = helper.CreateAudioSendStream(); + auto new_config = helper.config(); + + // CallEncoder will be called on overhead change. + EXPECT_CALL(*helper.channel_send(), CallEncoder(testing::_)).Times(1); + + const size_t transport_overhead_per_packet_bytes = 333; + send_stream->SetTransportOverhead(transport_overhead_per_packet_bytes); + + EXPECT_EQ(transport_overhead_per_packet_bytes, + send_stream->TestOnlyGetPerPacketOverheadBytes()); +} + +TEST(AudioSendStreamTest, OnAudioOverheadChanged) { + ConfigHelper helper(false, true); + auto send_stream = helper.CreateAudioSendStream(); + auto new_config = helper.config(); + + // CallEncoder will be called on overhead change. + EXPECT_CALL(*helper.channel_send(), CallEncoder(testing::_)).Times(1); + + const size_t audio_overhead_per_packet_bytes = 555; + send_stream->OnOverheadChanged(audio_overhead_per_packet_bytes); + EXPECT_EQ(audio_overhead_per_packet_bytes, + send_stream->TestOnlyGetPerPacketOverheadBytes()); +} + +TEST(AudioSendStreamTest, OnAudioAndTransportOverheadChanged) { + ConfigHelper helper(false, true); + auto send_stream = helper.CreateAudioSendStream(); + auto new_config = helper.config(); + + // CallEncoder will be called when each of overhead changes. + EXPECT_CALL(*helper.channel_send(), CallEncoder(testing::_)).Times(2); + + const size_t transport_overhead_per_packet_bytes = 333; + send_stream->SetTransportOverhead(transport_overhead_per_packet_bytes); + + const size_t audio_overhead_per_packet_bytes = 555; + send_stream->OnOverheadChanged(audio_overhead_per_packet_bytes); + + EXPECT_EQ( + transport_overhead_per_packet_bytes + audio_overhead_per_packet_bytes, + send_stream->TestOnlyGetPerPacketOverheadBytes()); +} + // Validates that reconfiguring the AudioSendStream with a Frame encryptor // correctly reconfigures on the object without crashing. TEST(AudioSendStreamTest, ReconfigureWithFrameEncryptor) {
diff --git a/audio/audio_state.cc b/audio/audio_state.cc index 7d473ae..334eaed 100644 --- a/audio/audio_state.cc +++ b/audio/audio_state.cc
@@ -17,9 +17,9 @@ #include "absl/memory/memory.h" #include "audio/audio_receive_stream.h" #include "modules/audio_device/include/audio_device.h" -#include "rtc_base/atomicops.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" +#include "rtc_base/ref_counted_object.h" #include "rtc_base/thread.h" namespace webrtc { @@ -168,20 +168,6 @@ audio_transport_.SetStereoChannelSwapping(enable); } -// Reference count; implementation copied from rtc::RefCountedObject. -void AudioState::AddRef() const { - rtc::AtomicOps::Increment(&ref_count_); -} - -// Reference count; implementation copied from rtc::RefCountedObject. -rtc::RefCountReleaseStatus AudioState::Release() const { - if (rtc::AtomicOps::Decrement(&ref_count_) == 0) { - delete this; - return rtc::RefCountReleaseStatus::kDroppedLastRef; - } - return rtc::RefCountReleaseStatus::kOtherRefsRemained; -} - void AudioState::UpdateAudioTransportWithSendingStreams() { RTC_DCHECK(thread_checker_.CalledOnValidThread()); std::vector<webrtc::AudioSendStream*> sending_streams; @@ -199,6 +185,6 @@ rtc::scoped_refptr<AudioState> AudioState::Create( const AudioState::Config& config) { - return rtc::scoped_refptr<AudioState>(new internal::AudioState(config)); + return new rtc::RefCountedObject<internal::AudioState>(config); } } // namespace webrtc
diff --git a/audio/audio_state.h b/audio/audio_state.h index 9e302c4..60250da 100644 --- a/audio/audio_state.h +++ b/audio/audio_state.h
@@ -18,9 +18,9 @@ #include "audio/audio_transport_impl.h" #include "audio/null_audio_poller.h" #include "call/audio_state.h" -#include "rtc_base/constructormagic.h" -#include "rtc_base/criticalsection.h" -#include "rtc_base/refcount.h" +#include "rtc_base/constructor_magic.h" +#include "rtc_base/critical_section.h" +#include "rtc_base/ref_count.h" #include "rtc_base/thread_checker.h" namespace webrtc { @@ -30,7 +30,7 @@ namespace internal { -class AudioState final : public webrtc::AudioState { +class AudioState : public webrtc::AudioState { public: explicit AudioState(const AudioState::Config& config); ~AudioState() override; @@ -60,10 +60,6 @@ void RemoveSendingStream(webrtc::AudioSendStream* stream); private: - // rtc::RefCountInterface implementation. - void AddRef() const override; - rtc::RefCountReleaseStatus Release() const override; - void UpdateAudioTransportWithSendingStreams(); rtc::ThreadChecker thread_checker_; @@ -72,10 +68,6 @@ bool recording_enabled_ = true; bool playout_enabled_ = true; - // Reference count; implementation copied from rtc::RefCountedObject. - // TODO(nisse): Use RefCountedObject or RefCountedBase instead. - mutable volatile int ref_count_ = 0; - // Transports mixed audio from the mixer to the audio device and // recorded audio to the sending streams. AudioTransportImpl audio_transport_;
diff --git a/audio/audio_state_unittest.cc b/audio/audio_state_unittest.cc index dc622df..75bf4e1 100644 --- a/audio/audio_state_unittest.cc +++ b/audio/audio_state_unittest.cc
@@ -16,7 +16,7 @@ #include "modules/audio_device/include/mock_audio_device.h" #include "modules/audio_mixer/audio_mixer_impl.h" #include "modules/audio_processing/include/mock_audio_processing.h" -#include "rtc_base/refcountedobject.h" +#include "rtc_base/ref_counted_object.h" #include "test/gtest.h" namespace webrtc { @@ -98,14 +98,14 @@ TEST(AudioStateTest, ConstructDestruct) { ConfigHelper helper; - std::unique_ptr<internal::AudioState> audio_state( - new internal::AudioState(helper.config())); + rtc::scoped_refptr<internal::AudioState> audio_state( + new rtc::RefCountedObject<internal::AudioState>(helper.config())); } TEST(AudioStateTest, RecordedAudioArrivesAtSingleStream) { ConfigHelper helper; - std::unique_ptr<internal::AudioState> audio_state( - new internal::AudioState(helper.config())); + rtc::scoped_refptr<internal::AudioState> audio_state( + new rtc::RefCountedObject<internal::AudioState>(helper.config())); MockAudioSendStream stream; audio_state->AddSendingStream(&stream, 8000, 2); @@ -142,8 +142,8 @@ TEST(AudioStateTest, RecordedAudioArrivesAtMultipleStreams) { ConfigHelper helper; - std::unique_ptr<internal::AudioState> audio_state( - new internal::AudioState(helper.config())); + rtc::scoped_refptr<internal::AudioState> audio_state( + new rtc::RefCountedObject<internal::AudioState>(helper.config())); MockAudioSendStream stream_1; MockAudioSendStream stream_2; @@ -196,8 +196,9 @@ constexpr size_t kNumChannels = 2; ConfigHelper helper; - std::unique_ptr<internal::AudioState> audio_state( - new internal::AudioState(helper.config())); + rtc::scoped_refptr<internal::AudioState> audio_state( + new rtc::RefCountedObject<internal::AudioState>(helper.config())); + audio_state->SetStereoChannelSwapping(true); MockAudioSendStream stream; @@ -227,8 +228,8 @@ constexpr size_t kNumChannels = 1; ConfigHelper helper; - std::unique_ptr<internal::AudioState> audio_state( - new internal::AudioState(helper.config())); + rtc::scoped_refptr<internal::AudioState> audio_state( + new rtc::RefCountedObject<internal::AudioState>(helper.config())); // Push a silent buffer -> Level stats should be zeros except for duration. {
diff --git a/audio/audio_transport_impl.cc b/audio/audio_transport_impl.cc index 539456e..cdbdacd 100644 --- a/audio/audio_transport_impl.cc +++ b/audio/audio_transport_impl.cc
@@ -133,9 +133,9 @@ // Typing detection (utilizes the APM/VAD decision). We let the VAD determine // if we're using this feature or not. - // TODO(solenberg): is_enabled() takes a lock. Work around that. + // TODO(solenberg): GetConfig() takes a lock. Work around that. bool typing_detected = false; - if (audio_processing_->voice_detection()->is_enabled()) { + if (audio_processing_->GetConfig().voice_detection.enabled) { if (audio_frame->vad_activity_ != AudioFrame::kVadUnknown) { bool vad_active = audio_frame->vad_activity_ == AudioFrame::kVadActive; typing_detected = typing_detection_.Process(key_pressed, vad_active); @@ -214,7 +214,6 @@ int64_t* ntp_time_ms) { RTC_DCHECK_EQ(bits_per_sample, 16); RTC_DCHECK_GE(number_of_channels, 1); - RTC_DCHECK_LE(number_of_channels, 2); RTC_DCHECK_GE(sample_rate, AudioProcessing::NativeRate::kSampleRate8kHz); // 100 = 1 second / data duration (10 ms).
diff --git a/audio/audio_transport_impl.h b/audio/audio_transport_impl.h index 3a3155c..4c244a1 100644 --- a/audio/audio_transport_impl.h +++ b/audio/audio_transport_impl.h
@@ -14,14 +14,14 @@ #include <vector> #include "api/audio/audio_mixer.h" +#include "api/scoped_refptr.h" #include "audio/audio_level.h" #include "common_audio/resampler/include/push_resampler.h" #include "modules/audio_device/include/audio_device.h" #include "modules/audio_processing/include/audio_processing.h" #include "modules/audio_processing/typing_detection.h" -#include "rtc_base/constructormagic.h" -#include "rtc_base/criticalsection.h" -#include "rtc_base/scoped_ref_ptr.h" +#include "rtc_base/constructor_magic.h" +#include "rtc_base/critical_section.h" #include "rtc_base/thread_annotations.h" namespace webrtc {
diff --git a/audio/channel_receive.cc b/audio/channel_receive.cc index 483147f..79523c8 100644 --- a/audio/channel_receive.cc +++ b/audio/channel_receive.cc
@@ -33,16 +33,17 @@ #include "modules/rtp_rtcp/source/contributing_sources.h" #include "modules/rtp_rtcp/source/rtp_header_extensions.h" #include "modules/rtp_rtcp/source/rtp_packet_received.h" +#include "modules/rtp_rtcp/source/rtp_rtcp_config.h" #include "modules/utility/include/process_thread.h" #include "rtc_base/checks.h" -#include "rtc_base/criticalsection.h" +#include "rtc_base/critical_section.h" #include "rtc_base/format_macros.h" #include "rtc_base/location.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_minmax.h" #include "rtc_base/race_checker.h" #include "rtc_base/thread_checker.h" -#include "rtc_base/timeutils.h" +#include "rtc_base/time_utils.h" #include "system_wrappers/include/metrics.h" namespace webrtc { @@ -51,50 +52,32 @@ namespace { constexpr double kAudioSampleDurationSeconds = 0.01; -constexpr int64_t kMaxRetransmissionWindowMs = 1000; -constexpr int64_t kMinRetransmissionWindowMs = 30; // Video Sync. constexpr int kVoiceEngineMinMinPlayoutDelayMs = 0; constexpr int kVoiceEngineMaxMinPlayoutDelayMs = 10000; -webrtc::FrameType WebrtcFrameTypeForMediaTransportFrameType( - MediaTransportEncodedAudioFrame::FrameType frame_type) { - switch (frame_type) { - case MediaTransportEncodedAudioFrame::FrameType::kSpeech: - return kAudioFrameSpeech; - break; - - case MediaTransportEncodedAudioFrame::FrameType:: - kDiscountinuousTransmission: - return kAudioFrameCN; - break; - } -} - -WebRtcRTPHeader CreateWebrtcRTPHeaderForMediaTransportFrame( +RTPHeader CreateRTPHeaderForMediaTransportFrame( const MediaTransportEncodedAudioFrame& frame, uint64_t channel_id) { - webrtc::WebRtcRTPHeader webrtc_header = {}; - webrtc_header.header.payloadType = frame.payload_type(); - webrtc_header.header.payload_type_frequency = frame.sampling_rate_hz(); - webrtc_header.header.timestamp = frame.starting_sample_index(); - webrtc_header.header.sequenceNumber = frame.sequence_number(); + webrtc::RTPHeader rtp_header; + rtp_header.payloadType = frame.payload_type(); + rtp_header.payload_type_frequency = frame.sampling_rate_hz(); + rtp_header.timestamp = frame.starting_sample_index(); + rtp_header.sequenceNumber = frame.sequence_number(); - webrtc_header.frameType = - WebrtcFrameTypeForMediaTransportFrameType(frame.frame_type()); - - webrtc_header.header.ssrc = static_cast<uint32_t>(channel_id); + rtp_header.ssrc = static_cast<uint32_t>(channel_id); // The rest are initialized by the RTPHeader constructor. - return webrtc_header; + return rtp_header; } class ChannelReceive : public ChannelReceiveInterface, public MediaTransportAudioSinkInterface { public: // Used for receive streams. - ChannelReceive(ProcessThread* module_process_thread, + ChannelReceive(Clock* clock, + ProcessThread* module_process_thread, AudioDeviceModule* audio_device_module, MediaTransportInterface* media_transport, Transport* rtcp_send_transport, @@ -103,6 +86,7 @@ size_t jitter_buffer_max_packets, bool jitter_buffer_fast_playout, int jitter_buffer_min_delay_ms, + bool jitter_buffer_enable_rtx_handling, rtc::scoped_refptr<AudioDecoderFactory> decoder_factory, absl::optional<AudioCodecPairId> codec_pair_id, rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor, @@ -119,7 +103,8 @@ void StopPlayout() override; // Codecs - bool GetRecCodec(CodecInst* codec) const override; + absl::optional<std::pair<int, SdpAudioFormat>> + GetReceiveCodec() const override; bool ReceivedRTCPPacket(const uint8_t* data, size_t length) override; @@ -143,6 +128,10 @@ void SetMinimumPlayoutDelay(int delayMs) override; uint32_t GetPlayoutTimestamp() const override; + // Audio quality. + bool SetBaseMinimumPlayoutDelayMs(int delay_ms) override; + int GetBaseMinimumPlayoutDelayMs() const override; + // Produces the transport-related timestamps; current_delay_ms is left unset. absl::optional<Syncable::Info> GetSyncInfo() const override; @@ -184,7 +173,7 @@ int32_t OnReceivedPayloadData(const uint8_t* payloadData, size_t payloadSize, - const WebRtcRTPHeader* rtpHeader); + const RTPHeader& rtpHeader); bool Playing() const { rtc::CritScope lock(&playing_lock_); @@ -272,10 +261,9 @@ webrtc::CryptoOptions crypto_options_; }; -int32_t ChannelReceive::OnReceivedPayloadData( - const uint8_t* payloadData, - size_t payloadSize, - const WebRtcRTPHeader* rtpHeader) { +int32_t ChannelReceive::OnReceivedPayloadData(const uint8_t* payloadData, + size_t payloadSize, + const RTPHeader& rtp_header) { // We should not be receiving any RTP packets if media_transport is set. RTC_CHECK(!media_transport_); @@ -286,7 +274,7 @@ } // Push the incoming payload (parsed and ready for decoding) into the ACM - if (audio_coding_->IncomingPacket(payloadData, payloadSize, *rtpHeader) != + if (audio_coding_->IncomingPacket(payloadData, payloadSize, rtp_header) != 0) { RTC_DLOG(LS_ERROR) << "ChannelReceive::OnReceivedPayloadData() unable to " "push data to the ACM"; @@ -319,8 +307,7 @@ // Send encoded audio frame to Decoder / NetEq. if (audio_coding_->IncomingPacket( frame.encoded_data().data(), frame.encoded_data().size(), - CreateWebrtcRTPHeaderForMediaTransportFrame(frame, channel_id)) != - 0) { + CreateRTPHeaderForMediaTransportFrame(frame, channel_id)) != 0) { RTC_DLOG(LS_ERROR) << "ChannelReceive::OnData: unable to " "push data to the ACM"; } @@ -442,6 +429,7 @@ } ChannelReceive::ChannelReceive( + Clock* clock, ProcessThread* module_process_thread, AudioDeviceModule* audio_device_module, MediaTransportInterface* media_transport, @@ -451,16 +439,16 @@ size_t jitter_buffer_max_packets, bool jitter_buffer_fast_playout, int jitter_buffer_min_delay_ms, + bool jitter_buffer_enable_rtx_handling, rtc::scoped_refptr<AudioDecoderFactory> decoder_factory, absl::optional<AudioCodecPairId> codec_pair_id, rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor, const webrtc::CryptoOptions& crypto_options) : event_log_(rtc_event_log), - rtp_receive_statistics_( - ReceiveStatistics::Create(Clock::GetRealTimeClock())), + rtp_receive_statistics_(ReceiveStatistics::Create(clock)), remote_ssrc_(remote_ssrc), _outputAudioLevel(), - ntp_estimator_(Clock::GetRealTimeClock()), + ntp_estimator_(clock), playout_timestamp_rtp_(0), playout_delay_ms_(0), rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()), @@ -485,12 +473,15 @@ acm_config.neteq_config.enable_fast_accelerate = jitter_buffer_fast_playout; acm_config.neteq_config.min_delay_ms = jitter_buffer_min_delay_ms; acm_config.neteq_config.enable_muted_state = true; + acm_config.neteq_config.enable_rtx_handling = + jitter_buffer_enable_rtx_handling; audio_coding_.reset(AudioCodingModule::Create(acm_config)); _outputAudioLevel.Clear(); rtp_receive_statistics_->EnableRetransmitDetection(remote_ssrc_, true); RtpRtcp::Configuration configuration; + configuration.clock = clock; configuration.audio = true; configuration.receiver_only = true; configuration.outgoing_transport = rtcp_send_transport; @@ -552,9 +543,10 @@ _outputAudioLevel.Clear(); } -bool ChannelReceive::GetRecCodec(CodecInst* codec) const { +absl::optional<std::pair<int, SdpAudioFormat>> + ChannelReceive::GetReceiveCodec() const { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); - return (audio_coding_->ReceiveCodec(codec) == 0); + return audio_coding_->ReceiveCodec(); } std::vector<webrtc::RtpSource> ChannelReceive::GetSources() const { @@ -628,8 +620,6 @@ const uint8_t* payload = packet + header.headerLength; assert(packet_length >= header.headerLength); size_t payload_length = packet_length - header.headerLength; - WebRtcRTPHeader webrtc_rtp_header = {}; - webrtc_rtp_header.header = header; size_t payload_data_length = payload_length - header.paddingLength; @@ -668,11 +658,9 @@ } if (payload_data_length == 0) { - webrtc_rtp_header.frameType = kEmptyFrame; - return OnReceivedPayloadData(nullptr, 0, &webrtc_rtp_header); + return OnReceivedPayloadData(nullptr, 0, header); } - return OnReceivedPayloadData(payload, payload_data_length, - &webrtc_rtp_header); + return OnReceivedPayloadData(payload, payload_data_length, header); } // May be called on either worker thread or network thread. @@ -690,13 +678,6 @@ return true; } - int64_t nack_window_ms = rtt; - if (nack_window_ms < kMinRetransmissionWindowMs) { - nack_window_ms = kMinRetransmissionWindowMs; - } else if (nack_window_ms > kMaxRetransmissionWindowMs) { - nack_window_ms = kMaxRetransmissionWindowMs; - } - uint32_t ntp_secs = 0; uint32_t ntp_frac = 0; uint32_t rtp_timestamp = 0; @@ -802,11 +783,14 @@ void ChannelReceive::SetNACKStatus(bool enable, int max_packets) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); // None of these functions can fail. - rtp_receive_statistics_->SetMaxReorderingThreshold(max_packets); - if (enable) + if (enable) { + rtp_receive_statistics_->SetMaxReorderingThreshold(max_packets); audio_coding_->EnableNack(max_packets); - else + } else { + rtp_receive_statistics_->SetMaxReorderingThreshold( + kDefaultMaxReorderingThreshold); audio_coding_->DisableNack(); + } } // Called when we are missing one or more packets. @@ -848,12 +832,8 @@ RTC_DCHECK(module_process_thread_checker_.CalledOnValidThread()); // Limit to range accepted by both VoE and ACM, so we're at least getting as // close as possible, instead of failing. - delay_ms = rtc::SafeClamp(delay_ms, 0, 10000); - if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) || - (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs)) { - RTC_DLOG(LS_ERROR) << "SetMinimumPlayoutDelay() invalid min delay"; - return; - } + delay_ms = rtc::SafeClamp(delay_ms, kVoiceEngineMinMinPlayoutDelayMs, + kVoiceEngineMaxMinPlayoutDelayMs); if (audio_coding_->SetMinimumPlayoutDelay(delay_ms) != 0) { RTC_DLOG(LS_ERROR) << "SetMinimumPlayoutDelay() failed to set min playout delay"; @@ -868,6 +848,14 @@ } } +bool ChannelReceive::SetBaseMinimumPlayoutDelayMs(int delay_ms) { + return audio_coding_->SetBaseMinimumPlayoutDelayMs(delay_ms); +} + +int ChannelReceive::GetBaseMinimumPlayoutDelayMs() const { + return audio_coding_->GetBaseMinimumPlayoutDelayMs(); +} + absl::optional<Syncable::Info> ChannelReceive::GetSyncInfo() const { RTC_DCHECK(module_process_thread_checker_.CalledOnValidThread()); Syncable::Info info; @@ -920,13 +908,13 @@ } int ChannelReceive::GetRtpTimestampRateHz() const { - const auto format = audio_coding_->ReceiveFormat(); + const auto decoder = audio_coding_->ReceiveCodec(); // Default to the playout frequency if we've not gotten any packets yet. // TODO(ossu): Zero clockrate can only happen if we've added an external // decoder for a format we don't support internally. Remove once that way of // adding decoders is gone! - return (format && format->clockrate_hz != 0) - ? format->clockrate_hz + return (decoder && decoder->second.clockrate_hz != 0) + ? decoder->second.clockrate_hz : audio_coding_->PlayoutFrequency(); } @@ -973,6 +961,7 @@ } // namespace std::unique_ptr<ChannelReceiveInterface> CreateChannelReceive( + Clock* clock, ProcessThread* module_process_thread, AudioDeviceModule* audio_device_module, MediaTransportInterface* media_transport, @@ -982,16 +971,17 @@ size_t jitter_buffer_max_packets, bool jitter_buffer_fast_playout, int jitter_buffer_min_delay_ms, + bool jitter_buffer_enable_rtx_handling, rtc::scoped_refptr<AudioDecoderFactory> decoder_factory, absl::optional<AudioCodecPairId> codec_pair_id, rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor, const webrtc::CryptoOptions& crypto_options) { return absl::make_unique<ChannelReceive>( - module_process_thread, audio_device_module, media_transport, + clock, module_process_thread, audio_device_module, media_transport, rtcp_send_transport, rtc_event_log, remote_ssrc, jitter_buffer_max_packets, jitter_buffer_fast_playout, - jitter_buffer_min_delay_ms, decoder_factory, codec_pair_id, - frame_decryptor, crypto_options); + jitter_buffer_min_delay_ms, jitter_buffer_enable_rtx_handling, + decoder_factory, codec_pair_id, frame_decryptor, crypto_options); } } // namespace voe
diff --git a/audio/channel_receive.h b/audio/channel_receive.h index 9027623..b3e4f9c 100644 --- a/audio/channel_receive.h +++ b/audio/channel_receive.h
@@ -13,6 +13,7 @@ #include <map> #include <memory> +#include <utility> #include <vector> #include "absl/types/optional.h" @@ -20,9 +21,9 @@ #include "api/audio_codecs/audio_decoder_factory.h" #include "api/call/audio_sink.h" #include "api/call/transport.h" -#include "api/crypto/cryptooptions.h" +#include "api/crypto/crypto_options.h" #include "api/media_transport_interface.h" -#include "api/rtpreceiverinterface.h" +#include "api/rtp_receiver_interface.h" #include "call/rtp_packet_sink_interface.h" #include "call/syncable.h" #include "modules/audio_coding/include/audio_coding_module.h" @@ -79,7 +80,9 @@ virtual void StartPlayout() = 0; virtual void StopPlayout() = 0; - virtual bool GetRecCodec(CodecInst* codec) const = 0; + // Payload type and format of last received RTP packet, if any. + virtual absl::optional<std::pair<int, SdpAudioFormat>> + GetReceiveCodec() const = 0; virtual bool ReceivedRTCPPacket(const uint8_t* data, size_t length) = 0; @@ -99,6 +102,12 @@ virtual void SetMinimumPlayoutDelay(int delay_ms) = 0; virtual uint32_t GetPlayoutTimestamp() const = 0; + // Audio quality. + // Base minimum delay sets lower bound on minimum delay value which + // determines minimum delay until audio playout. + virtual bool SetBaseMinimumPlayoutDelayMs(int delay_ms) = 0; + virtual int GetBaseMinimumPlayoutDelayMs() const = 0; + // Produces the transport-related timestamps; current_delay_ms is left unset. virtual absl::optional<Syncable::Info> GetSyncInfo() const = 0; @@ -127,6 +136,7 @@ }; std::unique_ptr<ChannelReceiveInterface> CreateChannelReceive( + Clock* clock, ProcessThread* module_process_thread, AudioDeviceModule* audio_device_module, MediaTransportInterface* media_transport, @@ -136,6 +146,7 @@ size_t jitter_buffer_max_packets, bool jitter_buffer_fast_playout, int jitter_buffer_min_delay_ms, + bool jitter_buffer_enable_rtx_handling, rtc::scoped_refptr<AudioDecoderFactory> decoder_factory, absl::optional<AudioCodecPairId> codec_pair_id, rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor,
diff --git a/audio/channel_send.cc b/audio/channel_send.cc index c458fe4..0c8be1f 100644 --- a/audio/channel_send.cc +++ b/audio/channel_send.cc
@@ -20,7 +20,7 @@ #include "absl/memory/memory.h" #include "api/array_view.h" #include "api/call/transport.h" -#include "api/crypto/frameencryptorinterface.h" +#include "api/crypto/frame_encryptor_interface.h" #include "audio/utility/audio_frame_operations.h" #include "call/rtp_transport_controller_send_interface.h" #include "logging/rtc_event_log/events/rtc_event_audio_playout.h" @@ -31,7 +31,7 @@ #include "modules/pacing/packet_router.h" #include "modules/utility/include/process_thread.h" #include "rtc_base/checks.h" -#include "rtc_base/criticalsection.h" +#include "rtc_base/critical_section.h" #include "rtc_base/event.h" #include "rtc_base/format_macros.h" #include "rtc_base/location.h" @@ -41,7 +41,8 @@ #include "rtc_base/rate_limiter.h" #include "rtc_base/task_queue.h" #include "rtc_base/thread_checker.h" -#include "rtc_base/timeutils.h" +#include "rtc_base/time_utils.h" +#include "system_wrappers/include/clock.h" #include "system_wrappers/include/field_trial.h" #include "system_wrappers/include/metrics.h" @@ -78,8 +79,6 @@ class ChannelSend : public ChannelSendInterface, - public Transport, - public OverheadObserver, public AudioPacketizationCallback, // receive encoded packets from the // ACM public TargetTransferRateObserver { @@ -88,9 +87,11 @@ // declaration. friend class VoERtcpObserver; - ChannelSend(rtc::TaskQueue* encoder_queue, + ChannelSend(Clock* clock, + rtc::TaskQueue* encoder_queue, ProcessThread* module_process_thread, MediaTransportInterface* media_transport, + OverheadObserver* overhead_observer, Transport* rtp_transport, RtcpRttStats* rtcp_rtt_stats, RtcEventLog* rtc_event_log, @@ -106,6 +107,7 @@ std::unique_ptr<AudioEncoder> encoder) override; void ModifyEncoder(rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier) override; + void CallEncoder(rtc::FunctionView<void(AudioEncoder*)> modifier) override; // API methods void StartSend() override; @@ -134,6 +136,9 @@ // RTP+RTCP void SetLocalSSRC(uint32_t ssrc) override; + void SetRid(const std::string& rid, + int extension_id, + int repaired_extension_id) override; void SetMid(const std::string& mid, int extension_id) override; void SetExtmapAllowMixed(bool extmap_allow_mixed) override; void SetSendAudioLevelIndicationStatus(bool enable, int id) override; @@ -158,8 +163,6 @@ // packet. void ProcessAndEncodeAudio(std::unique_ptr<AudioFrame> audio_frame) override; - void SetTransportOverhead(size_t transport_overhead_per_packet) override; - // The existence of this function alongside OnUplinkPacketLossRate is // a compromise. We want the encoder to be agnostic of the PLR source, but // we also don't want it to receive conflicting information from TWCC and @@ -186,23 +189,11 @@ size_t payloadSize, const RTPFragmentationHeader* fragmentation) override; - // From Transport (called by the RTP/RTCP module) - bool SendRtp(const uint8_t* data, - size_t len, - const PacketOptions& packet_options) override; - bool SendRtcp(const uint8_t* data, size_t len) override; - - // From OverheadObserver in the RTP/RTCP module - void OnOverheadChanged(size_t overhead_bytes_per_packet) override; - void OnUplinkPacketLossRate(float packet_loss_rate); bool InputMute() const; int SetSendRtpHeaderExtension(bool enable, RTPExtensionType type, int id); - void UpdateOverheadForEncoder() - RTC_EXCLUSIVE_LOCKS_REQUIRED(overhead_per_packet_lock_); - int32_t SendRtpAudio(FrameType frameType, uint8_t payloadType, uint32_t timeStamp, @@ -238,7 +229,6 @@ // audio thread to another, but access is still sequential. rtc::RaceChecker audio_thread_race_checker_; - rtc::CriticalSection _callbackCritSect; rtc::CriticalSection volume_settings_critsect_; bool sending_ RTC_GUARDED_BY(&worker_thread_checker_) = false; @@ -250,11 +240,8 @@ std::unique_ptr<AudioCodingModule> audio_coding_; uint32_t _timeStamp RTC_GUARDED_BY(encoder_queue_); - uint16_t send_sequence_number_; - // uses ProcessThread* const _moduleProcessThreadPtr; - Transport* const _transportPtr; // WebRtc socket or external transport RmsLevel rms_level_ RTC_GUARDED_BY(encoder_queue_); bool input_mute_ RTC_GUARDED_BY(volume_settings_critsect_); bool previous_frame_muted_ RTC_GUARDED_BY(encoder_queue_); @@ -262,10 +249,7 @@ // TODO(henrika): can today be accessed on the main thread and on the // task queue; hence potential race. bool _includeAudioLevelIndication; - size_t transport_overhead_per_packet_ - RTC_GUARDED_BY(overhead_per_packet_lock_); - size_t rtp_overhead_per_packet_ RTC_GUARDED_BY(overhead_per_packet_lock_); - rtc::CriticalSection overhead_per_packet_lock_; + // RtcpBandwidthObserver const std::unique_ptr<VoERtcpObserver> rtcp_observer_; @@ -416,7 +400,7 @@ public: explicit VoERtcpObserver(ChannelSend* owner) : owner_(owner), bandwidth_observer_(nullptr) {} - virtual ~VoERtcpObserver() {} + ~VoERtcpObserver() override {} void SetBandwidthObserver(RtcpBandwidthObserver* bandwidth_observer) { rtc::CritScope lock(&crit_); @@ -515,6 +499,12 @@ rtc::ArrayView<const uint8_t> payload(payloadData, payloadSize); if (media_transport() != nullptr) { + if (frameType == kEmptyFrame) { + // TODO(bugs.webrtc.org/9719): Media transport Send doesn't support + // sending empty frames. + return 0; + } + return SendMediaTransportAudio(frameType, payloadType, timeStamp, payload, fragmentation); } else { @@ -606,7 +596,7 @@ sampling_rate_hz = media_transport_sampling_frequency_; channel_id = media_transport_channel_id_; } - const MediaTransportEncodedAudioFrame frame( + MediaTransportEncodedAudioFrame frame( /*sampling_rate_hz=*/sampling_rate_hz, // TODO(nisse): Timestamp and sample index are the same for all supported @@ -641,48 +631,11 @@ return 0; } -bool ChannelSend::SendRtp(const uint8_t* data, - size_t len, - const PacketOptions& options) { - // We should not be sending RTP packets if media transport is available. - RTC_CHECK(!media_transport()); - - rtc::CritScope cs(&_callbackCritSect); - - if (_transportPtr == NULL) { - RTC_DLOG(LS_ERROR) - << "ChannelSend::SendPacket() failed to send RTP packet due to" - << " invalid transport object"; - return false; - } - - if (!_transportPtr->SendRtp(data, len, options)) { - RTC_DLOG(LS_ERROR) << "ChannelSend::SendPacket() RTP transmission failed"; - return false; - } - return true; -} - -bool ChannelSend::SendRtcp(const uint8_t* data, size_t len) { - rtc::CritScope cs(&_callbackCritSect); - if (_transportPtr == NULL) { - RTC_DLOG(LS_ERROR) - << "ChannelSend::SendRtcp() failed to send RTCP packet due to" - << " invalid transport object"; - return false; - } - - int n = _transportPtr->SendRtcp(data, len); - if (n < 0) { - RTC_DLOG(LS_ERROR) << "ChannelSend::SendRtcp() transmission failed"; - return false; - } - return true; -} - -ChannelSend::ChannelSend(rtc::TaskQueue* encoder_queue, +ChannelSend::ChannelSend(Clock* clock, + rtc::TaskQueue* encoder_queue, ProcessThread* module_process_thread, MediaTransportInterface* media_transport, + OverheadObserver* overhead_observer, Transport* rtp_transport, RtcpRttStats* rtcp_rtt_stats, RtcEventLog* rtc_event_log, @@ -693,20 +646,16 @@ : event_log_(rtc_event_log), _timeStamp(0), // This is just an offset, RTP module will add it's own // random offset - send_sequence_number_(0), _moduleProcessThreadPtr(module_process_thread), - _transportPtr(rtp_transport), input_mute_(false), previous_frame_muted_(false), _includeAudioLevelIndication(false), - transport_overhead_per_packet_(0), - rtp_overhead_per_packet_(0), rtcp_observer_(new VoERtcpObserver(this)), feedback_observer_proxy_(new TransportFeedbackProxy()), seq_num_allocator_proxy_(new TransportSequenceNumberProxy()), rtp_packet_sender_proxy_(new RtpPacketSenderProxy()), - retransmission_rate_limiter_(new RateLimiter(Clock::GetRealTimeClock(), - kMaxRetransmissionWindowMs)), + retransmission_rate_limiter_( + new RateLimiter(clock, kMaxRetransmissionWindowMs)), use_twcc_plr_for_ana_( webrtc::field_trial::FindFullName("UseTwccPlrForAna") == "Enabled"), encoder_queue_(encoder_queue), @@ -726,13 +675,19 @@ // RTPMediaTransport. In this case it means that overhead and bandwidth // observers should not be called when using media transport. if (!media_transport_) { - configuration.overhead_observer = this; + // TODO(sukhanov): Overhead observer is only needed for RTP path, because in + // media transport audio overhead is currently considered constant (see + // getter MediaTransportInterface::GetAudioPacketOverhead). In the future + // when we introduce RTP media transport we should make audio overhead + // interface consistent and work for both RTP and non-RTP implementations. + configuration.overhead_observer = overhead_observer; configuration.bandwidth_callback = rtcp_observer_.get(); configuration.transport_feedback_callback = feedback_observer_proxy_.get(); } + configuration.clock = clock; configuration.audio = true; - configuration.outgoing_transport = this; + configuration.outgoing_transport = rtp_transport; configuration.paced_sender = rtp_packet_sender_proxy_.get(); configuration.transport_sequence_number_allocator = @@ -753,7 +708,6 @@ if (media_transport_) { RTC_DLOG(LS_INFO) << "Setting media_transport_ rate observers."; media_transport_->AddTargetTransferRateObserver(this); - OnOverheadChanged(media_transport_->GetAudioPacketOverhead()); } else { RTC_DLOG(LS_INFO) << "Not setting media_transport_ rate observers."; } @@ -780,7 +734,6 @@ } StopSend(); - int error = audio_coding_->RegisterTransportCallback(NULL); RTC_DCHECK_EQ(0, error); @@ -793,11 +746,6 @@ RTC_DCHECK(!sending_); sending_ = true; - // Resume the previous sequence number which was reset by StopSend(). This - // needs to be done before |sending| is set to true on the RTP/RTCP module. - if (send_sequence_number_) { - _rtpRtcpModule->SetSequenceNumber(send_sequence_number_); - } _rtpRtcpModule->SetSendingMediaStatus(true); int ret = _rtpRtcpModule->SetSendingStatus(true); RTC_DCHECK_EQ(0, ret); @@ -833,14 +781,6 @@ } flush.Wait(rtc::Event::kForever); - // Store the sequence number to be able to pick up the same sequence for - // the next StartSend(). This is needed for restarting device, otherwise - // it might cause libSRTP to complain about packets being replayed. - // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring - // CL is landed. See issue - // https://code.google.com/p/webrtc/issues/detail?id=2111 . - send_sequence_number_ = _rtpRtcpModule->SequenceNumber(); - // Reset sending SSRC and sequence number and triggers direct transmission // of RTCP BYE if (_rtpRtcpModule->SetSendingStatus(false) == -1) { @@ -854,33 +794,14 @@ RTC_DCHECK_RUN_ON(&worker_thread_checker_); RTC_DCHECK_GE(payload_type, 0); RTC_DCHECK_LE(payload_type, 127); - // TODO(ossu): Make CodecInsts up, for now: one for the RTP/RTCP module and - // one for for us to keep track of sample rate and number of channels, etc. // The RTP/RTCP module needs to know the RTP timestamp rate (i.e. clockrate) // as well as some other things, so we collect this info and send it along. - CodecInst rtp_codec; - rtp_codec.pltype = payload_type; - strncpy(rtp_codec.plname, "audio", sizeof(rtp_codec.plname)); - rtp_codec.plname[sizeof(rtp_codec.plname) - 1] = 0; - // Seems unclear if it should be clock rate or sample rate. CodecInst - // supposedly carries the sample rate, but only clock rate seems sensible to - // send to the RTP/RTCP module. - rtp_codec.plfreq = encoder->RtpTimestampRateHz(); - rtp_codec.pacsize = rtc::CheckedDivExact( - static_cast<int>(encoder->Max10MsFramesInAPacket() * rtp_codec.plfreq), - 100); - rtp_codec.channels = encoder->NumChannels(); - rtp_codec.rate = 0; - - if (_rtpRtcpModule->RegisterSendPayload(rtp_codec) != 0) { - _rtpRtcpModule->DeRegisterSendPayload(payload_type); - if (_rtpRtcpModule->RegisterSendPayload(rtp_codec) != 0) { - RTC_DLOG(LS_ERROR) - << "SetEncoder() failed to register codec to RTP/RTCP module"; - return false; - } - } + _rtpRtcpModule->RegisterAudioSendPayload(payload_type, + "audio", + encoder->RtpTimestampRateHz(), + encoder->NumChannels(), + 0); if (media_transport_) { rtc::CritScope cs(&media_transport_lock_); @@ -895,10 +816,22 @@ void ChannelSend::ModifyEncoder( rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier) { - RTC_DCHECK_RUN_ON(&worker_thread_checker_); + // This method can be called on the worker thread, module process thread + // or network thread. Audio coding is thread safe, so we do not need to + // enforce the calling thread. audio_coding_->ModifyEncoder(modifier); } +void ChannelSend::CallEncoder(rtc::FunctionView<void(AudioEncoder*)> modifier) { + ModifyEncoder([modifier](std::unique_ptr<AudioEncoder>* encoder_ptr) { + if (*encoder_ptr) { + modifier(encoder_ptr->get()); + } else { + RTC_DLOG(LS_WARNING) << "Trying to call unset encoder."; + } + }); +} + void ChannelSend::OnBitrateAllocation(BitrateAllocationUpdate update) { // This method can be called on the worker thread, module process thread // or on a TaskQueue via VideoSendStreamImpl::OnEncoderConfigurationChanged. @@ -908,10 +841,8 @@ // module_process_thread_checker_.CalledOnValidThread()); rtc::CritScope lock(&bitrate_crit_section_); - audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) { - if (*encoder) { - (*encoder)->OnReceivedUplinkAllocation(update); - } + CallEncoder([&](AudioEncoder* encoder) { + encoder->OnReceivedUplinkAllocation(update); }); retransmission_rate_limiter_->SetMaxRate(update.target_bitrate.bps()); configured_bitrate_bps_ = update.target_bitrate.bps(); @@ -926,31 +857,25 @@ RTC_DCHECK_RUN_ON(&worker_thread_checker_); if (!use_twcc_plr_for_ana_) return; - audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) { - if (*encoder) { - (*encoder)->OnReceivedUplinkPacketLossFraction(packet_loss_rate); - } + CallEncoder([&](AudioEncoder* encoder) { + encoder->OnReceivedUplinkPacketLossFraction(packet_loss_rate); }); } void ChannelSend::OnRecoverableUplinkPacketLossRate( float recoverable_packet_loss_rate) { RTC_DCHECK_RUN_ON(&worker_thread_checker_); - audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) { - if (*encoder) { - (*encoder)->OnReceivedUplinkRecoverablePacketLossFraction( - recoverable_packet_loss_rate); - } + CallEncoder([&](AudioEncoder* encoder) { + encoder->OnReceivedUplinkRecoverablePacketLossFraction( + recoverable_packet_loss_rate); }); } void ChannelSend::OnUplinkPacketLossRate(float packet_loss_rate) { if (use_twcc_plr_for_ana_) return; - audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) { - if (*encoder) { - (*encoder)->OnReceivedUplinkPacketLossFraction(packet_loss_rate); - } + CallEncoder([&](AudioEncoder* encoder) { + encoder->OnReceivedUplinkPacketLossFraction(packet_loss_rate); }); } @@ -1017,19 +942,8 @@ RTC_DCHECK_RUN_ON(&worker_thread_checker_); RTC_DCHECK_LE(0, payload_type); RTC_DCHECK_GE(127, payload_type); - CodecInst codec = {0}; - codec.pltype = payload_type; - codec.plfreq = payload_frequency; - memcpy(codec.plname, "telephone-event", 16); - if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) { - _rtpRtcpModule->DeRegisterSendPayload(codec.pltype); - if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) { - RTC_DLOG(LS_ERROR) - << "SetSendTelephoneEventPayloadType() failed to register " - "send payload type"; - return false; - } - } + _rtpRtcpModule->RegisterAudioSendPayload(payload_type, "telephone-event", + payload_frequency, 0, 0); return true; } @@ -1044,6 +958,23 @@ _rtpRtcpModule->SetSSRC(ssrc); } +void ChannelSend::SetRid(const std::string& rid, + int extension_id, + int repaired_extension_id) { + RTC_DCHECK_RUN_ON(&worker_thread_checker_); + if (extension_id != 0) { + int ret = SetSendRtpHeaderExtension(!rid.empty(), kRtpExtensionRtpStreamId, + extension_id); + RTC_DCHECK_EQ(0, ret); + } + if (repaired_extension_id != 0) { + int ret = SetSendRtpHeaderExtension(!rid.empty(), kRtpExtensionRtpStreamId, + repaired_extension_id); + RTC_DCHECK_EQ(0, ret); + } + _rtpRtcpModule->SetRid(rid); +} + void ChannelSend::SetMid(const std::string& mid, int extension_id) { RTC_DCHECK_RUN_ON(&worker_thread_checker_); int ret = SetSendRtpHeaderExtension(true, kRtpExtensionMid, extension_id); @@ -1220,30 +1151,6 @@ _timeStamp += static_cast<uint32_t>(audio_input->samples_per_channel_); } -void ChannelSend::UpdateOverheadForEncoder() { - size_t overhead_per_packet = - transport_overhead_per_packet_ + rtp_overhead_per_packet_; - audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) { - if (*encoder) { - (*encoder)->OnReceivedOverhead(overhead_per_packet); - } - }); -} - -void ChannelSend::SetTransportOverhead(size_t transport_overhead_per_packet) { - RTC_DCHECK_RUN_ON(&worker_thread_checker_); - rtc::CritScope cs(&overhead_per_packet_lock_); - transport_overhead_per_packet_ = transport_overhead_per_packet; - UpdateOverheadForEncoder(); -} - -// TODO(solenberg): Make AudioSendStream an OverheadObserver instead. -void ChannelSend::OnOverheadChanged(size_t overhead_bytes_per_packet) { - rtc::CritScope cs(&overhead_per_packet_lock_); - rtp_overhead_per_packet_ = overhead_bytes_per_packet; - UpdateOverheadForEncoder(); -} - ANAStats ChannelSend::GetANAStatistics() const { RTC_DCHECK_RUN_ON(&worker_thread_checker_); return audio_coding_->GetANAStats(); @@ -1310,7 +1217,7 @@ RTC_DCHECK_RUN_ON(&worker_thread_checker_); rtc::CritScope cs(&encoder_queue_lock_); if (encoder_queue_is_active_) { - encoder_queue_->PostTask([this, frame_encryptor]() { + encoder_queue_->PostTask([this, frame_encryptor]() mutable { this->frame_encryptor_ = std::move(frame_encryptor); }); } else { @@ -1318,6 +1225,9 @@ } } +// TODO(sukhanov): Consider moving TargetTransferRate observer to +// AudioSendStream. Since AudioSendStream owns encoder and configures ANA, it +// makes sense to consolidate all rate (and overhead) calculation there. void ChannelSend::OnTargetTransferRate(TargetTransferRate rate) { RTC_DCHECK(media_transport_); OnReceivedRtt(rate.network_estimate.round_trip_time.ms()); @@ -1325,20 +1235,18 @@ void ChannelSend::OnReceivedRtt(int64_t rtt_ms) { // Invoke audio encoders OnReceivedRtt(). - audio_coding_->ModifyEncoder( - [rtt_ms](std::unique_ptr<AudioEncoder>* encoder) { - if (*encoder) { - (*encoder)->OnReceivedRtt(rtt_ms); - } - }); + CallEncoder( + [rtt_ms](AudioEncoder* encoder) { encoder->OnReceivedRtt(rtt_ms); }); } } // namespace std::unique_ptr<ChannelSendInterface> CreateChannelSend( + Clock* clock, rtc::TaskQueue* encoder_queue, ProcessThread* module_process_thread, MediaTransportInterface* media_transport, + OverheadObserver* overhead_observer, Transport* rtp_transport, RtcpRttStats* rtcp_rtt_stats, RtcEventLog* rtc_event_log, @@ -1347,9 +1255,10 @@ bool extmap_allow_mixed, int rtcp_report_interval_ms) { return absl::make_unique<ChannelSend>( - encoder_queue, module_process_thread, media_transport, rtp_transport, - rtcp_rtt_stats, rtc_event_log, frame_encryptor, crypto_options, - extmap_allow_mixed, rtcp_report_interval_ms); + clock, encoder_queue, module_process_thread, media_transport, + overhead_observer, rtp_transport, rtcp_rtt_stats, rtc_event_log, + frame_encryptor, crypto_options, extmap_allow_mixed, + rtcp_report_interval_ms); } } // namespace voe
diff --git a/audio/channel_send.h b/audio/channel_send.h index 083e9a6..4ab53c0 100644 --- a/audio/channel_send.h +++ b/audio/channel_send.h
@@ -17,7 +17,7 @@ #include "api/audio/audio_frame.h" #include "api/audio_codecs/audio_encoder.h" -#include "api/crypto/cryptooptions.h" +#include "api/crypto/crypto_options.h" #include "api/media_transport_interface.h" #include "modules/rtp_rtcp/include/rtp_rtcp.h" #include "rtc_base/function_view.h" @@ -63,8 +63,13 @@ std::unique_ptr<AudioEncoder> encoder) = 0; virtual void ModifyEncoder( rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier) = 0; + virtual void CallEncoder(rtc::FunctionView<void(AudioEncoder*)> modifier) = 0; virtual void SetLocalSSRC(uint32_t ssrc) = 0; + // Use 0 to indicate that the extension should not be registered. + virtual void SetRid(const std::string& rid, + int extension_id, + int repaired_extension_id) = 0; virtual void SetMid(const std::string& mid, int extension_id) = 0; virtual void SetRTCP_CNAME(absl::string_view c_name) = 0; virtual void SetExtmapAllowMixed(bool extmap_allow_mixed) = 0; @@ -85,7 +90,6 @@ virtual void ProcessAndEncodeAudio( std::unique_ptr<AudioFrame> audio_frame) = 0; - virtual void SetTransportOverhead(size_t transport_overhead_per_packet) = 0; virtual RtpRtcp* GetRtpRtcp() const = 0; virtual void OnTwccBasedUplinkPacketLossRate(float packet_loss_rate) = 0; @@ -111,9 +115,11 @@ }; std::unique_ptr<ChannelSendInterface> CreateChannelSend( + Clock* clock, rtc::TaskQueue* encoder_queue, ProcessThread* module_process_thread, MediaTransportInterface* media_transport, + OverheadObserver* overhead_observer, Transport* rtp_transport, RtcpRttStats* rtcp_rtt_stats, RtcEventLog* rtc_event_log,
diff --git a/audio/mock_voe_channel_proxy.h b/audio/mock_voe_channel_proxy.h index eee25c5..a03ce7e 100644 --- a/audio/mock_voe_channel_proxy.h +++ b/audio/mock_voe_channel_proxy.h
@@ -14,6 +14,7 @@ #include <map> #include <memory> #include <string> +#include <utility> #include <vector> #include "api/test/mock_frame_encryptor.h" @@ -52,7 +53,10 @@ MOCK_CONST_METHOD0(GetPlayoutTimestamp, uint32_t()); MOCK_CONST_METHOD0(GetSyncInfo, absl::optional<Syncable::Info>()); MOCK_METHOD1(SetMinimumPlayoutDelay, void(int delay_ms)); - MOCK_CONST_METHOD1(GetRecCodec, bool(CodecInst* codec_inst)); + MOCK_METHOD1(SetBaseMinimumPlayoutDelayMs, bool(int delay_ms)); + MOCK_CONST_METHOD0(GetBaseMinimumPlayoutDelayMs, int()); + MOCK_CONST_METHOD0(GetReceiveCodec, + absl::optional<std::pair<int, SdpAudioFormat>>()); MOCK_METHOD1(SetReceiveCodecs, void(const std::map<int, SdpAudioFormat>& codecs)); MOCK_CONST_METHOD0(GetSources, std::vector<RtpSource>()); @@ -72,6 +76,12 @@ MOCK_METHOD1( ModifyEncoder, void(rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier)); + MOCK_METHOD1(CallEncoder, + void(rtc::FunctionView<void(AudioEncoder*)> modifier)); + MOCK_METHOD3(SetRid, + void(const std::string& rid, + int extension_id, + int repaired_extension_id)); MOCK_METHOD2(SetMid, void(const std::string& mid, int extension_id)); MOCK_METHOD1(SetLocalSSRC, void(uint32_t ssrc)); MOCK_METHOD1(SetRTCP_CNAME, void(absl::string_view c_name));
diff --git a/audio/null_audio_poller.cc b/audio/null_audio_poller.cc index d2b1199..063a367 100644 --- a/audio/null_audio_poller.cc +++ b/audio/null_audio_poller.cc
@@ -15,7 +15,7 @@ #include "rtc_base/checks.h" #include "rtc_base/location.h" #include "rtc_base/thread.h" -#include "rtc_base/timeutils.h" +#include "rtc_base/time_utils.h" namespace webrtc { namespace internal {
diff --git a/audio/null_audio_poller.h b/audio/null_audio_poller.h index f91eb7d..9a81426 100644 --- a/audio/null_audio_poller.h +++ b/audio/null_audio_poller.h
@@ -14,8 +14,8 @@ #include <stdint.h> #include "modules/audio_device/include/audio_device_defines.h" -#include "rtc_base/messagehandler.h" -#include "rtc_base/messagequeue.h" +#include "rtc_base/message_handler.h" +#include "rtc_base/message_queue.h" #include "rtc_base/thread_checker.h" namespace webrtc {
diff --git a/audio/remix_resample.cc b/audio/remix_resample.cc index cc59e2a..e77c386 100644 --- a/audio/remix_resample.cc +++ b/audio/remix_resample.cc
@@ -80,7 +80,7 @@ // The audio in dst_frame really is mono at this point; MonoToStereo will // set this back to stereo. dst_frame->num_channels_ = 1; - AudioFrameOperations::MonoToStereo(dst_frame); + AudioFrameOperations::UpmixChannels(2, dst_frame); } }
diff --git a/audio/transport_feedback_packet_loss_tracker_unittest.cc b/audio/transport_feedback_packet_loss_tracker_unittest.cc index f522635..cc90651 100644 --- a/audio/transport_feedback_packet_loss_tracker_unittest.cc +++ b/audio/transport_feedback_packet_loss_tracker_unittest.cc
@@ -561,8 +561,8 @@ // to weed out potential bugs with wrap-around handling. constexpr uint16_t kBases[] = {0x0000, 0x3456, 0xc032, 0xfffe}; -INSTANTIATE_TEST_CASE_P(_, - TransportFeedbackPacketLossTrackerTest, - testing::ValuesIn(kBases)); +INSTANTIATE_TEST_SUITE_P(_, + TransportFeedbackPacketLossTrackerTest, + testing::ValuesIn(kBases)); } // namespace webrtc
diff --git a/audio/utility/BUILD.gn b/audio/utility/BUILD.gn index 11a65bd..f60b512 100644 --- a/audio/utility/BUILD.gn +++ b/audio/utility/BUILD.gn
@@ -22,7 +22,9 @@ deps = [ "../../api/audio:audio_frame_api", + "../../common_audio", "../../rtc_base:checks", + "../../rtc_base:deprecation", "../../rtc_base:rtc_base_approved", ] } @@ -40,9 +42,5 @@ "../../test:test_support", "//testing/gtest", ] - if (!build_with_chromium && is_clang) { - # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). - suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] - } } }
diff --git a/audio/utility/audio_frame_operations.cc b/audio/utility/audio_frame_operations.cc index 1a8232b..d3180a7 100644 --- a/audio/utility/audio_frame_operations.cc +++ b/audio/utility/audio_frame_operations.cc
@@ -13,7 +13,9 @@ #include <string.h> #include <algorithm> #include <cstdint> +#include <utility> +#include "common_audio/include/audio_util.h" #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_conversions.h" @@ -69,60 +71,20 @@ } } -void AudioFrameOperations::MonoToStereo(const int16_t* src_audio, - size_t samples_per_channel, - int16_t* dst_audio) { - for (size_t i = 0; i < samples_per_channel; i++) { - dst_audio[2 * i] = src_audio[i]; - dst_audio[2 * i + 1] = src_audio[i]; - } -} - int AudioFrameOperations::MonoToStereo(AudioFrame* frame) { if (frame->num_channels_ != 1) { return -1; } - if ((frame->samples_per_channel_ * 2) >= AudioFrame::kMaxDataSizeSamples) { - // Not enough memory to expand from mono to stereo. - return -1; - } - - if (!frame->muted()) { - // TODO(yujo): this operation can be done in place. - int16_t data_copy[AudioFrame::kMaxDataSizeSamples]; - memcpy(data_copy, frame->data(), - sizeof(int16_t) * frame->samples_per_channel_); - MonoToStereo(data_copy, frame->samples_per_channel_, frame->mutable_data()); - } - frame->num_channels_ = 2; - + UpmixChannels(2, frame); return 0; } -void AudioFrameOperations::StereoToMono(const int16_t* src_audio, - size_t samples_per_channel, - int16_t* dst_audio) { - for (size_t i = 0; i < samples_per_channel; i++) { - dst_audio[i] = - (static_cast<int32_t>(src_audio[2 * i]) + src_audio[2 * i + 1]) >> 1; - } -} - int AudioFrameOperations::StereoToMono(AudioFrame* frame) { if (frame->num_channels_ != 2) { return -1; } - - RTC_DCHECK_LE(frame->samples_per_channel_ * 2, - AudioFrame::kMaxDataSizeSamples); - - if (!frame->muted()) { - StereoToMono(frame->data(), frame->samples_per_channel_, - frame->mutable_data()); - } - frame->num_channels_ = 1; - - return 0; + DownmixChannels(1, frame); + return frame->num_channels_ == 1 ? 0 : -1; } void AudioFrameOperations::QuadToStereo(const int16_t* src_audio, @@ -154,65 +116,66 @@ return 0; } -void AudioFrameOperations::QuadToMono(const int16_t* src_audio, - size_t samples_per_channel, - int16_t* dst_audio) { - for (size_t i = 0; i < samples_per_channel; i++) { - dst_audio[i] = - (static_cast<int32_t>(src_audio[4 * i]) + src_audio[4 * i + 1] + - src_audio[4 * i + 2] + src_audio[4 * i + 3]) >> - 2; - } -} - -int AudioFrameOperations::QuadToMono(AudioFrame* frame) { - if (frame->num_channels_ != 4) { - return -1; - } - - RTC_DCHECK_LE(frame->samples_per_channel_ * 4, - AudioFrame::kMaxDataSizeSamples); - - if (!frame->muted()) { - QuadToMono(frame->data(), frame->samples_per_channel_, - frame->mutable_data()); - } - frame->num_channels_ = 1; - - return 0; -} - void AudioFrameOperations::DownmixChannels(const int16_t* src_audio, size_t src_channels, size_t samples_per_channel, size_t dst_channels, int16_t* dst_audio) { - if (src_channels == 2 && dst_channels == 1) { - StereoToMono(src_audio, samples_per_channel, dst_audio); + if (src_channels > 1 && dst_channels == 1) { + DownmixInterleavedToMono(src_audio, samples_per_channel, src_channels, + dst_audio); return; } else if (src_channels == 4 && dst_channels == 2) { QuadToStereo(src_audio, samples_per_channel, dst_audio); return; - } else if (src_channels == 4 && dst_channels == 1) { - QuadToMono(src_audio, samples_per_channel, dst_audio); - return; } RTC_NOTREACHED() << "src_channels: " << src_channels << ", dst_channels: " << dst_channels; } -int AudioFrameOperations::DownmixChannels(size_t dst_channels, - AudioFrame* frame) { - if (frame->num_channels_ == 2 && dst_channels == 1) { - return StereoToMono(frame); +void AudioFrameOperations::DownmixChannels(size_t dst_channels, + AudioFrame* frame) { + RTC_DCHECK_LE(frame->samples_per_channel_ * frame->num_channels_, + AudioFrame::kMaxDataSizeSamples); + if (frame->num_channels_ > 1 && dst_channels == 1) { + if (!frame->muted()) { + DownmixInterleavedToMono(frame->data(), frame->samples_per_channel_, + frame->num_channels_, frame->mutable_data()); + } + frame->num_channels_ = 1; } else if (frame->num_channels_ == 4 && dst_channels == 2) { - return QuadToStereo(frame); - } else if (frame->num_channels_ == 4 && dst_channels == 1) { - return QuadToMono(frame); + int err = QuadToStereo(frame); + RTC_DCHECK_EQ(err, 0); + } else { + RTC_NOTREACHED() << "src_channels: " << frame->num_channels_ + << ", dst_channels: " << dst_channels; + } +} + +void AudioFrameOperations::UpmixChannels(size_t target_number_of_channels, + AudioFrame* frame) { + RTC_DCHECK_EQ(frame->num_channels_, 1); + RTC_DCHECK_LE(frame->samples_per_channel_ * target_number_of_channels, + AudioFrame::kMaxDataSizeSamples); + + if (frame->num_channels_ != 1 || + frame->samples_per_channel_ * target_number_of_channels > + AudioFrame::kMaxDataSizeSamples) { + return; } - return -1; + if (!frame->muted()) { + // Up-mixing done in place. Going backwards through the frame ensure nothing + // is irrevocably overwritten. + for (int i = frame->samples_per_channel_ - 1; i >= 0; i--) { + for (size_t j = 0; j < target_number_of_channels; ++j) { + frame->mutable_data()[target_number_of_channels * i + j] = + frame->data()[i]; + } + } + } + frame->num_channels_ = target_number_of_channels; } void AudioFrameOperations::SwapStereoChannels(AudioFrame* frame) { @@ -223,9 +186,7 @@ int16_t* frame_data = frame->mutable_data(); for (size_t i = 0; i < frame->samples_per_channel_ * 2; i += 2) { - int16_t temp_data = frame_data[i]; - frame_data[i] = frame_data[i + 1]; - frame_data[i + 1] = temp_data; + std::swap(frame_data[i], frame_data[i + 1]); } }
diff --git a/audio/utility/audio_frame_operations.h b/audio/utility/audio_frame_operations.h index c1445b6..65c310c 100644 --- a/audio/utility/audio_frame_operations.h +++ b/audio/utility/audio_frame_operations.h
@@ -15,6 +15,7 @@ #include <stdint.h> #include "api/audio/audio_frame.h" +#include "rtc_base/deprecation.h" namespace webrtc { @@ -32,28 +33,15 @@ // |result_frame| is empty. static void Add(const AudioFrame& frame_to_add, AudioFrame* result_frame); - // Upmixes mono |src_audio| to stereo |dst_audio|. This is an out-of-place - // operation, meaning src_audio and dst_audio must point to different - // buffers. It is the caller's responsibility to ensure that |dst_audio| is - // sufficiently large. - static void MonoToStereo(const int16_t* src_audio, - size_t samples_per_channel, - int16_t* dst_audio); - // |frame.num_channels_| will be updated. This version checks for sufficient - // buffer size and that |num_channels_| is mono. - static int MonoToStereo(AudioFrame* frame); - - // Downmixes stereo |src_audio| to mono |dst_audio|. This is an in-place - // operation, meaning |src_audio| and |dst_audio| may point to the same - // buffer. - static void StereoToMono(const int16_t* src_audio, - size_t samples_per_channel, - int16_t* dst_audio); + // buffer size and that |num_channels_| is mono. Use UpmixChannels + // instead. TODO(bugs.webrtc.org/8649): remove. + RTC_DEPRECATED static int MonoToStereo(AudioFrame* frame); // |frame.num_channels_| will be updated. This version checks that - // |num_channels_| is stereo. - static int StereoToMono(AudioFrame* frame); + // |num_channels_| is stereo. Use DownmixChannels + // instead. TODO(bugs.webrtc.org/8649): remove. + RTC_DEPRECATED static int StereoToMono(AudioFrame* frame); // Downmixes 4 channels |src_audio| to stereo |dst_audio|. This is an in-place // operation, meaning |src_audio| and |dst_audio| may point to the same @@ -66,17 +54,6 @@ // |num_channels_| is 4 channels. static int QuadToStereo(AudioFrame* frame); - // Downmixes 4 channels |src_audio| to mono |dst_audio|. This is an in-place - // operation, meaning |src_audio| and |dst_audio| may point to the same - // buffer. - static void QuadToMono(const int16_t* src_audio, - size_t samples_per_channel, - int16_t* dst_audio); - - // |frame.num_channels_| will be updated. This version checks that - // |num_channels_| is 4 channels. - static int QuadToMono(AudioFrame* frame); - // Downmixes |src_channels| |src_audio| to |dst_channels| |dst_audio|. // This is an in-place operation, meaning |src_audio| and |dst_audio| // may point to the same buffer. Supported channel combinations are @@ -88,10 +65,16 @@ int16_t* dst_audio); // |frame.num_channels_| will be updated. This version checks that + // |num_channels_| and |dst_channels| are valid and performs relevant downmix. + // Supported channel combinations are N channels to Mono, and Quad to Stereo. + static void DownmixChannels(size_t dst_channels, AudioFrame* frame); + + // |frame.num_channels_| will be updated. This version checks that // |num_channels_| and |dst_channels| are valid and performs relevant - // downmix. Supported channel combinations are Stereo to Mono, Quad to Mono, - // and Quad to Stereo. - static int DownmixChannels(size_t dst_channels, AudioFrame* frame); + // downmix. Supported channel combinations are Mono to N + // channels. The single channel is replicated. + static void UpmixChannels(size_t target_number_of_channels, + AudioFrame* frame); // Swap the left and right channels of |frame|. Fails silently if |frame| is // not stereo.
diff --git a/audio/utility/audio_frame_operations_unittest.cc b/audio/utility/audio_frame_operations_unittest.cc index 76f1dcd..dd41d1a 100644 --- a/audio/utility/audio_frame_operations_unittest.cc +++ b/audio/utility/audio_frame_operations_unittest.cc
@@ -103,19 +103,21 @@ } } +#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) TEST_F(AudioFrameOperationsTest, MonoToStereoFailsWithBadParameters) { - EXPECT_EQ(-1, AudioFrameOperations::MonoToStereo(&frame_)); - + EXPECT_DEATH(AudioFrameOperations::UpmixChannels(2, &frame_), ""); frame_.samples_per_channel_ = AudioFrame::kMaxDataSizeSamples; frame_.num_channels_ = 1; - EXPECT_EQ(-1, AudioFrameOperations::MonoToStereo(&frame_)); + EXPECT_DEATH(AudioFrameOperations::UpmixChannels(2, &frame_), ""); } +#endif TEST_F(AudioFrameOperationsTest, MonoToStereoSucceeds) { frame_.num_channels_ = 1; SetFrameData(1, &frame_); - EXPECT_EQ(0, AudioFrameOperations::MonoToStereo(&frame_)); + AudioFrameOperations::UpmixChannels(2, &frame_); + EXPECT_EQ(2u, frame_.num_channels_); AudioFrame stereo_frame; stereo_frame.samples_per_channel_ = 320; @@ -127,36 +129,22 @@ TEST_F(AudioFrameOperationsTest, MonoToStereoMuted) { frame_.num_channels_ = 1; ASSERT_TRUE(frame_.muted()); - EXPECT_EQ(0, AudioFrameOperations::MonoToStereo(&frame_)); + AudioFrameOperations::UpmixChannels(2, &frame_); + EXPECT_EQ(2u, frame_.num_channels_); EXPECT_TRUE(frame_.muted()); } -TEST_F(AudioFrameOperationsTest, MonoToStereoBufferSucceeds) { - AudioFrame target_frame; - frame_.num_channels_ = 1; - SetFrameData(4, &frame_); - - target_frame.num_channels_ = 2; - target_frame.samples_per_channel_ = frame_.samples_per_channel_; - - AudioFrameOperations::MonoToStereo(frame_.data(), frame_.samples_per_channel_, - target_frame.mutable_data()); - - AudioFrame stereo_frame; - stereo_frame.samples_per_channel_ = 320; - stereo_frame.num_channels_ = 2; - SetFrameData(4, 4, &stereo_frame); - VerifyFramesAreEqual(stereo_frame, target_frame); -} - +#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) TEST_F(AudioFrameOperationsTest, StereoToMonoFailsWithBadParameters) { frame_.num_channels_ = 1; - EXPECT_EQ(-1, AudioFrameOperations::StereoToMono(&frame_)); + EXPECT_DEATH(AudioFrameOperations::DownmixChannels(1, &frame_), ""); } +#endif TEST_F(AudioFrameOperationsTest, StereoToMonoSucceeds) { SetFrameData(4, 2, &frame_); - EXPECT_EQ(0, AudioFrameOperations::StereoToMono(&frame_)); + AudioFrameOperations::DownmixChannels(1, &frame_); + EXPECT_EQ(1u, frame_.num_channels_); AudioFrame mono_frame; mono_frame.samples_per_channel_ = 320; @@ -167,7 +155,8 @@ TEST_F(AudioFrameOperationsTest, StereoToMonoMuted) { ASSERT_TRUE(frame_.muted()); - EXPECT_EQ(0, AudioFrameOperations::StereoToMono(&frame_)); + AudioFrameOperations::DownmixChannels(1, &frame_); + EXPECT_EQ(1u, frame_.num_channels_); EXPECT_TRUE(frame_.muted()); } @@ -178,8 +167,9 @@ target_frame.num_channels_ = 1; target_frame.samples_per_channel_ = frame_.samples_per_channel_; - AudioFrameOperations::StereoToMono(frame_.data(), frame_.samples_per_channel_, - target_frame.mutable_data()); + AudioFrameOperations::DownmixChannels(frame_.data(), 2, + frame_.samples_per_channel_, 1, + target_frame.mutable_data()); AudioFrame mono_frame; mono_frame.samples_per_channel_ = 320; @@ -190,8 +180,8 @@ TEST_F(AudioFrameOperationsTest, StereoToMonoDoesNotWrapAround) { SetFrameData(-32768, -32768, &frame_); - EXPECT_EQ(0, AudioFrameOperations::StereoToMono(&frame_)); - + AudioFrameOperations::DownmixChannels(1, &frame_); + EXPECT_EQ(1u, frame_.num_channels_); AudioFrame mono_frame; mono_frame.samples_per_channel_ = 320; mono_frame.num_channels_ = 1; @@ -199,18 +189,12 @@ VerifyFramesAreEqual(mono_frame, frame_); } -TEST_F(AudioFrameOperationsTest, QuadToMonoFailsWithBadParameters) { - frame_.num_channels_ = 1; - EXPECT_EQ(-1, AudioFrameOperations::QuadToMono(&frame_)); - frame_.num_channels_ = 2; - EXPECT_EQ(-1, AudioFrameOperations::QuadToMono(&frame_)); -} - TEST_F(AudioFrameOperationsTest, QuadToMonoSucceeds) { frame_.num_channels_ = 4; SetFrameData(4, 2, 6, 8, &frame_); - EXPECT_EQ(0, AudioFrameOperations::QuadToMono(&frame_)); + AudioFrameOperations::DownmixChannels(1, &frame_); + EXPECT_EQ(1u, frame_.num_channels_); AudioFrame mono_frame; mono_frame.samples_per_channel_ = 320; @@ -222,7 +206,8 @@ TEST_F(AudioFrameOperationsTest, QuadToMonoMuted) { frame_.num_channels_ = 4; ASSERT_TRUE(frame_.muted()); - EXPECT_EQ(0, AudioFrameOperations::QuadToMono(&frame_)); + AudioFrameOperations::DownmixChannels(1, &frame_); + EXPECT_EQ(1u, frame_.num_channels_); EXPECT_TRUE(frame_.muted()); } @@ -234,8 +219,9 @@ target_frame.num_channels_ = 1; target_frame.samples_per_channel_ = frame_.samples_per_channel_; - AudioFrameOperations::QuadToMono(frame_.data(), frame_.samples_per_channel_, - target_frame.mutable_data()); + AudioFrameOperations::DownmixChannels(frame_.data(), 4, + frame_.samples_per_channel_, 1, + target_frame.mutable_data()); AudioFrame mono_frame; mono_frame.samples_per_channel_ = 320; mono_frame.num_channels_ = 1; @@ -246,7 +232,8 @@ TEST_F(AudioFrameOperationsTest, QuadToMonoDoesNotWrapAround) { frame_.num_channels_ = 4; SetFrameData(-32768, -32768, -32768, -32768, &frame_); - EXPECT_EQ(0, AudioFrameOperations::QuadToMono(&frame_)); + AudioFrameOperations::DownmixChannels(1, &frame_); + EXPECT_EQ(1u, frame_.num_channels_); AudioFrame mono_frame; mono_frame.samples_per_channel_ = 320;
diff --git a/common_audio/BUILD.gn b/common_audio/BUILD.gn index 74b0c60..f7ffa00 100644 --- a/common_audio/BUILD.gn +++ b/common_audio/BUILD.gn
@@ -58,7 +58,7 @@ "../system_wrappers:cpu_features_api", "third_party/fft4g:fft4g", "//third_party/abseil-cpp/absl/container:inlined_vector", - "//third_party/abseil-cpp/absl/memory:memory", + "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/types:optional", ]
diff --git a/common_audio/audio_converter.cc b/common_audio/audio_converter.cc index 0f97abb..c560346 100644 --- a/common_audio/audio_converter.cc +++ b/common_audio/audio_converter.cc
@@ -31,7 +31,7 @@ size_t dst_channels, size_t dst_frames) : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {} - ~CopyConverter() override{}; + ~CopyConverter() override {} void Convert(const float* const* src, size_t src_size, @@ -52,7 +52,7 @@ size_t dst_channels, size_t dst_frames) : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {} - ~UpmixConverter() override{}; + ~UpmixConverter() override {} void Convert(const float* const* src, size_t src_size, @@ -74,7 +74,7 @@ size_t dst_channels, size_t dst_frames) : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {} - ~DownmixConverter() override{}; + ~DownmixConverter() override {} void Convert(const float* const* src, size_t src_size, @@ -103,7 +103,7 @@ resamplers_.push_back(std::unique_ptr<PushSincResampler>( new PushSincResampler(src_frames, dst_frames))); } - ~ResampleConverter() override{}; + ~ResampleConverter() override {} void Convert(const float* const* src, size_t src_size, @@ -132,7 +132,7 @@ std::unique_ptr<ChannelBuffer<float>>(new ChannelBuffer<float>( (*it)->dst_frames(), (*it)->dst_channels()))); } - ~CompositionConverter() override{}; + ~CompositionConverter() override {} void Convert(const float* const* src, size_t src_size,
diff --git a/common_audio/audio_converter.h b/common_audio/audio_converter.h index 24a5e72..73ad1ef 100644 --- a/common_audio/audio_converter.h +++ b/common_audio/audio_converter.h
@@ -14,7 +14,7 @@ #include <stddef.h> #include <memory> -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/common_audio/real_fourier_unittest.cc b/common_audio/real_fourier_unittest.cc index 1324887..eac4fce 100644 --- a/common_audio/real_fourier_unittest.cc +++ b/common_audio/real_fourier_unittest.cc
@@ -68,7 +68,7 @@ }; using FftTypes = ::testing::Types<RealFourierOoura>; -TYPED_TEST_CASE(RealFourierTest, FftTypes); +TYPED_TEST_SUITE(RealFourierTest, FftTypes); TYPED_TEST(RealFourierTest, SimpleForwardTransform) { this->real_buffer_[0] = 1.0f;
diff --git a/common_audio/resampler/push_sinc_resampler.h b/common_audio/resampler/push_sinc_resampler.h index db9cdc1..b002ff7 100644 --- a/common_audio/resampler/push_sinc_resampler.h +++ b/common_audio/resampler/push_sinc_resampler.h
@@ -16,7 +16,7 @@ #include <memory> #include "common_audio/resampler/sinc_resampler.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/common_audio/resampler/push_sinc_resampler_unittest.cc b/common_audio/resampler/push_sinc_resampler_unittest.cc index 2f53a74..ee111c4 100644 --- a/common_audio/resampler/push_sinc_resampler_unittest.cc +++ b/common_audio/resampler/push_sinc_resampler_unittest.cc
@@ -16,7 +16,7 @@ #include "common_audio/include/audio_util.h" #include "common_audio/resampler/push_sinc_resampler.h" #include "common_audio/resampler/sinusoidal_linear_chirp_source.h" -#include "rtc_base/timeutils.h" +#include "rtc_base/time_utils.h" #include "test/gmock.h" #include "test/gtest.h" @@ -255,7 +255,7 @@ // Thresholds chosen arbitrarily based on what each resampling reported during // testing. All thresholds are in dbFS, http://en.wikipedia.org/wiki/DBFS. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PushSincResamplerTest, PushSincResamplerTest, ::testing::Values(
diff --git a/common_audio/resampler/sinc_resampler.h b/common_audio/resampler/sinc_resampler.h index 0be4318..ffd70d9 100644 --- a/common_audio/resampler/sinc_resampler.h +++ b/common_audio/resampler/sinc_resampler.h
@@ -17,7 +17,7 @@ #include <stddef.h> #include <memory> -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" #include "rtc_base/gtest_prod_util.h" #include "rtc_base/memory/aligned_malloc.h" #include "rtc_base/system/arch.h"
diff --git a/common_audio/resampler/sinc_resampler_unittest.cc b/common_audio/resampler/sinc_resampler_unittest.cc index eb5424d..3aedacc 100644 --- a/common_audio/resampler/sinc_resampler_unittest.cc +++ b/common_audio/resampler/sinc_resampler_unittest.cc
@@ -24,7 +24,7 @@ #include "common_audio/resampler/sinusoidal_linear_chirp_source.h" #include "rtc_base/stringize_macros.h" #include "rtc_base/system/arch.h" -#include "rtc_base/timeutils.h" +#include "rtc_base/time_utils.h" #include "system_wrappers/include/cpu_features_wrapper.h" #include "test/gmock.h" #include "test/gtest.h" @@ -340,7 +340,7 @@ // Thresholds chosen arbitrarily based on what each resampling reported during // testing. All thresholds are in dbFS, http://en.wikipedia.org/wiki/DBFS. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SincResamplerTest, SincResamplerTest, testing::Values(
diff --git a/common_audio/resampler/sinusoidal_linear_chirp_source.h b/common_audio/resampler/sinusoidal_linear_chirp_source.h index 71dcff5..81f6a24 100644 --- a/common_audio/resampler/sinusoidal_linear_chirp_source.h +++ b/common_audio/resampler/sinusoidal_linear_chirp_source.h
@@ -15,7 +15,7 @@ #define COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_ #include "common_audio/resampler/sinc_resampler.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/common_audio/smoothing_filter.cc b/common_audio/smoothing_filter.cc index 0d5aaa4..e5ce987 100644 --- a/common_audio/smoothing_filter.cc +++ b/common_audio/smoothing_filter.cc
@@ -13,7 +13,7 @@ #include <cmath> #include "rtc_base/checks.h" -#include "rtc_base/timeutils.h" +#include "rtc_base/time_utils.h" namespace webrtc {
diff --git a/common_audio/smoothing_filter.h b/common_audio/smoothing_filter.h index c467d85..e5f561e 100644 --- a/common_audio/smoothing_filter.h +++ b/common_audio/smoothing_filter.h
@@ -14,7 +14,7 @@ #include <stdint.h> #include "absl/types/optional.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/common_audio/smoothing_filter_unittest.cc b/common_audio/smoothing_filter_unittest.cc index abe4272..5f6711e 100644 --- a/common_audio/smoothing_filter_unittest.cc +++ b/common_audio/smoothing_filter_unittest.cc
@@ -12,7 +12,7 @@ #include <memory> #include "common_audio/smoothing_filter.h" -#include "rtc_base/fakeclock.h" +#include "rtc_base/fake_clock.h" #include "test/gtest.h" namespace webrtc {
diff --git a/common_audio/sparse_fir_filter.h b/common_audio/sparse_fir_filter.h index 22bcdff..5197a8e 100644 --- a/common_audio/sparse_fir_filter.h +++ b/common_audio/sparse_fir_filter.h
@@ -14,7 +14,7 @@ #include <cstring> #include <vector> -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/common_audio/wav_file.h b/common_audio/wav_file.h index cbce59d..7e790e0 100644 --- a/common_audio/wav_file.h +++ b/common_audio/wav_file.h
@@ -17,7 +17,7 @@ #include <cstddef> #include <string> -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" #include "rtc_base/platform_file.h" namespace webrtc {
diff --git a/common_audio/wav_file_unittest.cc b/common_audio/wav_file_unittest.cc index d40229a..b7e5d3f 100644 --- a/common_audio/wav_file_unittest.cc +++ b/common_audio/wav_file_unittest.cc
@@ -17,7 +17,7 @@ #include "common_audio/wav_file.h" #include "common_audio/wav_header.h" #include "test/gtest.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" // WavWriterTest.CPPFileDescriptor and WavWriterTest.CPP flaky on Mac. // See webrtc:9247.
diff --git a/common_audio/window_generator.h b/common_audio/window_generator.h index ad3b445..0cbe24a 100644 --- a/common_audio/window_generator.h +++ b/common_audio/window_generator.h
@@ -13,7 +13,7 @@ #include <stddef.h> -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/common_types.h b/common_types.h index 848b899..2b877d6 100644 --- a/common_types.h +++ b/common_types.h
@@ -14,12 +14,8 @@ #include <stddef.h> // For size_t #include <cstdint> -#include "absl/strings/match.h" -// TODO(sprang): Remove this include when all usage includes it directly. -#include "api/video/video_bitrate_allocation.h" // TODO(bugs.webrtc.org/7660): Delete include once downstream code is updated. #include "api/video/video_codec_type.h" -#include "rtc_base/checks.h" #if defined(_MSC_VER) // Disable "new behavior: elements of array will be default initialized" @@ -27,8 +23,6 @@ #pragma warning(disable : 4351) #endif -#define RTP_PAYLOAD_NAME_SIZE 32u - namespace webrtc { enum FrameType { @@ -158,29 +152,6 @@ virtual void OnOverheadChanged(size_t overhead_bytes_per_packet) = 0; }; -// ================================================================== -// Voice specific types -// ================================================================== - -// Each codec supported can be described by this structure. -struct CodecInst { - int pltype; - char plname[RTP_PAYLOAD_NAME_SIZE]; - int plfreq; - int pacsize; - size_t channels; - int rate; // bits/sec unlike {start,min,max}Bitrate elsewhere in this file! - - bool operator==(const CodecInst& other) const { - return pltype == other.pltype && - absl::EqualsIgnoreCase(plname, other.plname) && - plfreq == other.plfreq && pacsize == other.pacsize && - channels == other.channels && rate == other.rate; - } - - bool operator!=(const CodecInst& other) const { return !(*this == other); } -}; - // RTP enum { kRtpCsrcSize = 15 }; // RFC 3550 page 13
diff --git a/cras-config/aec_config.cc b/cras-config/aec_config.cc index d0cf19b..d8fb369 100644 --- a/cras-config/aec_config.cc +++ b/cras-config/aec_config.cc
@@ -24,8 +24,6 @@ if (ini == NULL) return; - config->buffering.use_new_render_buffering = - AEC_GET_INT(ini, BUFFERING, USE_NEW_RENDER_BUFFERING); config->buffering.excess_render_detection_interval_blocks = AEC_GET_INT(ini, BUFFERING, EXCESS_RENDER_DETECTION_INTERVAL_BLOCKS); @@ -38,18 +36,10 @@ AEC_GET_INT(ini, DELAY, DOWN_SAMPLING_FACTOR); config->delay.num_filters = AEC_GET_INT(ini, DELAY, NUM_FILTERS); - config->delay.api_call_jitter_blocks = - AEC_GET_INT(ini, DELAY, API_CALL_JITTER_BLOCKS); - config->delay.min_echo_path_delay_blocks = - AEC_GET_INT(ini, DELAY, MIN_ECHO_PATH_DELAY_BLOCKS); - config->delay.delay_headroom_blocks = - AEC_GET_INT(ini, DELAY, DELAY_HEADROOM_BLOCKS); - config->delay.hysteresis_limit_1_blocks = - AEC_GET_INT(ini, DELAY, HYSTERESIS_LIMIT_1_BLOCKS); - config->delay.hysteresis_limit_2_blocks = - AEC_GET_INT(ini, DELAY, HYSTERESIS_LIMIT_2_BLOCKS); - config->delay.skew_hysteresis_blocks = - AEC_GET_INT(ini, DELAY, SKEW_HYSTERESIS_BLOCKS); + config->delay.delay_headroom_samples = + AEC_GET_INT(ini, DELAY, DELAY_HEADROOM_SAMPLES); + config->delay.hysteresis_limit_blocks = + AEC_GET_INT(ini, DELAY, HYSTERESIS_LIMIT_BLOCKS); config->delay.fixed_capture_delay_samples = AEC_GET_INT(ini, DELAY, FIXED_CAPTURE_DELAY_SAMPLES); config->delay.delay_estimate_smoothing = @@ -121,12 +111,8 @@ config->erle.num_sections = AEC_GET_INT(ini, ERLE, NUM_SECTIONS); - config->ep_strength.lf = - AEC_GET_FLOAT(ini, EP_STRENGTH, LF); - config->ep_strength.mf = - AEC_GET_FLOAT(ini, EP_STRENGTH, MF); - config->ep_strength.hf = - AEC_GET_FLOAT(ini, EP_STRENGTH, HF); + config->ep_strength.default_gain = + AEC_GET_FLOAT(ini, EP_STRENGTH, DEFAULT_GAIN); config->ep_strength.default_len = AEC_GET_FLOAT(ini, EP_STRENGTH, DEFAULT_LEN); config->ep_strength.reverb_based_on_render = @@ -161,14 +147,6 @@ config->render_levels.poor_excitation_render_limit_ds8 = AEC_GET_FLOAT(ini, RENDER_LEVELS, POOR_EXCITATION_RENDER_LIMIT_DS8); - config->echo_removal_control.gain_rampup.initial_gain = - AEC_GET_FLOAT(ini, ECHO_REMOVAL_CTL, INITIAL_GAIN); - config->echo_removal_control.gain_rampup.first_non_zero_gain = - AEC_GET_FLOAT(ini, ECHO_REMOVAL_CTL, FIRST_NON_ZERO_GAIN); - config->echo_removal_control.gain_rampup.non_zero_gain_blocks = - AEC_GET_INT(ini, ECHO_REMOVAL_CTL, NON_ZERO_GAIN_BLOCKS); - config->echo_removal_control.gain_rampup.full_gain_blocks = - AEC_GET_INT(ini, ECHO_REMOVAL_CTL, FULL_GAIN_BLOCKS); config->echo_removal_control.has_clock_drift = AEC_GET_INT(ini, ECHO_REMOVAL_CTL, HAS_CLOCK_DRIFT); config->echo_removal_control.linear_and_stable_echo_path = @@ -288,8 +266,6 @@ syslog(LOG_ERR, "---- aec config dump ----"); syslog(LOG_ERR, "Buffering:"); - syslog(LOG_ERR, " use_new_render_buffering %d", - config.buffering.use_new_render_buffering); syslog(LOG_ERR, " excess_render_detection_interval_blocks %zu", config.buffering.excess_render_detection_interval_blocks); syslog(LOG_ERR, " max_allowed_excess_render_blocks %zu", @@ -300,15 +276,9 @@ config.delay.default_delay, config.delay.down_sampling_factor, config.delay.num_filters); - syslog(LOG_ERR, " api_call_jitter_blocks %zu, min_echo_path_delay_blocks %zu", - config.delay.api_call_jitter_blocks, - config.delay.min_echo_path_delay_blocks); - syslog(LOG_ERR, " delay_headroom_blocks %zu, hysteresis_limit_1_blocks %zu", - config.delay.delay_headroom_blocks, - config.delay.hysteresis_limit_1_blocks); - syslog(LOG_ERR, " hysteresis_limit_2_blocks %zu, skew_hysteresis_blocks %zu", - config.delay.hysteresis_limit_2_blocks, - config.delay.skew_hysteresis_blocks); + syslog(LOG_ERR, " delay_headroom_samples %zu, hysteresis_limit_blocks %zu", + config.delay.delay_headroom_samples, + config.delay.hysteresis_limit_blocks); syslog(LOG_ERR, " fixed_capture_delay_samples %zu", config.delay.fixed_capture_delay_samples); syslog(LOG_ERR, " delay_estimate_smoothing %f", @@ -359,10 +329,8 @@ syslog(LOG_ERR, "Erle: min %f max_l %f max_h %f onset_detection %d", config.erle.min, config.erle.max_l, config.erle.max_h, config.erle.onset_detection); - syslog(LOG_ERR, "Ep strength: lf %f mf %f hf %f default_len %f", - config.ep_strength.lf, - config.ep_strength.mf, - config.ep_strength.hf, + syslog(LOG_ERR, "Ep strength: default_gain %f default_len %f", + config.ep_strength.default_gain, config.ep_strength.default_len); syslog(LOG_ERR, " echo_can_saturate %d, bounded_erl %d," " ep_strength.reverb_based_on_render %d", @@ -394,12 +362,6 @@ config.render_levels.poor_excitation_render_limit_ds8); syslog(LOG_ERR, "Echo removal control:"); syslog(LOG_ERR, " gain rampup:"); - syslog(LOG_ERR, " initial_gain %f, first_non_zero_gain %f", - config.echo_removal_control.gain_rampup.initial_gain, - config.echo_removal_control.gain_rampup.first_non_zero_gain); - syslog(LOG_ERR, " non_zero_gain_blocks %d, full_gain_blocks %d", - config.echo_removal_control.gain_rampup.non_zero_gain_blocks, - config.echo_removal_control.gain_rampup.full_gain_blocks); syslog(LOG_ERR, " has_clock_drift %d", config.echo_removal_control.has_clock_drift); syslog(LOG_ERR, " linear_and_stable_echo_path %d",
diff --git a/cras-config/aec_config.h b/cras-config/aec_config.h index 33185b3..3b6fd5d 100644 --- a/cras-config/aec_config.h +++ b/cras-config/aec_config.h
@@ -10,8 +10,6 @@ #include "api/audio/echo_canceller3_config.h" -#define AEC_BUFFERING_USE_NEW_RENDER_BUFFERING "buffering:use_new_render_buffering" -#define AEC_BUFFERING_USE_NEW_RENDER_BUFFERING_VALUE 1 #define AEC_BUFFERING_EXCESS_RENDER_DETECTION_INTERVAL_BLOCKS \ "buffering:excess_render_detection_interval_blocks" #define AEC_BUFFERING_EXCESS_RENDER_DETECTION_INTERVAL_BLOCKS_VALUE 250 @@ -25,18 +23,10 @@ #define AEC_DELAY_DOWN_SAMPLING_FACTOR_VALUE 4 #define AEC_DELAY_NUM_FILTERS "delay:num_filters" #define AEC_DELAY_NUM_FILTERS_VALUE 5 -#define AEC_DELAY_API_CALL_JITTER_BLOCKS "delay:api_call_jitter_blocks" -#define AEC_DELAY_API_CALL_JITTER_BLOCKS_VALUE 26 -#define AEC_DELAY_MIN_ECHO_PATH_DELAY_BLOCKS "delay:min_echo_path_delay_blocks" -#define AEC_DELAY_MIN_ECHO_PATH_DELAY_BLOCKS_VALUE 0 -#define AEC_DELAY_DELAY_HEADROOM_BLOCKS "delay:delay_headroom_blocks" -#define AEC_DELAY_DELAY_HEADROOM_BLOCKS_VALUE 2 -#define AEC_DELAY_HYSTERESIS_LIMIT_1_BLOCKS "delay:hysteresis_limit_1_blocks" -#define AEC_DELAY_HYSTERESIS_LIMIT_1_BLOCKS_VALUE 1 -#define AEC_DELAY_HYSTERESIS_LIMIT_2_BLOCKS "delay:hysteresis_limit_2_blocks" -#define AEC_DELAY_HYSTERESIS_LIMIT_2_BLOCKS_VALUE 1 -#define AEC_DELAY_SKEW_HYSTERESIS_BLOCKS "delay:skew_hysteresis_blocks" -#define AEC_DELAY_SKEW_HYSTERESIS_BLOCKS_VALUE 3 +#define AEC_DELAY_DELAY_HEADROOM_SAMPLES "delay:delay_headroom_samples" +#define AEC_DELAY_DELAY_HEADROOM_SAMPLES_VALUE 32 +#define AEC_DELAY_HYSTERESIS_LIMIT_BLOCKS "delay:hysteresis_limit_blocks" +#define AEC_DELAY_HYSTERESIS_LIMIT_BLOCKS_VALUE 1 #define AEC_DELAY_FIXED_CAPTURE_DELAY_SAMPLES \ "delay:fixed_capture_delay_samples" #define AEC_DELAY_FIXED_CAPTURE_DELAY_SAMPLES_VALUE 0 @@ -124,12 +114,8 @@ #define AEC_ERLE_NUM_SECTIONS_VALUE 1 // EpStrength -#define AEC_EP_STRENGTH_LF "ep_strength:lf" -#define AEC_EP_STRENGTH_LF_VALUE 1.f -#define AEC_EP_STRENGTH_MF "ep_strength:mf" -#define AEC_EP_STRENGTH_MF_VALUE 1.f -#define AEC_EP_STRENGTH_HF "ep_strength:hf" -#define AEC_EP_STRENGTH_HF_VALUE 1.f +#define AEC_EP_STRENGTH_DEFAULT_GAIN "ep_strength:default_gain" +#define AEC_EP_STRENGTH_DEFAULT_GAIN_VALUE 1.f #define AEC_EP_STRENGTH_DEFAULT_LEN "ep_strength:default_len" #define AEC_EP_STRENGTH_DEFAULT_LEN_VALUE 0.83f #define AEC_EP_STRENGTH_REVERB_BASED_ON_RENDER \ @@ -175,17 +161,6 @@ #define AEC_RENDER_LEVELS_POOR_EXCITATION_RENDER_LIMIT_DS8_VALUE 20.f // Echo removal controls -#define AEC_ECHO_REMOVAL_CTL_INITIAL_GAIN "echo_removal_control:initial_gain" -#define AEC_ECHO_REMOVAL_CTL_INITIAL_GAIN_VALUE 0.0f -#define AEC_ECHO_REMOVAL_CTL_FIRST_NON_ZERO_GAIN \ - "echo_removal_control:first_non_zero_gain" -#define AEC_ECHO_REMOVAL_CTL_FIRST_NON_ZERO_GAIN_VALUE 0.001f -#define AEC_ECHO_REMOVAL_CTL_NON_ZERO_GAIN_BLOCKS \ - "echo_removal_control:non_zero_gain_blocks" -#define AEC_ECHO_REMOVAL_CTL_NON_ZERO_GAIN_BLOCKS_VALUE 187 -#define AEC_ECHO_REMOVAL_CTL_FULL_GAIN_BLOCKS \ - "echo_removal_control:full_gain_blocks" -#define AEC_ECHO_REMOVAL_CTL_FULL_GAIN_BLOCKS_VALUE 312 #define AEC_ECHO_REMOVAL_CTL_HAS_CLOCK_DRIFT \ "echo_removal_control:has_clock_drift" #define AEC_ECHO_REMOVAL_CTL_HAS_CLOCK_DRIFT_VALUE 0
diff --git a/modules/audio_coding/BUILD.gn b/modules/audio_coding/BUILD.gn index df4ba23..5a47245 100644 --- a/modules/audio_coding/BUILD.gn +++ b/modules/audio_coding/BUILD.gn
@@ -8,59 +8,12 @@ import("../../webrtc.gni") import("audio_coding.gni") -if (!build_with_mozilla) { +if (rtc_enable_protobuf) { import("//third_party/protobuf/proto_library.gni") } visibility = [ ":*" ] -rtc_static_library("audio_format_conversion") { - visibility += webrtc_default_visibility - sources = [ - "codecs/audio_format_conversion.cc", - "codecs/audio_format_conversion.h", - ] - deps = [ - "../..:webrtc_common", - "../../api:array_view", - "../../api/audio_codecs:audio_codecs_api", - "../../rtc_base:checks", - "../../rtc_base:rtc_base_approved", - "../../rtc_base:sanitizer", - "//third_party/abseil-cpp/absl/strings", - "//third_party/abseil-cpp/absl/types:optional", - ] -} - -rtc_static_library("rent_a_codec") { - # Client code SHOULD NOT USE THIS TARGET, but for now it needs to be public - # because there exists client code that uses it. - # TODO(bugs.webrtc.org/9808): Move to private visibility as soon as that - # client code gets updated. - visibility += [ "*" ] - - sources = [ - "acm2/acm_codec_database.cc", - "acm2/acm_codec_database.h", - "acm2/rent_a_codec.cc", - "acm2/rent_a_codec.h", - ] - deps = [ - ":audio_coding_module_typedefs", - ":neteq_decoder_enum", - "../..:webrtc_common", - "../../api:array_view", - "../../api/audio_codecs:audio_codecs_api", - "../../rtc_base:checks", - "../../rtc_base:protobuf_utils", - "../../rtc_base:rtc_base_approved", - "../../system_wrappers", - "//third_party/abseil-cpp/absl/strings", - "//third_party/abseil-cpp/absl/types:optional", - ] - defines = audio_codec_defines -} - rtc_source_set("audio_coding_module_typedefs") { sources = [ "include/audio_coding_module_typedefs.h", @@ -89,8 +42,6 @@ deps = [ ":audio_coding_module_typedefs", ":neteq", - ":neteq_decoder_enum", - ":rent_a_codec", "..:module_api", "..:module_api_public", "../..:webrtc_common", @@ -440,6 +391,7 @@ deps = [ ":isac_bwinfo", "../..:webrtc_common", + "../../api:scoped_refptr", "../../api/audio_codecs:audio_codecs_api", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", @@ -815,6 +767,7 @@ "../../api/audio_codecs/opus:audio_encoder_opus_config", "../../common_audio", "../../rtc_base:checks", + "../../rtc_base:protobuf_utils", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_numerics", "../../rtc_base:safe_minmax", @@ -825,7 +778,6 @@ ] public_deps = [ ":webrtc_opus_c", - "../../rtc_base:protobuf_utils", ] defines = audio_codec_defines @@ -948,23 +900,6 @@ ":ana_debug_dump_proto", ] } - - if (!build_with_chromium && is_clang) { - # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). - suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] - } -} - -rtc_source_set("neteq_decoder_enum") { - sources = [ - "neteq/neteq_decoder_enum.cc", - "neteq/neteq_decoder_enum.h", - ] - deps = [ - "../../api/audio_codecs:audio_codecs_api", - "../../rtc_base:rtc_base_approved", - "//third_party/abseil-cpp/absl/types:optional", - ] } rtc_static_library("neteq") { @@ -1003,6 +938,8 @@ "neteq/expand.h", "neteq/expand_uma_logger.cc", "neteq/expand_uma_logger.h", + "neteq/histogram.cc", + "neteq/histogram.h", "neteq/include/neteq.h", "neteq/merge.cc", "neteq/merge.h", @@ -1039,13 +976,13 @@ deps = [ ":audio_coding_module_typedefs", - ":neteq_decoder_enum", ":webrtc_cng", "..:module_api", "..:module_api_public", "../..:webrtc_common", "../../api:array_view", "../../api:libjingle_peerconnection_api", + "../../api:scoped_refptr", "../../api/audio:audio_frame_api", "../../api/audio_codecs:audio_codecs_api", "../../common_audio", @@ -1059,6 +996,7 @@ "../../rtc_base/system:fallthrough", "../../system_wrappers:field_trial", "../../system_wrappers:metrics", + "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] @@ -1092,10 +1030,10 @@ "../../api:neteq_simulator_api", "../../api/audio:audio_frame_api", "../../api/audio_codecs:audio_codecs_api", - "../../api/audio_codecs:builtin_audio_decoder_factory", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../rtp_rtcp", + "../rtp_rtcp:rtp_rtcp_format", "//third_party/abseil-cpp/absl/types:optional", ] defines = audio_codec_defines @@ -1120,11 +1058,6 @@ "neteq/tools/rtp_generator.h", ] - if (!build_with_chromium && is_clang) { - # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). - suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] - } - deps = [ ":pcm16b", "../..:webrtc_common", @@ -1170,11 +1103,6 @@ "neteq/tools/neteq_stats_plotter.h", ] - if (!build_with_chromium && is_clang) { - # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). - suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] - } - deps = [ "..:module_api", "../..:webrtc_common", @@ -1220,11 +1148,6 @@ "neteq/tools/rtc_event_log_source.h", ] - if (!build_with_chromium && is_clang) { - # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). - suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] - } - deps = [ ":neteq_tools_minimal", "../../logging:rtc_event_log_parser", @@ -1232,6 +1155,7 @@ "../../rtc_base:rtc_base_approved", "../rtp_rtcp", "../rtp_rtcp:rtp_rtcp_format", + "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/types:optional", ] public_deps = [ @@ -1343,14 +1267,11 @@ "test/opus_test.cc", "test/opus_test.h", "test/target_delay_unittest.cc", - "test/utility.cc", - "test/utility.h", ] deps = [ ":audio_coding", ":audio_coding_module_typedefs", ":audio_encoder_cng", - ":audio_format_conversion", ":pcm16b_c", ":red", ":webrtc_opus_c", @@ -1379,14 +1300,11 @@ "../../system_wrappers", "../../test:fileutils", "../../test:test_support", + "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", ] defines = audio_coding_defines - if (!build_with_chromium && is_clang) { - # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). - suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] - } } rtc_source_set("audio_coding_perf_tests") { @@ -1402,7 +1320,6 @@ ":neteq_test_tools", "../..:webrtc_common", "../../api/audio_codecs/opus:audio_encoder_opus", - "../../rtc_base:protobuf_utils", "../../rtc_base:rtc_base_approved", "../../system_wrappers", "../../system_wrappers:field_trial", @@ -1410,11 +1327,6 @@ "../../test:perf_test", "../../test:test_support", ] - - if (!build_with_chromium && is_clang) { - # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). - suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] - } } rtc_source_set("acm_receive_test") { @@ -1427,9 +1339,9 @@ defines = audio_coding_defines deps = audio_coding_deps + [ + "../../api:scoped_refptr", "..:module_api", ":audio_coding", - ":audio_format_conversion", "../../api/audio_codecs:audio_codecs_api", "../../api/audio_codecs:builtin_audio_decoder_factory", ":neteq_tools", @@ -1453,7 +1365,6 @@ "../../api/audio:audio_frame_api", "../../rtc_base:checks", ":audio_coding", - ":audio_format_conversion", ":neteq_tools", "../../api/audio_codecs:builtin_audio_decoder_factory", "../../api/audio_codecs:builtin_audio_encoder_factory", @@ -1495,7 +1406,6 @@ "../../api/audio_codecs:audio_codecs_api", "../../api/audio_codecs/opus:audio_encoder_opus", "../../common_audio", - "../../rtc_base:protobuf_utils", "../../rtc_base/system:arch", "../../test:test_main", "//testing/gtest", @@ -1528,22 +1438,20 @@ deps = [ "../../rtc_base:checks", "../../test:fileutils", + "//third_party/abseil-cpp/absl/types:optional", ] sources = [ "neteq/tools/neteq_test_factory.cc", "neteq/tools/neteq_test_factory.h", ] - if (!build_with_chromium && is_clang) { - # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). - suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] - } - deps += [ ":neteq", ":neteq_test_tools", "../..:webrtc_common", + "../../api/audio_codecs:builtin_audio_decoder_factory", "../../rtc_base:rtc_base_approved", + "../../test:audio_codec_mocks", "../../test:test_support", "//third_party/abseil-cpp/absl/memory", ] @@ -1594,11 +1502,6 @@ "codecs/tools/audio_codec_speed_test.h", ] - if (!build_with_chromium && is_clang) { - # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). - suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] - } - data = audio_codec_speed_tests_resources if (is_android) { @@ -1626,17 +1529,10 @@ rtc_source_set("neteq_test_support") { testonly = true sources = [ - "neteq/tools/neteq_external_decoder_test.cc", - "neteq/tools/neteq_external_decoder_test.h", "neteq/tools/neteq_performance_test.cc", "neteq/tools/neteq_performance_test.h", ] - if (!build_with_chromium && is_clang) { - # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). - suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] - } - deps = [ ":neteq", ":neteq_test_tools", @@ -1661,11 +1557,6 @@ "neteq/tools/neteq_quality_test.h", ] - if (!build_with_chromium && is_clang) { - # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). - suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] - } - deps = [ ":neteq", ":neteq_test_tools", @@ -2033,6 +1924,7 @@ "neteq/dtmf_buffer_unittest.cc", "neteq/dtmf_tone_generator_unittest.cc", "neteq/expand_unittest.cc", + "neteq/histogram_unittest.cc", "neteq/merge_unittest.cc", "neteq/mock/mock_buffer_level_filter.h", "neteq/mock/mock_decoder_database.h", @@ -2041,13 +1933,12 @@ "neteq/mock/mock_dtmf_buffer.h", "neteq/mock/mock_dtmf_tone_generator.h", "neteq/mock/mock_expand.h", - "neteq/mock/mock_external_decoder_pcm16b.h", + "neteq/mock/mock_histogram.h", "neteq/mock/mock_packet_buffer.h", "neteq/mock/mock_red_payload_splitter.h", "neteq/mock/mock_statistics_calculator.h", "neteq/nack_tracker_unittest.cc", "neteq/neteq_decoder_plc_unittest.cc", - "neteq/neteq_external_decoder_unittest.cc", "neteq/neteq_impl_unittest.cc", "neteq/neteq_network_stats_unittest.cc", "neteq/neteq_stereo_unittest.cc", @@ -2072,7 +1963,6 @@ ":audio_coding", ":audio_coding_module_typedefs", ":audio_encoder_cng", - ":audio_format_conversion", ":audio_network_adaptor", ":g711", ":ilbc", @@ -2086,10 +1976,10 @@ ":neteq_test_tools", ":pcm16b", ":red", - ":rent_a_codec", ":webrtc_cng", ":webrtc_opus", "..:module_api", + "..:module_api_public", "../..:webrtc_common", "../../api/audio:audio_frame_api", "../../api/audio_codecs:audio_codecs_api", @@ -2105,11 +1995,11 @@ "../../logging:rtc_event_log_api", "../../modules/rtp_rtcp:rtp_rtcp_format", "../../rtc_base:checks", - "../../rtc_base:protobuf_utils", "../../rtc_base:rtc_base", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_base_tests_utils", "../../rtc_base:sanitizer", + "../../rtc_base:timeutils", "../../rtc_base/system:arch", "../../system_wrappers", "../../system_wrappers:cpu_features_api", @@ -2135,11 +2025,6 @@ ":neteq_unittest_proto", ] } - - if (!build_with_chromium && is_clang) { - # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). - suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] - } } }
diff --git a/modules/audio_coding/acm2/acm_codec_database.cc b/modules/audio_coding/acm2/acm_codec_database.cc deleted file mode 100644 index cada80c..0000000 --- a/modules/audio_coding/acm2/acm_codec_database.cc +++ /dev/null
@@ -1,336 +0,0 @@ -/* - * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -/* - * This file generates databases with information about all supported audio - * codecs. - */ - -// TODO(tlegrand): Change constant input pointers in all functions to constant -// references, where appropriate. -#include "modules/audio_coding/acm2/acm_codec_database.h" - -#include "absl/strings/match.h" -#include "api/array_view.h" -#include "modules/audio_coding/acm2/rent_a_codec.h" - -#if ((defined WEBRTC_CODEC_ISAC) && (defined WEBRTC_CODEC_ISACFX)) -#error iSAC and iSACFX codecs cannot be enabled at the same time -#endif - -namespace webrtc { - -namespace acm2 { - -namespace { - -// Checks if the bitrate is valid for iSAC. -bool IsISACRateValid(int rate) { - return (rate == -1) || ((rate <= 56000) && (rate >= 10000)); -} - -// Checks if the bitrate is valid for iLBC. -bool IsILBCRateValid(int rate, int frame_size_samples) { - if (((frame_size_samples == 240) || (frame_size_samples == 480)) && - (rate == 13300)) { - return true; - } else if (((frame_size_samples == 160) || (frame_size_samples == 320)) && - (rate == 15200)) { - return true; - } else { - return false; - } -} - -// Checks if the bitrate is valid for Opus. -bool IsOpusRateValid(int rate) { - return (rate >= 6000) && (rate <= 510000); -} - -} // namespace - -// Not yet used payload-types. -// 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, -// 67, 66, 65 - -const CodecInst ACMCodecDB::database_[] = { -#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) - {103, "ISAC", 16000, 480, 1, 32000}, -#if (defined(WEBRTC_CODEC_ISAC)) - {104, "ISAC", 32000, 960, 1, 56000}, -#endif -#endif - // Mono - {107, "L16", 8000, 80, 1, 128000}, - {108, "L16", 16000, 160, 1, 256000}, - {109, "L16", 32000, 320, 1, 512000}, - // Stereo - {111, "L16", 8000, 80, 2, 128000}, - {112, "L16", 16000, 160, 2, 256000}, - {113, "L16", 32000, 320, 2, 512000}, - // G.711, PCM mu-law and A-law. - // Mono - {0, "PCMU", 8000, 160, 1, 64000}, - {8, "PCMA", 8000, 160, 1, 64000}, - // Stereo - {110, "PCMU", 8000, 160, 2, 64000}, - {118, "PCMA", 8000, 160, 2, 64000}, -#ifdef WEBRTC_CODEC_ILBC - {102, "ILBC", 8000, 240, 1, 13300}, -#endif - // Mono - {9, "G722", 16000, 320, 1, 64000}, - // Stereo - {119, "G722", 16000, 320, 2, 64000}, -#ifdef WEBRTC_CODEC_OPUS - // Opus internally supports 48, 24, 16, 12, 8 kHz. - // Mono and stereo. - {120, "opus", 48000, 960, 2, 64000}, -#endif - // Comfort noise for four different sampling frequencies. - {13, "CN", 8000, 240, 1, 0}, - {98, "CN", 16000, 480, 1, 0}, - {99, "CN", 32000, 960, 1, 0}, -#ifdef ENABLE_48000_HZ - {100, "CN", 48000, 1440, 1, 0}, -#endif - {106, "telephone-event", 8000, 240, 1, 0}, - {114, "telephone-event", 16000, 240, 1, 0}, - {115, "telephone-event", 32000, 240, 1, 0}, - {116, "telephone-event", 48000, 240, 1, 0}, -#ifdef WEBRTC_CODEC_RED - {127, "red", 8000, 0, 1, 0}, -#endif - // To prevent compile errors due to trailing commas. - {-1, "Null", -1, -1, 0, -1}}; - -// Create database with all codec settings at compile time. -// Each entry needs the following parameters in the given order: -// Number of allowed packet sizes, a vector with the allowed packet sizes, -// Basic block samples, max number of channels that are supported. -const ACMCodecDB::CodecSettings ACMCodecDB::codec_settings_[] = { -#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) - {2, {480, 960}, 0, 1}, -#if (defined(WEBRTC_CODEC_ISAC)) - {1, {960}, 0, 1}, -#endif -#endif - // Mono - {4, {80, 160, 240, 320}, 0, 2}, - {4, {160, 320, 480, 640}, 0, 2}, - {2, {320, 640}, 0, 2}, - // Stereo - {4, {80, 160, 240, 320}, 0, 2}, - {4, {160, 320, 480, 640}, 0, 2}, - {2, {320, 640}, 0, 2}, - // G.711, PCM mu-law and A-law. - // Mono - {6, {80, 160, 240, 320, 400, 480}, 0, 2}, - {6, {80, 160, 240, 320, 400, 480}, 0, 2}, - // Stereo - {6, {80, 160, 240, 320, 400, 480}, 0, 2}, - {6, {80, 160, 240, 320, 400, 480}, 0, 2}, -#ifdef WEBRTC_CODEC_ILBC - {4, {160, 240, 320, 480}, 0, 1}, -#endif - // Mono - {6, {160, 320, 480, 640, 800, 960}, 0, 2}, - // Stereo - {6, {160, 320, 480, 640, 800, 960}, 0, 2}, -#ifdef WEBRTC_CODEC_OPUS -// Opus supports frames shorter than 10ms, -// but it doesn't help us to use them. -// Mono and stereo. -#if WEBRTC_OPUS_SUPPORT_120MS_PTIME - {5, {480, 960, 1920, 2880, 5760}, 0, 2}, -#else - {4, {480, 960, 1920, 2880}, 0, 2}, -#endif -#endif - // Comfort noise for three different sampling frequencies. - {1, {240}, 240, 1}, - {1, {480}, 480, 1}, - {1, {960}, 960, 1}, -// TODO(solenberg): What is this flag? It is never set in the build files. -#ifdef ENABLE_48000_HZ - {1, {1440}, 1440, 1}, -#endif - {1, {240}, 240, 1}, - {1, {240}, 240, 1}, - {1, {240}, 240, 1}, - {1, {240}, 240, 1}, -#ifdef WEBRTC_CODEC_RED - {1, {0}, 0, 1}, -#endif - // To prevent compile errors due to trailing commas. - {-1, {-1}, -1, 0}}; - -// Create a database of all NetEQ decoders at compile time. -const NetEqDecoder ACMCodecDB::neteq_decoders_[] = { -#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) - NetEqDecoder::kDecoderISAC, -#if (defined(WEBRTC_CODEC_ISAC)) - NetEqDecoder::kDecoderISACswb, -#endif -#endif - // Mono - NetEqDecoder::kDecoderPCM16B, NetEqDecoder::kDecoderPCM16Bwb, - NetEqDecoder::kDecoderPCM16Bswb32kHz, - // Stereo - NetEqDecoder::kDecoderPCM16B_2ch, NetEqDecoder::kDecoderPCM16Bwb_2ch, - NetEqDecoder::kDecoderPCM16Bswb32kHz_2ch, - // G.711, PCM mu-las and A-law. - // Mono - NetEqDecoder::kDecoderPCMu, NetEqDecoder::kDecoderPCMa, - // Stereo - NetEqDecoder::kDecoderPCMu_2ch, NetEqDecoder::kDecoderPCMa_2ch, -#ifdef WEBRTC_CODEC_ILBC - NetEqDecoder::kDecoderILBC, -#endif - // Mono - NetEqDecoder::kDecoderG722, - // Stereo - NetEqDecoder::kDecoderG722_2ch, -#ifdef WEBRTC_CODEC_OPUS - // Mono and stereo. - NetEqDecoder::kDecoderOpus, -#endif - // Comfort noise for three different sampling frequencies. - NetEqDecoder::kDecoderCNGnb, NetEqDecoder::kDecoderCNGwb, - NetEqDecoder::kDecoderCNGswb32kHz, -#ifdef ENABLE_48000_HZ - NetEqDecoder::kDecoderCNGswb48kHz, -#endif - NetEqDecoder::kDecoderAVT, NetEqDecoder::kDecoderAVT16kHz, - NetEqDecoder::kDecoderAVT32kHz, NetEqDecoder::kDecoderAVT48kHz, -#ifdef WEBRTC_CODEC_RED - NetEqDecoder::kDecoderRED, -#endif -}; - -// Enumerator for error codes when asking for codec database id. -enum { - kInvalidCodec = -10, - kInvalidPayloadtype = -30, - kInvalidPacketSize = -40, - kInvalidRate = -50 -}; - -// Gets the codec id number from the database. If there is some mismatch in -// the codec settings, the function will return an error code. -// NOTE! The first mismatch found will generate the return value. -int ACMCodecDB::CodecNumber(const CodecInst& codec_inst) { - // Look for a matching codec in the database. - int codec_id = CodecId(codec_inst); - - // Checks if we found a matching codec. - if (codec_id == -1) { - return kInvalidCodec; - } - - // Checks the validity of payload type - if (!RentACodec::IsPayloadTypeValid(codec_inst.pltype)) { - return kInvalidPayloadtype; - } - - // Comfort Noise is special case, packet-size & rate is not checked. - if (absl::EqualsIgnoreCase(database_[codec_id].plname, "CN")) { - return codec_id; - } - - // RED is special case, packet-size & rate is not checked. - if (absl::EqualsIgnoreCase(database_[codec_id].plname, "red")) { - return codec_id; - } - - // Checks the validity of packet size. - if (codec_settings_[codec_id].num_packet_sizes > 0) { - bool packet_size_ok = false; - int i; - int packet_size_samples; - for (i = 0; i < codec_settings_[codec_id].num_packet_sizes; i++) { - packet_size_samples = codec_settings_[codec_id].packet_sizes_samples[i]; - if (codec_inst.pacsize == packet_size_samples) { - packet_size_ok = true; - break; - } - } - - if (!packet_size_ok) { - return kInvalidPacketSize; - } - } - - if (codec_inst.pacsize < 1) { - return kInvalidPacketSize; - } - - // Check the validity of rate. Codecs with multiple rates have their own - // function for this. - if (absl::EqualsIgnoreCase("isac", codec_inst.plname)) { - return IsISACRateValid(codec_inst.rate) ? codec_id : kInvalidRate; - } else if (absl::EqualsIgnoreCase("ilbc", codec_inst.plname)) { - return IsILBCRateValid(codec_inst.rate, codec_inst.pacsize) ? codec_id - : kInvalidRate; - } else if (absl::EqualsIgnoreCase("opus", codec_inst.plname)) { - return IsOpusRateValid(codec_inst.rate) ? codec_id : kInvalidRate; - } - - return database_[codec_id].rate == codec_inst.rate ? codec_id : kInvalidRate; -} - -// Looks for a matching payload name, frequency, and channels in the -// codec list. Need to check all three since some codecs have several codec -// entries with different frequencies and/or channels. -// Does not check other codec settings, such as payload type and packet size. -// Returns the id of the codec, or -1 if no match is found. -int ACMCodecDB::CodecId(const CodecInst& codec_inst) { - return (CodecId(codec_inst.plname, codec_inst.plfreq, codec_inst.channels)); -} - -int ACMCodecDB::CodecId(const char* payload_name, - int frequency, - size_t channels) { - for (const CodecInst& ci : database_) { - bool name_match = false; - bool frequency_match = false; - bool channels_match = false; - - // Payload name, sampling frequency and number of channels need to match. - // NOTE! If |frequency| is -1, the frequency is not applicable, and is - // always treated as true, like for RED. - name_match = absl::EqualsIgnoreCase(ci.plname, payload_name); - frequency_match = (frequency == ci.plfreq) || (frequency == -1); - // The number of channels must match for all codecs but Opus. - if (!absl::EqualsIgnoreCase(payload_name, "opus")) { - channels_match = (channels == ci.channels); - } else { - // For opus we just check that number of channels is valid. - channels_match = (channels == 1 || channels == 2); - } - - if (name_match && frequency_match && channels_match) { - // We have found a matching codec in the list. - return &ci - database_; - } - } - - // We didn't find a matching codec. - return -1; -} -// Gets codec id number from database for the receiver. -int ACMCodecDB::ReceiverCodecNumber(const CodecInst& codec_inst) { - // Look for a matching codec in the database. - return CodecId(codec_inst); -} - -} // namespace acm2 - -} // namespace webrtc
diff --git a/modules/audio_coding/acm2/acm_codec_database.h b/modules/audio_coding/acm2/acm_codec_database.h deleted file mode 100644 index ee6bb46..0000000 --- a/modules/audio_coding/acm2/acm_codec_database.h +++ /dev/null
@@ -1,81 +0,0 @@ -/* - * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -/* - * This file generates databases with information about all supported audio - * codecs. - */ - -#ifndef MODULES_AUDIO_CODING_ACM2_ACM_CODEC_DATABASE_H_ -#define MODULES_AUDIO_CODING_ACM2_ACM_CODEC_DATABASE_H_ - -#include "common_types.h" // NOLINT(build/include) -#include "modules/audio_coding/acm2/rent_a_codec.h" - -namespace webrtc { - -namespace acm2 { - -// TODO(tlegrand): replace class ACMCodecDB with a namespace. -class ACMCodecDB { - public: - // kMaxNumCodecs - Maximum number of codecs that can be activated in one - // build. - // kMaxNumPacketSize - Maximum number of allowed packet sizes for one codec. - // These might need to be increased if adding a new codec to the database - static const int kMaxNumCodecs = 50; - static const int kMaxNumPacketSize = 6; - - // Codec specific settings - // - // num_packet_sizes - number of allowed packet sizes. - // packet_sizes_samples - list of the allowed packet sizes. - // basic_block_samples - assigned a value different from 0 if the codec - // requires to be fed with a specific number of samples - // that can be different from packet size. - // channel_support - number of channels supported to encode; - // 1 = mono, 2 = stereo, etc. - struct CodecSettings { - int num_packet_sizes; - int packet_sizes_samples[kMaxNumPacketSize]; - int basic_block_samples; - size_t channel_support; - }; - - // Returns codec id from database, given the information received in the input - // [codec_inst]. - // Input: - // [codec_inst] - Information about the codec for which we require the - // database id. - // Return: - // codec id if successful, otherwise < 0. - static int CodecNumber(const CodecInst& codec_inst); - static int CodecId(const CodecInst& codec_inst); - static int CodecId(const char* payload_name, int frequency, size_t channels); - static int ReceiverCodecNumber(const CodecInst& codec_inst); - - // Databases with information about the supported codecs - // database_ - stored information about all codecs: payload type, name, - // sampling frequency, packet size in samples, default channel - // support, and default rate. - // codec_settings_ - stored codec settings: number of allowed packet sizes, - // a vector with the allowed packet sizes, basic block - // samples, and max number of channels that are supported. - // neteq_decoders_ - list of supported decoders in NetEQ. - static const CodecInst database_[kMaxNumCodecs]; - static const CodecSettings codec_settings_[kMaxNumCodecs]; - static const NetEqDecoder neteq_decoders_[kMaxNumCodecs]; -}; - -} // namespace acm2 - -} // namespace webrtc - -#endif // MODULES_AUDIO_CODING_ACM2_ACM_CODEC_DATABASE_H_
diff --git a/modules/audio_coding/acm2/acm_receive_test.cc b/modules/audio_coding/acm2/acm_receive_test.cc index c149ec1..078c991 100644 --- a/modules/audio_coding/acm2/acm_receive_test.cc +++ b/modules/audio_coding/acm2/acm_receive_test.cc
@@ -14,9 +14,7 @@ #include <memory> -#include "absl/strings/match.h" #include "api/audio_codecs/builtin_audio_decoder_factory.h" -#include "modules/audio_coding/codecs/audio_format_conversion.h" #include "modules/audio_coding/include/audio_coding_module.h" #include "modules/audio_coding/neteq/tools/audio_sink.h" #include "modules/audio_coding/neteq/tools/packet.h" @@ -28,89 +26,6 @@ namespace test { namespace { -// Returns true if the codec should be registered, otherwise false. Changes -// the number of channels for the Opus codec to always be 1. -bool ModifyAndUseThisCodec(CodecInst* codec_param) { - if (absl::EqualsIgnoreCase(codec_param->plname, "CN") && - codec_param->plfreq == 48000) - return false; // Skip 48 kHz comfort noise. - - if (absl::EqualsIgnoreCase(codec_param->plname, "telephone-event")) - return false; // Skip DTFM. - - return true; -} - -// Remaps payload types from ACM's default to those used in the resource file -// neteq_universal_new.rtp. Returns true if the codec should be registered, -// otherwise false. The payload types are set as follows (all are mono codecs): -// PCMu = 0; -// PCMa = 8; -// Comfort noise 8 kHz = 13 -// Comfort noise 16 kHz = 98 -// Comfort noise 32 kHz = 99 -// iLBC = 102 -// iSAC wideband = 103 -// iSAC super-wideband = 104 -// AVT/DTMF = 106 -// RED = 117 -// PCM16b 8 kHz = 93 -// PCM16b 16 kHz = 94 -// PCM16b 32 kHz = 95 -// G.722 = 94 -bool RemapPltypeAndUseThisCodec(const char* plname, - int plfreq, - size_t channels, - int* pltype) { - if (channels != 1) - return false; // Don't use non-mono codecs. - - // Re-map pltypes to those used in the NetEq test files. - if (absl::EqualsIgnoreCase(plname, "PCMU") && plfreq == 8000) { - *pltype = 0; - } else if (absl::EqualsIgnoreCase(plname, "PCMA") && plfreq == 8000) { - *pltype = 8; - } else if (absl::EqualsIgnoreCase(plname, "CN") && plfreq == 8000) { - *pltype = 13; - } else if (absl::EqualsIgnoreCase(plname, "CN") && plfreq == 16000) { - *pltype = 98; - } else if (absl::EqualsIgnoreCase(plname, "CN") && plfreq == 32000) { - *pltype = 99; - } else if (absl::EqualsIgnoreCase(plname, "ILBC")) { - *pltype = 102; - } else if (absl::EqualsIgnoreCase(plname, "ISAC") && plfreq == 16000) { - *pltype = 103; - } else if (absl::EqualsIgnoreCase(plname, "ISAC") && plfreq == 32000) { - *pltype = 104; - } else if (absl::EqualsIgnoreCase(plname, "telephone-event") && - plfreq == 8000) { - *pltype = 106; - } else if (absl::EqualsIgnoreCase(plname, "telephone-event") && - plfreq == 16000) { - *pltype = 114; - } else if (absl::EqualsIgnoreCase(plname, "telephone-event") && - plfreq == 32000) { - *pltype = 115; - } else if (absl::EqualsIgnoreCase(plname, "telephone-event") && - plfreq == 48000) { - *pltype = 116; - } else if (absl::EqualsIgnoreCase(plname, "red")) { - *pltype = 117; - } else if (absl::EqualsIgnoreCase(plname, "L16") && plfreq == 8000) { - *pltype = 93; - } else if (absl::EqualsIgnoreCase(plname, "L16") && plfreq == 16000) { - *pltype = 94; - } else if (absl::EqualsIgnoreCase(plname, "L16") && plfreq == 32000) { - *pltype = 95; - } else if (absl::EqualsIgnoreCase(plname, "G722")) { - *pltype = 9; - } else { - // Don't use any other codecs. - return false; - } - return true; -} - AudioCodingModule::Config MakeAcmConfig( Clock* clock, rtc::scoped_refptr<AudioDecoderFactory> decoder_factory) { @@ -119,7 +34,6 @@ config.decoder_factory = std::move(decoder_factory); return config; } - } // namespace AcmReceiveTestOldApi::AcmReceiveTestOldApi( @@ -139,36 +53,43 @@ AcmReceiveTestOldApi::~AcmReceiveTestOldApi() = default; void AcmReceiveTestOldApi::RegisterDefaultCodecs() { - CodecInst my_codec_param; - for (int n = 0; n < acm_->NumberOfCodecs(); n++) { - ASSERT_EQ(0, acm_->Codec(n, &my_codec_param)) << "Failed to get codec."; - if (ModifyAndUseThisCodec(&my_codec_param)) { - ASSERT_EQ(true, - acm_->RegisterReceiveCodec(my_codec_param.pltype, - CodecInstToSdp(my_codec_param))) - << "Couldn't register receive codec.\n"; - } - } + acm_->SetReceiveCodecs({{103, {"ISAC", 16000, 1}}, + {104, {"ISAC", 32000, 1}}, + {107, {"L16", 8000, 1}}, + {108, {"L16", 16000, 1}}, + {109, {"L16", 32000, 1}}, + {111, {"L16", 8000, 2}}, + {112, {"L16", 16000, 2}}, + {113, {"L16", 32000, 2}}, + {0, {"PCMU", 8000, 1}}, + {110, {"PCMU", 8000, 2}}, + {8, {"PCMA", 8000, 1}}, + {118, {"PCMA", 8000, 2}}, + {102, {"ILBC", 8000, 1}}, + {9, {"G722", 8000, 1}}, + {119, {"G722", 8000, 2}}, + {120, {"OPUS", 48000, 2, {{"stereo", "1"}}}}, + {13, {"CN", 8000, 1}}, + {98, {"CN", 16000, 1}}, + {99, {"CN", 32000, 1}}}); } +// Remaps payload types from ACM's default to those used in the resource file +// neteq_universal_new.rtp. void AcmReceiveTestOldApi::RegisterNetEqTestCodecs() { - CodecInst my_codec_param; - for (int n = 0; n < acm_->NumberOfCodecs(); n++) { - ASSERT_EQ(0, acm_->Codec(n, &my_codec_param)) << "Failed to get codec."; - if (!ModifyAndUseThisCodec(&my_codec_param)) { - // Skip this codec. - continue; - } - - if (RemapPltypeAndUseThisCodec(my_codec_param.plname, my_codec_param.plfreq, - my_codec_param.channels, - &my_codec_param.pltype)) { - ASSERT_EQ(true, - acm_->RegisterReceiveCodec(my_codec_param.pltype, - CodecInstToSdp(my_codec_param))) - << "Couldn't register receive codec.\n"; - } - } + acm_->SetReceiveCodecs({{103, {"ISAC", 16000, 1}}, + {104, {"ISAC", 32000, 1}}, + {93, {"L16", 8000, 1}}, + {94, {"L16", 16000, 1}}, + {95, {"L16", 32000, 1}}, + {0, {"PCMU", 8000, 1}}, + {8, {"PCMA", 8000, 1}}, + {102, {"ILBC", 8000, 1}}, + {9, {"G722", 8000, 1}}, + {120, {"OPUS", 48000, 2}}, + {13, {"CN", 8000, 1}}, + {98, {"CN", 16000, 1}}, + {99, {"CN", 32000, 1}}}); } void AcmReceiveTestOldApi::Run() { @@ -199,18 +120,15 @@ AfterGetAudio(); } - // Insert packet after converting from RTPHeader to WebRtcRTPHeader. - WebRtcRTPHeader header; - header.header = packet->header(); - header.frameType = kAudioFrameSpeech; - EXPECT_EQ(0, - acm_->IncomingPacket( - packet->payload(), - static_cast<int32_t>(packet->payload_length_bytes()), header)) + EXPECT_EQ(0, acm_->IncomingPacket( + packet->payload(), + static_cast<int32_t>(packet->payload_length_bytes()), + packet->header())) << "Failure when inserting packet:" << std::endl - << " PT = " << static_cast<int>(header.header.payloadType) << std::endl - << " TS = " << header.header.timestamp << std::endl - << " SN = " << header.header.sequenceNumber; + << " PT = " << static_cast<int>(packet->header().payloadType) + << std::endl + << " TS = " << packet->header().timestamp << std::endl + << " SN = " << packet->header().sequenceNumber; } }
diff --git a/modules/audio_coding/acm2/acm_receive_test.h b/modules/audio_coding/acm2/acm_receive_test.h index 83ffcb3..9d004c6 100644 --- a/modules/audio_coding/acm2/acm_receive_test.h +++ b/modules/audio_coding/acm2/acm_receive_test.h
@@ -16,14 +16,13 @@ #include <string> #include "api/audio_codecs/audio_decoder_factory.h" -#include "rtc_base/constructormagic.h" -#include "rtc_base/scoped_ref_ptr.h" +#include "api/scoped_refptr.h" +#include "rtc_base/constructor_magic.h" #include "system_wrappers/include/clock.h" namespace webrtc { class AudioCodingModule; class AudioDecoder; -struct CodecInst; namespace test { class AudioSink; @@ -34,7 +33,8 @@ enum NumOutputChannels : size_t { kArbitraryChannels = 0, kMonoOutput = 1, - kStereoOutput = 2 + kStereoOutput = 2, + kQuadOutput = 4 }; AcmReceiveTestOldApi(PacketSource* packet_source,
diff --git a/modules/audio_coding/acm2/acm_receiver.cc b/modules/audio_coding/acm2/acm_receiver.cc index d3af7c0..da7d621 100644 --- a/modules/audio_coding/acm2/acm_receiver.cc +++ b/modules/audio_coding/acm2/acm_receiver.cc
@@ -20,9 +20,7 @@ #include "api/audio_codecs/audio_decoder.h" #include "modules/audio_coding/acm2/acm_resampler.h" #include "modules/audio_coding/acm2/call_statistics.h" -#include "modules/audio_coding/acm2/rent_a_codec.h" #include "modules/audio_coding/neteq/include/neteq.h" -#include "modules/audio_coding/neteq/neteq_decoder_enum.h" #include "modules/include/module_common_types.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" @@ -60,56 +58,66 @@ return -1; } +bool AcmReceiver::SetBaseMinimumDelayMs(int delay_ms) { + return neteq_->SetBaseMinimumDelayMs(delay_ms); +} + +int AcmReceiver::GetBaseMinimumDelayMs() const { + return neteq_->GetBaseMinimumDelayMs(); +} + absl::optional<int> AcmReceiver::last_packet_sample_rate_hz() const { rtc::CritScope lock(&crit_sect_); - return last_packet_sample_rate_hz_; + if (!last_decoder_) { + return absl::nullopt; + } + return last_decoder_->second.clockrate_hz; } int AcmReceiver::last_output_sample_rate_hz() const { return neteq_->last_output_sample_rate_hz(); } -int AcmReceiver::InsertPacket(const WebRtcRTPHeader& rtp_header, +int AcmReceiver::InsertPacket(const RTPHeader& rtp_header, rtc::ArrayView<const uint8_t> incoming_payload) { - uint32_t receive_timestamp = 0; - const RTPHeader* header = &rtp_header.header; // Just a shorthand. - if (incoming_payload.empty()) { - neteq_->InsertEmptyPacket(rtp_header.header); + neteq_->InsertEmptyPacket(rtp_header); return 0; } + int payload_type = rtp_header.payloadType; + auto format = neteq_->GetDecoderFormat(payload_type); + if (format && absl::EqualsIgnoreCase(format->name, "red")) { + // This is a RED packet. Get the format of the audio codec. + payload_type = incoming_payload[0] & 0x7f; + format = neteq_->GetDecoderFormat(payload_type); + } + if (!format) { + RTC_LOG_F(LS_ERROR) << "Payload-type " + << payload_type + << " is not registered."; + return -1; + } + { rtc::CritScope lock(&crit_sect_); - - const absl::optional<CodecInst> ci = - RtpHeaderToDecoder(*header, incoming_payload[0]); - if (!ci) { - RTC_LOG_F(LS_ERROR) << "Payload-type " - << static_cast<int>(header->payloadType) - << " is not registered."; - return -1; - } - receive_timestamp = NowInTimestamp(ci->plfreq); - - if (absl::EqualsIgnoreCase(ci->plname, "cn")) { - if (last_audio_decoder_ && last_audio_decoder_->channels > 1) { + if (absl::EqualsIgnoreCase(format->name, "cn")) { + if (last_decoder_ && last_decoder_->second.num_channels > 1) { // This is a CNG and the audio codec is not mono, so skip pushing in // packets into NetEq. return 0; } } else { - last_audio_decoder_ = ci; - last_audio_format_ = neteq_->GetDecoderFormat(ci->pltype); - RTC_DCHECK(last_audio_format_); - last_packet_sample_rate_hz_ = ci->plfreq; + RTC_DCHECK(format); + last_decoder_ = std::make_pair(payload_type, *format); } } // |crit_sect_| is released. - if (neteq_->InsertPacket(rtp_header.header, incoming_payload, - receive_timestamp) < 0) { + uint32_t receive_timestamp = NowInTimestamp(format->clockrate_hz); + if (neteq_->InsertPacket(rtp_header, incoming_payload, receive_timestamp) < + 0) { RTC_LOG(LERROR) << "AcmReceiver::InsertPacket " - << static_cast<int>(header->payloadType) + << static_cast<int>(rtp_header.payloadType) << " Failed to insert packet"; return -1; } @@ -186,85 +194,6 @@ neteq_->SetCodecs(codecs); } -int32_t AcmReceiver::AddCodec(int acm_codec_id, - uint8_t payload_type, - size_t channels, - int /*sample_rate_hz*/, - AudioDecoder* audio_decoder, - const std::string& name) { - // TODO(kwiberg): This function has been ignoring the |sample_rate_hz| - // argument for a long time. Arguably, it should simply be removed. - - const auto neteq_decoder = [acm_codec_id, channels]() -> NetEqDecoder { - if (acm_codec_id == -1) - return NetEqDecoder::kDecoderArbitrary; // External decoder. - const absl::optional<RentACodec::CodecId> cid = - RentACodec::CodecIdFromIndex(acm_codec_id); - RTC_DCHECK(cid) << "Invalid codec index: " << acm_codec_id; - const absl::optional<NetEqDecoder> ned = - RentACodec::NetEqDecoderFromCodecId(*cid, channels); - RTC_DCHECK(ned) << "Invalid codec ID: " << static_cast<int>(*cid); - return *ned; - }(); - const absl::optional<SdpAudioFormat> new_format = - NetEqDecoderToSdpAudioFormat(neteq_decoder); - - rtc::CritScope lock(&crit_sect_); - - const auto old_format = neteq_->GetDecoderFormat(payload_type); - if (old_format && new_format && *old_format == *new_format) { - // Re-registering the same codec. Do nothing and return. - return 0; - } - - if (neteq_->RemovePayloadType(payload_type) != NetEq::kOK) { - RTC_LOG(LERROR) << "Cannot remove payload " - << static_cast<int>(payload_type); - return -1; - } - - int ret_val; - if (!audio_decoder) { - ret_val = neteq_->RegisterPayloadType(neteq_decoder, name, payload_type); - } else { - ret_val = neteq_->RegisterExternalDecoder(audio_decoder, neteq_decoder, - name, payload_type); - } - if (ret_val != NetEq::kOK) { - RTC_LOG(LERROR) << "AcmReceiver::AddCodec " << acm_codec_id - << static_cast<int>(payload_type) - << " channels: " << channels; - return -1; - } - return 0; -} - -bool AcmReceiver::AddCodec(int rtp_payload_type, - const SdpAudioFormat& audio_format) { - const auto old_format = neteq_->GetDecoderFormat(rtp_payload_type); - if (old_format && *old_format == audio_format) { - // Re-registering the same codec. Do nothing and return. - return true; - } - - if (neteq_->RemovePayloadType(rtp_payload_type) != NetEq::kOK) { - RTC_LOG(LERROR) - << "AcmReceiver::AddCodec: Could not remove existing decoder" - " for payload type " - << rtp_payload_type; - return false; - } - - const bool success = - neteq_->RegisterPayloadType(rtp_payload_type, audio_format); - if (!success) { - RTC_LOG(LERROR) << "AcmReceiver::AddCodec failed for payload type " - << rtp_payload_type << ", decoder format " - << rtc::ToString(audio_format); - } - return success; -} - void AcmReceiver::FlushBuffers() { neteq_->FlushBuffers(); } @@ -272,24 +201,7 @@ void AcmReceiver::RemoveAllCodecs() { rtc::CritScope lock(&crit_sect_); neteq_->RemoveAllPayloadTypes(); - last_audio_decoder_ = absl::nullopt; - last_audio_format_ = absl::nullopt; - last_packet_sample_rate_hz_ = absl::nullopt; -} - -int AcmReceiver::RemoveCodec(uint8_t payload_type) { - rtc::CritScope lock(&crit_sect_); - if (neteq_->RemovePayloadType(payload_type) != NetEq::kOK) { - RTC_LOG(LERROR) << "AcmReceiver::RemoveCodec " - << static_cast<int>(payload_type); - return -1; - } - if (last_audio_decoder_ && payload_type == last_audio_decoder_->pltype) { - last_audio_decoder_ = absl::nullopt; - last_audio_format_ = absl::nullopt; - last_packet_sample_rate_hz_ = absl::nullopt; - } - return 0; + last_decoder_ = absl::nullopt; } absl::optional<uint32_t> AcmReceiver::GetPlayoutTimestamp() { @@ -304,18 +216,14 @@ return neteq_->TargetDelayMs(); } -int AcmReceiver::LastAudioCodec(CodecInst* codec) const { +absl::optional<std::pair<int, SdpAudioFormat>> + AcmReceiver::LastDecoder() const { rtc::CritScope lock(&crit_sect_); - if (!last_audio_decoder_) { - return -1; + if (!last_decoder_) { + return absl::nullopt; } - *codec = *last_audio_decoder_; - return 0; -} - -absl::optional<SdpAudioFormat> AcmReceiver::LastAudioFormat() const { - rtc::CritScope lock(&crit_sect_); - return last_audio_format_; + RTC_DCHECK_NE(-1, last_decoder_->first); // Payload type should be valid. + return last_decoder_; } void AcmReceiver::GetNetworkStatistics(NetworkStatistics* acm_stat) { @@ -345,8 +253,12 @@ acm_stat->concealedSamples = neteq_lifetime_stat.concealed_samples; acm_stat->concealmentEvents = neteq_lifetime_stat.concealment_events; acm_stat->jitterBufferDelayMs = neteq_lifetime_stat.jitter_buffer_delay_ms; + acm_stat->jitterBufferEmittedCount = + neteq_lifetime_stat.jitter_buffer_emitted_count; acm_stat->delayedPacketOutageSamples = neteq_lifetime_stat.delayed_packet_outage_samples; + acm_stat->relativePacketArrivalDelayMs = + neteq_lifetime_stat.relative_packet_arrival_delay_ms; NetEqOperationsAndState neteq_operations_and_state = neteq_->GetOperationsAndState(); @@ -354,26 +266,6 @@ neteq_operations_and_state.packet_buffer_flushes; } -int AcmReceiver::DecoderByPayloadType(uint8_t payload_type, - CodecInst* codec) const { - rtc::CritScope lock(&crit_sect_); - const absl::optional<CodecInst> ci = neteq_->GetDecoder(payload_type); - if (ci) { - *codec = *ci; - return 0; - } else { - RTC_LOG(LERROR) << "AcmReceiver::DecoderByPayloadType " - << static_cast<int>(payload_type); - return -1; - } -} - -absl::optional<SdpAudioFormat> AcmReceiver::DecoderByPayloadType( - int payload_type) const { - rtc::CritScope lock(&crit_sect_); - return neteq_->GetDecoderFormat(payload_type); -} - int AcmReceiver::EnableNack(size_t max_nack_list_size) { neteq_->EnableNack(max_nack_list_size); return 0; @@ -393,19 +285,6 @@ // TODO(turajs): Should NetEq Buffer be flushed? } -const absl::optional<CodecInst> AcmReceiver::RtpHeaderToDecoder( - const RTPHeader& rtp_header, - uint8_t first_payload_byte) const { - const absl::optional<CodecInst> ci = - neteq_->GetDecoder(rtp_header.payloadType); - if (ci && absl::EqualsIgnoreCase(ci->plname, "red")) { - // This is a RED packet. Get the payload of the audio codec. - return neteq_->GetDecoder(first_payload_byte & 0x7f); - } else { - return ci; - } -} - uint32_t AcmReceiver::NowInTimestamp(int decoder_sampling_rate) const { // Down-cast the time to (32-6)-bit since we only care about // the least significant bits. (32-6) bits cover 2^(32-6) = 67108864 ms.
diff --git a/modules/audio_coding/acm2/acm_receiver.h b/modules/audio_coding/acm2/acm_receiver.h index 8e7d839..1f449a3 100644 --- a/modules/audio_coding/acm2/acm_receiver.h +++ b/modules/audio_coding/acm2/acm_receiver.h
@@ -15,6 +15,7 @@ #include <map> #include <memory> #include <string> +#include <utility> #include <vector> #include "absl/types/optional.h" @@ -24,16 +25,14 @@ #include "modules/audio_coding/acm2/acm_resampler.h" #include "modules/audio_coding/acm2/call_statistics.h" #include "modules/audio_coding/include/audio_coding_module.h" -#include "rtc_base/criticalsection.h" +#include "rtc_base/critical_section.h" #include "rtc_base/thread_annotations.h" namespace webrtc { class Clock; -struct CodecInst; class NetEq; struct RTPHeader; -struct WebRtcRTPHeader; namespace acm2 { @@ -58,7 +57,7 @@ // Return value : 0 if OK. // <0 if NetEq returned an error. // - int InsertPacket(const WebRtcRTPHeader& rtp_header, + int InsertPacket(const RTPHeader& rtp_header, rtc::ArrayView<const uint8_t> incoming_payload); // @@ -85,43 +84,6 @@ void SetCodecs(const std::map<int, SdpAudioFormat>& codecs); // - // Adds a new codec to the NetEq codec database. - // - // Input: - // - acm_codec_id : ACM codec ID; -1 means external decoder. - // - payload_type : payload type. - // - sample_rate_hz : sample rate. - // - audio_decoder : pointer to a decoder object. If it's null, then - // NetEq will internally create a decoder object - // based on the value of |acm_codec_id| (which - // mustn't be -1). Otherwise, NetEq will use the - // given decoder for the given payload type. NetEq - // won't take ownership of the decoder; it's up to - // the caller to delete it when it's no longer - // needed. - // - // Providing an existing decoder object here is - // necessary for external decoders, but may also be - // used for built-in decoders if NetEq doesn't have - // all the info it needs to construct them properly - // (e.g. iSAC, where the decoder needs to be paired - // with an encoder). - // - // Return value : 0 if OK. - // <0 if NetEq returned an error. - // - int AddCodec(int acm_codec_id, - uint8_t payload_type, - size_t channels, - int sample_rate_hz, - AudioDecoder* audio_decoder, - const std::string& name); - - // Adds a new decoder to the NetEq codec database. Returns true iff - // successful. - bool AddCodec(int rtp_payload_type, const SdpAudioFormat& audio_format); - - // // Sets a minimum delay for packet buffer. The given delay is maintained, // unless channel condition dictates a higher delay. // @@ -145,6 +107,16 @@ // int SetMaximumDelay(int delay_ms); + // Sets a base minimum delay in milliseconds for the packet buffer. + // Base minimum delay sets lower bound minimum delay value which + // is set via SetMinimumDelay. + // + // Returns true if value was successfully set, false overwise. + bool SetBaseMinimumDelayMs(int delay_ms); + + // Returns current value of base minimum delay in milliseconds. + int GetBaseMinimumDelayMs() const; + // // Resets the initial delay to zero. // @@ -173,17 +145,6 @@ void FlushBuffers(); // - // Removes a payload-type from the NetEq codec database. - // - // Input: - // - payload_type : the payload-type to be removed. - // - // Return value : 0 if OK. - // -1 if an error occurred. - // - int RemoveCodec(uint8_t payload_type); - - // // Remove all registered codecs. // void RemoveAllCodecs(); @@ -204,30 +165,10 @@ int TargetDelayMs() const; // - // Get the audio codec associated with the last non-CNG/non-DTMF received - // payload. If no non-CNG/non-DTMF packet is received -1 is returned, - // otherwise return 0. + // Get payload type and format of the last non-CNG/non-DTMF received payload. + // If no non-CNG/non-DTMF packet is received absl::nullopt is returned. // - int LastAudioCodec(CodecInst* codec) const; - - absl::optional<SdpAudioFormat> LastAudioFormat() const; - - // - // Get a decoder given its registered payload-type. - // - // Input: - // -payload_type : the payload-type of the codec to be retrieved. - // - // Output: - // -codec : codec associated with the given payload-type. - // - // Return value : 0 if succeeded. - // -1 if failed, e.g. given payload-type is not - // registered. - // - int DecoderByPayloadType(uint8_t payload_type, - CodecInst* codec) const; - absl::optional<SdpAudioFormat> DecoderByPayloadType(int payload_type) const; + absl::optional<std::pair<int, SdpAudioFormat>> LastDecoder() const; // // Enable NACK and set the maximum size of the NACK list. If NACK is already @@ -260,32 +201,17 @@ void GetDecodingCallStatistics(AudioDecodingCallStats* stats) const; private: - struct Decoder { - int acm_codec_id; - uint8_t payload_type; - // This field is meaningful for codecs where both mono and - // stereo versions are registered under the same ID. - size_t channels; - int sample_rate_hz; - }; - - const absl::optional<CodecInst> RtpHeaderToDecoder( - const RTPHeader& rtp_header, - uint8_t first_payload_byte) const - RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_sect_); - uint32_t NowInTimestamp(int decoder_sampling_rate) const; rtc::CriticalSection crit_sect_; - absl::optional<CodecInst> last_audio_decoder_ RTC_GUARDED_BY(crit_sect_); - absl::optional<SdpAudioFormat> last_audio_format_ RTC_GUARDED_BY(crit_sect_); + absl::optional<std::pair<int, SdpAudioFormat>> last_decoder_ + RTC_GUARDED_BY(crit_sect_); ACMResampler resampler_ RTC_GUARDED_BY(crit_sect_); std::unique_ptr<int16_t[]> last_audio_buffer_ RTC_GUARDED_BY(crit_sect_); CallStatistics call_stats_ RTC_GUARDED_BY(crit_sect_); const std::unique_ptr<NetEq> neteq_; // NetEq is thread-safe; no lock needed. - const Clock* const clock_; + Clock* const clock_; bool resampled_last_output_frame_ RTC_GUARDED_BY(crit_sect_); - absl::optional<int> last_packet_sample_rate_hz_ RTC_GUARDED_BY(crit_sect_); }; } // namespace acm2
diff --git a/modules/audio_coding/acm2/acm_receiver_unittest.cc b/modules/audio_coding/acm2/acm_receiver_unittest.cc index 46384fe..e5a7684 100644 --- a/modules/audio_coding/acm2/acm_receiver_unittest.cc +++ b/modules/audio_coding/acm2/acm_receiver_unittest.cc
@@ -15,7 +15,6 @@ #include "api/audio_codecs/builtin_audio_decoder_factory.h" #include "api/audio_codecs/builtin_audio_encoder_factory.h" -#include "modules/audio_coding/acm2/rent_a_codec.h" #include "modules/audio_coding/codecs/cng/audio_encoder_cng.h" #include "modules/audio_coding/include/audio_coding_module.h" #include "modules/audio_coding/neteq/tools/rtp_generator.h" @@ -24,7 +23,7 @@ #include "rtc_base/numerics/safe_conversions.h" #include "system_wrappers/include/clock.h" #include "test/gtest.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" namespace webrtc { @@ -51,13 +50,12 @@ acm_->InitializeReceiver(); acm_->RegisterTransportCallback(this); - rtp_header_.header.sequenceNumber = 0; - rtp_header_.header.timestamp = 0; - rtp_header_.header.markerBit = false; - rtp_header_.header.ssrc = 0x12345678; // Arbitrary. - rtp_header_.header.numCSRCs = 0; - rtp_header_.header.payloadType = 0; - rtp_header_.frameType = kAudioFrameSpeech; + rtp_header_.sequenceNumber = 0; + rtp_header_.timestamp = 0; + rtp_header_.markerBit = false; + rtp_header_.ssrc = 0x12345678; // Arbitrary. + rtp_header_.numCSRCs = 0; + rtp_header_.payloadType = 0; } void TearDown() override {} @@ -105,14 +103,6 @@ return num_10ms_frames; } - template <size_t N> - void AddSetOfCodecs(rtc::ArrayView<SdpAudioFormat> formats) { - static int payload_type = 0; - for (const auto& format : formats) { - EXPECT_TRUE(receiver_->AddCodec(payload_type++, format)); - } - } - int SendData(FrameType frame_type, uint8_t payload_type, uint32_t timestamp, @@ -122,9 +112,8 @@ if (frame_type == kEmptyFrame) return 0; - rtp_header_.header.payloadType = payload_type; - rtp_header_.frameType = frame_type; - rtp_header_.header.timestamp = timestamp; + rtp_header_.payloadType = payload_type; + rtp_header_.timestamp = timestamp; int ret_val = receiver_->InsertPacket( rtp_header_, @@ -133,7 +122,7 @@ assert(false); return -1; } - rtp_header_.header.sequenceNumber++; + rtp_header_.sequenceNumber++; packet_sent_ = true; last_frame_type_ = frame_type; return 0; @@ -146,7 +135,7 @@ AudioCodingModule::Config config_; std::unique_ptr<AcmReceiver> receiver_; std::unique_ptr<AudioCodingModule> acm_; - WebRtcRTPHeader rtp_header_; + RTPHeader rtp_header_; uint32_t timestamp_; bool packet_sent_; // Set when SendData is called reset when inserting audio. uint32_t last_packet_send_timestamp_; @@ -154,111 +143,26 @@ }; #if defined(WEBRTC_ANDROID) -#define MAYBE_AddCodecGetCodec DISABLED_AddCodecGetCodec -#else -#define MAYBE_AddCodecGetCodec AddCodecGetCodec -#endif -TEST_F(AcmReceiverTestOldApi, MAYBE_AddCodecGetCodec) { - const std::vector<AudioCodecSpec> codecs = - decoder_factory_->GetSupportedDecoders(); - - // Add codec. - for (size_t n = 0; n < codecs.size(); ++n) { - if (n & 0x1) { // Just add codecs with odd index. - const int payload_type = rtc::checked_cast<int>(n); - EXPECT_TRUE(receiver_->AddCodec(payload_type, codecs[n].format)); - } - } - // Get codec and compare. - for (size_t n = 0; n < codecs.size(); ++n) { - const int payload_type = rtc::checked_cast<int>(n); - if (n & 0x1) { - // Codecs with odd index should match the reference. - EXPECT_EQ(absl::make_optional(codecs[n].format), - receiver_->DecoderByPayloadType(payload_type)); - } else { - // Codecs with even index are not registered. - EXPECT_EQ(absl::nullopt, receiver_->DecoderByPayloadType(payload_type)); - } - } -} - -#if defined(WEBRTC_ANDROID) -#define MAYBE_AddCodecChangePayloadType DISABLED_AddCodecChangePayloadType -#else -#define MAYBE_AddCodecChangePayloadType AddCodecChangePayloadType -#endif -TEST_F(AcmReceiverTestOldApi, MAYBE_AddCodecChangePayloadType) { - const SdpAudioFormat format("giraffe", 8000, 1); - - // Register the same codec with different payloads. - EXPECT_EQ(true, receiver_->AddCodec(17, format)); - EXPECT_EQ(true, receiver_->AddCodec(18, format)); - - // Both payload types should exist. - EXPECT_EQ(absl::make_optional(format), receiver_->DecoderByPayloadType(17)); - EXPECT_EQ(absl::make_optional(format), receiver_->DecoderByPayloadType(18)); -} - -#if defined(WEBRTC_ANDROID) -#define MAYBE_AddCodecChangeCodecId DISABLED_AddCodecChangeCodecId -#else -#define MAYBE_AddCodecChangeCodecId AddCodecChangeCodecId -#endif -TEST_F(AcmReceiverTestOldApi, AddCodecChangeCodecId) { - const SdpAudioFormat format1("giraffe", 8000, 1); - const SdpAudioFormat format2("gnu", 16000, 1); - - // Register the same payload type with different codec ID. - EXPECT_EQ(true, receiver_->AddCodec(17, format1)); - EXPECT_EQ(true, receiver_->AddCodec(17, format2)); - - // Make sure that the last codec is used. - EXPECT_EQ(absl::make_optional(format2), receiver_->DecoderByPayloadType(17)); -} - -#if defined(WEBRTC_ANDROID) -#define MAYBE_AddCodecRemoveCodec DISABLED_AddCodecRemoveCodec -#else -#define MAYBE_AddCodecRemoveCodec AddCodecRemoveCodec -#endif -TEST_F(AcmReceiverTestOldApi, MAYBE_AddCodecRemoveCodec) { - EXPECT_EQ(true, receiver_->AddCodec(17, SdpAudioFormat("giraffe", 8000, 1))); - - // Remove non-existing codec should not fail. ACM1 legacy. - EXPECT_EQ(0, receiver_->RemoveCodec(18)); - - // Remove an existing codec. - EXPECT_EQ(0, receiver_->RemoveCodec(17)); - - // Ask for the removed codec, must fail. - EXPECT_EQ(absl::nullopt, receiver_->DecoderByPayloadType(17)); -} - -#if defined(WEBRTC_ANDROID) #define MAYBE_SampleRate DISABLED_SampleRate #else #define MAYBE_SampleRate SampleRate #endif TEST_F(AcmReceiverTestOldApi, MAYBE_SampleRate) { - const std::vector<SdpAudioFormat> codecs = {{"ISAC", 16000, 1}, - {"ISAC", 32000, 1}}; - for (size_t i = 0; i < codecs.size(); ++i) { - const int payload_type = rtc::checked_cast<int>(i); - EXPECT_EQ(true, receiver_->AddCodec(payload_type, codecs[i])); - } + const std::map<int, SdpAudioFormat> codecs = {{0, {"ISAC", 16000, 1}}, + {1, {"ISAC", 32000, 1}}}; + receiver_->SetCodecs(codecs); constexpr int kOutSampleRateHz = 8000; // Different than codec sample rate. for (size_t i = 0; i < codecs.size(); ++i) { const int payload_type = rtc::checked_cast<int>(i); const int num_10ms_frames = - InsertOnePacketOfSilence(SetEncoder(payload_type, codecs[i])); + InsertOnePacketOfSilence(SetEncoder(payload_type, codecs.at(i))); for (int k = 0; k < num_10ms_frames; ++k) { AudioFrame frame; bool muted; EXPECT_EQ(0, receiver_->GetAudio(kOutSampleRateHz, &frame, &muted)); } - EXPECT_EQ(encoder_factory_->QueryAudioEncoder(codecs[i])->sample_rate_hz, + EXPECT_EQ(encoder_factory_->QueryAudioEncoder(codecs.at(i))->sample_rate_hz, receiver_->last_output_sample_rate_hz()); } } @@ -278,7 +182,7 @@ EXPECT_TRUE(config_.neteq_config.for_test_no_time_stretching); constexpr int payload_type = 17; - EXPECT_TRUE(receiver_->AddCodec(payload_type, codec)); + receiver_->SetCodecs({{payload_type, codec}}); const AudioCodecInfo info = SetEncoder(payload_type, codec); const int output_sample_rate_hz = info.sample_rate_hz; @@ -356,7 +260,7 @@ constexpr int payload_type = 34; const SdpAudioFormat codec = {"L16", 16000, 1}; const AudioCodecInfo info = SetEncoder(payload_type, codec); - EXPECT_TRUE(receiver_->AddCodec(payload_type, codec)); + receiver_->SetCodecs({{payload_type, codec}}); constexpr int kNumPackets = 5; AudioFrame frame; for (int n = 0; n < kNumPackets; ++n) { @@ -387,7 +291,7 @@ const SdpAudioFormat codec = {"L16", 16000, 1}; const AudioCodecInfo info = SetEncoder(payload_type, codec); encoder_factory_->QueryAudioEncoder(codec).value(); - EXPECT_TRUE(receiver_->AddCodec(payload_type, codec)); + receiver_->SetCodecs({{payload_type, codec}}); const int kNumPackets = 5; AudioFrame frame; for (int n = 0; n < kNumPackets; ++n) { @@ -407,43 +311,43 @@ #endif #if defined(WEBRTC_CODEC_ISAC) TEST_F(AcmReceiverTestOldApi, MAYBE_LastAudioCodec) { - const std::vector<SdpAudioFormat> codecs = {{"ISAC", 16000, 1}, - {"PCMA", 8000, 1}, - {"ISAC", 32000, 1}, - {"L16", 32000, 1}}; - for (size_t i = 0; i < codecs.size(); ++i) { - const int payload_type = rtc::checked_cast<int>(i); - EXPECT_TRUE(receiver_->AddCodec(payload_type, codecs[i])); - } - - const std::map<int, int> cng_payload_types = { - {8000, 100}, {16000, 101}, {32000, 102}}; - for (const auto& x : cng_payload_types) { - const int sample_rate_hz = x.first; - const int payload_type = x.second; - EXPECT_TRUE(receiver_->AddCodec(payload_type, {"CN", sample_rate_hz, 1})); + const std::map<int, SdpAudioFormat> codecs = {{0, {"ISAC", 16000, 1}}, + {1, {"PCMA", 8000, 1}}, + {2, {"ISAC", 32000, 1}}, + {3, {"L16", 32000, 1}}}; + const std::map<int, int> cng_payload_types = {{8000, 100}, + {16000, 101}, + {32000, 102}}; + { + std::map<int, SdpAudioFormat> receive_codecs = codecs; + for (const auto& cng_type : cng_payload_types) { + receive_codecs.emplace( + std::make_pair(cng_type.second, SdpAudioFormat("CN", cng_type.first, 1))); + } + receiver_->SetCodecs(receive_codecs); } // No audio payload is received. - EXPECT_EQ(absl::nullopt, receiver_->LastAudioFormat()); + EXPECT_EQ(absl::nullopt, receiver_->LastDecoder()); // Start with sending DTX. packet_sent_ = false; InsertOnePacketOfSilence( - SetEncoder(0, codecs[0], cng_payload_types)); // Enough to test + SetEncoder(0, codecs.at(0), cng_payload_types)); // Enough to test // with one codec. ASSERT_TRUE(packet_sent_); EXPECT_EQ(kAudioFrameCN, last_frame_type_); // Has received, only, DTX. Last Audio codec is undefined. - EXPECT_EQ(absl::nullopt, receiver_->LastAudioFormat()); - EXPECT_FALSE(receiver_->last_packet_sample_rate_hz()); + EXPECT_EQ(absl::nullopt, receiver_->LastDecoder()); + EXPECT_EQ(absl::nullopt, receiver_->last_packet_sample_rate_hz()); for (size_t i = 0; i < codecs.size(); ++i) { // Set DTX off to send audio payload. packet_sent_ = false; const int payload_type = rtc::checked_cast<int>(i); - const AudioCodecInfo info_without_cng = SetEncoder(payload_type, codecs[i]); + const AudioCodecInfo info_without_cng = + SetEncoder(payload_type, codecs.at(i)); InsertOnePacketOfSilence(info_without_cng); // Sanity check if Actually an audio payload received, and it should be @@ -456,7 +360,7 @@ // Set VAD on to send DTX. Then check if the "Last Audio codec" returns // the expected codec. Encode repeatedly until a DTX is sent. const AudioCodecInfo info_with_cng = - SetEncoder(payload_type, codecs[i], cng_payload_types); + SetEncoder(payload_type, codecs.at(i), cng_payload_types); while (last_frame_type_ != kAudioFrameCN) { packet_sent_ = false; InsertOnePacketOfSilence(info_with_cng); @@ -464,7 +368,7 @@ } EXPECT_EQ(info_with_cng.sample_rate_hz, receiver_->last_packet_sample_rate_hz()); - EXPECT_EQ(codecs[i], receiver_->LastAudioFormat()); + EXPECT_EQ(codecs.at(i), receiver_->LastDecoder()->second); } } #endif
diff --git a/modules/audio_coding/acm2/acm_send_test.cc b/modules/audio_coding/acm2/acm_send_test.cc index c5e010c..b6110b6 100644 --- a/modules/audio_coding/acm2/acm_send_test.cc +++ b/modules/audio_coding/acm2/acm_send_test.cc
@@ -14,15 +14,15 @@ #include <stdio.h> #include <string.h> +#include "absl/strings/match.h" #include "api/audio_codecs/audio_encoder.h" #include "api/audio_codecs/builtin_audio_decoder_factory.h" #include "api/audio_codecs/builtin_audio_encoder_factory.h" -#include "modules/audio_coding/codecs/audio_format_conversion.h" #include "modules/audio_coding/include/audio_coding_module.h" #include "modules/audio_coding/neteq/tools/input_audio_file.h" #include "modules/audio_coding/neteq/tools/packet.h" #include "rtc_base/checks.h" -#include "rtc_base/stringencode.h" +#include "rtc_base/string_encode.h" #include "test/gtest.h" namespace webrtc { @@ -59,23 +59,28 @@ AcmSendTestOldApi::~AcmSendTestOldApi() = default; bool AcmSendTestOldApi::RegisterCodec(const char* payload_name, - int sampling_freq_hz, - int channels, + int clockrate_hz, + int num_channels, int payload_type, int frame_size_samples) { - CodecInst codec; - RTC_CHECK_EQ(0, AudioCodingModule::Codec(payload_name, &codec, - sampling_freq_hz, channels)); - codec.pltype = payload_type; - codec.pacsize = frame_size_samples; - auto factory = CreateBuiltinAudioEncoderFactory(); - SdpAudioFormat format = CodecInstToSdp(codec); + SdpAudioFormat format(payload_name, clockrate_hz, num_channels); + if (absl::EqualsIgnoreCase(payload_name, "g722")) { + RTC_CHECK_EQ(16000, clockrate_hz); + format.clockrate_hz = 8000; + } else if (absl::EqualsIgnoreCase(payload_name, "opus")) { + RTC_CHECK(num_channels == 1 || num_channels == 2); + if (num_channels == 2) { + format.parameters["stereo"] = "1"; + } + format.num_channels = 2; + } format.parameters["ptime"] = rtc::ToString(rtc::CheckedDivExact( - frame_size_samples, rtc::CheckedDivExact(sampling_freq_hz, 1000))); + frame_size_samples, rtc::CheckedDivExact(clockrate_hz, 1000))); + auto factory = CreateBuiltinAudioEncoderFactory(); acm_->SetEncoder( factory->MakeAudioEncoder(payload_type, format, absl::nullopt)); codec_registered_ = true; - input_frame_.num_channels_ = channels; + input_frame_.num_channels_ = num_channels; assert(input_block_size_samples_ * input_frame_.num_channels_ <= AudioFrame::kMaxDataSizeSamples); return codec_registered_; @@ -101,13 +106,9 @@ // Insert audio and process until one packet is produced. while (clock_.TimeInMilliseconds() < test_duration_ms_) { clock_.AdvanceTimeMilliseconds(kBlockSizeMs); - RTC_CHECK(audio_source_->Read(input_block_size_samples_, - input_frame_.mutable_data())); - if (input_frame_.num_channels_ > 1) { - InputAudioFile::DuplicateInterleaved( - input_frame_.data(), input_block_size_samples_, - input_frame_.num_channels_, input_frame_.mutable_data()); - } + RTC_CHECK(audio_source_->Read( + input_block_size_samples_ * input_frame_.num_channels_, + input_frame_.mutable_data())); data_to_send_ = false; RTC_CHECK_GE(acm_->Add10MsData(input_frame_), 0); input_frame_.timestamp_ += static_cast<uint32_t>(input_block_size_samples_);
diff --git a/modules/audio_coding/acm2/acm_send_test.h b/modules/audio_coding/acm2/acm_send_test.h index 3479de0..24d230b 100644 --- a/modules/audio_coding/acm2/acm_send_test.h +++ b/modules/audio_coding/acm2/acm_send_test.h
@@ -17,7 +17,7 @@ #include "api/audio/audio_frame.h" #include "modules/audio_coding/include/audio_coding_module.h" #include "modules/audio_coding/neteq/tools/packet_source.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" #include "system_wrappers/include/clock.h" namespace webrtc {
diff --git a/modules/audio_coding/acm2/audio_coding_module.cc b/modules/audio_coding/acm2/audio_coding_module.cc index c0aab3a..1547b37 100644 --- a/modules/audio_coding/acm2/audio_coding_module.cc +++ b/modules/audio_coding/acm2/audio_coding_module.cc
@@ -18,12 +18,11 @@ #include "api/array_view.h" #include "modules/audio_coding/acm2/acm_receiver.h" #include "modules/audio_coding/acm2/acm_resampler.h" -#include "modules/audio_coding/acm2/rent_a_codec.h" #include "modules/include/module_common_types.h" #include "modules/include/module_common_types_public.h" #include "rtc_base/buffer.h" #include "rtc_base/checks.h" -#include "rtc_base/criticalsection.h" +#include "rtc_base/critical_section.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/thread_annotations.h" @@ -45,9 +44,6 @@ void ModifyEncoder(rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier) override; - // Get current send codec. - absl::optional<CodecInst> SendCodec() const override; - // Sets the bitrate to the specified value in bits/sec. In case the codec does // not support the requested value it will choose an appropriate value // instead. @@ -90,24 +86,13 @@ void SetReceiveCodecs(const std::map<int, SdpAudioFormat>& codecs) override; - bool RegisterReceiveCodec(int rtp_payload_type, - const SdpAudioFormat& audio_format) override; - - int RegisterExternalReceiveCodec(int rtp_payload_type, - AudioDecoder* external_decoder, - int sample_rate_hz, - int num_channels, - const std::string& name) override; - // Get current received codec. - int ReceiveCodec(CodecInst* current_codec) const override; - - absl::optional<SdpAudioFormat> ReceiveFormat() const override; + absl::optional<std::pair<int, SdpAudioFormat>> ReceiveCodec() const override; // Incoming packet from network parsed and ready for decode. int IncomingPacket(const uint8_t* incoming_payload, const size_t payload_length, - const WebRtcRTPHeader& rtp_info) override; + const RTPHeader& rtp_info) override; // Minimum playout delay. int SetMinimumPlayoutDelay(int time_ms) override; @@ -115,6 +100,10 @@ // Maximum playout delay. int SetMaximumPlayoutDelay(int time_ms) override; + bool SetBaseMinimumPlayoutDelayMs(int delay_ms) override; + + int GetBaseMinimumPlayoutDelayMs() const override; + absl::optional<uint32_t> PlayoutTimestamp() override; int FilteredCurrentDelayMs() const override; @@ -141,8 +130,6 @@ int DisableOpusDtx() override; - int UnregisterReceiveCodec(uint8_t payload_type) override; - int EnableNack(size_t max_nack_list_size) override; void DisableNack() override; @@ -317,42 +304,6 @@ } } -// Wraps a raw AudioEncoder pointer. The idea is that you can put one of these -// in a unique_ptr, to protect the contained raw pointer from being deleted -// when the unique_ptr expires. (This is of course a bad idea in general, but -// backwards compatibility.) -class RawAudioEncoderWrapper final : public AudioEncoder { - public: - RawAudioEncoderWrapper(AudioEncoder* enc) : enc_(enc) {} - int SampleRateHz() const override { return enc_->SampleRateHz(); } - size_t NumChannels() const override { return enc_->NumChannels(); } - int RtpTimestampRateHz() const override { return enc_->RtpTimestampRateHz(); } - size_t Num10MsFramesInNextPacket() const override { - return enc_->Num10MsFramesInNextPacket(); - } - size_t Max10MsFramesInAPacket() const override { - return enc_->Max10MsFramesInAPacket(); - } - int GetTargetBitrate() const override { return enc_->GetTargetBitrate(); } - EncodedInfo EncodeImpl(uint32_t rtp_timestamp, - rtc::ArrayView<const int16_t> audio, - rtc::Buffer* encoded) override { - return enc_->Encode(rtp_timestamp, audio, encoded); - } - void Reset() override { return enc_->Reset(); } - bool SetFec(bool enable) override { return enc_->SetFec(enable); } - bool SetDtx(bool enable) override { return enc_->SetDtx(enable); } - bool SetApplication(Application application) override { - return enc_->SetApplication(application); - } - void SetMaxPlaybackRate(int frequency_hz) override { - return enc_->SetMaxPlaybackRate(frequency_hz); - } - - private: - AudioEncoder* enc_; -}; - void AudioCodingModuleImpl::ChangeLogger::MaybeLog(int value) { if (value != last_value_ || first_time_) { first_time_ = false; @@ -480,26 +431,6 @@ modifier(&encoder_stack_); } -// Get current send codec. -absl::optional<CodecInst> AudioCodingModuleImpl::SendCodec() const { - rtc::CritScope lock(&acm_crit_sect_); - if (encoder_stack_) { - CodecInst ci; - ci.channels = encoder_stack_->NumChannels(); - ci.plfreq = encoder_stack_->SampleRateHz(); - ci.pacsize = rtc::CheckedDivExact( - static_cast<int>(encoder_stack_->Max10MsFramesInAPacket() * ci.plfreq), - 100); - ci.pltype = -1; // Not valid. - ci.rate = -1; // Not valid. - static const char kName[] = "external"; - memcpy(ci.plname, kName, sizeof(kName)); - return ci; - } else { - return absl::nullopt; - } -} - void AudioCodingModuleImpl::SetBitRate(int bitrate_bps) { rtc::CritScope lock(&acm_crit_sect_); if (encoder_stack_) { @@ -546,7 +477,9 @@ return -1; } - if (audio_frame.num_channels_ != 1 && audio_frame.num_channels_ != 2) { + if (audio_frame.num_channels_ != 1 && audio_frame.num_channels_ != 2 && + audio_frame.num_channels_ != 4 && audio_frame.num_channels_ != 6 && + audio_frame.num_channels_ != 8) { RTC_LOG(LS_ERROR) << "Cannot Add 10 ms audio, invalid number of channels."; return -1; } @@ -721,9 +654,6 @@ // start-up. if (receiver_initialized_) receiver_.RemoveAllCodecs(); - receiver_.ResetInitialDelay(); - receiver_.SetMinimumDelay(0); - receiver_.SetMaximumDelay(0); receiver_.FlushBuffers(); receiver_initialized_ = true; @@ -748,60 +678,16 @@ receiver_.SetCodecs(codecs); } -bool AudioCodingModuleImpl::RegisterReceiveCodec( - int rtp_payload_type, - const SdpAudioFormat& audio_format) { +absl::optional<std::pair<int, SdpAudioFormat>> + AudioCodingModuleImpl::ReceiveCodec() const { rtc::CritScope lock(&acm_crit_sect_); - RTC_DCHECK(receiver_initialized_); - - if (!acm2::RentACodec::IsPayloadTypeValid(rtp_payload_type)) { - RTC_LOG_F(LS_ERROR) << "Invalid payload-type " << rtp_payload_type - << " for decoder."; - return false; - } - - return receiver_.AddCodec(rtp_payload_type, audio_format); -} - -int AudioCodingModuleImpl::RegisterExternalReceiveCodec( - int rtp_payload_type, - AudioDecoder* external_decoder, - int sample_rate_hz, - int num_channels, - const std::string& name) { - rtc::CritScope lock(&acm_crit_sect_); - RTC_DCHECK(receiver_initialized_); - if (num_channels > 2 || num_channels < 0) { - RTC_LOG_F(LS_ERROR) << "Unsupported number of channels: " << num_channels; - return -1; - } - - // Check if the payload-type is valid. - if (!acm2::RentACodec::IsPayloadTypeValid(rtp_payload_type)) { - RTC_LOG_F(LS_ERROR) << "Invalid payload-type " << rtp_payload_type - << " for external decoder."; - return -1; - } - - return receiver_.AddCodec(-1 /* external */, rtp_payload_type, num_channels, - sample_rate_hz, external_decoder, name); -} - -// Get current received codec. -int AudioCodingModuleImpl::ReceiveCodec(CodecInst* current_codec) const { - rtc::CritScope lock(&acm_crit_sect_); - return receiver_.LastAudioCodec(current_codec); -} - -absl::optional<SdpAudioFormat> AudioCodingModuleImpl::ReceiveFormat() const { - rtc::CritScope lock(&acm_crit_sect_); - return receiver_.LastAudioFormat(); + return receiver_.LastDecoder(); } // Incoming packet from network parsed and ready for decode. int AudioCodingModuleImpl::IncomingPacket(const uint8_t* incoming_payload, const size_t payload_length, - const WebRtcRTPHeader& rtp_header) { + const RTPHeader& rtp_header) { RTC_DCHECK_EQ(payload_length == 0, incoming_payload == nullptr); return receiver_.InsertPacket( rtp_header, @@ -825,6 +711,15 @@ return receiver_.SetMaximumDelay(time_ms); } +bool AudioCodingModuleImpl::SetBaseMinimumPlayoutDelayMs(int delay_ms) { + // All necessary validation happens on NetEq level. + return receiver_.SetBaseMinimumDelayMs(delay_ms); +} + +int AudioCodingModuleImpl::GetBaseMinimumPlayoutDelayMs() const { + return receiver_.GetBaseMinimumDelayMs(); +} + // Get 10 milliseconds of raw audio data to play out. // Automatic resample to the requested frequency. int AudioCodingModuleImpl::PlayoutData10Ms(int desired_freq_hz, @@ -902,10 +797,6 @@ return true; } -int AudioCodingModuleImpl::UnregisterReceiveCodec(uint8_t payload_type) { - return receiver_.RemoveCodec(payload_type); -} - int AudioCodingModuleImpl::EnableNack(size_t max_nack_list_size) { return receiver_.EnableNack(max_nack_list_size); } @@ -951,52 +842,4 @@ return new AudioCodingModuleImpl(config); } -int AudioCodingModule::NumberOfCodecs() { - return static_cast<int>(acm2::RentACodec::NumberOfCodecs()); -} - -int AudioCodingModule::Codec(int list_id, CodecInst* codec) { - auto codec_id = acm2::RentACodec::CodecIdFromIndex(list_id); - if (!codec_id) - return -1; - auto ci = acm2::RentACodec::CodecInstById(*codec_id); - if (!ci) - return -1; - *codec = *ci; - return 0; -} - -int AudioCodingModule::Codec(const char* payload_name, - CodecInst* codec, - int sampling_freq_hz, - size_t channels) { - absl::optional<CodecInst> ci = acm2::RentACodec::CodecInstByParams( - payload_name, sampling_freq_hz, channels); - if (ci) { - *codec = *ci; - return 0; - } else { - // We couldn't find a matching codec, so set the parameters to unacceptable - // values and return. - codec->plname[0] = '\0'; - codec->pltype = -1; - codec->pacsize = 0; - codec->rate = 0; - codec->plfreq = 0; - return -1; - } -} - -int AudioCodingModule::Codec(const char* payload_name, - int sampling_freq_hz, - size_t channels) { - absl::optional<acm2::RentACodec::CodecId> ci = - acm2::RentACodec::CodecIdByParams(payload_name, sampling_freq_hz, - channels); - if (!ci) - return -1; - absl::optional<int> i = acm2::RentACodec::CodecIndexFromId(*ci); - return i ? *i : -1; -} - } // namespace webrtc
diff --git a/modules/audio_coding/acm2/audio_coding_module_unittest.cc b/modules/audio_coding/acm2/audio_coding_module_unittest.cc index 4e262f7..4ee9add 100644 --- a/modules/audio_coding/acm2/audio_coding_module_unittest.cc +++ b/modules/audio_coding/acm2/audio_coding_module_unittest.cc
@@ -13,17 +13,20 @@ #include <memory> #include <vector> +#include "absl/memory/memory.h" #include "api/audio_codecs/audio_encoder.h" #include "api/audio_codecs/builtin_audio_decoder_factory.h" #include "api/audio_codecs/builtin_audio_encoder_factory.h" +#include "api/audio_codecs/opus/audio_decoder_opus.h" #include "api/audio_codecs/opus/audio_encoder_opus.h" #include "modules/audio_coding/acm2/acm_receive_test.h" #include "modules/audio_coding/acm2/acm_send_test.h" -#include "modules/audio_coding/codecs/audio_format_conversion.h" #include "modules/audio_coding/codecs/cng/audio_encoder_cng.h" #include "modules/audio_coding/codecs/g711/audio_decoder_pcm.h" #include "modules/audio_coding/codecs/g711/audio_encoder_pcm.h" #include "modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h" +#include "modules/audio_coding/codecs/opus/audio_decoder_opus.h" +#include "modules/audio_coding/codecs/opus/audio_encoder_opus.h" #include "modules/audio_coding/include/audio_coding_module.h" #include "modules/audio_coding/include/audio_coding_module_typedefs.h" #include "modules/audio_coding/neteq/tools/audio_checksum.h" @@ -34,20 +37,21 @@ #include "modules/audio_coding/neteq/tools/output_wav_file.h" #include "modules/audio_coding/neteq/tools/packet.h" #include "modules/audio_coding/neteq/tools/rtp_file_source.h" -#include "rtc_base/criticalsection.h" +#include "rtc_base/critical_section.h" #include "rtc_base/event.h" -#include "rtc_base/messagedigest.h" +#include "rtc_base/message_digest.h" #include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/platform_thread.h" -#include "rtc_base/refcountedobject.h" +#include "rtc_base/ref_counted_object.h" #include "rtc_base/system/arch.h" #include "rtc_base/thread_annotations.h" #include "system_wrappers/include/clock.h" #include "system_wrappers/include/sleep.h" +#include "test/audio_decoder_proxy_factory.h" #include "test/gtest.h" #include "test/mock_audio_decoder.h" #include "test/mock_audio_encoder.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" using ::testing::AtLeast; using ::testing::Invoke; @@ -71,21 +75,20 @@ virtual ~RtpUtility() {} - void Populate(WebRtcRTPHeader* rtp_header) { - rtp_header->header.sequenceNumber = 0xABCD; - rtp_header->header.timestamp = 0xABCDEF01; - rtp_header->header.payloadType = payload_type_; - rtp_header->header.markerBit = false; - rtp_header->header.ssrc = 0x1234; - rtp_header->header.numCSRCs = 0; - rtp_header->frameType = kAudioFrameSpeech; + void Populate(RTPHeader* rtp_header) { + rtp_header->sequenceNumber = 0xABCD; + rtp_header->timestamp = 0xABCDEF01; + rtp_header->payloadType = payload_type_; + rtp_header->markerBit = false; + rtp_header->ssrc = 0x1234; + rtp_header->numCSRCs = 0; - rtp_header->header.payload_type_frequency = kSampleRateHz; + rtp_header->payload_type_frequency = kSampleRateHz; } - void Forward(WebRtcRTPHeader* rtp_header) { - ++rtp_header->header.sequenceNumber; - rtp_header->header.timestamp += samples_per_packet_; + void Forward(RTPHeader* rtp_header) { + ++rtp_header->sequenceNumber; + rtp_header->timestamp += samples_per_packet_; } private: @@ -190,12 +193,11 @@ // Set up L16 codec. virtual void SetUpL16Codec() { audio_format_ = SdpAudioFormat("L16", kSampleRateHz, 1); - ASSERT_EQ(0, AudioCodingModule::Codec("L16", &codec_, kSampleRateHz, 1)); - codec_.pltype = kPayloadType; + pac_size_ = 160; } virtual void RegisterCodec() { - EXPECT_EQ(true, acm_->RegisterReceiveCodec(kPayloadType, *audio_format_)); + acm_->SetReceiveCodecs({{kPayloadType, *audio_format_}}); acm_->SetEncoder(CreateBuiltinAudioEncoderFactory()->MakeAudioEncoder( kPayloadType, *audio_format_, absl::nullopt)); } @@ -226,7 +228,7 @@ virtual void VerifyEncoding() { int last_length = packet_cb_.last_payload_len_bytes(); - EXPECT_TRUE(last_length == 2 * codec_.pacsize || last_length == 0) + EXPECT_TRUE(last_length == 2 * pac_size_ || last_length == 0) << "Last encoded packet was " << last_length << " bytes."; } @@ -238,13 +240,11 @@ std::unique_ptr<RtpUtility> rtp_utility_; std::unique_ptr<AudioCodingModule> acm_; PacketizationCallbackStubOldApi packet_cb_; - WebRtcRTPHeader rtp_header_; + RTPHeader rtp_header_; AudioFrame input_frame_; - // These two have to be kept in sync for now. In the future, we'll be able to - // eliminate the CodecInst and keep only the SdpAudioFormat. absl::optional<SdpAudioFormat> audio_format_; - CodecInst codec_; + int pac_size_ = -1; Clock* clock_; }; @@ -343,7 +343,7 @@ // Also checks that the frame type is kAudioFrameSpeech. TEST_F(AudioCodingModuleTestOldApi, TransportCallbackIsInvokedForEachPacket) { const int k10MsBlocksPerPacket = 3; - codec_.pacsize = k10MsBlocksPerPacket * kSampleRateHz / 100; + pac_size_ = k10MsBlocksPerPacket * kSampleRateHz / 100; audio_format_->parameters["ptime"] = "30"; RegisterCodec(); const int kLoops = 10; @@ -363,7 +363,7 @@ TEST_F(AudioCodingModuleTestOldApi, TimestampSeriesContinuesWhenCodecChanges) { RegisterCodec(); // This registers the default codec. uint32_t expected_ts = input_frame_.timestamp_; - int blocks_per_packet = codec_.pacsize / (kSampleRateHz / 100); + int blocks_per_packet = pac_size_ / (kSampleRateHz / 100); // Encode 5 packets of the first codec type. const int kNumPackets1 = 5; for (int j = 0; j < kNumPackets1; ++j) { @@ -373,14 +373,14 @@ } EXPECT_EQ(j + 1, packet_cb_.num_calls()); EXPECT_EQ(expected_ts, packet_cb_.last_timestamp()); - expected_ts += codec_.pacsize; + expected_ts += pac_size_; } // Change codec. - ASSERT_EQ(0, AudioCodingModule::Codec("ISAC", &codec_, kSampleRateHz, 1)); audio_format_ = SdpAudioFormat("ISAC", kSampleRateHz, 1); + pac_size_ = 480; RegisterCodec(); - blocks_per_packet = codec_.pacsize / (kSampleRateHz / 100); + blocks_per_packet = pac_size_ / (kSampleRateHz / 100); // Encode another 5 packets. const int kNumPackets2 = 5; for (int j = 0; j < kNumPackets2; ++j) { @@ -390,7 +390,7 @@ } EXPECT_EQ(kNumPackets1 + j + 1, packet_cb_.num_calls()); EXPECT_EQ(expected_ts, packet_cb_.last_timestamp()); - expected_ts += codec_.pacsize; + expected_ts += pac_size_; } } #endif @@ -404,9 +404,8 @@ : public AudioCodingModuleTestOldApi { protected: void RegisterCngCodec(int rtp_payload_type) { - EXPECT_EQ(true, - acm_->RegisterReceiveCodec( - rtp_payload_type, SdpAudioFormat("cn", kSampleRateHz, 1))); + acm_->SetReceiveCodecs({{kPayloadType, *audio_format_}, + {rtp_payload_type, {"cn", kSampleRateHz, 1}}}); acm_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* enc) { AudioEncoderCngConfig config; config.speech_encoder = std::move(*enc); @@ -461,7 +460,7 @@ TEST_F(AudioCodingModuleTestWithComfortNoiseOldApi, TransportCallbackTestForComfortNoiseRegisterCngLast) { const int k10MsBlocksPerPacket = 3; - codec_.pacsize = k10MsBlocksPerPacket * kSampleRateHz / 100; + pac_size_ = k10MsBlocksPerPacket * kSampleRateHz / 100; audio_format_->parameters["ptime"] = "30"; RegisterCodec(); const int kCngPayloadType = 105; @@ -650,12 +649,11 @@ void RegisterCodec() override { static_assert(kSampleRateHz == 16000, "test designed for iSAC 16 kHz"); audio_format_ = SdpAudioFormat("isac", kSampleRateHz, 1); - AudioCodingModule::Codec("ISAC", &codec_, kSampleRateHz, 1); - codec_.pltype = kPayloadType; + pac_size_ = 480; // Register iSAC codec in ACM, effectively unregistering the PCM16B codec // registered in AudioCodingModuleTestOldApi::SetUp(); - EXPECT_EQ(true, acm_->RegisterReceiveCodec(kPayloadType, *audio_format_)); + acm_->SetReceiveCodecs({{kPayloadType, *audio_format_}}); acm_->SetEncoder(CreateBuiltinAudioEncoderFactory()->MakeAudioEncoder( kPayloadType, *audio_format_, absl::nullopt)); } @@ -755,15 +753,11 @@ } void RegisterCodec() override { - static_assert(kSampleRateHz == 16000, "test designed for iSAC 16 kHz"); - AudioCodingModule::Codec("ISAC", &codec_, kSampleRateHz, 1); - codec_.pltype = kPayloadType; - // Register iSAC codec in ACM, effectively unregistering the PCM16B codec // registered in AudioCodingModuleTestOldApi::SetUp(); // Only register the decoder for now. The encoder is registered later. - ASSERT_EQ(true, acm_->RegisterReceiveCodec(codec_.pltype, - CodecInstToSdp(codec_))); + static_assert(kSampleRateHz == 16000, "test designed for iSAC 16 kHz"); + acm_->SetReceiveCodecs({{kPayloadType, {"ISAC", kSampleRateHz, 1}}}); } void StartThreads() { @@ -801,16 +795,15 @@ ++receive_packet_count_; // Encode new frame. - uint32_t input_timestamp = rtp_header_.header.timestamp; + uint32_t input_timestamp = rtp_header_.timestamp; while (info.encoded_bytes == 0) { info = isac_encoder_->Encode(input_timestamp, audio_loop_.GetNextBlock(), &encoded); input_timestamp += 160; // 10 ms at 16 kHz. } - EXPECT_EQ(rtp_header_.header.timestamp + kPacketSizeSamples, - input_timestamp); - EXPECT_EQ(rtp_header_.header.timestamp, info.encoded_timestamp); - EXPECT_EQ(rtp_header_.header.payloadType, info.payload_type); + EXPECT_EQ(rtp_header_.timestamp + kPacketSizeSamples, input_timestamp); + EXPECT_EQ(rtp_header_.timestamp, info.encoded_timestamp); + EXPECT_EQ(rtp_header_.payloadType, info.payload_type); } // Now we're not holding the crit sect when calling ACM. @@ -946,7 +939,7 @@ ->test_case_name() + "_" + ::testing::UnitTest::GetInstance()->current_test_info()->name() + "_output.wav"; - test::OutputWavFile output_file(output_file_name, output_freq_hz); + test::OutputWavFile output_file(output_file_name, output_freq_hz, 1); test::AudioSinkFork output(&checksum, &output_file); test::AcmReceiveTestOldApi test( @@ -968,35 +961,35 @@ #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) && \ defined(WEBRTC_CODEC_ILBC) TEST_F(AcmReceiverBitExactnessOldApi, 8kHzOutput) { - Run(8000, PlatformChecksum("7294941b62293e143d6d6c84955923fd", - "f26b8c9aa8257c7185925fa5b102f46a", - "65e5ef5c3de9c2abf3c8d0989772e9fc", + Run(8000, PlatformChecksum("bcfbe2e89b4317b22e29557168edf187", + "af15addb648cf7f032d6415672365fb3", + "54a0008eb79537dee1d8fdaa5bc29f4b", "4598140b5e4f7ee66c5adad609e65a3e", - "04a1d3e735730b6d7dbd5df10f717d27")); + "3155d7f2593a3276986f36221a61783c")); } TEST_F(AcmReceiverBitExactnessOldApi, 16kHzOutput) { - Run(16000, PlatformChecksum("de8143dd3cc23241f1e1d5cf14e04b8a", - "eada3f321120d8d5afffbe4170a55d2f", - "135d8c3c7b92aa13d45cad7c91068e3e", + Run(16000, PlatformChecksum("1737deef193e6c90e139ce82b7361ae4", + "9e2a9f7728c71d6559ce3a32d2b10a5d", + "114958862099142ac78b12100c21cb8d", "f2aad418af974a3b1694d5ae5cc2c3c7", - "728b69068332efade35b1a9c32029e1b")); + "af2889a5ca84fb40c9aa209b9318ee7a")); } TEST_F(AcmReceiverBitExactnessOldApi, 32kHzOutput) { - Run(32000, PlatformChecksum("521d336237bdcc9ab44050e9da8917fc", - "73d44a7bedb6dfa7c70cf997223d8c10", - "f3ee2f14b03fb8e98f526f82583f84d9", + Run(32000, PlatformChecksum("1bf40ff024c6aa5b832d1d242c29cb3b", + "3c9690cd136e9ecd1b26a22f70fe1d5c", + "a1a3a01d8e25fcd11f1cedcd02e968b8", "100869c8dcde51346c2073e52a272d98", - "5f338b4bc38707d0a14d75a357e1546e")); + "33695077e9ec6bca80819ce2ba263a78")); } TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutput) { - Run(48000, PlatformChecksum("5955e31373828969de7fb308fb58a84e", - "83c0eca235b1a806426ff6ca8655cdf7", - "1126a8c03d1ebc6aa7348b9c541e2082", + Run(48000, PlatformChecksum("bf92db1e502deff5adf6fd2e6ab9a2e5", + "c37b110ab50d87620972daee5d1eaf31", + "5d55b68be7bcf39b60fcc74519363fb4", "bd44bf97e7899186532f91235cef444d", - "9d092dbc96e7ef6870b78c1056e87315")); + "32eec738698ffe62b9777d6a349cd596")); } TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutputExternalDecoder) { @@ -1079,13 +1072,23 @@ rtc::scoped_refptr<rtc::RefCountedObject<ADFactory>> factory( new rtc::RefCountedObject<ADFactory>); Run(48000, - PlatformChecksum("5955e31373828969de7fb308fb58a84e", - "83c0eca235b1a806426ff6ca8655cdf7", - "1126a8c03d1ebc6aa7348b9c541e2082", + PlatformChecksum("bf92db1e502deff5adf6fd2e6ab9a2e5", + "c37b110ab50d87620972daee5d1eaf31", + "5d55b68be7bcf39b60fcc74519363fb4", "bd44bf97e7899186532f91235cef444d", - "9d092dbc96e7ef6870b78c1056e87315"), + "32eec738698ffe62b9777d6a349cd596"), factory, [](AudioCodingModule* acm) { - acm->RegisterReceiveCodec(0, {"MockPCMu", 8000, 1}); + acm->SetReceiveCodecs({{0, {"MockPCMu", 8000, 1}}, + {103, {"ISAC", 16000, 1}}, + {104, {"ISAC", 32000, 1}}, + {93, {"L16", 8000, 1}}, + {94, {"L16", 16000, 1}}, + {95, {"L16", 32000, 1}}, + {8, {"PCMA", 8000, 1}}, + {102, {"ILBC", 8000, 1}}, + {13, {"CN", 8000, 1}}, + {98, {"CN", 16000, 1}}, + {99, {"CN", 32000, 1}}}); }); } #endif @@ -1117,15 +1120,12 @@ // Sets up the test::AcmSendTest object. Returns true on success, otherwise // false. - bool SetUpSender() { - const std::string input_file_name = - webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"); + bool SetUpSender(std::string input_file_name, int source_rate) { // Note that |audio_source_| will loop forever. The test duration is set // explicitly by |kTestDurationMs|. audio_source_.reset(new test::InputAudioFile(input_file_name)); - static const int kSourceRateHz = 32000; - send_test_.reset(new test::AcmSendTestOldApi( - audio_source_.get(), kSourceRateHz, kTestDurationMs)); + send_test_.reset(new test::AcmSendTestOldApi(audio_source_.get(), + source_rate, kTestDurationMs)); return send_test_.get() != NULL; } @@ -1158,7 +1158,11 @@ void Run(const std::string& audio_checksum_ref, const std::string& payload_checksum_ref, int expected_packets, - test::AcmReceiveTestOldApi::NumOutputChannels expected_channels) { + test::AcmReceiveTestOldApi::NumOutputChannels expected_channels, + rtc::scoped_refptr<AudioDecoderFactory> decoder_factory = nullptr) { + if (!decoder_factory) { + decoder_factory = CreateBuiltinAudioDecoderFactory(); + } // Set up the receiver used to decode the packets and verify the decoded // output. test::AudioChecksum audio_checksum; @@ -1170,12 +1174,12 @@ "_" + ::testing::UnitTest::GetInstance()->current_test_info()->name() + "_output.wav"; const int kOutputFreqHz = 8000; - test::OutputWavFile output_file(output_file_name, kOutputFreqHz); + test::OutputWavFile output_file(output_file_name, kOutputFreqHz, + expected_channels); // Have the output audio sent both to file and to the checksum calculator. test::AudioSinkFork output(&audio_checksum, &output_file); test::AcmReceiveTestOldApi receive_test(this, &output, kOutputFreqHz, - expected_channels, - CreateBuiltinAudioDecoderFactory()); + expected_channels, decoder_factory); ASSERT_NO_FATAL_FAILURE(receive_test.RegisterDefaultCodecs()); // This is where the actual test is executed. @@ -1251,7 +1255,8 @@ int payload_type, int codec_frame_size_samples, int codec_frame_size_rtp_timestamps) { - ASSERT_TRUE(SetUpSender()); + ASSERT_TRUE(SetUpSender( + channels == 1 ? kTestFileMono32kHz : kTestFileFakeStereo32kHz, 32000)); ASSERT_TRUE(RegisterSendCodec(codec_name, codec_sample_rate_hz, channels, payload_type, codec_frame_size_samples, codec_frame_size_rtp_timestamps)); @@ -1260,7 +1265,7 @@ void SetUpTestExternalEncoder( std::unique_ptr<AudioEncoder> external_speech_encoder, int payload_type) { - ASSERT_TRUE(SetUpSender()); + ASSERT_TRUE(send_test_); RegisterExternalSendCodec(std::move(external_speech_encoder), payload_type); } @@ -1272,6 +1277,14 @@ uint16_t last_sequence_number_; uint32_t last_timestamp_; std::unique_ptr<rtc::MessageDigest> payload_checksum_; + const std::string kTestFileMono32kHz = + webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"); + const std::string kTestFileFakeStereo32kHz = + webrtc::test::ResourcePath("audio_coding/testfile_fake_stereo_32kHz", + "pcm"); + const std::string kTestFileQuad48kHz = webrtc::test::ResourcePath( + "audio_coding/speech_4_channels_48k_one_second", + "wav"); }; class AcmSenderBitExactnessNewApi : public AcmSenderBitExactnessOldApi {}; @@ -1471,7 +1484,7 @@ "ab88b1a049c36bdfeb7e8b057ef6982a", "27fef7b799393347ec3b5694369a1c36", "27fef7b799393347ec3b5694369a1c36"); -}; // namespace +} // namespace TEST_F(AcmSenderBitExactnessOldApi, Opus_stereo_20ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 2, 120, 960, 960)); @@ -1482,17 +1495,59 @@ TEST_F(AcmSenderBitExactnessNewApi, MAYBE_OpusFromFormat_stereo_20ms) { const auto config = AudioEncoderOpus::SdpToConfig( SdpAudioFormat("opus", 48000, 2, {{"stereo", "1"}})); + ASSERT_TRUE(SetUpSender(kTestFileFakeStereo32kHz, 32000)); ASSERT_NO_FATAL_FAILURE(SetUpTestExternalEncoder( AudioEncoderOpus::MakeAudioEncoder(*config, 120), 120)); Run(audio_checksum, payload_checksum, 50, test::AcmReceiveTestOldApi::kStereoOutput); } +TEST_F(AcmSenderBitExactnessNewApi, OpusManyChannels) { + constexpr int kNumChannels = 4; + constexpr int kOpusPayloadType = 120; + constexpr int kBitrateBps = 128000; + + // Read a 4 channel file at 48kHz. + ASSERT_TRUE(SetUpSender(kTestFileQuad48kHz, 48000)); + + // TODO(webrtc:8649): change to higher level + // AudioEncoderOpus::MakeAudioEncoder once a multistream encoder can be set up + // from SDP. + AudioEncoderOpusConfig config = *AudioEncoderOpus::SdpToConfig( + SdpAudioFormat("opus", 48000, 2, {{"stereo", "1"}})); + config.num_channels = kNumChannels; + config.bitrate_bps = kBitrateBps; + + ASSERT_NO_FATAL_FAILURE(SetUpTestExternalEncoder( + absl::make_unique<AudioEncoderOpusImpl>(config, kOpusPayloadType), + kOpusPayloadType)); + + AudioDecoderOpusImpl opus_decoder(kNumChannels); + + rtc::scoped_refptr<AudioDecoderFactory> decoder_factory = + new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&opus_decoder); + + // Set up an EXTERNAL DECODER to parse 4 channels. + Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( // audio checksum + "b70470884d9a8613eff019b0d1c8876e|d0a73d377e0ca1be6b06e989e0ad2c35", + "d0a73d377e0ca1be6b06e989e0ad2c35", + "b45d2ce5fc4723e9eb41350af9c68f56", "android arm64 audio checksum", + "1c9a3c9dacdd4b8fc9ff608227e531f2"), + // payload_checksum, + AcmReceiverBitExactnessOldApi::PlatformChecksum( // payload checksum + "c2e7d40f8269ef754bd86d6be9623fa7|76de0f4992e3937ca60d35bbb0d308d6", + "76de0f4992e3937ca60d35bbb0d308d6", + "2a310aca965c16c2dfd61a9f9fc0c877", "android arm64 payload checksum", + "2294f4b61fb8f174f5196776a0a49be7"), + 50, test::AcmReceiveTestOldApi::kQuadOutput, decoder_factory); +} + TEST_F(AcmSenderBitExactnessNewApi, OpusFromFormat_stereo_20ms_voip) { auto config = AudioEncoderOpus::SdpToConfig( SdpAudioFormat("opus", 48000, 2, {{"stereo", "1"}})); // If not set, default will be kAudio in case of stereo. config->application = AudioEncoderOpusConfig::ApplicationMode::kVoip; + ASSERT_TRUE(SetUpSender(kTestFileFakeStereo32kHz, 32000)); ASSERT_NO_FATAL_FAILURE(SetUpTestExternalEncoder( AudioEncoderOpus::MakeAudioEncoder(*config, 120), 120)); // Checksum depends on libopus being compiled with or without SSE. @@ -1746,11 +1801,11 @@ } TEST_F(AcmSenderBitExactnessOldApi, External_Pcmu_20ms) { - CodecInst codec_inst; - codec_inst.channels = 1; - codec_inst.pacsize = 160; - codec_inst.pltype = 0; - AudioEncoderPcmU encoder(codec_inst); + AudioEncoderPcmU::Config config; + config.frame_size_ms = 20; + config.num_channels = 1; + config.payload_type = 0; + AudioEncoderPcmU encoder(config); auto mock_encoder = absl::make_unique<MockAudioEncoder>(); // Set expectations on the mock encoder and also delegate the calls to the // real encoder. @@ -1776,8 +1831,9 @@ &encoder, static_cast<AudioEncoder::EncodedInfo (AudioEncoder::*)( uint32_t, rtc::ArrayView<const int16_t>, rtc::Buffer*)>( &AudioEncoderPcmU::Encode))); + ASSERT_TRUE(SetUpSender(kTestFileMono32kHz, 32000)); ASSERT_NO_FATAL_FAILURE( - SetUpTestExternalEncoder(std::move(mock_encoder), codec_inst.pltype)); + SetUpTestExternalEncoder(std::move(mock_encoder), config.payload_type)); Run("81a9d4c0bb72e9becc43aef124c981e9", "8f9b8750bd80fe26b6cbf6659b89f0f9", 50, test::AcmReceiveTestOldApi::kMonoOutput); }
diff --git a/modules/audio_coding/acm2/rent_a_codec.cc b/modules/audio_coding/acm2/rent_a_codec.cc deleted file mode 100644 index bfddc42b..0000000 --- a/modules/audio_coding/acm2/rent_a_codec.cc +++ /dev/null
@@ -1,72 +0,0 @@ -/* - * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "modules/audio_coding/acm2/rent_a_codec.h" - -#include <memory> -#include <utility> - -#include "rtc_base/logging.h" -#include "modules/audio_coding/acm2/acm_codec_database.h" - -namespace webrtc { -namespace acm2 { - -absl::optional<RentACodec::CodecId> RentACodec::CodecIdByParams( - const char* payload_name, - int sampling_freq_hz, - size_t channels) { - return CodecIdFromIndex( - ACMCodecDB::CodecId(payload_name, sampling_freq_hz, channels)); -} - -absl::optional<CodecInst> RentACodec::CodecInstById(CodecId codec_id) { - absl::optional<int> mi = CodecIndexFromId(codec_id); - return mi ? absl::optional<CodecInst>(ACMCodecDB::database_[*mi]) - : absl::nullopt; -} - -absl::optional<RentACodec::CodecId> RentACodec::CodecIdByInst( - const CodecInst& codec_inst) { - return CodecIdFromIndex(ACMCodecDB::CodecNumber(codec_inst)); -} - -absl::optional<CodecInst> RentACodec::CodecInstByParams( - const char* payload_name, - int sampling_freq_hz, - size_t channels) { - absl::optional<CodecId> codec_id = - CodecIdByParams(payload_name, sampling_freq_hz, channels); - if (!codec_id) - return absl::nullopt; - absl::optional<CodecInst> ci = CodecInstById(*codec_id); - RTC_DCHECK(ci); - - // Keep the number of channels from the function call. For most codecs it - // will be the same value as in default codec settings, but not for all. - ci->channels = channels; - - return ci; -} - -absl::optional<NetEqDecoder> RentACodec::NetEqDecoderFromCodecId( - CodecId codec_id, - size_t num_channels) { - absl::optional<int> i = CodecIndexFromId(codec_id); - if (!i) - return absl::nullopt; - const NetEqDecoder ned = ACMCodecDB::neteq_decoders_[*i]; - return (ned == NetEqDecoder::kDecoderOpus && num_channels == 2) - ? NetEqDecoder::kDecoderOpus_2ch - : ned; -} - -} // namespace acm2 -} // namespace webrtc
diff --git a/modules/audio_coding/acm2/rent_a_codec.h b/modules/audio_coding/acm2/rent_a_codec.h deleted file mode 100644 index 2cf1c6e..0000000 --- a/modules/audio_coding/acm2/rent_a_codec.h +++ /dev/null
@@ -1,143 +0,0 @@ -/* - * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef MODULES_AUDIO_CODING_ACM2_RENT_A_CODEC_H_ -#define MODULES_AUDIO_CODING_ACM2_RENT_A_CODEC_H_ - -#include <stddef.h> -#include <map> -#include <memory> - -#include "absl/types/optional.h" -#include "api/array_view.h" -#include "api/audio_codecs/audio_decoder.h" -#include "api/audio_codecs/audio_encoder.h" -#include "modules/audio_coding/include/audio_coding_module_typedefs.h" -#include "modules/audio_coding/neteq/neteq_decoder_enum.h" -#include "rtc_base/constructormagic.h" -#include "rtc_base/scoped_ref_ptr.h" - -namespace webrtc { - -struct CodecInst; -class LockedIsacBandwidthInfo; - -namespace acm2 { - -struct RentACodec { - enum class CodecId { -#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX) - kISAC, -#endif -#ifdef WEBRTC_CODEC_ISAC - kISACSWB, -#endif - // Mono - kPCM16B, - kPCM16Bwb, - kPCM16Bswb32kHz, - // Stereo - kPCM16B_2ch, - kPCM16Bwb_2ch, - kPCM16Bswb32kHz_2ch, - // Mono - kPCMU, - kPCMA, - // Stereo - kPCMU_2ch, - kPCMA_2ch, -#ifdef WEBRTC_CODEC_ILBC - kILBC, -#endif - kG722, // Mono - kG722_2ch, // Stereo -#ifdef WEBRTC_CODEC_OPUS - kOpus, // Mono and stereo -#endif - kCNNB, - kCNWB, - kCNSWB, -#ifdef ENABLE_48000_HZ - kCNFB, -#endif - kAVT, - kAVT16kHz, - kAVT32kHz, - kAVT48kHz, -#ifdef WEBRTC_CODEC_RED - kRED, -#endif - kNumCodecs, // Implementation detail. Don't use. - -// Set unsupported codecs to -1. -#if !defined(WEBRTC_CODEC_ISAC) && !defined(WEBRTC_CODEC_ISACFX) - kISAC = -1, -#endif -#ifndef WEBRTC_CODEC_ISAC - kISACSWB = -1, -#endif - // 48 kHz not supported, always set to -1. - kPCM16Bswb48kHz = -1, -#ifndef WEBRTC_CODEC_ILBC - kILBC = -1, -#endif -#ifndef WEBRTC_CODEC_OPUS - kOpus = -1, // Mono and stereo -#endif -#ifndef WEBRTC_CODEC_RED - kRED = -1, -#endif -#ifndef ENABLE_48000_HZ - kCNFB = -1, -#endif - - kNone = -1 - }; - - static inline size_t NumberOfCodecs() { - return static_cast<size_t>(CodecId::kNumCodecs); - } - - static inline absl::optional<int> CodecIndexFromId(CodecId codec_id) { - const int i = static_cast<int>(codec_id); - return i >= 0 && i < static_cast<int>(NumberOfCodecs()) - ? absl::optional<int>(i) - : absl::nullopt; - } - - static inline absl::optional<CodecId> CodecIdFromIndex(int codec_index) { - return static_cast<size_t>(codec_index) < NumberOfCodecs() - ? absl::optional<RentACodec::CodecId>( - static_cast<RentACodec::CodecId>(codec_index)) - : absl::nullopt; - } - - static absl::optional<CodecId> CodecIdByParams(const char* payload_name, - int sampling_freq_hz, - size_t channels); - static absl::optional<CodecInst> CodecInstById(CodecId codec_id); - static absl::optional<CodecId> CodecIdByInst(const CodecInst& codec_inst); - static absl::optional<CodecInst> CodecInstByParams(const char* payload_name, - int sampling_freq_hz, - size_t channels); - - static inline bool IsPayloadTypeValid(int payload_type) { - return payload_type >= 0 && payload_type <= 127; - } - - static absl::optional<NetEqDecoder> NetEqDecoderFromCodecId( - CodecId codec_id, - size_t num_channels); -}; - -} // namespace acm2 -} // namespace webrtc - -#endif // MODULES_AUDIO_CODING_ACM2_RENT_A_CODEC_H_
diff --git a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.cc b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.cc index 9e47a06..ff6ac01 100644 --- a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.cc +++ b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.cc
@@ -18,7 +18,7 @@ #include "modules/audio_coding/audio_network_adaptor/debug_dump_writer.h" #include "modules/audio_coding/audio_network_adaptor/event_log_writer.h" #include "rtc_base/checks.h" -#include "rtc_base/timeutils.h" +#include "rtc_base/time_utils.h" #include "system_wrappers/include/field_trial.h" namespace webrtc { @@ -29,7 +29,7 @@ constexpr float kEventLogMinPacketLossChangeFraction = 0.5; } // namespace -AudioNetworkAdaptorImpl::Config::Config() : event_log(nullptr){}; +AudioNetworkAdaptorImpl::Config::Config() : event_log(nullptr) {} AudioNetworkAdaptorImpl::Config::~Config() = default;
diff --git a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h index 4c1c19b..fc2358b 100644 --- a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h +++ b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h
@@ -20,7 +20,7 @@ #include "modules/audio_coding/audio_network_adaptor/debug_dump_writer.h" #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h" #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc index be9550a..76531d0 100644 --- a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc +++ b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc
@@ -18,7 +18,7 @@ #include "modules/audio_coding/audio_network_adaptor/mock/mock_controller.h" #include "modules/audio_coding/audio_network_adaptor/mock/mock_controller_manager.h" #include "modules/audio_coding/audio_network_adaptor/mock/mock_debug_dump_writer.h" -#include "rtc_base/fakeclock.h" +#include "rtc_base/fake_clock.h" #include "test/field_trial.h" #include "test/gtest.h"
diff --git a/modules/audio_coding/audio_network_adaptor/bitrate_controller.h b/modules/audio_coding/audio_network_adaptor/bitrate_controller.h index 6b6330b..41bfbd1 100644 --- a/modules/audio_coding/audio_network_adaptor/bitrate_controller.h +++ b/modules/audio_coding/audio_network_adaptor/bitrate_controller.h
@@ -16,7 +16,7 @@ #include "absl/types/optional.h" #include "modules/audio_coding/audio_network_adaptor/controller.h" #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { namespace audio_network_adaptor {
diff --git a/modules/audio_coding/audio_network_adaptor/channel_controller.h b/modules/audio_coding/audio_network_adaptor/channel_controller.h index 0d775b1..f211f40 100644 --- a/modules/audio_coding/audio_network_adaptor/channel_controller.h +++ b/modules/audio_coding/audio_network_adaptor/channel_controller.h
@@ -16,7 +16,7 @@ #include "absl/types/optional.h" #include "modules/audio_coding/audio_network_adaptor/controller.h" #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/audio_network_adaptor/controller_manager.cc b/modules/audio_coding/audio_network_adaptor/controller_manager.cc index 32f9fcb..4c0e61c 100644 --- a/modules/audio_coding/audio_network_adaptor/controller_manager.cc +++ b/modules/audio_coding/audio_network_adaptor/controller_manager.cc
@@ -11,6 +11,7 @@ #include "modules/audio_coding/audio_network_adaptor/controller_manager.h" #include <cmath> +#include <string> #include <utility> #include "modules/audio_coding/audio_network_adaptor/bitrate_controller.h" @@ -22,7 +23,7 @@ #include "modules/audio_coding/audio_network_adaptor/frame_length_controller.h" #include "modules/audio_coding/audio_network_adaptor/util/threshold_curve.h" #include "rtc_base/ignore_wundef.h" -#include "rtc_base/timeutils.h" +#include "rtc_base/time_utils.h" #if WEBRTC_ENABLE_PROTOBUF RTC_PUSH_IGNORING_WUNDEF() @@ -147,13 +148,13 @@ } FrameLengthController::Config ctor_config( - std::vector<int>(), initial_frame_length_ms, min_encoder_bitrate_bps, + std::set<int>(), initial_frame_length_ms, min_encoder_bitrate_bps, config.fl_increasing_packet_loss_fraction(), config.fl_decreasing_packet_loss_fraction(), fl_increase_overhead_offset, fl_decrease_overhead_offset, std::move(fl_changing_bandwidths_bps)); for (auto frame_length : encoder_frame_lengths_ms) - ctor_config.encoder_frame_lengths_ms.push_back(frame_length); + ctor_config.encoder_frame_lengths_ms.insert(frame_length); return std::unique_ptr<FrameLengthController>( new FrameLengthController(ctor_config)); @@ -213,7 +214,7 @@ ControllerManagerImpl::Config::~Config() = default; std::unique_ptr<ControllerManager> ControllerManagerImpl::Create( - const ProtoString& config_string, + const std::string& config_string, size_t num_encoder_channels, rtc::ArrayView<const int> encoder_frame_lengths_ms, int min_encoder_bitrate_bps, @@ -229,7 +230,7 @@ } std::unique_ptr<ControllerManager> ControllerManagerImpl::Create( - const ProtoString& config_string, + const std::string& config_string, size_t num_encoder_channels, rtc::ArrayView<const int> encoder_frame_lengths_ms, int min_encoder_bitrate_bps,
diff --git a/modules/audio_coding/audio_network_adaptor/controller_manager.h b/modules/audio_coding/audio_network_adaptor/controller_manager.h index 1ff9bbf..f46450d 100644 --- a/modules/audio_coding/audio_network_adaptor/controller_manager.h +++ b/modules/audio_coding/audio_network_adaptor/controller_manager.h
@@ -13,11 +13,11 @@ #include <map> #include <memory> +#include <string> #include <vector> #include "modules/audio_coding/audio_network_adaptor/controller.h" -#include "rtc_base/constructormagic.h" -#include "rtc_base/protobuf_utils.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { @@ -47,7 +47,7 @@ }; static std::unique_ptr<ControllerManager> Create( - const ProtoString& config_string, + const std::string& config_string, size_t num_encoder_channels, rtc::ArrayView<const int> encoder_frame_lengths_ms, int min_encoder_bitrate_bps, @@ -58,7 +58,7 @@ bool initial_dtx_enabled); static std::unique_ptr<ControllerManager> Create( - const ProtoString& config_string, + const std::string& config_string, size_t num_encoder_channels, rtc::ArrayView<const int> encoder_frame_lengths_ms, int min_encoder_bitrate_bps,
diff --git a/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc b/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc index 061e4aa..ce47699 100644 --- a/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc +++ b/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc
@@ -8,14 +8,14 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include <string> #include <utility> #include "modules/audio_coding/audio_network_adaptor/controller_manager.h" #include "modules/audio_coding/audio_network_adaptor/mock/mock_controller.h" #include "modules/audio_coding/audio_network_adaptor/mock/mock_debug_dump_writer.h" -#include "rtc_base/fakeclock.h" +#include "rtc_base/fake_clock.h" #include "rtc_base/ignore_wundef.h" -#include "rtc_base/protobuf_utils.h" #include "test/gtest.h" #if WEBRTC_ENABLE_PROTOBUF @@ -266,7 +266,7 @@ constexpr int kMinBitrateBps = 6000; ControllerManagerStates CreateControllerManager( - const ProtoString& config_string) { + const std::string& config_string) { ControllerManagerStates states; constexpr size_t kNumEncoderChannels = 2; const std::vector<int> encoder_frame_lengths_ms = {20, 60}; @@ -319,8 +319,8 @@ } MATCHER_P(ControllerManagerEqual, value, "") { - ProtoString value_string; - ProtoString arg_string; + std::string value_string; + std::string arg_string; EXPECT_TRUE(arg.SerializeToString(&arg_string)); EXPECT_TRUE(value.SerializeToString(&value_string)); return arg_string == value_string; @@ -339,7 +339,7 @@ AddFrameLengthControllerConfig(&config); AddBitrateControllerConfig(&config); - ProtoString config_string; + std::string config_string; config.SerializeToString(&config_string); constexpr size_t kNumEncoderChannels = 2; @@ -373,7 +373,7 @@ AddFrameLengthControllerConfig(&config); AddBitrateControllerConfig(&config); - ProtoString config_string; + std::string config_string; config.SerializeToString(&config_string); auto states = CreateControllerManager(config_string); @@ -395,7 +395,7 @@ AddDtxControllerConfig(&config); AddBitrateControllerConfig(&config); - ProtoString config_string; + std::string config_string; config.SerializeToString(&config_string); auto states = CreateControllerManager(config_string); @@ -426,7 +426,7 @@ AddBitrateControllerConfig(&config); - ProtoString config_string; + std::string config_string; config.SerializeToString(&config_string); auto states = CreateControllerManager(config_string);
diff --git a/modules/audio_coding/audio_network_adaptor/debug_dump_writer.cc b/modules/audio_coding/audio_network_adaptor/debug_dump_writer.cc index 8e04e8e..805df0a 100644 --- a/modules/audio_coding/audio_network_adaptor/debug_dump_writer.cc +++ b/modules/audio_coding/audio_network_adaptor/debug_dump_writer.cc
@@ -10,11 +10,12 @@ #include "modules/audio_coding/audio_network_adaptor/debug_dump_writer.h" +#include <string> + #include "absl/types/optional.h" #include "rtc_base/checks.h" #include "rtc_base/ignore_wundef.h" #include "rtc_base/numerics/safe_conversions.h" -#include "rtc_base/protobuf_utils.h" #include "rtc_base/system/file_wrapper.h" #if WEBRTC_ENABLE_PROTOBUF @@ -38,7 +39,7 @@ void DumpEventToFile(const Event& event, FileWrapper* dump_file) { RTC_CHECK(dump_file->is_open()); - ProtoString dump_data; + std::string dump_data; event.SerializeToString(&dump_data); int32_t size = rtc::checked_cast<int32_t>(event.ByteSizeLong()); dump_file->Write(&size, sizeof(size)); @@ -67,14 +68,13 @@ #endif private: - std::unique_ptr<FileWrapper> dump_file_; + FileWrapper dump_file_; }; -DebugDumpWriterImpl::DebugDumpWriterImpl(FILE* file_handle) - : dump_file_(FileWrapper::Create()) { +DebugDumpWriterImpl::DebugDumpWriterImpl(FILE* file_handle) { #if WEBRTC_ENABLE_PROTOBUF - dump_file_->OpenFromFileHandle(file_handle); - RTC_CHECK(dump_file_->is_open()); + dump_file_ = FileWrapper(file_handle); + RTC_CHECK(dump_file_.is_open()); #else RTC_NOTREACHED(); #endif @@ -110,7 +110,7 @@ *metrics.uplink_recoverable_packet_loss_fraction); } - DumpEventToFile(event, dump_file_.get()); + DumpEventToFile(event, &dump_file_); #endif // WEBRTC_ENABLE_PROTOBUF } @@ -143,7 +143,7 @@ if (config.num_channels) dump_config->set_num_channels(*config.num_channels); - DumpEventToFile(event, dump_file_.get()); + DumpEventToFile(event, &dump_file_); #endif // WEBRTC_ENABLE_PROTOBUF } @@ -157,7 +157,7 @@ event.set_type(Event::CONTROLLER_MANAGER_CONFIG); event.mutable_controller_manager_config()->CopyFrom( controller_manager_config); - DumpEventToFile(event, dump_file_.get()); + DumpEventToFile(event, &dump_file_); } #endif // WEBRTC_ENABLE_PROTOBUF
diff --git a/modules/audio_coding/audio_network_adaptor/debug_dump_writer.h b/modules/audio_coding/audio_network_adaptor/debug_dump_writer.h index b464eb6..367f659 100644 --- a/modules/audio_coding/audio_network_adaptor/debug_dump_writer.h +++ b/modules/audio_coding/audio_network_adaptor/debug_dump_writer.h
@@ -15,7 +15,7 @@ #include "modules/audio_coding/audio_network_adaptor/controller.h" #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" #include "rtc_base/ignore_wundef.h" #include "rtc_base/system/file_wrapper.h" #if WEBRTC_ENABLE_PROTOBUF
diff --git a/modules/audio_coding/audio_network_adaptor/dtx_controller.h b/modules/audio_coding/audio_network_adaptor/dtx_controller.h index d3334ec..83fdf3d 100644 --- a/modules/audio_coding/audio_network_adaptor/dtx_controller.h +++ b/modules/audio_coding/audio_network_adaptor/dtx_controller.h
@@ -14,7 +14,7 @@ #include "absl/types/optional.h" #include "modules/audio_coding/audio_network_adaptor/controller.h" #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/audio_network_adaptor/event_log_writer.h b/modules/audio_coding/audio_network_adaptor/event_log_writer.h index 72b5245..c5e57e6 100644 --- a/modules/audio_coding/audio_network_adaptor/event_log_writer.h +++ b/modules/audio_coding/audio_network_adaptor/event_log_writer.h
@@ -12,7 +12,7 @@ #define MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_EVENT_LOG_WRITER_H_ #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { class RtcEventLog;
diff --git a/modules/audio_coding/audio_network_adaptor/event_log_writer_unittest.cc b/modules/audio_coding/audio_network_adaptor/event_log_writer_unittest.cc index 42189c3..b1e3313 100644 --- a/modules/audio_coding/audio_network_adaptor/event_log_writer_unittest.cc +++ b/modules/audio_coding/audio_network_adaptor/event_log_writer_unittest.cc
@@ -13,6 +13,7 @@ #include "logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h" #include "logging/rtc_event_log/mock/mock_rtc_event_log.h" #include "modules/audio_coding/audio_network_adaptor/event_log_writer.h" +#include "rtc_base/checks.h" #include "test/gtest.h" namespace webrtc {
diff --git a/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.h b/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.h index b7d3d56..87afe2e 100644 --- a/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.h +++ b/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.h
@@ -18,7 +18,7 @@ #include "modules/audio_coding/audio_network_adaptor/controller.h" #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h" #include "modules/audio_coding/audio_network_adaptor/util/threshold_curve.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based_unittest.cc b/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based_unittest.cc index de66717..d3f54ee 100644 --- a/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based_unittest.cc +++ b/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based_unittest.cc
@@ -422,7 +422,7 @@ // Test that FEC is turned on whenever we're on the curve or above it, // independent of the starting FEC state. - for (std::vector<NetworkState> states_list : {on, above}) { + for (const std::vector<NetworkState>& states_list : {on, above}) { for (NetworkState net_state : states_list) { for (bool initial_fec_enabled : {false, true}) { auto states =
diff --git a/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based.h b/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based.h index 421cb70..c547bff 100644 --- a/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based.h +++ b/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based.h
@@ -15,7 +15,7 @@ #include "modules/audio_coding/audio_network_adaptor/controller.h" #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h" #include "modules/audio_coding/audio_network_adaptor/util/threshold_curve.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based_unittest.cc b/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based_unittest.cc index 8e8704e..4438a23 100644 --- a/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based_unittest.cc +++ b/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based_unittest.cc
@@ -462,7 +462,7 @@ // Test that FEC is turned on whenever we're on the curve or above it, // independent of the starting FEC state. - for (std::vector<NetworkState> states_list : {on, above}) { + for (const std::vector<NetworkState>& states_list : {on, above}) { for (NetworkState net_state : states_list) { for (bool initial_fec_enabled : {false, true}) { FecControllerRplrBased controller(
diff --git a/modules/audio_coding/audio_network_adaptor/frame_length_controller.cc b/modules/audio_coding/audio_network_adaptor/frame_length_controller.cc index b123c7c..3cb91fd 100644 --- a/modules/audio_coding/audio_network_adaptor/frame_length_controller.cc +++ b/modules/audio_coding/audio_network_adaptor/frame_length_controller.cc
@@ -28,7 +28,7 @@ } // namespace FrameLengthController::Config::Config( - const std::vector<int>& encoder_frame_lengths_ms, + const std::set<int>& encoder_frame_lengths_ms, int initial_frame_length_ms, int min_encoder_bitrate_bps, float fl_increasing_packet_loss_fraction,
diff --git a/modules/audio_coding/audio_network_adaptor/frame_length_controller.h b/modules/audio_coding/audio_network_adaptor/frame_length_controller.h index f0a5aab..e182247 100644 --- a/modules/audio_coding/audio_network_adaptor/frame_length_controller.h +++ b/modules/audio_coding/audio_network_adaptor/frame_length_controller.h
@@ -13,12 +13,12 @@ #include <stddef.h> #include <map> -#include <vector> +#include <set> #include "absl/types/optional.h" #include "modules/audio_coding/audio_network_adaptor/controller.h" #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { @@ -33,7 +33,7 @@ int from_frame_length_ms; int to_frame_length_ms; }; - Config(const std::vector<int>& encoder_frame_lengths_ms, + Config(const std::set<int>& encoder_frame_lengths_ms, int initial_frame_length_ms, int min_encoder_bitrate_bps, float fl_increasing_packet_loss_fraction, @@ -43,7 +43,7 @@ std::map<FrameLengthChange, int> fl_changing_bandwidths_bps); Config(const Config& other); ~Config(); - std::vector<int> encoder_frame_lengths_ms; + std::set<int> encoder_frame_lengths_ms; int initial_frame_length_ms; int min_encoder_bitrate_bps; // Uplink packet loss fraction below which frame length can increase. @@ -74,7 +74,7 @@ const Config config_; - std::vector<int>::const_iterator frame_length_ms_; + std::set<int>::const_iterator frame_length_ms_; absl::optional<int> uplink_bandwidth_bps_;
diff --git a/modules/audio_coding/audio_network_adaptor/frame_length_controller_unittest.cc b/modules/audio_coding/audio_network_adaptor/frame_length_controller_unittest.cc index f97ad4f..8d6d815 100644 --- a/modules/audio_coding/audio_network_adaptor/frame_length_controller_unittest.cc +++ b/modules/audio_coding/audio_network_adaptor/frame_length_controller_unittest.cc
@@ -42,7 +42,7 @@ std::unique_ptr<FrameLengthController> CreateController( const std::map<FrameLengthController::Config::FrameLengthChange, int>& frame_length_change_criteria, - const std::vector<int>& encoder_frame_lengths_ms, + const std::set<int>& encoder_frame_lengths_ms, int initial_frame_length_ms) { std::unique_ptr<FrameLengthController> controller( new FrameLengthController(FrameLengthController::Config(
diff --git a/modules/audio_coding/codecs/audio_format_conversion.cc b/modules/audio_coding/codecs/audio_format_conversion.cc deleted file mode 100644 index f068301..0000000 --- a/modules/audio_coding/codecs/audio_format_conversion.cc +++ /dev/null
@@ -1,89 +0,0 @@ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "modules/audio_coding/codecs/audio_format_conversion.h" - -#include <string.h> -#include <string> -#include <utility> - -#include "absl/strings/match.h" -#include "api/array_view.h" -#include "rtc_base/checks.h" -#include "rtc_base/sanitizer.h" - -namespace webrtc { - -namespace { - -CodecInst MakeCodecInst(int payload_type, - const char* name, - int sample_rate, - size_t num_channels) { - // Create a CodecInst with some fields set. The remaining fields are zeroed, - // but we tell MSan to consider them uninitialized. - CodecInst ci = {0}; - rtc::MsanMarkUninitialized(rtc::MakeArrayView(&ci, 1)); - ci.pltype = payload_type; - strncpy(ci.plname, name, sizeof(ci.plname)); - ci.plname[sizeof(ci.plname) - 1] = '\0'; - ci.plfreq = sample_rate; - ci.channels = num_channels; - return ci; -} - -} // namespace - -SdpAudioFormat CodecInstToSdp(const CodecInst& ci) { - if (absl::EqualsIgnoreCase(ci.plname, "g722")) { - RTC_CHECK_EQ(16000, ci.plfreq); - RTC_CHECK(ci.channels == 1 || ci.channels == 2); - return {"g722", 8000, ci.channels}; - } else if (absl::EqualsIgnoreCase(ci.plname, "opus")) { - RTC_CHECK_EQ(48000, ci.plfreq); - RTC_CHECK(ci.channels == 1 || ci.channels == 2); - return ci.channels == 1 - ? SdpAudioFormat("opus", 48000, 2) - : SdpAudioFormat("opus", 48000, 2, {{"stereo", "1"}}); - } else { - return {ci.plname, ci.plfreq, ci.channels}; - } -} - -CodecInst SdpToCodecInst(int payload_type, const SdpAudioFormat& audio_format) { - if (absl::EqualsIgnoreCase(audio_format.name, "g722")) { - RTC_CHECK_EQ(8000, audio_format.clockrate_hz); - RTC_CHECK(audio_format.num_channels == 1 || audio_format.num_channels == 2); - return MakeCodecInst(payload_type, "g722", 16000, - audio_format.num_channels); - } else if (absl::EqualsIgnoreCase(audio_format.name, "opus")) { - RTC_CHECK_EQ(48000, audio_format.clockrate_hz); - RTC_CHECK_EQ(2, audio_format.num_channels); - const int num_channels = [&] { - auto stereo = audio_format.parameters.find("stereo"); - if (stereo != audio_format.parameters.end()) { - if (stereo->second == "0") { - return 1; - } else if (stereo->second == "1") { - return 2; - } else { - RTC_CHECK(false); // Bad stereo parameter. - } - } - return 1; // Default to mono. - }(); - return MakeCodecInst(payload_type, "opus", 48000, num_channels); - } else { - return MakeCodecInst(payload_type, audio_format.name.c_str(), - audio_format.clockrate_hz, audio_format.num_channels); - } -} - -} // namespace webrtc
diff --git a/modules/audio_coding/codecs/audio_format_conversion.h b/modules/audio_coding/codecs/audio_format_conversion.h deleted file mode 100644 index d981741..0000000 --- a/modules/audio_coding/codecs/audio_format_conversion.h +++ /dev/null
@@ -1,24 +0,0 @@ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef MODULES_AUDIO_CODING_CODECS_AUDIO_FORMAT_CONVERSION_H_ -#define MODULES_AUDIO_CODING_CODECS_AUDIO_FORMAT_CONVERSION_H_ - -#include "api/audio_codecs/audio_format.h" -#include "common_types.h" // NOLINT(build/include) - -namespace webrtc { - -SdpAudioFormat CodecInstToSdp(const CodecInst& codec_inst); -CodecInst SdpToCodecInst(int payload_type, const SdpAudioFormat& audio_format); - -} // namespace webrtc - -#endif // MODULES_AUDIO_CODING_CODECS_AUDIO_FORMAT_CONVERSION_H_
diff --git a/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc b/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc index 64f0159..a548be8 100644 --- a/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc +++ b/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc
@@ -103,9 +103,9 @@ } } -INSTANTIATE_TEST_CASE_P(BuiltinAudioEncoderFactoryTest, - AudioEncoderFactoryTest, - ::testing::Values(CreateBuiltinAudioEncoderFactory())); +INSTANTIATE_TEST_SUITE_P(BuiltinAudioEncoderFactoryTest, + AudioEncoderFactoryTest, + ::testing::Values(CreateBuiltinAudioEncoderFactory())); TEST(BuiltinAudioEncoderFactoryTest, SupportsTheExpectedFormats) { using ::testing::ElementsAreArray; @@ -116,6 +116,7 @@ const std::vector<SdpAudioFormat> supported_formats = [&specs] { std::vector<SdpAudioFormat> formats; + formats.reserve(specs.size()); for (const auto& spec : specs) { formats.push_back(spec.format); }
diff --git a/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc b/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc index e3655b4..3ecefd4 100644 --- a/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc +++ b/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc
@@ -13,7 +13,7 @@ #include "common_audio/vad/mock/mock_vad.h" #include "modules/audio_coding/codecs/cng/audio_encoder_cng.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" #include "rtc_base/numerics/safe_conversions.h" #include "test/gtest.h" #include "test/mock_audio_encoder.h"
diff --git a/modules/audio_coding/codecs/cng/cng_unittest.cc b/modules/audio_coding/codecs/cng/cng_unittest.cc index 81688b1..80349e2 100644 --- a/modules/audio_coding/codecs/cng/cng_unittest.cc +++ b/modules/audio_coding/codecs/cng/cng_unittest.cc
@@ -12,7 +12,7 @@ #include "modules/audio_coding/codecs/cng/webrtc_cng.h" #include "test/gtest.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" namespace webrtc {
diff --git a/modules/audio_coding/codecs/g711/audio_decoder_pcm.h b/modules/audio_coding/codecs/g711/audio_decoder_pcm.h index 9a01b8a..8fae71c 100644 --- a/modules/audio_coding/codecs/g711/audio_decoder_pcm.h +++ b/modules/audio_coding/codecs/g711/audio_decoder_pcm.h
@@ -18,7 +18,7 @@ #include "api/audio_codecs/audio_decoder.h" #include "rtc_base/buffer.h" #include "rtc_base/checks.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc b/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc index dce1635..fd560e4 100644 --- a/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc +++ b/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
@@ -12,25 +12,11 @@ #include <cstdint> -#include "common_types.h" #include "modules/audio_coding/codecs/g711/g711_interface.h" #include "rtc_base/checks.h" namespace webrtc { -namespace { - -template <typename T> -typename T::Config CreateConfig(const CodecInst& codec_inst) { - typename T::Config config; - config.frame_size_ms = codec_inst.pacsize / 8; - config.num_channels = codec_inst.channels; - config.payload_type = codec_inst.pltype; - return config; -} - -} // namespace - bool AudioEncoderPcm::Config::IsOk() const { return (frame_size_ms % 10 == 0) && (num_channels >= 1); } @@ -103,9 +89,6 @@ speech_buffer_.clear(); } -AudioEncoderPcmA::AudioEncoderPcmA(const CodecInst& codec_inst) - : AudioEncoderPcmA(CreateConfig<AudioEncoderPcmA>(codec_inst)) {} - size_t AudioEncoderPcmA::EncodeCall(const int16_t* audio, size_t input_len, uint8_t* encoded) { @@ -120,9 +103,6 @@ return AudioEncoder::CodecType::kPcmA; } -AudioEncoderPcmU::AudioEncoderPcmU(const CodecInst& codec_inst) - : AudioEncoderPcmU(CreateConfig<AudioEncoderPcmU>(codec_inst)) {} - size_t AudioEncoderPcmU::EncodeCall(const int16_t* audio, size_t input_len, uint8_t* encoded) {
diff --git a/modules/audio_coding/codecs/g711/audio_encoder_pcm.h b/modules/audio_coding/codecs/g711/audio_encoder_pcm.h index 37b67cf..e41c2a3 100644 --- a/modules/audio_coding/codecs/g711/audio_encoder_pcm.h +++ b/modules/audio_coding/codecs/g711/audio_encoder_pcm.h
@@ -14,7 +14,7 @@ #include <vector> #include "api/audio_codecs/audio_encoder.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { @@ -69,8 +69,6 @@ uint32_t first_timestamp_in_buffer_; }; -struct CodecInst; - class AudioEncoderPcmA final : public AudioEncoderPcm { public: struct Config : public AudioEncoderPcm::Config { @@ -79,7 +77,6 @@ explicit AudioEncoderPcmA(const Config& config) : AudioEncoderPcm(config, kSampleRateHz) {} - explicit AudioEncoderPcmA(const CodecInst& codec_inst); protected: size_t EncodeCall(const int16_t* audio, @@ -103,7 +100,6 @@ explicit AudioEncoderPcmU(const Config& config) : AudioEncoderPcm(config, kSampleRateHz) {} - explicit AudioEncoderPcmU(const CodecInst& codec_inst); protected: size_t EncodeCall(const int16_t* audio,
diff --git a/modules/audio_coding/codecs/g722/audio_decoder_g722.h b/modules/audio_coding/codecs/g722/audio_decoder_g722.h index 3240448..6911e0b 100644 --- a/modules/audio_coding/codecs/g722/audio_decoder_g722.h +++ b/modules/audio_coding/codecs/g722/audio_decoder_g722.h
@@ -12,7 +12,7 @@ #define MODULES_AUDIO_CODING_CODECS_G722_AUDIO_DECODER_G722_H_ #include "api/audio_codecs/audio_decoder.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" typedef struct WebRtcG722DecInst G722DecInst;
diff --git a/modules/audio_coding/codecs/g722/audio_encoder_g722.cc b/modules/audio_coding/codecs/g722/audio_encoder_g722.cc index e63d590..d293163 100644 --- a/modules/audio_coding/codecs/g722/audio_encoder_g722.cc +++ b/modules/audio_coding/codecs/g722/audio_encoder_g722.cc
@@ -12,7 +12,6 @@ #include <cstdint> -#include "common_types.h" #include "modules/audio_coding/codecs/g722/g722_interface.h" #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_conversions.h" @@ -23,13 +22,6 @@ const size_t kSampleRateHz = 16000; -AudioEncoderG722Config CreateConfig(const CodecInst& codec_inst) { - AudioEncoderG722Config config; - config.num_channels = rtc::dchecked_cast<int>(codec_inst.channels); - config.frame_size_ms = codec_inst.pacsize / 16; - return config; -} - } // namespace AudioEncoderG722Impl::AudioEncoderG722Impl(const AudioEncoderG722Config& config, @@ -52,9 +44,6 @@ Reset(); } -AudioEncoderG722Impl::AudioEncoderG722Impl(const CodecInst& codec_inst) - : AudioEncoderG722Impl(CreateConfig(codec_inst), codec_inst.pltype) {} - AudioEncoderG722Impl::~AudioEncoderG722Impl() = default; int AudioEncoderG722Impl::SampleRateHz() const {
diff --git a/modules/audio_coding/codecs/g722/audio_encoder_g722.h b/modules/audio_coding/codecs/g722/audio_encoder_g722.h index 3cf1439..cf45fb5 100644 --- a/modules/audio_coding/codecs/g722/audio_encoder_g722.h +++ b/modules/audio_coding/codecs/g722/audio_encoder_g722.h
@@ -17,16 +17,13 @@ #include "api/audio_codecs/g722/audio_encoder_g722_config.h" #include "modules/audio_coding/codecs/g722/g722_interface.h" #include "rtc_base/buffer.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { -struct CodecInst; - class AudioEncoderG722Impl final : public AudioEncoder { public: AudioEncoderG722Impl(const AudioEncoderG722Config& config, int payload_type); - explicit AudioEncoderG722Impl(const CodecInst& codec_inst); ~AudioEncoderG722Impl() override; int SampleRateHz() const override;
diff --git a/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h b/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h index fcb2074..d73ef0d 100644 --- a/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h +++ b/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h
@@ -17,7 +17,7 @@ #include "api/audio_codecs/audio_decoder.h" #include "rtc_base/buffer.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" typedef struct iLBC_decinst_t_ IlbcDecoderInstance;
diff --git a/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc b/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc index 8801fd5..ac9214b 100644 --- a/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc +++ b/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc
@@ -13,7 +13,6 @@ #include <algorithm> #include <cstdint> -#include "common_types.h" #include "modules/audio_coding/codecs/ilbc/ilbc.h" #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_conversions.h" @@ -24,12 +23,6 @@ const int kSampleRateHz = 8000; -AudioEncoderIlbcConfig CreateConfig(const CodecInst& codec_inst) { - AudioEncoderIlbcConfig config; - config.frame_size_ms = codec_inst.pacsize / 8; - return config; -} - int GetIlbcBitrate(int ptime) { switch (ptime) { case 20: @@ -58,9 +51,6 @@ Reset(); } -AudioEncoderIlbcImpl::AudioEncoderIlbcImpl(const CodecInst& codec_inst) - : AudioEncoderIlbcImpl(CreateConfig(codec_inst), codec_inst.pltype) {} - AudioEncoderIlbcImpl::~AudioEncoderIlbcImpl() { RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderFree(encoder_)); }
diff --git a/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h b/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h index a238689..ada613b 100644 --- a/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h +++ b/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h
@@ -14,16 +14,13 @@ #include "api/audio_codecs/audio_encoder.h" #include "api/audio_codecs/ilbc/audio_encoder_ilbc_config.h" #include "modules/audio_coding/codecs/ilbc/ilbc.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { -struct CodecInst; - class AudioEncoderIlbcImpl final : public AudioEncoder { public: AudioEncoderIlbcImpl(const AudioEncoderIlbcConfig& config, int payload_type); - explicit AudioEncoderIlbcImpl(const CodecInst& codec_inst); ~AudioEncoderIlbcImpl() override; int SampleRateHz() const override;
diff --git a/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc b/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc index 5ec1219..689292f 100644 --- a/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc +++ b/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc
@@ -103,7 +103,7 @@ // Also test the maximum number of frames in one packet for 20 and 30 ms. // The maximum is defined by the largest payload length that can be uniquely // resolved to a frame size of either 38 bytes (20 ms) or 50 bytes (30 ms). -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( IlbcTest, SplitIlbcTest, ::testing::Values(std::pair<int, int>(1, 20), // 1 frame, 20 ms.
diff --git a/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h b/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h index f840ffa..7cadd91 100644 --- a/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h +++ b/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h
@@ -15,9 +15,9 @@ #include "absl/types/optional.h" #include "api/audio_codecs/audio_decoder.h" +#include "api/scoped_refptr.h" #include "modules/audio_coding/codecs/isac/locked_bandwidth_info.h" -#include "rtc_base/constructormagic.h" -#include "rtc_base/scoped_ref_ptr.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h b/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h index 541b90c..c6ef795 100644 --- a/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h +++ b/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
@@ -14,14 +14,12 @@ #include <vector> #include "api/audio_codecs/audio_encoder.h" +#include "api/scoped_refptr.h" #include "modules/audio_coding/codecs/isac/locked_bandwidth_info.h" -#include "rtc_base/constructormagic.h" -#include "rtc_base/scoped_ref_ptr.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { -struct CodecInst; - template <typename T> class AudioEncoderIsacT final : public AudioEncoder { public: @@ -52,9 +50,6 @@ }; explicit AudioEncoderIsacT(const Config& config); - explicit AudioEncoderIsacT( - const CodecInst& codec_inst, - const rtc::scoped_refptr<LockedIsacBandwidthInfo>& bwinfo); ~AudioEncoderIsacT() override; int SampleRateHz() const override;
diff --git a/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h b/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h index cbf15fc..3448139 100644 --- a/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h +++ b/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
@@ -11,28 +11,11 @@ #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_ #define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_ -#include "common_types.h" // NOLINT(build/include) #include "rtc_base/checks.h" namespace webrtc { template <typename T> -typename AudioEncoderIsacT<T>::Config CreateIsacConfig( - const CodecInst& codec_inst, - const rtc::scoped_refptr<LockedIsacBandwidthInfo>& bwinfo) { - typename AudioEncoderIsacT<T>::Config config; - config.bwinfo = bwinfo; - config.payload_type = codec_inst.pltype; - config.sample_rate_hz = codec_inst.plfreq; - config.frame_size_ms = - rtc::CheckedDivExact(1000 * codec_inst.pacsize, config.sample_rate_hz); - config.adaptive_mode = (codec_inst.rate == -1); - if (codec_inst.rate != -1) - config.bit_rate = codec_inst.rate; - return config; -} - -template <typename T> bool AudioEncoderIsacT<T>::Config::IsOk() const { if (max_bit_rate < 32000 && max_bit_rate != -1) return false; @@ -67,12 +50,6 @@ } template <typename T> -AudioEncoderIsacT<T>::AudioEncoderIsacT( - const CodecInst& codec_inst, - const rtc::scoped_refptr<LockedIsacBandwidthInfo>& bwinfo) - : AudioEncoderIsacT(CreateIsacConfig<T>(codec_inst, bwinfo)) {} - -template <typename T> AudioEncoderIsacT<T>::~AudioEncoderIsacT() { RTC_CHECK_EQ(0, T::Free(isac_state_)); }
diff --git a/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c b/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c index e565e85..7355330 100644 --- a/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c +++ b/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c
@@ -9,7 +9,6 @@ */ #include "modules/audio_coding/codecs/isac/fix/source/pitch_estimator.h" - #include "common_audio/signal_processing/include/signal_processing_library.h" #include "modules/audio_coding/codecs/isac/fix/source/settings.h" #include "modules/audio_coding/codecs/isac/fix/source/structs.h" @@ -55,7 +54,8 @@ const int16_t Gain = 21299; // 1.3 in Q14 int16_t oldLagQ7; int16_t oldGainQ12, lagdeltaQ7, curLagQ7, gaindeltaQ12, curGainQ12; - size_t indW32 = 0, frcQQ = 0; + size_t frcQQ = 0; + int32_t indW32 = 0; const int16_t* fracoeffQQ = NULL; // Assumptions in ARM assembly for WebRtcIsacfix_PitchFilterCoreARM().
diff --git a/modules/audio_coding/codecs/isac/locked_bandwidth_info.h b/modules/audio_coding/codecs/isac/locked_bandwidth_info.h index 37074f8..0b1bc7d 100644 --- a/modules/audio_coding/codecs/isac/locked_bandwidth_info.h +++ b/modules/audio_coding/codecs/isac/locked_bandwidth_info.h
@@ -12,8 +12,8 @@ #define MODULES_AUDIO_CODING_CODECS_ISAC_LOCKED_BANDWIDTH_INFO_H_ #include "modules/audio_coding/codecs/isac/bandwidth_info.h" -#include "rtc_base/atomicops.h" -#include "rtc_base/criticalsection.h" +#include "rtc_base/atomic_ops.h" +#include "rtc_base/critical_section.h" #include "rtc_base/thread_annotations.h" namespace webrtc {
diff --git a/modules/audio_coding/codecs/isac/main/source/isac_unittest.cc b/modules/audio_coding/codecs/isac/main/source/isac_unittest.cc index 3ec28cc..6d9b013 100644 --- a/modules/audio_coding/codecs/isac/main/source/isac_unittest.cc +++ b/modules/audio_coding/codecs/isac/main/source/isac_unittest.cc
@@ -11,7 +11,7 @@ #include "modules/audio_coding/codecs/isac/main/include/isac.h" #include "test/gtest.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" struct WebRtcISACStruct;
diff --git a/modules/audio_coding/codecs/isac/unittest.cc b/modules/audio_coding/codecs/isac/unittest.cc index 5855d56..076510b 100644 --- a/modules/audio_coding/codecs/isac/unittest.cc +++ b/modules/audio_coding/codecs/isac/unittest.cc
@@ -19,7 +19,7 @@ #include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/strings/string_builder.h" #include "test/gtest.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" namespace webrtc { @@ -252,6 +252,6 @@ return cases; } -INSTANTIATE_TEST_CASE_P(, IsacCommonTest, testing::ValuesIn(TestCases())); +INSTANTIATE_TEST_SUITE_P(, IsacCommonTest, testing::ValuesIn(TestCases())); } // namespace webrtc
diff --git a/modules/audio_coding/codecs/legacy_encoded_audio_frame_unittest.cc b/modules/audio_coding/codecs/legacy_encoded_audio_frame_unittest.cc index 9079bcd..2ca1d4c 100644 --- a/modules/audio_coding/codecs/legacy_encoded_audio_frame_unittest.cc +++ b/modules/audio_coding/codecs/legacy_encoded_audio_frame_unittest.cc
@@ -10,12 +10,28 @@ #include "modules/audio_coding/codecs/legacy_encoded_audio_frame.h" -#include "modules/audio_coding/acm2/rent_a_codec.h" #include "rtc_base/numerics/safe_conversions.h" #include "test/gtest.h" namespace webrtc { +enum class NetEqDecoder { + kDecoderPCMu, + kDecoderPCMa, + kDecoderPCMu_2ch, + kDecoderPCMa_2ch, + kDecoderPCM16B, + kDecoderPCM16Bwb, + kDecoderPCM16Bswb32kHz, + kDecoderPCM16Bswb48kHz, + kDecoderPCM16B_2ch, + kDecoderPCM16Bwb_2ch, + kDecoderPCM16Bswb32kHz_2ch, + kDecoderPCM16Bswb48kHz_2ch, + kDecoderPCM16B_5ch, + kDecoderG722, +}; + class SplitBySamplesTest : public ::testing::TestWithParam<NetEqDecoder> { protected: virtual void SetUp() { @@ -144,7 +160,7 @@ } } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( LegacyEncodedAudioFrame, SplitBySamplesTest, ::testing::Values(NetEqDecoder::kDecoderPCMu,
diff --git a/modules/audio_coding/codecs/opus/audio_decoder_opus.cc b/modules/audio_coding/codecs/opus/audio_decoder_opus.cc index 357cb1a..b6eada9 100644 --- a/modules/audio_coding/codecs/opus/audio_decoder_opus.cc +++ b/modules/audio_coding/codecs/opus/audio_decoder_opus.cc
@@ -71,8 +71,10 @@ AudioDecoderOpusImpl::AudioDecoderOpusImpl(size_t num_channels) : channels_(num_channels) { - RTC_DCHECK(num_channels == 1 || num_channels == 2); - WebRtcOpus_DecoderCreate(&dec_state_, channels_); + RTC_DCHECK(num_channels == 1 || num_channels == 2 || num_channels == 4 || + num_channels == 6 || num_channels == 8); + const int error = WebRtcOpus_DecoderCreate(&dec_state_, channels_); + RTC_DCHECK(error == 0); WebRtcOpus_DecoderInit(dec_state_); }
diff --git a/modules/audio_coding/codecs/opus/audio_decoder_opus.h b/modules/audio_coding/codecs/opus/audio_decoder_opus.h index 8043425..d8cc5c1 100644 --- a/modules/audio_coding/codecs/opus/audio_decoder_opus.h +++ b/modules/audio_coding/codecs/opus/audio_decoder_opus.h
@@ -18,7 +18,7 @@ #include "api/audio_codecs/audio_decoder.h" #include "modules/audio_coding/codecs/opus/opus_interface.h" #include "rtc_base/buffer.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/codecs/opus/audio_encoder_opus.cc b/modules/audio_coding/codecs/opus/audio_encoder_opus.cc index 1a88acf..69aa8b9 100644 --- a/modules/audio_coding/codecs/opus/audio_encoder_opus.cc +++ b/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
@@ -12,11 +12,11 @@ #include <algorithm> #include <iterator> +#include <string> #include <utility> #include "absl/memory/memory.h" #include "absl/strings/match.h" -#include "common_types.h" #include "modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h" #include "modules/audio_coding/audio_network_adaptor/controller_manager.h" #include "modules/audio_coding/codecs/opus/opus_interface.h" @@ -26,9 +26,8 @@ #include "rtc_base/numerics/exp_filter.h" #include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/numerics/safe_minmax.h" -#include "rtc_base/protobuf_utils.h" #include "rtc_base/string_to_number.h" -#include "rtc_base/timeutils.h" +#include "rtc_base/time_utils.h" #include "system_wrappers/include/field_trial.h" namespace webrtc { @@ -334,19 +333,6 @@ return absl::nullopt; } -AudioEncoderOpusConfig AudioEncoderOpusImpl::CreateConfig( - const CodecInst& codec_inst) { - AudioEncoderOpusConfig config; - config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48); - config.num_channels = codec_inst.channels; - config.bitrate_bps = codec_inst.rate; - config.application = config.num_channels == 1 - ? AudioEncoderOpusConfig::ApplicationMode::kVoip - : AudioEncoderOpusConfig::ApplicationMode::kAudio; - config.supported_frame_lengths_ms.push_back(config.frame_size_ms); - return config; -} - absl::optional<AudioEncoderOpusConfig> AudioEncoderOpusImpl::SdpToConfig( const SdpAudioFormat& format) { if (!absl::EqualsIgnoreCase(format.name, "opus") || @@ -457,7 +443,7 @@ : AudioEncoderOpusImpl( config, payload_type, - [this](const ProtoString& config_string, RtcEventLog* event_log) { + [this](const std::string& config_string, RtcEventLog* event_log) { return DefaultAudioNetworkAdaptorCreator(config_string, event_log); }, // We choose 5sec as initial time constant due to empirical data. @@ -494,9 +480,6 @@ SetProjectedPacketLossRate(packet_loss_rate_); } -AudioEncoderOpusImpl::AudioEncoderOpusImpl(const CodecInst& codec_inst) - : AudioEncoderOpusImpl(CreateConfig(codec_inst), codec_inst.pltype) {} - AudioEncoderOpusImpl::AudioEncoderOpusImpl(int payload_type, const SdpAudioFormat& format) : AudioEncoderOpusImpl(*SdpToConfig(format), payload_type) {} @@ -784,7 +767,9 @@ AudioEncoderOpusConfig::ApplicationMode::kVoip ? 0 : 1)); - RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, GetBitrateBps(config))); + const int bitrate = GetBitrateBps(config); + RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, bitrate)); + RTC_LOG(LS_INFO) << "Set Opus bitrate to " << bitrate << " bps."; if (config.fec_enabled) { RTC_CHECK_EQ(0, WebRtcOpus_EnableFec(inst_)); } else { @@ -847,17 +832,23 @@ } void AudioEncoderOpusImpl::SetTargetBitrate(int bits_per_second) { - config_.bitrate_bps = rtc::SafeClamp<int>( + const int new_bitrate = rtc::SafeClamp<int>( bits_per_second, AudioEncoderOpusConfig::kMinBitrateBps, AudioEncoderOpusConfig::kMaxBitrateBps); - RTC_DCHECK(config_.IsOk()); - RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, GetBitrateBps(config_))); + if (config_.bitrate_bps && *config_.bitrate_bps != new_bitrate) { + config_.bitrate_bps = new_bitrate; + RTC_DCHECK(config_.IsOk()); + const int bitrate = GetBitrateBps(config_); + RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, bitrate)); + RTC_LOG(LS_INFO) << "Set Opus bitrate to " << bitrate << " bps."; + bitrate_changed_ = true; + } + const auto new_complexity = GetNewComplexity(config_); if (new_complexity && complexity_ != *new_complexity) { complexity_ = *new_complexity; RTC_CHECK_EQ(0, WebRtcOpus_SetComplexity(inst_, complexity_)); } - bitrate_changed_ = true; } void AudioEncoderOpusImpl::ApplyAudioNetworkAdaptor() { @@ -879,7 +870,7 @@ std::unique_ptr<AudioNetworkAdaptor> AudioEncoderOpusImpl::DefaultAudioNetworkAdaptorCreator( - const ProtoString& config_string, + const std::string& config_string, RtcEventLog* event_log) const { AudioNetworkAdaptorImpl::Config config; config.event_log = event_log;
diff --git a/modules/audio_coding/codecs/opus/audio_encoder_opus.h b/modules/audio_coding/codecs/opus/audio_encoder_opus.h index 150423f..dc14620 100644 --- a/modules/audio_coding/codecs/opus/audio_encoder_opus.h +++ b/modules/audio_coding/codecs/opus/audio_encoder_opus.h
@@ -23,15 +23,12 @@ #include "common_audio/smoothing_filter.h" #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h" #include "modules/audio_coding/codecs/opus/opus_interface.h" -#include "rtc_base/constructormagic.h" -#include "rtc_base/protobuf_utils.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { class RtcEventLog; -struct CodecInst; - class AudioEncoderOpusImpl final : public AudioEncoder { public: class NewPacketLossRateOptimizer { @@ -43,9 +40,9 @@ float OptimizePacketLossRate(float packet_loss_rate) const; // Getters for testing. - float min_packet_loss_rate() const { return min_packet_loss_rate_; }; - float max_packet_loss_rate() const { return max_packet_loss_rate_; }; - float slope() const { return slope_; }; + float min_packet_loss_rate() const { return min_packet_loss_rate_; } + float max_packet_loss_rate() const { return max_packet_loss_rate_; } + float slope() const { return slope_; } private: const float min_packet_loss_rate_; @@ -54,8 +51,6 @@ RTC_DISALLOW_COPY_AND_ASSIGN(NewPacketLossRateOptimizer); }; - static AudioEncoderOpusConfig CreateConfig(const CodecInst& codec_inst); - // Returns empty if the current bitrate falls within the hysteresis window, // defined by complexity_threshold_bps +/- complexity_threshold_window_bps. // Otherwise, returns the current complexity depending on whether the @@ -83,7 +78,6 @@ const AudioNetworkAdaptorCreator& audio_network_adaptor_creator, std::unique_ptr<SmoothingFilter> bitrate_smoother); - explicit AudioEncoderOpusImpl(const CodecInst& codec_inst); AudioEncoderOpusImpl(int payload_type, const SdpAudioFormat& format); ~AudioEncoderOpusImpl() override; @@ -176,7 +170,7 @@ void ApplyAudioNetworkAdaptor(); std::unique_ptr<AudioNetworkAdaptor> DefaultAudioNetworkAdaptorCreator( - const ProtoString& config_string, + const std::string& config_string, RtcEventLog* event_log) const; void MaybeUpdateUplinkBandwidth();
diff --git a/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc b/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc index d5c2c84..b3b531f 100644 --- a/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc +++ b/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc
@@ -15,17 +15,16 @@ #include "absl/memory/memory.h" #include "api/audio_codecs/opus/audio_encoder_opus.h" #include "common_audio/mocks/mock_smoothing_filter.h" -#include "common_types.h" // NOLINT(build/include) #include "modules/audio_coding/audio_network_adaptor/mock/mock_audio_network_adaptor.h" #include "modules/audio_coding/codecs/opus/audio_encoder_opus.h" #include "modules/audio_coding/codecs/opus/opus_interface.h" #include "modules/audio_coding/neteq/tools/audio_loop.h" #include "rtc_base/checks.h" -#include "rtc_base/fakeclock.h" +#include "rtc_base/fake_clock.h" #include "test/field_trial.h" #include "test/gmock.h" #include "test/gtest.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" namespace webrtc { using ::testing::NiceMock; @@ -33,21 +32,11 @@ namespace { -const CodecInst kDefaultOpusSettings = {105, "opus", 48000, 960, 1, 32000}; +constexpr int kDefaultOpusPayloadType = 105; +constexpr int kDefaultOpusRate = 32000; +constexpr int kDefaultOpusPacSize = 960; constexpr int64_t kInitialTimeUs = 12345678; -AudioEncoderOpusConfig CreateConfig(const CodecInst& codec_inst) { - AudioEncoderOpusConfig config; - config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48); - config.num_channels = codec_inst.channels; - config.bitrate_bps = codec_inst.rate; - config.application = config.num_channels == 1 - ? AudioEncoderOpusConfig::ApplicationMode::kVoip - : AudioEncoderOpusConfig::ApplicationMode::kAudio; - config.supported_frame_lengths_ms.push_back(config.frame_size_ms); - return config; -} - AudioEncoderOpusConfig CreateConfigWithParameters( const SdpAudioFormat::Parameters& params) { const SdpAudioFormat format("opus", 48000, 2, params); @@ -79,16 +68,23 @@ return adaptor; }; - CodecInst codec_inst = kDefaultOpusSettings; - codec_inst.channels = num_channels; - states->config = CreateConfig(codec_inst); + AudioEncoderOpusConfig config; + config.frame_size_ms = rtc::CheckedDivExact(kDefaultOpusPacSize, 48); + config.num_channels = num_channels; + config.bitrate_bps = kDefaultOpusRate; + config.application = num_channels == 1 + ? AudioEncoderOpusConfig::ApplicationMode::kVoip + : AudioEncoderOpusConfig::ApplicationMode::kAudio; + config.supported_frame_lengths_ms.push_back(config.frame_size_ms); + states->config = config; + std::unique_ptr<MockSmoothingFilter> bitrate_smoother( new MockSmoothingFilter()); states->mock_bitrate_smoother = bitrate_smoother.get(); - states->encoder.reset(new AudioEncoderOpusImpl( - states->config, codec_inst.pltype, std::move(creator), - std::move(bitrate_smoother))); + states->encoder.reset( + new AudioEncoderOpusImpl(states->config, kDefaultOpusPayloadType, creator, + std::move(bitrate_smoother))); return states; } @@ -436,12 +432,12 @@ auto states = CreateCodec(2); - states->encoder->OnReceivedUplinkBandwidth(kDefaultOpusSettings.rate * 2, + states->encoder->OnReceivedUplinkBandwidth(kDefaultOpusRate * 2, absl::nullopt); // Since |OnReceivedOverhead| has not been called, the codec bitrate should // not change. - EXPECT_EQ(kDefaultOpusSettings.rate, states->encoder->GetTargetBitrate()); + EXPECT_EQ(kDefaultOpusRate, states->encoder->GetTargetBitrate()); } TEST(AudioEncoderOpusTest, OverheadRemovedFromTargetAudioBitrate) { @@ -456,7 +452,7 @@ constexpr int kTargetBitrateBps = 40000; states->encoder->OnReceivedUplinkBandwidth(kTargetBitrateBps, absl::nullopt); - int packet_rate = rtc::CheckedDivExact(48000, kDefaultOpusSettings.pacsize); + int packet_rate = rtc::CheckedDivExact(48000, kDefaultOpusPacSize); EXPECT_EQ(kTargetBitrateBps - 8 * static_cast<int>(kOverheadBytesPerPacket) * packet_rate, states->encoder->GetTargetBitrate()); @@ -474,7 +470,7 @@ constexpr size_t kOverheadBytesPerPacket = 64; states->encoder->OnReceivedOverhead(kOverheadBytesPerPacket); - int packet_rate = rtc::CheckedDivExact(48000, kDefaultOpusSettings.pacsize); + int packet_rate = rtc::CheckedDivExact(48000, kDefaultOpusPacSize); // Set a target rate that is smaller than |kMinBitrateBps| when overhead is // subtracted. The eventual codec rate should be bounded by |kMinBitrateBps|.
diff --git a/modules/audio_coding/codecs/opus/opus_bandwidth_unittest.cc b/modules/audio_coding/codecs/opus/opus_bandwidth_unittest.cc index 7e6b626..2c8edf0 100644 --- a/modules/audio_coding/codecs/opus/opus_bandwidth_unittest.cc +++ b/modules/audio_coding/codecs/opus/opus_bandwidth_unittest.cc
@@ -16,7 +16,7 @@ #include "modules/audio_coding/neteq/tools/audio_loop.h" #include "test/field_trial.h" #include "test/gtest.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" namespace webrtc { namespace {
diff --git a/modules/audio_coding/codecs/opus/opus_complexity_unittest.cc b/modules/audio_coding/codecs/opus/opus_complexity_unittest.cc index 4c9174d..84bad33 100644 --- a/modules/audio_coding/codecs/opus/opus_complexity_unittest.cc +++ b/modules/audio_coding/codecs/opus/opus_complexity_unittest.cc
@@ -11,9 +11,9 @@ #include "api/audio_codecs/opus/audio_encoder_opus.h" #include "modules/audio_coding/neteq/tools/audio_loop.h" #include "rtc_base/format_macros.h" -#include "rtc_base/timeutils.h" +#include "rtc_base/time_utils.h" #include "test/gtest.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" #include "test/testsupport/perf_test.h" namespace webrtc {
diff --git a/modules/audio_coding/codecs/opus/opus_fec_test.cc b/modules/audio_coding/codecs/opus/opus_fec_test.cc index 4fab8a7..7552c20 100644 --- a/modules/audio_coding/codecs/opus/opus_fec_test.cc +++ b/modules/audio_coding/codecs/opus/opus_fec_test.cc
@@ -13,7 +13,7 @@ #include "modules/audio_coding/codecs/opus/opus_interface.h" #include "rtc_base/format_macros.h" #include "test/gtest.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" using std::string; using std::tuple; @@ -238,6 +238,6 @@ string("pcm"))}; // 64 kbps, stereo -INSTANTIATE_TEST_CASE_P(AllTest, OpusFecTest, ::testing::ValuesIn(param_set)); +INSTANTIATE_TEST_SUITE_P(AllTest, OpusFecTest, ::testing::ValuesIn(param_set)); } // namespace webrtc
diff --git a/modules/audio_coding/codecs/opus/opus_inst.h b/modules/audio_coding/codecs/opus/opus_inst.h index 2473a5c..0b31181 100644 --- a/modules/audio_coding/codecs/opus/opus_inst.h +++ b/modules/audio_coding/codecs/opus/opus_inst.h
@@ -17,16 +17,23 @@ RTC_PUSH_IGNORING_WUNDEF() #include "opus.h" +#include "opus_multistream.h" RTC_POP_IGNORING_WUNDEF() struct WebRtcOpusEncInst { - OpusEncoder* encoder; + union { + OpusEncoder* encoder; + OpusMSEncoder* multistream_encoder; + } encoder; size_t channels; int in_dtx_mode; }; struct WebRtcOpusDecInst { - OpusDecoder* decoder; + union { + OpusDecoder* decoder; + OpusMSDecoder* multistream_decoder; + } decoder; int prev_decoded_samples; size_t channels; int in_dtx_mode;
diff --git a/modules/audio_coding/codecs/opus/opus_interface.c b/modules/audio_coding/codecs/opus/opus_interface.c index d219098..3369f8e 100644 --- a/modules/audio_coding/codecs/opus/opus_interface.c +++ b/modules/audio_coding/codecs/opus/opus_interface.c
@@ -37,6 +37,40 @@ kWebRtcOpusDefaultFrameSize = 960, }; +int16_t GetSurroundParameters(int channels, + int *streams, + int *coupled_streams, + unsigned char *mapping) { + int opus_error; + int ret = 0; + // Use 'surround encoder create' to get values for 'coupled_streams', + // 'streams' and 'mapping'. + OpusMSEncoder* ms_encoder_ptr = opus_multistream_surround_encoder_create( + 48000, + channels, + /* mapping family */ channels <= 2 ? 0 : 1, + streams, + coupled_streams, + mapping, + OPUS_APPLICATION_VOIP, // Application type shouldn't affect + // streams/mapping values. + &opus_error); + + // This shouldn't fail; if it fails, + // signal an error and return invalid values. + if (opus_error != OPUS_OK || ms_encoder_ptr == NULL) { + ret = -1; + *streams = -1; + *coupled_streams = -1; + } + + // We don't need the encoder. + if (ms_encoder_ptr != NULL) { + opus_multistream_encoder_destroy(ms_encoder_ptr); + } + return ret; +} + int16_t WebRtcOpus_EncoderCreate(OpusEncInst** inst, size_t channels, int32_t application) { @@ -55,13 +89,34 @@ return -1; } - OpusEncInst* state = calloc(1, sizeof(OpusEncInst)); + OpusEncInst* state = (OpusEncInst*)calloc(1, sizeof(OpusEncInst)); RTC_DCHECK(state); int error; - state->encoder = opus_encoder_create(48000, (int)channels, opus_app, - &error); - if (error != OPUS_OK || !state->encoder) { + if (channels <= 2) { + state->encoder.encoder = opus_encoder_create(48000, (int)channels, opus_app, + &error); + + } else { + unsigned char mapping[255]; + memset(mapping, 0, 255); + int streams = -1; + int coupled_streams = -1; + + state->encoder.multistream_encoder = + opus_multistream_surround_encoder_create( + 48000, + channels, + /* mapping family */ 1, + &streams, + &coupled_streams, + mapping, + opus_app, + &error); + } + + if (error != OPUS_OK || (!state->encoder.encoder && + !state->encoder.multistream_encoder)) { WebRtcOpus_EncoderFree(state); return -1; } @@ -75,7 +130,11 @@ int16_t WebRtcOpus_EncoderFree(OpusEncInst* inst) { if (inst) { - opus_encoder_destroy(inst->encoder); + if (inst->channels <= 2) { + opus_encoder_destroy(inst->encoder.encoder); + } else { + opus_multistream_encoder_destroy(inst->encoder.multistream_encoder); + } free(inst); return 0; } else { @@ -94,11 +153,19 @@ return -1; } - res = opus_encode(inst->encoder, - (const opus_int16*)audio_in, - (int)samples, - encoded, - (opus_int32)length_encoded_buffer); + if (inst->channels <= 2) { + res = opus_encode(inst->encoder.encoder, + (const opus_int16*)audio_in, + (int)samples, + encoded, + (opus_int32)length_encoded_buffer); + } else { + res = opus_multistream_encode(inst->encoder.multistream_encoder, + (const opus_int16*)audio_in, + (int)samples, + encoded, + (opus_int32)length_encoded_buffer); + } if (res <= 0) { return -1; @@ -120,9 +187,15 @@ return res; } +#define ENCODER_CTL(inst, vargs) ( \ + inst->channels <= 2 ? \ + opus_encoder_ctl(inst->encoder.encoder, vargs) \ + : opus_multistream_encoder_ctl(inst->encoder.multistream_encoder, vargs)) + + int16_t WebRtcOpus_SetBitRate(OpusEncInst* inst, int32_t rate) { if (inst) { - return opus_encoder_ctl(inst->encoder, OPUS_SET_BITRATE(rate)); + return ENCODER_CTL(inst, OPUS_SET_BITRATE(rate)); } else { return -1; } @@ -130,8 +203,7 @@ int16_t WebRtcOpus_SetPacketLossRate(OpusEncInst* inst, int32_t loss_rate) { if (inst) { - return opus_encoder_ctl(inst->encoder, - OPUS_SET_PACKET_LOSS_PERC(loss_rate)); + return ENCODER_CTL(inst, OPUS_SET_PACKET_LOSS_PERC(loss_rate)); } else { return -1; } @@ -154,13 +226,52 @@ } else { set_bandwidth = OPUS_BANDWIDTH_FULLBAND; } - return opus_encoder_ctl(inst->encoder, - OPUS_SET_MAX_BANDWIDTH(set_bandwidth)); + return ENCODER_CTL(inst, OPUS_SET_MAX_BANDWIDTH(set_bandwidth)); +} + +int16_t WebRtcOpus_GetMaxPlaybackRate(OpusEncInst* const inst, + int32_t* result_hz) { + if (inst->channels <= 2) { + if (opus_encoder_ctl( + inst->encoder.encoder, + OPUS_GET_MAX_BANDWIDTH(result_hz)) == OPUS_OK) { + return 0; + } + return -1; + } + + opus_int32 max_bandwidth; + int s; + int ret; + + max_bandwidth = 0; + ret = OPUS_OK; + s = 0; + while (ret == OPUS_OK) { + OpusEncoder *enc; + opus_int32 bandwidth; + + ret = ENCODER_CTL(inst, OPUS_MULTISTREAM_GET_ENCODER_STATE(s, &enc)); + if (ret == OPUS_BAD_ARG) + break; + if (ret != OPUS_OK) + return -1; + if (opus_encoder_ctl(enc, OPUS_GET_MAX_BANDWIDTH(&bandwidth)) != OPUS_OK) + return -1; + + if (max_bandwidth != 0 && max_bandwidth != bandwidth) + return -1; + + max_bandwidth = bandwidth; + s++; + } + *result_hz = max_bandwidth; + return 0; } int16_t WebRtcOpus_EnableFec(OpusEncInst* inst) { if (inst) { - return opus_encoder_ctl(inst->encoder, OPUS_SET_INBAND_FEC(1)); + return ENCODER_CTL(inst, OPUS_SET_INBAND_FEC(1)); } else { return -1; } @@ -168,7 +279,7 @@ int16_t WebRtcOpus_DisableFec(OpusEncInst* inst) { if (inst) { - return opus_encoder_ctl(inst->encoder, OPUS_SET_INBAND_FEC(0)); + return ENCODER_CTL(inst, OPUS_SET_INBAND_FEC(0)); } else { return -1; } @@ -184,21 +295,21 @@ // last long during a pure silence, if the signal type is not forced. // TODO(minyue): Remove the signal type forcing when Opus DTX works properly // without it. - int ret = opus_encoder_ctl(inst->encoder, - OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + int ret = ENCODER_CTL(inst, + OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); if (ret != OPUS_OK) return ret; - return opus_encoder_ctl(inst->encoder, OPUS_SET_DTX(1)); + return ENCODER_CTL(inst, OPUS_SET_DTX(1)); } int16_t WebRtcOpus_DisableDtx(OpusEncInst* inst) { if (inst) { - int ret = opus_encoder_ctl(inst->encoder, - OPUS_SET_SIGNAL(OPUS_AUTO)); + int ret = ENCODER_CTL(inst, + OPUS_SET_SIGNAL(OPUS_AUTO)); if (ret != OPUS_OK) return ret; - return opus_encoder_ctl(inst->encoder, OPUS_SET_DTX(0)); + return ENCODER_CTL(inst, OPUS_SET_DTX(0)); } else { return -1; } @@ -206,7 +317,7 @@ int16_t WebRtcOpus_EnableCbr(OpusEncInst* inst) { if (inst) { - return opus_encoder_ctl(inst->encoder, OPUS_SET_VBR(0)); + return ENCODER_CTL(inst, OPUS_SET_VBR(0)); } else { return -1; } @@ -214,7 +325,7 @@ int16_t WebRtcOpus_DisableCbr(OpusEncInst* inst) { if (inst) { - return opus_encoder_ctl(inst->encoder, OPUS_SET_VBR(1)); + return ENCODER_CTL(inst, OPUS_SET_VBR(1)); } else { return -1; } @@ -222,7 +333,8 @@ int16_t WebRtcOpus_SetComplexity(OpusEncInst* inst, int32_t complexity) { if (inst) { - return opus_encoder_ctl(inst->encoder, OPUS_SET_COMPLEXITY(complexity)); + return ENCODER_CTL(inst, + OPUS_SET_COMPLEXITY(complexity)); } else { return -1; } @@ -233,7 +345,8 @@ return -1; } int32_t bandwidth; - if (opus_encoder_ctl(inst->encoder, OPUS_GET_BANDWIDTH(&bandwidth)) == 0) { + if (ENCODER_CTL(inst, + OPUS_GET_BANDWIDTH(&bandwidth)) == 0) { return bandwidth; } else { return -1; @@ -243,7 +356,8 @@ int16_t WebRtcOpus_SetBandwidth(OpusEncInst* inst, int32_t bandwidth) { if (inst) { - return opus_encoder_ctl(inst->encoder, OPUS_SET_BANDWIDTH(bandwidth)); + return ENCODER_CTL(inst, + OPUS_SET_BANDWIDTH(bandwidth)); } else { return -1; } @@ -253,11 +367,11 @@ if (!inst) return -1; if (num_channels == 0) { - return opus_encoder_ctl(inst->encoder, + return ENCODER_CTL(inst, OPUS_SET_FORCE_CHANNELS(OPUS_AUTO)); } else if (num_channels == 1 || num_channels == 2) { - return opus_encoder_ctl(inst->encoder, - OPUS_SET_FORCE_CHANNELS(num_channels)); + return ENCODER_CTL(inst, + OPUS_SET_FORCE_CHANNELS(num_channels)); } else { return -1; } @@ -268,16 +382,37 @@ OpusDecInst* state; if (inst != NULL) { - /* Create Opus decoder state. */ + // Create Opus decoder state. state = (OpusDecInst*) calloc(1, sizeof(OpusDecInst)); if (state == NULL) { return -1; } - /* Create new memory, always at 48000 Hz. */ - state->decoder = opus_decoder_create(48000, (int)channels, &error); - if (error == OPUS_OK && state->decoder != NULL) { - /* Creation of memory all ok. */ + if (channels <= 2) { + state->decoder.decoder = opus_decoder_create(48000, + (int)channels, &error); + } else { + unsigned char mapping[255]; + memset(mapping, 0, 255); + int streams = -1; + int coupled_streams = -1; + if (GetSurroundParameters(channels, &streams, + &coupled_streams, mapping) != 0) { + free(state); + return -1; + } + + // Create new memory, always at 48000 Hz. + state->decoder.multistream_decoder = opus_multistream_decoder_create( + 48000, (int)channels, + /* streams = */ streams, + /* coupled streams = */ coupled_streams, + mapping, + &error); + } + if (error == OPUS_OK && (state->decoder.decoder || + state->decoder.multistream_decoder)) { + // Creation of memory all ok. state->channels = channels; state->prev_decoded_samples = kWebRtcOpusDefaultFrameSize; state->in_dtx_mode = 0; @@ -285,9 +420,12 @@ return 0; } - /* If memory allocation was unsuccessful, free the entire state. */ - if (state->decoder) { - opus_decoder_destroy(state->decoder); + // If memory allocation was unsuccessful, free the entire state. + if (state->decoder.decoder) { + opus_decoder_destroy(state->decoder.decoder); + + } else if (state->decoder.multistream_decoder) { + opus_multistream_decoder_destroy(state->decoder.multistream_decoder); } free(state); } @@ -296,7 +434,11 @@ int16_t WebRtcOpus_DecoderFree(OpusDecInst* inst) { if (inst) { - opus_decoder_destroy(inst->decoder); + if (inst->channels <= 2) { + opus_decoder_destroy(inst->decoder.decoder); + } else if (inst->channels > 2) { + opus_multistream_decoder_destroy(inst->decoder.multistream_decoder); + } free(inst); return 0; } else { @@ -309,7 +451,12 @@ } void WebRtcOpus_DecoderInit(OpusDecInst* inst) { - opus_decoder_ctl(inst->decoder, OPUS_RESET_STATE); + if (inst->channels <= 2) { + opus_decoder_ctl(inst->decoder.decoder, OPUS_RESET_STATE); + } else { + opus_multistream_decoder_ctl(inst->decoder.multistream_decoder, + OPUS_RESET_STATE); + } inst->in_dtx_mode = 0; } @@ -324,6 +471,10 @@ // fact a 1-byte TOC with a 1-byte payload. That will be erroneously // interpreted as comfort noise output, but such a payload is probably // faulty anyway. + + // TODO(webrtc:10218): This is wrong for multistream opus. Then are several + // single-stream packets glued together with some packet size bytes in + // between. See https://tools.ietf.org/html/rfc6716#appendix-B inst->in_dtx_mode = 1; return 2; // Comfort noise. } else { @@ -338,8 +489,15 @@ static int DecodeNative(OpusDecInst* inst, const uint8_t* encoded, size_t encoded_bytes, int frame_size, int16_t* decoded, int16_t* audio_type, int decode_fec) { - int res = opus_decode(inst->decoder, encoded, (opus_int32)encoded_bytes, - (opus_int16*)decoded, frame_size, decode_fec); + int res = -1; + if (inst->channels <= 2) { + res = opus_decode(inst->decoder.decoder, encoded, (opus_int32)encoded_bytes, + (opus_int16*)decoded, frame_size, decode_fec); + } else { + res = opus_multistream_decode( + inst->decoder.multistream_decoder, encoded, (opus_int32)encoded_bytes, + (opus_int16*)decoded, frame_size, decode_fec); + } if (res <= 0) return -1;
diff --git a/modules/audio_coding/codecs/opus/opus_interface.h b/modules/audio_coding/codecs/opus/opus_interface.h index ddb4ff9..0e97734 100644 --- a/modules/audio_coding/codecs/opus/opus_interface.h +++ b/modules/audio_coding/codecs/opus/opus_interface.h
@@ -125,6 +125,22 @@ */ int16_t WebRtcOpus_SetMaxPlaybackRate(OpusEncInst* inst, int32_t frequency_hz); +/**************************************************************************** + * WebRtcOpus_GetMaxPlaybackRate(...) + * + * Queries the maximum playback rate for encoding. If different single-stream + * encoders have different maximum playback rates, this function fails. + * + * Input: + * - inst : Encoder context. + * Output: + * - result_hz : The maximum playback rate in Hz. + * Return value : 0 - Success + * -1 - Error + */ +int16_t WebRtcOpus_GetMaxPlaybackRate(OpusEncInst* const inst, + int32_t* result_hz); + /* TODO(minyue): Check whether an API to check the FEC and the packet loss rate * is needed. It might not be very useful since there are not many use cases and * the caller can always maintain the states. */
diff --git a/modules/audio_coding/codecs/opus/opus_speed_test.cc b/modules/audio_coding/codecs/opus/opus_speed_test.cc index 03b59ed..1a629a8 100644 --- a/modules/audio_coding/codecs/opus/opus_speed_test.cc +++ b/modules/audio_coding/codecs/opus/opus_speed_test.cc
@@ -96,17 +96,17 @@ EncodeDecode(kDurationSec); \ } -ADD_TEST(10); -ADD_TEST(9); -ADD_TEST(8); -ADD_TEST(7); -ADD_TEST(6); -ADD_TEST(5); -ADD_TEST(4); -ADD_TEST(3); -ADD_TEST(2); -ADD_TEST(1); -ADD_TEST(0); +ADD_TEST(10) +ADD_TEST(9) +ADD_TEST(8) +ADD_TEST(7) +ADD_TEST(6) +ADD_TEST(5) +ADD_TEST(4) +ADD_TEST(3) +ADD_TEST(2) +ADD_TEST(1) +ADD_TEST(0) #define ADD_BANDWIDTH_TEST(bandwidth) \ TEST_P(OpusSpeedTest, OpusSetBandwidthTest##bandwidth) { \ @@ -116,11 +116,11 @@ EncodeDecode(kDurationSec); \ } -ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_NARROWBAND); -ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_MEDIUMBAND); -ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_WIDEBAND); -ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_SUPERWIDEBAND); -ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_FULLBAND); +ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_NARROWBAND) +ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_MEDIUMBAND) +ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_WIDEBAND) +ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_SUPERWIDEBAND) +ADD_BANDWIDTH_TEST(OPUS_BANDWIDTH_FULLBAND) // List all test cases: (channel, bit rat, filename, extension). const coding_param param_set[] = { @@ -140,6 +140,8 @@ string("pcm"), true)}; -INSTANTIATE_TEST_CASE_P(AllTest, OpusSpeedTest, ::testing::ValuesIn(param_set)); +INSTANTIATE_TEST_SUITE_P(AllTest, + OpusSpeedTest, + ::testing::ValuesIn(param_set)); } // namespace webrtc
diff --git a/modules/audio_coding/codecs/opus/opus_unittest.cc b/modules/audio_coding/codecs/opus/opus_unittest.cc index 034f8cd..56dfd6a 100644 --- a/modules/audio_coding/codecs/opus/opus_unittest.cc +++ b/modules/audio_coding/codecs/opus/opus_unittest.cc
@@ -17,7 +17,7 @@ #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_conversions.h" #include "test/gtest.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" namespace webrtc { @@ -27,7 +27,7 @@ using ::testing::Combine; // Maximum number of bytes in output bitstream. -const size_t kMaxBytes = 1000; +const size_t kMaxBytes = 2000; // Sample rate of Opus. const size_t kOpusRateKhz = 48; // Number of samples-per-channel in a 20 ms frame, sampled at 48 kHz. @@ -86,10 +86,14 @@ void OpusTest::PrepareSpeechData(size_t channel, int block_length_ms, int loop_length_ms) { + std::map<int, std::string> channel_to_basename = { + {1, "audio_coding/testfile32kHz"}, + {2, "audio_coding/teststereo32kHz"}, + {4, "audio_coding/speech_4_channels_48k_one_second"}}; + std::map<int, std::string> channel_to_suffix = { + {1, "pcm"}, {2, "pcm"}, {4, "wav"}}; const std::string file_name = webrtc::test::ResourcePath( - (channel == 1) ? "audio_coding/testfile32kHz" - : "audio_coding/teststereo32kHz", - "pcm"); + channel_to_basename[channel], channel_to_suffix[channel]); if (loop_length_ms < block_length_ms) { loop_length_ms = block_length_ms; } @@ -103,7 +107,7 @@ int32_t set) { opus_int32 bandwidth; EXPECT_EQ(0, WebRtcOpus_SetMaxPlaybackRate(opus_encoder_, set)); - opus_encoder_ctl(opus_encoder_->encoder, OPUS_GET_MAX_BANDWIDTH(&bandwidth)); + EXPECT_EQ(0, WebRtcOpus_GetMaxPlaybackRate(opus_encoder_, &bandwidth)); EXPECT_EQ(expect, bandwidth); } @@ -354,13 +358,13 @@ // Test to see that an invalid pointer is caught. EXPECT_EQ(-1, WebRtcOpus_EncoderCreate(NULL, 1, 0)); // Invalid channel number. - EXPECT_EQ(-1, WebRtcOpus_EncoderCreate(&opus_encoder, 3, 0)); + EXPECT_EQ(-1, WebRtcOpus_EncoderCreate(&opus_encoder, 257, 0)); // Invalid applciation mode. EXPECT_EQ(-1, WebRtcOpus_EncoderCreate(&opus_encoder, 1, 2)); EXPECT_EQ(-1, WebRtcOpus_DecoderCreate(NULL, 1)); // Invalid channel number. - EXPECT_EQ(-1, WebRtcOpus_DecoderCreate(&opus_decoder, 3)); + EXPECT_EQ(-1, WebRtcOpus_DecoderCreate(&opus_decoder, 257)); } // Test failing Free. @@ -382,6 +386,11 @@ EXPECT_EQ(0, WebRtcOpus_DecoderFree(opus_decoder_)); } +#define ENCODER_CTL(inst, vargs) \ + inst->channels <= 2 \ + ? opus_encoder_ctl(inst->encoder.encoder, vargs) \ + : opus_multistream_encoder_ctl(inst->encoder.multistream_encoder, vargs) + TEST_P(OpusTest, OpusEncodeDecode) { PrepareSpeechData(channels_, 20, 20); @@ -399,7 +408,7 @@ // Check application mode. opus_int32 app; - opus_encoder_ctl(opus_encoder_->encoder, OPUS_GET_APPLICATION(&app)); + ENCODER_CTL(opus_encoder_, OPUS_GET_APPLICATION(&app)); EXPECT_EQ(application_ == 0 ? OPUS_APPLICATION_VOIP : OPUS_APPLICATION_AUDIO, app); @@ -450,6 +459,11 @@ } TEST_P(OpusTest, OpusSetBandwidth) { + if (channels_ > 2) { + // TODO(webrtc:10217): investigate why multi-stream Opus reports + // narrowband when it's configured with FULLBAND. + return; + } PrepareSpeechData(channels_, 20, 20); int16_t audio_type; @@ -495,7 +509,7 @@ ASSERT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_)); - if (channels_ == 2) { + if (channels_ >= 2) { EXPECT_EQ(-1, WebRtcOpus_SetForceChannels(opus_encoder_, 3)); EXPECT_EQ(0, WebRtcOpus_SetForceChannels(opus_encoder_, 2)); EXPECT_EQ(0, WebRtcOpus_SetForceChannels(opus_encoder_, 1)); @@ -568,17 +582,17 @@ opus_int32 dtx; // DTX is off by default. - opus_encoder_ctl(opus_encoder_->encoder, OPUS_GET_DTX(&dtx)); + ENCODER_CTL(opus_encoder_, OPUS_GET_DTX(&dtx)); EXPECT_EQ(0, dtx); // Test to enable DTX. EXPECT_EQ(0, WebRtcOpus_EnableDtx(opus_encoder_)); - opus_encoder_ctl(opus_encoder_->encoder, OPUS_GET_DTX(&dtx)); + ENCODER_CTL(opus_encoder_, OPUS_GET_DTX(&dtx)); EXPECT_EQ(1, dtx); // Test to disable DTX. EXPECT_EQ(0, WebRtcOpus_DisableDtx(opus_encoder_)); - opus_encoder_ctl(opus_encoder_->encoder, OPUS_GET_DTX(&dtx)); + ENCODER_CTL(opus_encoder_, OPUS_GET_DTX(&dtx)); EXPECT_EQ(0, dtx); // Free memory. @@ -592,6 +606,11 @@ } TEST_P(OpusTest, OpusDtxOn) { + if (channels_ > 2) { + // TODO(webrtc:10218): adapt the test to the sizes and order of multi-stream + // DTX packets. + return; + } TestDtxEffect(true, 10); TestDtxEffect(true, 20); TestDtxEffect(true, 40); @@ -723,6 +742,12 @@ } TEST_P(OpusTest, OpusDecodeRepacketized) { + if (channels_ > 2) { + // As per the Opus documentation + // https://mf4.xiph.org/jenkins/view/opus/job/opus/ws/doc/html/group__opus__repacketizer.html#details, + // multiple streams are not supported. + return; + } constexpr size_t kPackets = 6; PrepareSpeechData(channels_, 20, 20 * kPackets); @@ -785,8 +810,8 @@ EXPECT_EQ(0, WebRtcOpus_DecoderFree(opus_decoder_)); } -INSTANTIATE_TEST_CASE_P(VariousMode, - OpusTest, - Combine(Values(1, 2), Values(0, 1))); +INSTANTIATE_TEST_SUITE_P(VariousMode, + OpusTest, + Combine(Values(1, 2, 4), Values(0, 1))); } // namespace webrtc
diff --git a/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.h b/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.h index 9b478d8..0334104 100644 --- a/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.h +++ b/modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.h
@@ -17,7 +17,7 @@ #include "api/audio_codecs/audio_decoder.h" #include "rtc_base/buffer.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc b/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc index 106ab16..9445b1e 100644 --- a/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc +++ b/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.cc
@@ -10,7 +10,6 @@ #include "modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h" -#include "common_types.h" #include "modules/audio_coding/codecs/pcm16b/pcm16b.h" #include "rtc_base/checks.h" @@ -30,20 +29,6 @@ return CodecType::kOther; } -namespace { - -AudioEncoderPcm16B::Config CreateConfig(const CodecInst& codec_inst) { - AudioEncoderPcm16B::Config config; - config.num_channels = codec_inst.channels; - config.sample_rate_hz = codec_inst.plfreq; - config.frame_size_ms = rtc::CheckedDivExact( - codec_inst.pacsize, rtc::CheckedDivExact(config.sample_rate_hz, 1000)); - config.payload_type = codec_inst.pltype; - return config; -} - -} // namespace - bool AudioEncoderPcm16B::Config::IsOk() const { if ((sample_rate_hz != 8000) && (sample_rate_hz != 16000) && (sample_rate_hz != 32000) && (sample_rate_hz != 48000)) @@ -51,7 +36,4 @@ return AudioEncoderPcm::Config::IsOk(); } -AudioEncoderPcm16B::AudioEncoderPcm16B(const CodecInst& codec_inst) - : AudioEncoderPcm16B(CreateConfig(codec_inst)) {} - } // namespace webrtc
diff --git a/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h b/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h index d6fd6e1..71c7572 100644 --- a/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h +++ b/modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h
@@ -12,12 +12,10 @@ #define MODULES_AUDIO_CODING_CODECS_PCM16B_AUDIO_ENCODER_PCM16B_H_ #include "modules/audio_coding/codecs/g711/audio_encoder_pcm.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { -struct CodecInst; - class AudioEncoderPcm16B final : public AudioEncoderPcm { public: struct Config : public AudioEncoderPcm::Config { @@ -30,7 +28,6 @@ explicit AudioEncoderPcm16B(const Config& config) : AudioEncoderPcm(config, config.sample_rate_hz) {} - explicit AudioEncoderPcm16B(const CodecInst& codec_inst); protected: size_t EncodeCall(const int16_t* audio,
diff --git a/modules/audio_coding/codecs/red/audio_encoder_copy_red.h b/modules/audio_coding/codecs/red/audio_encoder_copy_red.h index 5a68876..f05de19 100644 --- a/modules/audio_coding/codecs/red/audio_encoder_copy_red.h +++ b/modules/audio_coding/codecs/red/audio_encoder_copy_red.h
@@ -19,7 +19,7 @@ #include "api/array_view.h" #include "api/audio_codecs/audio_encoder.h" #include "rtc_base/buffer.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/codecs/tools/audio_codec_speed_test.cc b/modules/audio_coding/codecs/tools/audio_codec_speed_test.cc index c539152..1e6b4f0 100644 --- a/modules/audio_coding/codecs/tools/audio_codec_speed_test.cc +++ b/modules/audio_coding/codecs/tools/audio_codec_speed_test.cc
@@ -12,7 +12,7 @@ #include "rtc_base/format_macros.h" #include "test/gtest.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" using ::std::get;
diff --git a/modules/audio_coding/include/audio_coding_module.h b/modules/audio_coding/include/audio_coding_module.h index f9fdba5..7e5bf1b 100644 --- a/modules/audio_coding/include/audio_coding_module.h +++ b/modules/audio_coding/include/audio_coding_module.h
@@ -13,12 +13,12 @@ #include <memory> #include <string> +#include <utility> #include <vector> #include "absl/types/optional.h" #include "api/audio_codecs/audio_decoder_factory.h" #include "api/audio_codecs/audio_encoder.h" -#include "common_types.h" // NOLINT(build/include) #include "modules/audio_coding/include/audio_coding_module_typedefs.h" #include "modules/audio_coding/neteq/include/neteq.h" #include "rtc_base/function_view.h" @@ -27,12 +27,11 @@ namespace webrtc { // forward declarations -struct CodecInst; -struct WebRtcRTPHeader; class AudioDecoder; class AudioEncoder; class AudioFrame; class RTPFragmentationHeader; +struct RTPHeader; #define WEBRTC_10MS_PCM_AUDIO 960 // 16 bits super wideband 48 kHz @@ -77,80 +76,6 @@ virtual ~AudioCodingModule() = default; /////////////////////////////////////////////////////////////////////////// - // Utility functions - // - - /////////////////////////////////////////////////////////////////////////// - // uint8_t NumberOfCodecs() - // Returns number of supported codecs. - // - // Return value: - // number of supported codecs. - /// - static int NumberOfCodecs(); - - /////////////////////////////////////////////////////////////////////////// - // int32_t Codec() - // Get supported codec with list number. - // - // Input: - // -list_id : list number. - // - // Output: - // -codec : a structure where the parameters of the codec, - // given by list number is written to. - // - // Return value: - // -1 if the list number (list_id) is invalid. - // 0 if succeeded. - // - static int Codec(int list_id, CodecInst* codec); - - /////////////////////////////////////////////////////////////////////////// - // int32_t Codec() - // Get supported codec with the given codec name, sampling frequency, and - // a given number of channels. - // - // Input: - // -payload_name : name of the codec. - // -sampling_freq_hz : sampling frequency of the codec. Note! for RED - // a sampling frequency of -1 is a valid input. - // -channels : number of channels ( 1 - mono, 2 - stereo). - // - // Output: - // -codec : a structure where the function returns the - // default parameters of the codec. - // - // Return value: - // -1 if no codec matches the given parameters. - // 0 if succeeded. - // - static int Codec(const char* payload_name, - CodecInst* codec, - int sampling_freq_hz, - size_t channels); - - /////////////////////////////////////////////////////////////////////////// - // int32_t Codec() - // - // Returns the list number of the given codec name, sampling frequency, and - // a given number of channels. - // - // Input: - // -payload_name : name of the codec. - // -sampling_freq_hz : sampling frequency of the codec. Note! for RED - // a sampling frequency of -1 is a valid input. - // -channels : number of channels ( 1 - mono, 2 - stereo). - // - // Return value: - // if the codec is found, the index of the codec in the list, - // -1 if the codec is not found. - // - static int Codec(const char* payload_name, - int sampling_freq_hz, - size_t channels); - - /////////////////////////////////////////////////////////////////////////// // Sender // @@ -170,15 +95,6 @@ } /////////////////////////////////////////////////////////////////////////// - // int32_t SendCodec() - // Get parameters for the codec currently registered as send codec. - // - // Return value: - // The send codec, or nothing if we don't have one - // - virtual absl::optional<CodecInst> SendCodec() const = 0; - - /////////////////////////////////////////////////////////////////////////// // Sets the bitrate to the specified value in bits/sec. If the value is not // supported by the codec, it will choose another appropriate value. // @@ -302,60 +218,17 @@ virtual void SetReceiveCodecs( const std::map<int, SdpAudioFormat>& codecs) = 0; - // Registers a decoder for the given payload type. Returns true iff - // successful. - virtual bool RegisterReceiveCodec(int rtp_payload_type, - const SdpAudioFormat& audio_format) = 0; - - // Registers an external decoder. The name is only used to provide information - // back to the caller about the decoder. Hence, the name is arbitrary, and may - // be empty. - virtual int RegisterExternalReceiveCodec(int rtp_payload_type, - AudioDecoder* external_decoder, - int sample_rate_hz, - int num_channels, - const std::string& name) = 0; - /////////////////////////////////////////////////////////////////////////// - // int32_t UnregisterReceiveCodec() - // Unregister the codec currently registered with a specific payload type - // from the list of possible receive codecs. - // - // Input: - // -payload_type : The number representing the payload type to - // unregister. - // - // Output: - // -1 if fails to unregister. - // 0 if the given codec is successfully unregistered. - // - virtual int UnregisterReceiveCodec(uint8_t payload_type) = 0; - - /////////////////////////////////////////////////////////////////////////// - // int32_t ReceiveCodec() - // Get the codec associated with last received payload. - // - // Output: - // -curr_receive_codec : parameters of the codec associated with the last - // received payload, c.f. common_types.h for - // the definition of CodecInst. + // absl::optional<std::pair<int, SdpAudioFormat>> ReceiveCodec() + // Get the codec info associated with last received payload. // // Return value: - // -1 if failed to retrieve the codec, - // 0 if the codec is successfully retrieved. - // - virtual int32_t ReceiveCodec(CodecInst* curr_receive_codec) const = 0; - - /////////////////////////////////////////////////////////////////////////// - // absl::optional<SdpAudioFormat> ReceiveFormat() - // Get the format associated with last received payload. - // - // Return value: - // An SdpAudioFormat describing the format associated with the last - // received payload. + // A payload type and SdpAudioFormat describing the format associated with + // the last received payload. // An empty Optional if no payload has yet been received. // - virtual absl::optional<SdpAudioFormat> ReceiveFormat() const = 0; + virtual absl::optional<std::pair<int, SdpAudioFormat>> + ReceiveCodec() const = 0; /////////////////////////////////////////////////////////////////////////// // int32_t IncomingPacket() @@ -373,7 +246,7 @@ // virtual int32_t IncomingPacket(const uint8_t* incoming_payload, const size_t payload_len_bytes, - const WebRtcRTPHeader& rtp_info) = 0; + const RTPHeader& rtp_header) = 0; /////////////////////////////////////////////////////////////////////////// // int SetMinimumPlayoutDelay() @@ -402,6 +275,15 @@ // virtual int SetMaximumPlayoutDelay(int time_ms) = 0; + // Sets a base minimum for the playout delay. Base minimum delay sets lower + // bound minimum delay value which is set via SetMinimumPlayoutDelay. + // + // Returns true if value was successfully set, false overwise. + virtual bool SetBaseMinimumPlayoutDelayMs(int delay_ms) = 0; + + // Returns current value of base minimum delay in milliseconds. + virtual int GetBaseMinimumPlayoutDelayMs() const = 0; + /////////////////////////////////////////////////////////////////////////// // int32_t PlayoutTimestamp() // The send timestamp of an RTP packet is associated with the decoded
diff --git a/modules/audio_coding/include/audio_coding_module_typedefs.h b/modules/audio_coding/include/audio_coding_module_typedefs.h index bafff72..7aa7f8b 100644 --- a/modules/audio_coding/include/audio_coding_module_typedefs.h +++ b/modules/audio_coding/include/audio_coding_module_typedefs.h
@@ -80,6 +80,7 @@ uint64_t concealedSamples; uint64_t concealmentEvents; uint64_t jitterBufferDelayMs; + uint64_t jitterBufferEmittedCount; // Stats below DO NOT correspond directly to anything in the WebRTC stats // Loss rate (network + late); fraction between 0 and 1, scaled to Q14. uint16_t currentPacketLossRate; @@ -121,6 +122,8 @@ uint64_t packetBufferFlushes; // number of samples expanded due to delayed packets uint64_t delayedPacketOutageSamples; + // arrival delay of incoming packets + uint64_t relativePacketArrivalDelayMs; }; } // namespace webrtc
diff --git a/modules/audio_coding/neteq/accelerate.h b/modules/audio_coding/neteq/accelerate.h index 1a3af42..124b633 100644 --- a/modules/audio_coding/neteq/accelerate.h +++ b/modules/audio_coding/neteq/accelerate.h
@@ -15,7 +15,7 @@ #include <stdint.h> #include "modules/audio_coding/neteq/time_stretch.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/audio_decoder_unittest.cc b/modules/audio_coding/neteq/audio_decoder_unittest.cc index 1ad4835..42d96db 100644 --- a/modules/audio_coding/neteq/audio_decoder_unittest.cc +++ b/modules/audio_coding/neteq/audio_decoder_unittest.cc
@@ -31,7 +31,7 @@ #include "modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h" #include "modules/audio_coding/neteq/tools/resample_input_audio_file.h" #include "test/gtest.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/audio_multi_vector.h b/modules/audio_coding/neteq/audio_multi_vector.h index a2dd3c3..a21bf57 100644 --- a/modules/audio_coding/neteq/audio_multi_vector.h +++ b/modules/audio_coding/neteq/audio_multi_vector.h
@@ -17,7 +17,7 @@ #include "api/array_view.h" #include "modules/audio_coding/neteq/audio_vector.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/audio_multi_vector_unittest.cc b/modules/audio_coding/neteq/audio_multi_vector_unittest.cc index 5b2ec20..d1351d8 100644 --- a/modules/audio_coding/neteq/audio_multi_vector_unittest.cc +++ b/modules/audio_coding/neteq/audio_multi_vector_unittest.cc
@@ -309,9 +309,9 @@ } } -INSTANTIATE_TEST_CASE_P(TestNumChannels, - AudioMultiVectorTest, - ::testing::Values(static_cast<size_t>(1), - static_cast<size_t>(2), - static_cast<size_t>(5))); +INSTANTIATE_TEST_SUITE_P(TestNumChannels, + AudioMultiVectorTest, + ::testing::Values(static_cast<size_t>(1), + static_cast<size_t>(2), + static_cast<size_t>(5))); } // namespace webrtc
diff --git a/modules/audio_coding/neteq/audio_vector.h b/modules/audio_coding/neteq/audio_vector.h index d0db332..c8279da 100644 --- a/modules/audio_coding/neteq/audio_vector.h +++ b/modules/audio_coding/neteq/audio_vector.h
@@ -16,7 +16,7 @@ #include <memory> #include "rtc_base/checks.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/background_noise.h b/modules/audio_coding/neteq/background_noise.h index 84d7eb9..d047942 100644 --- a/modules/audio_coding/neteq/background_noise.h +++ b/modules/audio_coding/neteq/background_noise.h
@@ -14,7 +14,7 @@ #include <string.h> // size_t #include <memory> -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/buffer_level_filter.h b/modules/audio_coding/neteq/buffer_level_filter.h index c8d27dc..83388fb 100644 --- a/modules/audio_coding/neteq/buffer_level_filter.h +++ b/modules/audio_coding/neteq/buffer_level_filter.h
@@ -13,7 +13,7 @@ #include <stddef.h> -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/comfort_noise.h b/modules/audio_coding/neteq/comfort_noise.h index 3a9bfde..f748772 100644 --- a/modules/audio_coding/neteq/comfort_noise.h +++ b/modules/audio_coding/neteq/comfort_noise.h
@@ -13,7 +13,7 @@ #include <stddef.h> -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/decision_logic.cc b/modules/audio_coding/neteq/decision_logic.cc index 83c2b3b..fda12c3 100644 --- a/modules/audio_coding/neteq/decision_logic.cc +++ b/modules/audio_coding/neteq/decision_logic.cc
@@ -23,34 +23,10 @@ #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_conversions.h" -#include "system_wrappers/include/field_trial.h" namespace { -constexpr char kPostponeDecodingFieldTrial[] = - "WebRTC-Audio-NetEqPostponeDecodingAfterExpand"; -int GetPostponeDecodingLevel() { - const bool enabled = - webrtc::field_trial::IsEnabled(kPostponeDecodingFieldTrial); - if (!enabled) - return 0; - - constexpr int kDefaultPostponeDecodingLevel = 50; - const std::string field_trial_string = - webrtc::field_trial::FindFullName(kPostponeDecodingFieldTrial); - int value = -1; - if (sscanf(field_trial_string.c_str(), "Enabled-%d", &value) == 1) { - if (value >= 0 && value <= 100) { - return value; - } else { - RTC_LOG(LS_WARNING) - << "Wrong value (" << value - << ") for postpone decoding after expand, using default (" - << kDefaultPostponeDecodingLevel << ")"; - } - } - return kDefaultPostponeDecodingLevel; -} +constexpr int kPostponeDecodingLevel = 50; } // namespace @@ -89,8 +65,7 @@ disallow_time_stretching_(disallow_time_stretching), timescale_countdown_( tick_timer_->GetNewCountdown(kMinTimescaleInterval + 1)), - num_consecutive_expands_(0), - postpone_decoding_level_(GetPostponeDecodingLevel()) { + num_consecutive_expands_(0) { delay_manager_->set_streaming_mode(false); SetSampleRate(fs_hz, output_size_samples); } @@ -141,6 +116,7 @@ const size_t samples_left = sync_buffer.FutureLength() - expand.overlap_length(); + // TODO(jakobi): Use buffer span instead of num samples. const size_t cur_size_samples = samples_left + packet_buffer_.NumSamplesInBuffer(decoder_frame_length); @@ -194,13 +170,14 @@ // if the mute factor is low enough (otherwise the expansion was short enough // to not be noticable). // Note that the MuteFactor is in Q14, so a value of 16384 corresponds to 1. + size_t current_span = + samples_left + packet_buffer_.GetSpanSamples(decoder_frame_length); if ((prev_mode == kModeExpand || prev_mode == kModeCodecPlc) && expand.MuteFactor(0) < 16384 / 2 && - cur_size_samples < static_cast<size_t>( - delay_manager_->TargetLevel() * packet_length_samples_ * - postpone_decoding_level_ / 100) >> 8 && + current_span < static_cast<size_t>(delay_manager_->TargetLevel() * + packet_length_samples_ * + kPostponeDecodingLevel / 100)>> 8 && !packet_buffer_.ContainsDtxOrCngPacket(decoder_database_)) { - RTC_DCHECK(webrtc::field_trial::IsEnabled(kPostponeDecodingFieldTrial)); return kExpand; }
diff --git a/modules/audio_coding/neteq/decision_logic.h b/modules/audio_coding/neteq/decision_logic.h index 2a53359..ad8e2cd 100644 --- a/modules/audio_coding/neteq/decision_logic.h +++ b/modules/audio_coding/neteq/decision_logic.h
@@ -13,7 +13,7 @@ #include "modules/audio_coding/neteq/defines.h" #include "modules/audio_coding/neteq/tick_timer.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { @@ -108,10 +108,6 @@ } void set_prev_time_scale(bool value) { prev_time_scale_ = value; } - int postpone_decoding_level_for_test() const { - return postpone_decoding_level_; - } - private: // The value 5 sets maximum time-stretch rate to about 100 ms/s. static const int kMinTimescaleInterval = 5; @@ -184,7 +180,6 @@ bool disallow_time_stretching_; std::unique_ptr<TickTimer::Countdown> timescale_countdown_; int num_consecutive_expands_; - const int postpone_decoding_level_; RTC_DISALLOW_COPY_AND_ASSIGN(DecisionLogic); };
diff --git a/modules/audio_coding/neteq/decision_logic_unittest.cc b/modules/audio_coding/neteq/decision_logic_unittest.cc index 183b9c7..5c3d489 100644 --- a/modules/audio_coding/neteq/decision_logic_unittest.cc +++ b/modules/audio_coding/neteq/decision_logic_unittest.cc
@@ -16,8 +16,8 @@ #include "modules/audio_coding/neteq/delay_manager.h" #include "modules/audio_coding/neteq/delay_peak_detector.h" #include "modules/audio_coding/neteq/packet_buffer.h" +#include "modules/audio_coding/neteq/statistics_calculator.h" #include "modules/audio_coding/neteq/tick_timer.h" -#include "test/field_trial.h" #include "test/gtest.h" #include "test/mock_audio_decoder_factory.h" @@ -29,72 +29,18 @@ DecoderDatabase decoder_database( new rtc::RefCountedObject<MockAudioDecoderFactory>, absl::nullopt); TickTimer tick_timer; + StatisticsCalculator stats; PacketBuffer packet_buffer(10, &tick_timer); - DelayPeakDetector delay_peak_detector(&tick_timer); - DelayManager delay_manager(240, 0, &delay_peak_detector, &tick_timer); + DelayPeakDetector delay_peak_detector(&tick_timer, false); + auto delay_manager = DelayManager::Create(240, 0, false, &delay_peak_detector, + &tick_timer, &stats); BufferLevelFilter buffer_level_filter; DecisionLogic* logic = DecisionLogic::Create( fs_hz, output_size_samples, false, &decoder_database, packet_buffer, - &delay_manager, &buffer_level_filter, &tick_timer); + delay_manager.get(), &buffer_level_filter, &tick_timer); delete logic; } -TEST(DecisionLogic, PostponeDecodingAfterExpansionSettings) { - constexpr int kDefaultPostponeDecodingLevel = 50; - constexpr int kFsHz = 8000; - constexpr int kOutputSizeSamples = kFsHz / 100; // Samples per 10 ms. - DecoderDatabase decoder_database( - new rtc::RefCountedObject<MockAudioDecoderFactory>, absl::nullopt); - TickTimer tick_timer; - PacketBuffer packet_buffer(10, &tick_timer); - DelayPeakDetector delay_peak_detector(&tick_timer); - DelayManager delay_manager(240, 0, &delay_peak_detector, &tick_timer); - BufferLevelFilter buffer_level_filter; - { - test::ScopedFieldTrials field_trial( - "WebRTC-Audio-NetEqPostponeDecodingAfterExpand/Enabled/"); - DecisionLogic logic(kFsHz, kOutputSizeSamples, false, &decoder_database, - packet_buffer, &delay_manager, &buffer_level_filter, - &tick_timer); - EXPECT_EQ(kDefaultPostponeDecodingLevel, - logic.postpone_decoding_level_for_test()); - } - { - test::ScopedFieldTrials field_trial( - "WebRTC-Audio-NetEqPostponeDecodingAfterExpand/Enabled-65/"); - DecisionLogic logic(kFsHz, kOutputSizeSamples, false, &decoder_database, - packet_buffer, &delay_manager, &buffer_level_filter, - &tick_timer); - EXPECT_EQ(65, logic.postpone_decoding_level_for_test()); - } - { - test::ScopedFieldTrials field_trial( - "WebRTC-Audio-NetEqPostponeDecodingAfterExpand/Disabled/"); - DecisionLogic logic(kFsHz, kOutputSizeSamples, false, &decoder_database, - packet_buffer, &delay_manager, &buffer_level_filter, - &tick_timer); - EXPECT_EQ(0, logic.postpone_decoding_level_for_test()); - } - { - test::ScopedFieldTrials field_trial( - "WebRTC-Audio-NetEqPostponeDecodingAfterExpand/Enabled--1/"); - DecisionLogic logic(kFsHz, kOutputSizeSamples, false, &decoder_database, - packet_buffer, &delay_manager, &buffer_level_filter, - &tick_timer); - EXPECT_EQ(kDefaultPostponeDecodingLevel, - logic.postpone_decoding_level_for_test()); - } - { - test::ScopedFieldTrials field_trial( - "WebRTC-Audio-NetEqPostponeDecodingAfterExpand/Enabled-101/"); - DecisionLogic logic(kFsHz, kOutputSizeSamples, false, &decoder_database, - packet_buffer, &delay_manager, &buffer_level_filter, - &tick_timer); - EXPECT_EQ(kDefaultPostponeDecodingLevel, - logic.postpone_decoding_level_for_test()); - } -} - // TODO(hlundin): Write more tests. } // namespace webrtc
diff --git a/modules/audio_coding/neteq/decoder_database.cc b/modules/audio_coding/neteq/decoder_database.cc index 0890beb..2049569 100644 --- a/modules/audio_coding/neteq/decoder_database.cc +++ b/modules/audio_coding/neteq/decoder_database.cc
@@ -18,7 +18,6 @@ #include "absl/strings/match.h" #include "api/audio_codecs/audio_decoder.h" -#include "common_types.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/strings/audio_format_to_string.h" @@ -44,7 +43,6 @@ audio_format_(audio_format), codec_pair_id_(codec_pair_id), factory_(factory), - external_decoder_(nullptr), cng_decoder_(CngDecoder::Create(audio_format)), subtype_(SubtypeFromFormat(audio_format)) {} @@ -54,48 +52,14 @@ AudioDecoderFactory* factory) : DecoderInfo(audio_format, codec_pair_id, factory, audio_format.name) {} -DecoderDatabase::DecoderInfo::DecoderInfo( - NetEqDecoder ct, - absl::optional<AudioCodecPairId> codec_pair_id, - AudioDecoderFactory* factory) - : DecoderInfo(*NetEqDecoderToSdpAudioFormat(ct), codec_pair_id, factory) {} - -DecoderDatabase::DecoderInfo::DecoderInfo(const SdpAudioFormat& audio_format, - AudioDecoder* ext_dec, - const std::string& codec_name) - : name_(codec_name), - audio_format_(audio_format), - codec_pair_id_(absl::nullopt), - factory_(nullptr), - external_decoder_(ext_dec), - subtype_(Subtype::kNormal) { - RTC_CHECK(ext_dec); -} - DecoderDatabase::DecoderInfo::DecoderInfo(DecoderInfo&&) = default; DecoderDatabase::DecoderInfo::~DecoderInfo() = default; -bool DecoderDatabase::DecoderInfo::CanGetDecoder() const { - if (subtype_ == Subtype::kNormal && !external_decoder_ && !decoder_) { - // TODO(ossu): Keep a check here for now, since a number of tests create - // DecoderInfos without factories. - RTC_DCHECK(factory_); - return factory_->IsSupportedDecoder(audio_format_); - } else { - return true; - } -} - AudioDecoder* DecoderDatabase::DecoderInfo::GetDecoder() const { if (subtype_ != Subtype::kNormal) { // These are handled internally, so they have no AudioDecoder objects. return nullptr; } - if (external_decoder_) { - RTC_DCHECK(!decoder_); - RTC_DCHECK(!cng_decoder_); - return external_decoder_; - } if (!decoder_) { // TODO(ossu): Keep a check here for now, since a number of tests create // DecoderInfos without factories. @@ -187,32 +151,6 @@ return changed_payload_types; } -int DecoderDatabase::RegisterPayload(uint8_t rtp_payload_type, - NetEqDecoder codec_type, - const std::string& name) { - if (rtp_payload_type > 0x7F) { - return kInvalidRtpPayloadType; - } - if (codec_type == NetEqDecoder::kDecoderArbitrary) { - return kCodecNotSupported; // Only supported through InsertExternal. - } - const auto opt_format = NetEqDecoderToSdpAudioFormat(codec_type); - if (!opt_format) { - return kCodecNotSupported; - } - DecoderInfo info(*opt_format, codec_pair_id_, decoder_factory_, name); - if (!info.CanGetDecoder()) { - return kCodecNotSupported; - } - auto ret = - decoders_.insert(std::make_pair(rtp_payload_type, std::move(info))); - if (ret.second == false) { - // Database already contains a decoder with type |rtp_payload_type|. - return kDecoderExists; - } - return kOK; -} - int DecoderDatabase::RegisterPayload(int rtp_payload_type, const SdpAudioFormat& audio_format) { if (rtp_payload_type < 0 || rtp_payload_type > 0x7f) { @@ -228,31 +166,6 @@ return kOK; } -int DecoderDatabase::InsertExternal(uint8_t rtp_payload_type, - NetEqDecoder codec_type, - const std::string& codec_name, - AudioDecoder* decoder) { - if (rtp_payload_type > 0x7F) { - return kInvalidRtpPayloadType; - } - if (!decoder) { - return kInvalidPointer; - } - - const auto opt_db_format = NetEqDecoderToSdpAudioFormat(codec_type); - const SdpAudioFormat format = - opt_db_format.value_or(SdpAudioFormat("arbitrary", 0, 0)); - - std::pair<DecoderMap::iterator, bool> ret; - DecoderInfo info(format, decoder, codec_name); - ret = decoders_.insert(std::make_pair(rtp_payload_type, std::move(info))); - if (ret.second == false) { - // Database already contains a decoder with type |rtp_payload_type|. - return kDecoderExists; - } - return kOK; -} - int DecoderDatabase::Remove(uint8_t rtp_payload_type) { if (decoders_.erase(rtp_payload_type) == 0) { // No decoder with that |rtp_payload_type|.
diff --git a/modules/audio_coding/neteq/decoder_database.h b/modules/audio_coding/neteq/decoder_database.h index 131e769..e0a3fe3 100644 --- a/modules/audio_coding/neteq/decoder_database.h +++ b/modules/audio_coding/neteq/decoder_database.h
@@ -17,12 +17,10 @@ #include "api/audio_codecs/audio_decoder_factory.h" #include "api/audio_codecs/audio_format.h" -#include "common_types.h" // NOLINT(build/include) // NULL +#include "api/scoped_refptr.h" #include "modules/audio_coding/codecs/cng/webrtc_cng.h" -#include "modules/audio_coding/neteq/neteq_decoder_enum.h" #include "modules/audio_coding/neteq/packet.h" -#include "rtc_base/constructormagic.h" -#include "rtc_base/scoped_ref_ptr.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { @@ -48,19 +46,9 @@ explicit DecoderInfo(const SdpAudioFormat& audio_format, absl::optional<AudioCodecPairId> codec_pair_id, AudioDecoderFactory* factory = nullptr); - explicit DecoderInfo(NetEqDecoder ct, - absl::optional<AudioCodecPairId> codec_pair_id, - AudioDecoderFactory* factory = nullptr); - DecoderInfo(const SdpAudioFormat& audio_format, - AudioDecoder* ext_dec, - const std::string& codec_name); DecoderInfo(DecoderInfo&&); ~DecoderInfo(); - // Was this info object created with a specification that allows us to - // actually produce a decoder? - bool CanGetDecoder() const; - // Get the AudioDecoder object, creating it first if necessary. AudioDecoder* GetDecoder() const; @@ -110,9 +98,6 @@ AudioDecoderFactory* const factory_; mutable std::unique_ptr<AudioDecoder> decoder_; - // Set iff this is an external decoder. - AudioDecoder* const external_decoder_; - // Set iff this is a comfort noise decoder. struct CngDecoder { static absl::optional<CngDecoder> Create(const SdpAudioFormat& format); @@ -153,26 +138,11 @@ virtual std::vector<int> SetCodecs( const std::map<int, SdpAudioFormat>& codecs); - // Registers |rtp_payload_type| as a decoder of type |codec_type|. The |name| - // is only used to populate the name field in the DecoderInfo struct in the - // database, and can be arbitrary (including empty). Returns kOK on success; - // otherwise an error code. - virtual int RegisterPayload(uint8_t rtp_payload_type, - NetEqDecoder codec_type, - const std::string& name); - // Registers a decoder for the given payload type. Returns kOK on success; // otherwise an error code. virtual int RegisterPayload(int rtp_payload_type, const SdpAudioFormat& audio_format); - // Registers an externally created AudioDecoder object, and associates it - // as a decoder of type |codec_type| with |rtp_payload_type|. - virtual int InsertExternal(uint8_t rtp_payload_type, - NetEqDecoder codec_type, - const std::string& codec_name, - AudioDecoder* decoder); - // Removes the entry for |rtp_payload_type| from the database. // Returns kDecoderNotFound or kOK depending on the outcome of the operation. virtual int Remove(uint8_t rtp_payload_type);
diff --git a/modules/audio_coding/neteq/decoder_database_unittest.cc b/modules/audio_coding/neteq/decoder_database_unittest.cc index 3c49faa..9a28cac 100644 --- a/modules/audio_coding/neteq/decoder_database_unittest.cc +++ b/modules/audio_coding/neteq/decoder_database_unittest.cc
@@ -15,7 +15,7 @@ #include <string> #include "api/audio_codecs/builtin_audio_decoder_factory.h" -#include "rtc_base/refcountedobject.h" +#include "rtc_base/ref_counted_object.h" #include "test/gmock.h" #include "test/gtest.h" #include "test/mock_audio_decoder.h" @@ -36,17 +36,12 @@ TEST(DecoderDatabase, InsertAndRemove) { rtc::scoped_refptr<MockAudioDecoderFactory> factory( new rtc::RefCountedObject<MockAudioDecoderFactory>); - EXPECT_CALL(*factory, IsSupportedDecoder(_)) - .WillOnce(Invoke([](const SdpAudioFormat& format) { - EXPECT_EQ("pcmu", format.name); - return true; - })); DecoderDatabase db(factory, absl::nullopt); const uint8_t kPayloadType = 0; const std::string kCodecName = "Robert\'); DROP TABLE Students;"; EXPECT_EQ( DecoderDatabase::kOK, - db.RegisterPayload(kPayloadType, NetEqDecoder::kDecoderPCMu, kCodecName)); + db.RegisterPayload(kPayloadType, SdpAudioFormat(kCodecName, 8000, 1))); EXPECT_EQ(1, db.Size()); EXPECT_FALSE(db.Empty()); EXPECT_EQ(DecoderDatabase::kOK, db.Remove(kPayloadType)); @@ -57,22 +52,13 @@ TEST(DecoderDatabase, InsertAndRemoveAll) { rtc::scoped_refptr<MockAudioDecoderFactory> factory( new rtc::RefCountedObject<MockAudioDecoderFactory>); - EXPECT_CALL(*factory, IsSupportedDecoder(_)) - .WillOnce(Invoke([](const SdpAudioFormat& format) { - EXPECT_EQ("pcmu", format.name); - return true; - })) - .WillOnce(Invoke([](const SdpAudioFormat& format) { - EXPECT_EQ("pcma", format.name); - return true; - })); DecoderDatabase db(factory, absl::nullopt); const std::string kCodecName1 = "Robert\'); DROP TABLE Students;"; const std::string kCodecName2 = "https://xkcd.com/327/"; EXPECT_EQ(DecoderDatabase::kOK, - db.RegisterPayload(0, NetEqDecoder::kDecoderPCMu, kCodecName1)); + db.RegisterPayload(0, SdpAudioFormat(kCodecName1, 8000, 1))); EXPECT_EQ(DecoderDatabase::kOK, - db.RegisterPayload(1, NetEqDecoder::kDecoderPCMa, kCodecName2)); + db.RegisterPayload(1, SdpAudioFormat(kCodecName2, 8000, 1))); EXPECT_EQ(2, db.Size()); EXPECT_FALSE(db.Empty()); db.RemoveAll(); @@ -83,11 +69,6 @@ TEST(DecoderDatabase, GetDecoderInfo) { rtc::scoped_refptr<MockAudioDecoderFactory> factory( new rtc::RefCountedObject<MockAudioDecoderFactory>); - EXPECT_CALL(*factory, IsSupportedDecoder(_)) - .WillOnce(Invoke([](const SdpAudioFormat& format) { - EXPECT_EQ("pcmu", format.name); - return true; - })); auto* decoder = new MockAudioDecoder; EXPECT_CALL(*factory, MakeAudioDecoderMock(_, _, _)) .WillOnce(Invoke([decoder](const SdpAudioFormat& format, @@ -98,10 +79,10 @@ })); DecoderDatabase db(factory, absl::nullopt); const uint8_t kPayloadType = 0; - const std::string kCodecName = "Robert\'); DROP TABLE Students;"; + const std::string kCodecName = "pcmu"; EXPECT_EQ( DecoderDatabase::kOK, - db.RegisterPayload(kPayloadType, NetEqDecoder::kDecoderPCMu, kCodecName)); + db.RegisterPayload(kPayloadType, SdpAudioFormat(kCodecName, 8000, 1))); const DecoderDatabase::DecoderInfo* info; info = db.GetDecoderInfo(kPayloadType); ASSERT_TRUE(info != NULL); @@ -115,10 +96,8 @@ TEST(DecoderDatabase, GetDecoder) { DecoderDatabase db(CreateBuiltinAudioDecoderFactory(), absl::nullopt); const uint8_t kPayloadType = 0; - const std::string kCodecName = "Robert\'); DROP TABLE Students;"; EXPECT_EQ(DecoderDatabase::kOK, - db.RegisterPayload(kPayloadType, NetEqDecoder::kDecoderPCM16B, - kCodecName)); + db.RegisterPayload(kPayloadType, SdpAudioFormat("l16", 8000, 1))); AudioDecoder* dec = db.GetDecoder(kPayloadType); ASSERT_TRUE(dec != NULL); } @@ -126,11 +105,6 @@ TEST(DecoderDatabase, TypeTests) { rtc::scoped_refptr<MockAudioDecoderFactory> factory( new rtc::RefCountedObject<MockAudioDecoderFactory>); - EXPECT_CALL(*factory, IsSupportedDecoder(_)) - .WillOnce(Invoke([](const SdpAudioFormat& format) { - EXPECT_EQ("pcmu", format.name); - return true; - })); DecoderDatabase db(factory, absl::nullopt); const uint8_t kPayloadTypePcmU = 0; const uint8_t kPayloadTypeCng = 13; @@ -140,16 +114,15 @@ // Load into database. EXPECT_EQ( DecoderDatabase::kOK, - db.RegisterPayload(kPayloadTypePcmU, NetEqDecoder::kDecoderPCMu, "pcmu")); + db.RegisterPayload(kPayloadTypePcmU, SdpAudioFormat("pcmu", 8000, 1))); EXPECT_EQ(DecoderDatabase::kOK, - db.RegisterPayload(kPayloadTypeCng, NetEqDecoder::kDecoderCNGnb, - "cng-nb")); + db.RegisterPayload(kPayloadTypeCng, SdpAudioFormat("cn", 8000, 1))); + EXPECT_EQ(DecoderDatabase::kOK, + db.RegisterPayload(kPayloadTypeDtmf, + SdpAudioFormat("telephone-event", 8000, 1))); EXPECT_EQ( DecoderDatabase::kOK, - db.RegisterPayload(kPayloadTypeDtmf, NetEqDecoder::kDecoderAVT, "avt")); - EXPECT_EQ( - DecoderDatabase::kOK, - db.RegisterPayload(kPayloadTypeRed, NetEqDecoder::kDecoderRED, "red")); + db.RegisterPayload(kPayloadTypeRed, SdpAudioFormat("red", 8000, 1))); EXPECT_EQ(4, db.Size()); // Test. EXPECT_FALSE(db.IsComfortNoise(kPayloadNotUsed)); @@ -165,52 +138,18 @@ EXPECT_TRUE(db.IsRed(kPayloadTypeRed)); } -TEST(DecoderDatabase, ExternalDecoder) { - DecoderDatabase db(new rtc::RefCountedObject<MockAudioDecoderFactory>, - absl::nullopt); - const uint8_t kPayloadType = 0; - const std::string kCodecName = "Robert\'); DROP TABLE Students;"; - MockAudioDecoder decoder; - // Load into database. - EXPECT_EQ(DecoderDatabase::kOK, - db.InsertExternal(kPayloadType, NetEqDecoder::kDecoderPCMu, - kCodecName, &decoder)); - EXPECT_EQ(1, db.Size()); - // Get decoder and make sure we get the external one. - EXPECT_EQ(&decoder, db.GetDecoder(kPayloadType)); - // Get the decoder info struct and check it too. - const DecoderDatabase::DecoderInfo* info; - info = db.GetDecoderInfo(kPayloadType); - ASSERT_TRUE(info != NULL); - EXPECT_TRUE(info->IsType("pcmu")); - EXPECT_EQ(info->get_name(), kCodecName); - EXPECT_EQ(kCodecName, info->get_name()); - // Expect not to delete the decoder when removing it from the database, since - // it was declared externally. - EXPECT_CALL(decoder, Die()).Times(0); - EXPECT_EQ(DecoderDatabase::kOK, db.Remove(kPayloadType)); - EXPECT_TRUE(db.Empty()); - - EXPECT_CALL(decoder, Die()).Times(1); // Will be called when |db| is deleted. -} - TEST(DecoderDatabase, CheckPayloadTypes) { constexpr int kNumPayloads = 10; rtc::scoped_refptr<MockAudioDecoderFactory> factory( new rtc::RefCountedObject<MockAudioDecoderFactory>); - EXPECT_CALL(*factory, IsSupportedDecoder(_)) - .Times(kNumPayloads) - .WillRepeatedly(Invoke([](const SdpAudioFormat& format) { - EXPECT_EQ("pcmu", format.name); - return true; - })); DecoderDatabase db(factory, absl::nullopt); // Load a number of payloads into the database. Payload types are 0, 1, ..., // while the decoder type is the same for all payload types (this does not // matter for the test). for (uint8_t payload_type = 0; payload_type < kNumPayloads; ++payload_type) { - EXPECT_EQ(DecoderDatabase::kOK, - db.RegisterPayload(payload_type, NetEqDecoder::kDecoderPCMu, "")); + EXPECT_EQ( + DecoderDatabase::kOK, + db.RegisterPayload(payload_type, SdpAudioFormat("pcmu", 8000, 1))); } PacketList packet_list; for (int i = 0; i < kNumPayloads + 1; ++i) { @@ -247,11 +186,11 @@ DecoderDatabase db(CreateBuiltinAudioDecoderFactory(), absl::nullopt); // Load payload types. ASSERT_EQ(DecoderDatabase::kOK, - db.RegisterPayload(0, NetEqDecoder::kDecoderPCMu, "pcmu")); + db.RegisterPayload(0, SdpAudioFormat("pcmu", 8000, 1))); ASSERT_EQ(DecoderDatabase::kOK, - db.RegisterPayload(103, NetEqDecoder::kDecoderISAC, "isac")); + db.RegisterPayload(103, SdpAudioFormat("isac", 16000, 1))); ASSERT_EQ(DecoderDatabase::kOK, - db.RegisterPayload(13, NetEqDecoder::kDecoderCNGnb, "cng-nb")); + db.RegisterPayload(13, SdpAudioFormat("cn", 8000, 1))); // Verify that no decoders are active from the start. EXPECT_EQ(NULL, db.GetActiveDecoder()); EXPECT_EQ(NULL, db.GetActiveCngDecoder());
diff --git a/modules/audio_coding/neteq/delay_manager.cc b/modules/audio_coding/neteq/delay_manager.cc index 67e6a13..4e2f3c7 100644 --- a/modules/audio_coding/neteq/delay_manager.cc +++ b/modules/audio_coding/neteq/delay_manager.cc
@@ -17,23 +17,39 @@ #include <numeric> #include <string> +#include "absl/memory/memory.h" #include "modules/audio_coding/neteq/delay_peak_detector.h" +#include "modules/audio_coding/neteq/histogram.h" +#include "modules/audio_coding/neteq/statistics_calculator.h" #include "modules/include/module_common_types_public.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/numerics/safe_minmax.h" #include "system_wrappers/include/field_trial.h" namespace { -constexpr int kLimitProbability = 53687091; // 1/20 in Q30. -constexpr int kLimitProbabilityStreaming = 536871; // 1/2000 in Q30. -constexpr int kMaxStreamingPeakPeriodMs = 600000; // 10 minutes in ms. +constexpr int kLimitProbability = 1020054733; // 19/20 in Q30. +constexpr int kLimitProbabilityStreaming = 1073204953; // 1999/2000 in Q30. +constexpr int kMaxStreamingPeakPeriodMs = 600000; // 10 minutes in ms. constexpr int kCumulativeSumDrift = 2; // Drift term for cumulative sum // |iat_cumulative_sum_|. -// Steady-state forgetting factor for |iat_vector_|, 0.9993 in Q15. -constexpr int kIatFactor_ = 32745; -constexpr int kMaxIat = 64; // Max inter-arrival time to register. +constexpr int kMinBaseMinimumDelayMs = 0; +constexpr int kMaxBaseMinimumDelayMs = 10000; +constexpr int kIatFactor = 32745; // 0.9993 in Q15. +constexpr int kMaxIat = 64; // Max inter-arrival time to register. +constexpr int kMaxReorderedPackets = + 10; // Max number of consecutive reordered packets. +constexpr int kMaxHistoryPackets = + 100; // Max number of packets used to calculate relative packet arrival + // delay. +constexpr int kDelayBuckets = 100; +constexpr int kBucketSizeMs = 20; + +int PercentileToQuantile(double percentile) { + return static_cast<int>((1 << 30) * percentile / 100.0 + 0.5); +} absl::optional<int> GetForcedLimitProbability() { constexpr char kForceTargetDelayPercentileFieldTrial[] = @@ -46,8 +62,8 @@ double percentile = -1.0; if (sscanf(field_trial_string.c_str(), "Enabled-%lf", &percentile) == 1 && percentile >= 0.0 && percentile <= 100.0) { - return absl::make_optional<int>(static_cast<int>( - (1 << 30) * (100.0 - percentile) / 100.0 + 0.5)); // in Q30. + return absl::make_optional<int>( + PercentileToQuantile(percentile)); // in Q30. } else { RTC_LOG(LS_WARNING) << "Invalid parameter for " << kForceTargetDelayPercentileFieldTrial @@ -57,64 +73,111 @@ return absl::nullopt; } +struct DelayHistogramConfig { + int quantile = 1020054733; // 0.95 in Q30. + int forget_factor = 32745; // 0.9993 in Q15. +}; + +absl::optional<DelayHistogramConfig> GetDelayHistogramConfig() { + constexpr char kDelayHistogramFieldTrial[] = + "WebRTC-Audio-NetEqDelayHistogram"; + const bool use_new_delay_manager = + webrtc::field_trial::IsEnabled(kDelayHistogramFieldTrial); + if (use_new_delay_manager) { + const auto field_trial_string = + webrtc::field_trial::FindFullName(kDelayHistogramFieldTrial); + DelayHistogramConfig config; + double percentile = -1.0; + double forget_factor = -1.0; + if (sscanf(field_trial_string.c_str(), "Enabled-%lf-%lf", &percentile, + &forget_factor) == 2 && + percentile >= 0.0 && percentile <= 100.0 && forget_factor >= 0.0 && + forget_factor <= 1.0) { + config.quantile = PercentileToQuantile(percentile); + config.forget_factor = (1 << 15) * forget_factor; + } + RTC_LOG(LS_INFO) << "Delay histogram config:" + << " quantile=" << config.quantile + << " forget_factor=" << config.forget_factor; + return absl::make_optional(config); + } + return absl::nullopt; +} + } // namespace namespace webrtc { DelayManager::DelayManager(size_t max_packets_in_buffer, - int base_min_target_delay_ms, + int base_minimum_delay_ms, + int histogram_quantile, + HistogramMode histogram_mode, + bool enable_rtx_handling, DelayPeakDetector* peak_detector, - const TickTimer* tick_timer) + const TickTimer* tick_timer, + StatisticsCalculator* statistics, + std::unique_ptr<Histogram> histogram) : first_packet_received_(false), max_packets_in_buffer_(max_packets_in_buffer), - iat_vector_(kMaxIat + 1, 0), - iat_factor_(0), + histogram_(std::move(histogram)), + histogram_quantile_(histogram_quantile), + histogram_mode_(histogram_mode), tick_timer_(tick_timer), - base_min_target_delay_ms_(base_min_target_delay_ms), + statistics_(statistics), + base_minimum_delay_ms_(base_minimum_delay_ms), + effective_minimum_delay_ms_(base_minimum_delay_ms), base_target_level_(4), // In Q0 domain. target_level_(base_target_level_ << 8), // In Q8 domain. packet_len_ms_(0), streaming_mode_(false), last_seq_no_(0), last_timestamp_(0), - minimum_delay_ms_(base_min_target_delay_ms_), - maximum_delay_ms_(target_level_), + minimum_delay_ms_(0), + maximum_delay_ms_(0), iat_cumulative_sum_(0), max_iat_cumulative_sum_(0), peak_detector_(*peak_detector), last_pack_cng_or_dtmf_(1), frame_length_change_experiment_( field_trial::IsEnabled("WebRTC-Audio-NetEqFramelengthExperiment")), - forced_limit_probability_(GetForcedLimitProbability()) { + enable_rtx_handling_(enable_rtx_handling) { assert(peak_detector); // Should never be NULL. - RTC_DCHECK_GE(base_min_target_delay_ms_, 0); - RTC_DCHECK_LE(minimum_delay_ms_, maximum_delay_ms_); + RTC_CHECK(histogram_); + RTC_DCHECK_GE(base_minimum_delay_ms_, 0); Reset(); } -DelayManager::~DelayManager() {} - -const DelayManager::IATVector& DelayManager::iat_vector() const { - return iat_vector_; -} - -// Set the histogram vector to an exponentially decaying distribution -// iat_vector_[i] = 0.5^(i+1), i = 0, 1, 2, ... -// iat_vector_ is in Q30. -void DelayManager::ResetHistogram() { - // Set temp_prob to (slightly more than) 1 in Q14. This ensures that the sum - // of iat_vector_ is 1. - uint16_t temp_prob = 0x4002; // 16384 + 2 = 100000000000010 binary. - IATVector::iterator it = iat_vector_.begin(); - for (; it < iat_vector_.end(); it++) { - temp_prob >>= 1; - (*it) = temp_prob << 16; +std::unique_ptr<DelayManager> DelayManager::Create( + size_t max_packets_in_buffer, + int base_minimum_delay_ms, + bool enable_rtx_handling, + DelayPeakDetector* peak_detector, + const TickTimer* tick_timer, + StatisticsCalculator* statistics) { + int quantile; + std::unique_ptr<Histogram> histogram; + HistogramMode mode; + auto delay_histogram_config = GetDelayHistogramConfig(); + if (delay_histogram_config) { + DelayHistogramConfig config = delay_histogram_config.value(); + quantile = config.quantile; + histogram = + absl::make_unique<Histogram>(kDelayBuckets, config.forget_factor); + mode = RELATIVE_ARRIVAL_DELAY; + } else { + quantile = GetForcedLimitProbability().value_or(kLimitProbability); + histogram = absl::make_unique<Histogram>(kMaxIat + 1, kIatFactor); + mode = INTER_ARRIVAL_TIME; } - base_target_level_ = 4; - target_level_ = base_target_level_ << 8; + return absl::make_unique<DelayManager>( + max_packets_in_buffer, base_minimum_delay_ms, quantile, mode, + enable_rtx_handling, peak_detector, tick_timer, statistics, + std::move(histogram)); } +DelayManager::~DelayManager() {} + int DelayManager::Update(uint16_t sequence_number, uint32_t timestamp, int sample_rate_hz) { @@ -146,34 +209,62 @@ rtc::saturated_cast<int>(1000 * packet_len_samp / sample_rate_hz); } + bool reordered = false; if (packet_len_ms > 0) { // Cannot update statistics unless |packet_len_ms| is valid. - // Calculate inter-arrival time (IAT) in integer "packet times" - // (rounding down). This is the value used as index to the histogram - // vector |iat_vector_|. - int iat_packets = packet_iat_stopwatch_->ElapsedMs() / packet_len_ms; - if (streaming_mode_) { UpdateCumulativeSums(packet_len_ms, sequence_number); } + // Inter-arrival time (IAT) in integer "packet times" (rounding down). This + // is the value added to the inter-arrival time histogram. + int iat_ms = packet_iat_stopwatch_->ElapsedMs(); + int iat_packets = iat_ms / packet_len_ms; // Check for discontinuous packet sequence and re-ordering. if (IsNewerSequenceNumber(sequence_number, last_seq_no_ + 1)) { // Compensate for gap in the sequence numbers. Reduce IAT with the - // expected extra time due to lost packets, but ensure that the IAT is - // not negative. - iat_packets -= static_cast<uint16_t>(sequence_number - last_seq_no_ - 1); - iat_packets = std::max(iat_packets, 0); + // expected extra time due to lost packets. + int packet_offset = + static_cast<uint16_t>(sequence_number - last_seq_no_ - 1); + iat_packets -= packet_offset; + iat_ms -= packet_offset * packet_len_ms; } else if (!IsNewerSequenceNumber(sequence_number, last_seq_no_)) { - iat_packets += static_cast<uint16_t>(last_seq_no_ + 1 - sequence_number); + int packet_offset = + static_cast<uint16_t>(last_seq_no_ + 1 - sequence_number); + iat_packets += packet_offset; + iat_ms += packet_offset * packet_len_ms; + reordered = true; } - // Saturate IAT at maximum value. - const int max_iat = kMaxIat; - iat_packets = std::min(iat_packets, max_iat); - UpdateHistogram(iat_packets); + int iat_delay = iat_ms - packet_len_ms; + int relative_delay; + if (reordered) { + relative_delay = std::max(iat_delay, 0); + } else { + UpdateDelayHistory(iat_delay); + relative_delay = CalculateRelativePacketArrivalDelay(); + } + statistics_->RelativePacketArrivalDelay(relative_delay); + + switch (histogram_mode_) { + case RELATIVE_ARRIVAL_DELAY: { + const int index = relative_delay / kBucketSizeMs; + if (index < histogram_->NumBuckets()) { + // Maximum delay to register is 2000 ms. + histogram_->Add(index); + } + break; + } + case INTER_ARRIVAL_TIME: { + // Saturate IAT between 0 and maximum value. + iat_packets = + std::max(std::min(iat_packets, histogram_->NumBuckets() - 1), 0); + histogram_->Add(iat_packets); + break; + } + } // Calculate new |target_level_| based on updated statistics. - target_level_ = CalculateTargetLevel(iat_packets); + target_level_ = CalculateTargetLevel(iat_packets, reordered); if (streaming_mode_) { target_level_ = std::max(target_level_, max_iat_cumulative_sum_); } @@ -181,6 +272,12 @@ LimitTargetLevel(); } // End if (packet_len_ms > 0). + if (enable_rtx_handling_ && reordered && + num_reordered_packets_ < kMaxReorderedPackets) { + ++num_reordered_packets_; + return 0; + } + num_reordered_packets_ = 0; // Prepare for next packet arrival. packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch(); last_seq_no_ = sequence_number; @@ -188,6 +285,26 @@ return 0; } +void DelayManager::UpdateDelayHistory(int iat_delay) { + delay_history_.push_back(iat_delay); + if (delay_history_.size() > kMaxHistoryPackets) { + delay_history_.pop_front(); + } +} + +int DelayManager::CalculateRelativePacketArrivalDelay() const { + // This effectively calculates arrival delay of a packet relative to the + // packet preceding the history window. If the arrival delay ever becomes + // smaller than zero, it means the reference packet is invalid, and we + // move the reference. + int relative_delay = 0; + for (int delay : delay_history_) { + relative_delay += delay; + relative_delay = std::max(relative_delay, 0); + } + return relative_delay; +} + void DelayManager::UpdateCumulativeSums(int packet_len_ms, uint16_t sequence_number) { // Calculate IAT in Q8, including fractions of a packet (i.e., more @@ -214,69 +331,19 @@ } } -// Each element in the vector is first multiplied by the forgetting factor -// |iat_factor_|. Then the vector element indicated by |iat_packets| is then -// increased (additive) by 1 - |iat_factor_|. This way, the probability of -// |iat_packets| is slightly increased, while the sum of the histogram remains -// constant (=1). -// Due to inaccuracies in the fixed-point arithmetic, the histogram may no -// longer sum up to 1 (in Q30) after the update. To correct this, a correction -// term is added or subtracted from the first element (or elements) of the -// vector. -// The forgetting factor |iat_factor_| is also updated. When the DelayManager -// is reset, the factor is set to 0 to facilitate rapid convergence in the -// beginning. With each update of the histogram, the factor is increased towards -// the steady-state value |kIatFactor_|. -void DelayManager::UpdateHistogram(size_t iat_packets) { - assert(iat_packets < iat_vector_.size()); - int vector_sum = 0; // Sum up the vector elements as they are processed. - // Multiply each element in |iat_vector_| with |iat_factor_|. - for (IATVector::iterator it = iat_vector_.begin(); it != iat_vector_.end(); - ++it) { - *it = (static_cast<int64_t>(*it) * iat_factor_) >> 15; - vector_sum += *it; - } - - // Increase the probability for the currently observed inter-arrival time - // by 1 - |iat_factor_|. The factor is in Q15, |iat_vector_| in Q30. - // Thus, left-shift 15 steps to obtain result in Q30. - iat_vector_[iat_packets] += (32768 - iat_factor_) << 15; - vector_sum += (32768 - iat_factor_) << 15; // Add to vector sum. - - // |iat_vector_| should sum up to 1 (in Q30), but it may not due to - // fixed-point rounding errors. - vector_sum -= 1 << 30; // Should be zero. Compensate if not. - if (vector_sum != 0) { - // Modify a few values early in |iat_vector_|. - int flip_sign = vector_sum > 0 ? -1 : 1; - IATVector::iterator it = iat_vector_.begin(); - while (it != iat_vector_.end() && abs(vector_sum) > 0) { - // Add/subtract 1/16 of the element, but not more than |vector_sum|. - int correction = flip_sign * std::min(abs(vector_sum), (*it) >> 4); - *it += correction; - vector_sum += correction; - ++it; - } - } - assert(vector_sum == 0); // Verify that the above is correct. - - // Update |iat_factor_| (changes only during the first seconds after a reset). - // The factor converges to |kIatFactor_|. - iat_factor_ += (kIatFactor_ - iat_factor_ + 3) >> 2; -} - // Enforces upper and lower limits for |target_level_|. The upper limit is // chosen to be minimum of i) 75% of |max_packets_in_buffer_|, to leave some // headroom for natural fluctuations around the target, and ii) equivalent of // |maximum_delay_ms_| in packets. Note that in practice, if no // |maximum_delay_ms_| is specified, this does not have any impact, since the // target level is far below the buffer capacity in all reasonable cases. -// The lower limit is equivalent of |minimum_delay_ms_| in packets. We update -// |least_required_level_| while the above limits are applied. +// The lower limit is equivalent of |effective_minimum_delay_ms_| in packets. +// We update |least_required_level_| while the above limits are applied. // TODO(hlundin): Move this check to the buffer logistics class. void DelayManager::LimitTargetLevel() { - if (packet_len_ms_ > 0 && minimum_delay_ms_ > 0) { - int minimum_delay_packet_q8 = (minimum_delay_ms_ << 8) / packet_len_ms_; + if (packet_len_ms_ > 0 && effective_minimum_delay_ms_ > 0) { + int minimum_delay_packet_q8 = + (effective_minimum_delay_ms_ << 8) / packet_len_ms_; target_level_ = std::max(target_level_, minimum_delay_packet_q8); } @@ -294,40 +361,31 @@ target_level_ = std::max(target_level_, 1 << 8); } -int DelayManager::CalculateTargetLevel(int iat_packets) { - int limit_probability = forced_limit_probability_.value_or(kLimitProbability); +int DelayManager::CalculateTargetLevel(int iat_packets, bool reordered) { + int limit_probability = histogram_quantile_; if (streaming_mode_) { limit_probability = kLimitProbabilityStreaming; } - // Calculate target buffer level from inter-arrival time histogram. - // Find the |iat_index| for which the probability of observing an - // inter-arrival time larger than or equal to |iat_index| is less than or - // equal to |limit_probability|. The sought probability is estimated using - // the histogram as the reverse cumulant PDF, i.e., the sum of elements from - // the end up until |iat_index|. Now, since the sum of all elements is 1 - // (in Q30) by definition, and since the solution is often a low value for - // |iat_index|, it is more efficient to start with |sum| = 1 and subtract - // elements from the start of the histogram. - size_t index = 0; // Start from the beginning of |iat_vector_|. - int sum = 1 << 30; // Assign to 1 in Q30. - sum -= iat_vector_[index]; // Ensure that target level is >= 1. - - do { - // Subtract the probabilities one by one until the sum is no longer greater - // than limit_probability. - ++index; - sum -= iat_vector_[index]; - } while ((sum > limit_probability) && (index < iat_vector_.size() - 1)); - - // This is the base value for the target buffer level. - int target_level = static_cast<int>(index); - base_target_level_ = static_cast<int>(index); - - // Update detector for delay peaks. - bool delay_peak_found = peak_detector_.Update(iat_packets, target_level); - if (delay_peak_found) { - target_level = std::max(target_level, peak_detector_.MaxPeakHeight()); + int bucket_index = histogram_->Quantile(limit_probability); + int target_level; + switch (histogram_mode_) { + case RELATIVE_ARRIVAL_DELAY: { + target_level = 1 + bucket_index * kBucketSizeMs / packet_len_ms_; + base_target_level_ = target_level; + break; + } + case INTER_ARRIVAL_TIME: { + target_level = bucket_index; + base_target_level_ = target_level; + // Update detector for delay peaks. + bool delay_peak_found = + peak_detector_.Update(iat_packets, reordered, target_level); + if (delay_peak_found) { + target_level = std::max(target_level, peak_detector_.MaxPeakHeight()); + } + break; + } } // Sanity check. |target_level| must be strictly positive. @@ -342,8 +400,10 @@ RTC_LOG_F(LS_ERROR) << "length_ms = " << length_ms; return -1; } - if (frame_length_change_experiment_ && packet_len_ms_ != length_ms) { - iat_vector_ = ScaleHistogram(iat_vector_, packet_len_ms_, length_ms); + if (histogram_mode_ == INTER_ARRIVAL_TIME && + frame_length_change_experiment_ && packet_len_ms_ != length_ms && + packet_len_ms_ > 0) { + histogram_->Scale(packet_len_ms_, length_ms); } packet_len_ms_ = length_ms; @@ -357,8 +417,9 @@ packet_len_ms_ = 0; // Packet size unknown. streaming_mode_ = false; peak_detector_.Reset(); - ResetHistogram(); // Resets target levels too. - iat_factor_ = 0; // Adapt the histogram faster for the first few packets. + histogram_->Reset(); + base_target_level_ = 4; + target_level_ = base_target_level_ << 8; packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch(); max_iat_stopwatch_ = tick_timer_->GetNewStopwatch(); iat_cumulative_sum_ = 0; @@ -368,12 +429,14 @@ double DelayManager::EstimatedClockDriftPpm() const { double sum = 0.0; - // Calculate the expected value based on the probabilities in |iat_vector_|. - for (size_t i = 0; i < iat_vector_.size(); ++i) { - sum += static_cast<double>(iat_vector_[i]) * i; + // Calculate the expected value based on the probabilities in + // |histogram_|. + auto buckets = histogram_->buckets(); + for (size_t i = 0; i < buckets.size(); ++i) { + sum += static_cast<double>(buckets[i]) * i; } - // The probabilities in |iat_vector_| are in Q30. Divide by 1 << 30 to convert - // to Q0; subtract the nominal inter-arrival time (1) to make a zero + // The probabilities in |histogram_| are in Q30. Divide by 1 << 30 to + // convert to Q0; subtract the nominal inter-arrival time (1) to make a zero // clockdrift represent as 0; mulitply by 1000000 to produce parts-per-million // (ppm). return (sum / (1 << 30) - 1) * 1e6; @@ -425,87 +488,53 @@ ++last_seq_no_; } -DelayManager::IATVector DelayManager::ScaleHistogram(const IATVector& histogram, - int old_packet_length, - int new_packet_length) { - if (old_packet_length == 0) { - // If we don't know the previous frame length, don't make any changes to the - // histogram. - return histogram; - } - RTC_DCHECK_GT(new_packet_length, 0); - RTC_DCHECK_EQ(old_packet_length % 10, 0); - RTC_DCHECK_EQ(new_packet_length % 10, 0); - IATVector new_histogram(histogram.size(), 0); - int64_t acc = 0; - int time_counter = 0; - size_t new_histogram_idx = 0; - for (size_t i = 0; i < histogram.size(); i++) { - acc += histogram[i]; - time_counter += old_packet_length; - // The bins should be scaled, to ensure the histogram still sums to one. - const int64_t scaled_acc = acc * new_packet_length / time_counter; - int64_t actually_used_acc = 0; - while (time_counter >= new_packet_length) { - const int64_t old_histogram_val = new_histogram[new_histogram_idx]; - new_histogram[new_histogram_idx] = - rtc::saturated_cast<int>(old_histogram_val + scaled_acc); - actually_used_acc += new_histogram[new_histogram_idx] - old_histogram_val; - new_histogram_idx = - std::min(new_histogram_idx + 1, new_histogram.size() - 1); - time_counter -= new_packet_length; - } - // Only subtract the part that was succesfully written to the new histogram. - acc -= actually_used_acc; - } - // If there is anything left in acc (due to rounding errors), add it to the - // last bin. If we cannot add everything to the last bin we need to add as - // much as possible to the bins after the last bin (this is only possible - // when compressing a histogram). - while (acc > 0 && new_histogram_idx < new_histogram.size()) { - const int64_t old_histogram_val = new_histogram[new_histogram_idx]; - new_histogram[new_histogram_idx] = - rtc::saturated_cast<int>(old_histogram_val + acc); - acc -= new_histogram[new_histogram_idx] - old_histogram_val; - new_histogram_idx++; - } - RTC_DCHECK_EQ(histogram.size(), new_histogram.size()); - if (acc == 0) { - // If acc is non-zero, we were not able to add everything to the new - // histogram, so this check will not hold. - RTC_DCHECK_EQ(accumulate(histogram.begin(), histogram.end(), 0ll), - accumulate(new_histogram.begin(), new_histogram.end(), 0ll)); - } - return new_histogram; +bool DelayManager::IsValidMinimumDelay(int delay_ms) const { + return 0 <= delay_ms && delay_ms <= MinimumDelayUpperBound(); +} + +bool DelayManager::IsValidBaseMinimumDelay(int delay_ms) const { + return kMinBaseMinimumDelayMs <= delay_ms && + delay_ms <= kMaxBaseMinimumDelayMs; } bool DelayManager::SetMinimumDelay(int delay_ms) { - // Minimum delay shouldn't be more than maximum delay, if any maximum is set. - // Also, if possible check |delay| to less than 75% of - // |max_packets_in_buffer_|. - if ((maximum_delay_ms_ > 0 && delay_ms > maximum_delay_ms_) || - (packet_len_ms_ > 0 && - delay_ms > - static_cast<int>(3 * max_packets_in_buffer_ * packet_len_ms_ / 4))) { + if (!IsValidMinimumDelay(delay_ms)) { return false; } - minimum_delay_ms_ = std::max(delay_ms, base_min_target_delay_ms_); + + minimum_delay_ms_ = delay_ms; + UpdateEffectiveMinimumDelay(); return true; } bool DelayManager::SetMaximumDelay(int delay_ms) { - if (delay_ms == 0) { - // Zero input unsets the maximum delay. - maximum_delay_ms_ = 0; - return true; - } else if (delay_ms < minimum_delay_ms_ || delay_ms < packet_len_ms_) { + // If |delay_ms| is zero then it unsets the maximum delay and target level is + // unconstrained by maximum delay. + if (delay_ms != 0 && + (delay_ms < minimum_delay_ms_ || delay_ms < packet_len_ms_)) { // Maximum delay shouldn't be less than minimum delay or less than a packet. return false; } + maximum_delay_ms_ = delay_ms; + UpdateEffectiveMinimumDelay(); return true; } +bool DelayManager::SetBaseMinimumDelay(int delay_ms) { + if (!IsValidBaseMinimumDelay(delay_ms)) { + return false; + } + + base_minimum_delay_ms_ = delay_ms; + UpdateEffectiveMinimumDelay(); + return true; +} + +int DelayManager::GetBaseMinimumDelay() const { + return base_minimum_delay_ms_; +} + int DelayManager::base_target_level() const { return base_target_level_; } @@ -519,4 +548,28 @@ void DelayManager::set_last_pack_cng_or_dtmf(int value) { last_pack_cng_or_dtmf_ = value; } + +void DelayManager::UpdateEffectiveMinimumDelay() { + // Clamp |base_minimum_delay_ms_| into the range which can be effectively + // used. + const int base_minimum_delay_ms = + rtc::SafeClamp(base_minimum_delay_ms_, 0, MinimumDelayUpperBound()); + effective_minimum_delay_ms_ = + std::max(minimum_delay_ms_, base_minimum_delay_ms); +} + +int DelayManager::MinimumDelayUpperBound() const { + // Choose the lowest possible bound discarding 0 cases which mean the value + // is not set and unconstrained. + int q75 = MaxBufferTimeQ75(); + q75 = q75 > 0 ? q75 : kMaxBaseMinimumDelayMs; + const int maximum_delay_ms = + maximum_delay_ms_ > 0 ? maximum_delay_ms_ : kMaxBaseMinimumDelayMs; + return std::min(maximum_delay_ms, q75); +} + +int DelayManager::MaxBufferTimeQ75() const { + const int max_buffer_time = max_packets_in_buffer_ * packet_len_ms_; + return rtc::dchecked_cast<int>(3 * max_buffer_time / 4); +} } // namespace webrtc
diff --git a/modules/audio_coding/neteq/delay_manager.h b/modules/audio_coding/neteq/delay_manager.h index 2c8081b..e54e950 100644 --- a/modules/audio_coding/neteq/delay_manager.h +++ b/modules/audio_coding/neteq/delay_manager.h
@@ -13,12 +13,14 @@ #include <string.h> // Provide access to size_t. +#include <deque> #include <memory> -#include <vector> #include "absl/types/optional.h" +#include "modules/audio_coding/neteq/histogram.h" +#include "modules/audio_coding/neteq/statistics_calculator.h" #include "modules/audio_coding/neteq/tick_timer.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { @@ -27,23 +29,35 @@ class DelayManager { public: - typedef std::vector<int> IATVector; + enum HistogramMode { + INTER_ARRIVAL_TIME, + RELATIVE_ARRIVAL_DELAY, + }; + + DelayManager(size_t max_packets_in_buffer, + int base_minimum_delay_ms, + int histogram_quantile, + HistogramMode histogram_mode, + bool enable_rtx_handling, + DelayPeakDetector* peak_detector, + const TickTimer* tick_timer, + StatisticsCalculator* statistics, + std::unique_ptr<Histogram> histogram); // Create a DelayManager object. Notify the delay manager that the packet // buffer can hold no more than |max_packets_in_buffer| packets (i.e., this // is the number of packet slots in the buffer) and that the target delay - // should be greater than or equal to |base_min_target_delay_ms|. Supply a + // should be greater than or equal to |base_minimum_delay_ms|. Supply a // PeakDetector object to the DelayManager. - DelayManager(size_t max_packets_in_buffer, - int base_min_target_delay_ms, - DelayPeakDetector* peak_detector, - const TickTimer* tick_timer); + static std::unique_ptr<DelayManager> Create(size_t max_packets_in_buffer, + int base_minimum_delay_ms, + bool enable_rtx_handling, + DelayPeakDetector* peak_detector, + const TickTimer* tick_timer, + StatisticsCalculator* statistics); virtual ~DelayManager(); - // Read the inter-arrival time histogram. Mainly for testing purposes. - virtual const IATVector& iat_vector() const; - // Updates the delay manager with a new incoming packet, with // |sequence_number| and |timestamp| from the RTP header. This updates the // inter-arrival time histogram and other statistics, as well as the @@ -57,7 +71,7 @@ // Sets target_level_ (in Q8) and returns the same value. Also calculates // and updates base_target_level_, which is the target buffer level before // taking delay peaks into account. - virtual int CalculateTargetLevel(int iat_packets); + virtual int CalculateTargetLevel(int iat_packets, bool reordered); // Notifies the DelayManager of how much audio data is carried in each packet. // The method updates the DelayPeakDetector too, and resets the inter-arrival @@ -101,53 +115,74 @@ // packet will shift the sequence numbers for the following packets. virtual void RegisterEmptyPacket(); - // Apply compression or stretching to the IAT histogram, for a change in frame - // size. This returns an updated histogram. This function is public for - // testability. - static IATVector ScaleHistogram(const IATVector& histogram, - int old_packet_length, - int new_packet_length); - // Accessors and mutators. // Assuming |delay| is in valid range. virtual bool SetMinimumDelay(int delay_ms); virtual bool SetMaximumDelay(int delay_ms); + virtual bool SetBaseMinimumDelay(int delay_ms); + virtual int GetBaseMinimumDelay() const; virtual int base_target_level() const; virtual void set_streaming_mode(bool value); virtual int last_pack_cng_or_dtmf() const; virtual void set_last_pack_cng_or_dtmf(int value); // This accessor is only intended for testing purposes. - const absl::optional<int>& forced_limit_probability_for_test() const { - return forced_limit_probability_; + int effective_minimum_delay_ms_for_test() const { + return effective_minimum_delay_ms_; } + // This accessor is only intended for testing purposes. + HistogramMode histogram_mode() const { return histogram_mode_; } + int histogram_quantile() const { return histogram_quantile_; } + int histogram_forget_factor() const { return histogram_->forget_factor(); } + private: - // Sets |iat_vector_| to the default start distribution and sets the - // |base_target_level_| and |target_level_| to the corresponding values. - void ResetHistogram(); + // Provides value which minimum delay can't exceed based on current buffer + // size and given |maximum_delay_ms_|. Lower bound is a constant 0. + int MinimumDelayUpperBound() const; + + // Provides 75% of currently possible maximum buffer size in milliseconds. + int MaxBufferTimeQ75() const; + + // Updates |delay_history_|. + void UpdateDelayHistory(int iat_delay); + + // Calculate relative packet arrival delay from |delay_history_|. + int CalculateRelativePacketArrivalDelay() const; // Updates |iat_cumulative_sum_| and |max_iat_cumulative_sum_|. (These are // used by the streaming mode.) This method is called by Update(). void UpdateCumulativeSums(int packet_len_ms, uint16_t sequence_number); - // Updates the histogram |iat_vector_|. The probability for inter-arrival time - // equal to |iat_packets| (in integer packets) is increased slightly, while - // all other entries are decreased. This method is called by Update(). - void UpdateHistogram(size_t iat_packets); + // Updates |effective_minimum_delay_ms_| delay based on current + // |minimum_delay_ms_|, |base_minimum_delay_ms_| and |maximum_delay_ms_| + // and buffer size. + void UpdateEffectiveMinimumDelay(); // Makes sure that |target_level_| is not too large, taking // |max_packets_in_buffer_| and |extra_delay_ms_| into account. This method is // called by Update(). void LimitTargetLevel(); + // Makes sure that |delay_ms| is less than maximum delay, if any maximum + // is set. Also, if possible check |delay_ms| to be less than 75% of + // |max_packets_in_buffer_|. + bool IsValidMinimumDelay(int delay_ms) const; + + bool IsValidBaseMinimumDelay(int delay_ms) const; + bool first_packet_received_; const size_t max_packets_in_buffer_; // Capacity of the packet buffer. - IATVector iat_vector_; // Histogram of inter-arrival times. - int iat_factor_; // Forgetting factor for updating the IAT histogram (Q15). + std::unique_ptr<Histogram> histogram_; + const int histogram_quantile_; + const HistogramMode histogram_mode_; const TickTimer* tick_timer_; - const int base_min_target_delay_ms_; // Lower bound for target_level_ and - // minimum_delay_ms_. + StatisticsCalculator* statistics_; + int base_minimum_delay_ms_; + // Provides delay which is used by LimitTargetLevel as lower bound on target + // delay. + int effective_minimum_delay_ms_; + // Time elapsed since last packet. std::unique_ptr<TickTimer::Stopwatch> packet_iat_stopwatch_; int base_target_level_; // Currently preferred buffer level before peak @@ -169,7 +204,9 @@ DelayPeakDetector& peak_detector_; int last_pack_cng_or_dtmf_; const bool frame_length_change_experiment_; - const absl::optional<int> forced_limit_probability_; + const bool enable_rtx_handling_; + int num_reordered_packets_ = 0; // Number of consecutive reordered packets. + std::deque<int> delay_history_; RTC_DISALLOW_COPY_AND_ASSIGN(DelayManager); };
diff --git a/modules/audio_coding/neteq/delay_manager_unittest.cc b/modules/audio_coding/neteq/delay_manager_unittest.cc index 6281a15..c57f074 100644 --- a/modules/audio_coding/neteq/delay_manager_unittest.cc +++ b/modules/audio_coding/neteq/delay_manager_unittest.cc
@@ -14,25 +14,36 @@ #include <math.h> +#include "absl/memory/memory.h" +#include "modules/audio_coding/neteq/histogram.h" #include "modules/audio_coding/neteq/mock/mock_delay_peak_detector.h" +#include "modules/audio_coding/neteq/mock/mock_histogram.h" +#include "modules/audio_coding/neteq/mock/mock_statistics_calculator.h" +#include "rtc_base/checks.h" #include "test/field_trial.h" #include "test/gmock.h" #include "test/gtest.h" namespace webrtc { +namespace { +constexpr int kMaxNumberOfPackets = 240; +constexpr int kMinDelayMs = 0; +constexpr int kTimeStepMs = 10; +constexpr int kFs = 8000; +constexpr int kFrameSizeMs = 20; +constexpr int kTsIncrement = kFrameSizeMs * kFs / 1000; +constexpr int kMaxBufferSizeMs = kMaxNumberOfPackets * kFrameSizeMs; +constexpr int kDefaultHistogramQuantile = 1020054733; +constexpr int kMaxIat = 64; +constexpr int kForgetFactor = 32745; +} // namespace + using ::testing::Return; using ::testing::_; class DelayManagerTest : public ::testing::Test { protected: - static const int kMaxNumberOfPackets = 240; - static const int kMinDelayMs = 0; - static const int kTimeStepMs = 10; - static const int kFs = 8000; - static const int kFrameSizeMs = 20; - static const int kTsIncrement = kFrameSizeMs * kFs / 1000; - DelayManagerTest(); virtual void SetUp(); virtual void TearDown(); @@ -43,13 +54,22 @@ std::unique_ptr<DelayManager> dm_; TickTimer tick_timer_; + MockStatisticsCalculator stats_; MockDelayPeakDetector detector_; + MockHistogram* mock_histogram_; uint16_t seq_no_; uint32_t ts_; + bool enable_rtx_handling_ = false; + bool use_mock_histogram_ = false; + DelayManager::HistogramMode histogram_mode_ = + DelayManager::HistogramMode::INTER_ARRIVAL_TIME; }; DelayManagerTest::DelayManagerTest() - : dm_(nullptr), detector_(&tick_timer_), seq_no_(0x1234), ts_(0x12345678) {} + : dm_(nullptr), + detector_(&tick_timer_, false), + seq_no_(0x1234), + ts_(0x12345678) {} void DelayManagerTest::SetUp() { RecreateDelayManager(); @@ -57,8 +77,18 @@ void DelayManagerTest::RecreateDelayManager() { EXPECT_CALL(detector_, Reset()).Times(1); - dm_.reset(new DelayManager(kMaxNumberOfPackets, kMinDelayMs, &detector_, - &tick_timer_)); + if (use_mock_histogram_) { + mock_histogram_ = new MockHistogram(kMaxIat, kForgetFactor); + std::unique_ptr<Histogram> histogram(mock_histogram_); + dm_ = absl::make_unique<DelayManager>( + kMaxNumberOfPackets, kMinDelayMs, kDefaultHistogramQuantile, + histogram_mode_, enable_rtx_handling_, &detector_, &tick_timer_, + &stats_, std::move(histogram)); + } else { + dm_ = DelayManager::Create(kMaxNumberOfPackets, kMinDelayMs, + enable_rtx_handling_, &detector_, &tick_timer_, + &stats_); + } } void DelayManagerTest::SetPacketAudioLength(int lengt_ms) { @@ -86,17 +116,6 @@ // object. } -TEST_F(DelayManagerTest, VectorInitialization) { - const DelayManager::IATVector& vec = dm_->iat_vector(); - double sum = 0.0; - for (size_t i = 0; i < vec.size(); i++) { - EXPECT_NEAR(ldexp(pow(0.5, static_cast<int>(i + 1)), 30), vec[i], 65537); - // Tolerance 65537 in Q30 corresponds to a delta of approximately 0.00006. - sum += vec[i]; - } - EXPECT_EQ(1 << 30, static_cast<int>(sum)); // Should be 1 in Q30. -} - TEST_F(DelayManagerTest, SetPacketAudioLength) { const int kLengthMs = 30; // Expect DelayManager to pass on the new length to the detector object. @@ -126,7 +145,7 @@ // Expect detector update method to be called once with inter-arrival time // equal to 1 packet, and (base) target level equal to 1 as well. // Return false to indicate no peaks found. - EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false)); + EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(false)); InsertNextPacket(); EXPECT_EQ(1 << 8, dm_->TargetLevel()); // In Q8. EXPECT_EQ(1, dm_->base_target_level()); @@ -149,7 +168,7 @@ // Expect detector update method to be called once with inter-arrival time // equal to 1 packet, and (base) target level equal to 1 as well. // Return false to indicate no peaks found. - EXPECT_CALL(detector_, Update(2, 2)).WillOnce(Return(false)); + EXPECT_CALL(detector_, Update(2, false, 2)).WillOnce(Return(false)); InsertNextPacket(); EXPECT_EQ(2 << 8, dm_->TargetLevel()); // In Q8. EXPECT_EQ(2, dm_->base_target_level()); @@ -172,7 +191,7 @@ // Expect detector update method to be called once with inter-arrival time // equal to 1 packet, and (base) target level equal to 1 as well. // Return true to indicate that peaks are found. Let the peak height be 5. - EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(true)); + EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(true)); EXPECT_CALL(detector_, MaxPeakHeight()).WillOnce(Return(5)); InsertNextPacket(); EXPECT_EQ(5 << 8, dm_->TargetLevel()); @@ -194,7 +213,7 @@ // Expect detector update method to be called once with inter-arrival time // equal to 1 packet, and (base) target level equal to 1 as well. // Return false to indicate no peaks found. - EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false)); + EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(false)); InsertNextPacket(); const int kExpectedTarget = 1; EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel()); // In Q8. @@ -216,7 +235,7 @@ // Second packet arrival. // Expect detector update method to be called once with inter-arrival time // equal to |kExpectedTarget| packet. Return true to indicate peaks found. - EXPECT_CALL(detector_, Update(kExpectedTarget, _)) + EXPECT_CALL(detector_, Update(kExpectedTarget, false, _)) .WillRepeatedly(Return(true)); EXPECT_CALL(detector_, MaxPeakHeight()) .WillRepeatedly(Return(kExpectedTarget)); @@ -246,7 +265,7 @@ // Second packet arrival. // Expect detector update method to be called once with inter-arrival time // equal to |kExpectedTarget| packet. Return true to indicate peaks found. - EXPECT_CALL(detector_, Update(kExpectedTarget, _)) + EXPECT_CALL(detector_, Update(kExpectedTarget, false, _)) .WillRepeatedly(Return(true)); EXPECT_CALL(detector_, MaxPeakHeight()) .WillRepeatedly(Return(kExpectedTarget)); @@ -264,6 +283,236 @@ EXPECT_EQ(kMinDelayPackets << 8, dm_->TargetLevel()); } +TEST_F(DelayManagerTest, BaseMinimumDelayCheckValidRange) { + SetPacketAudioLength(kFrameSizeMs); + + // Base minimum delay should be between [0, 10000] milliseconds. + EXPECT_FALSE(dm_->SetBaseMinimumDelay(-1)); + EXPECT_FALSE(dm_->SetBaseMinimumDelay(10001)); + EXPECT_EQ(dm_->GetBaseMinimumDelay(), 0); + + EXPECT_TRUE(dm_->SetBaseMinimumDelay(7999)); + EXPECT_EQ(dm_->GetBaseMinimumDelay(), 7999); +} + +TEST_F(DelayManagerTest, BaseMinimumDelayLowerThanMinimumDelay) { + SetPacketAudioLength(kFrameSizeMs); + constexpr int kBaseMinimumDelayMs = 100; + constexpr int kMinimumDelayMs = 200; + + // Base minimum delay sets lower bound on minimum. That is why when base + // minimum delay is lower than minimum delay we use minimum delay. + RTC_DCHECK_LT(kBaseMinimumDelayMs, kMinimumDelayMs); + + EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMs)); + EXPECT_TRUE(dm_->SetMinimumDelay(kMinimumDelayMs)); + EXPECT_EQ(dm_->effective_minimum_delay_ms_for_test(), kMinimumDelayMs); +} + +TEST_F(DelayManagerTest, BaseMinimumDelayGreaterThanMinimumDelay) { + SetPacketAudioLength(kFrameSizeMs); + constexpr int kBaseMinimumDelayMs = 70; + constexpr int kMinimumDelayMs = 30; + + // Base minimum delay sets lower bound on minimum. That is why when base + // minimum delay is greater than minimum delay we use base minimum delay. + RTC_DCHECK_GT(kBaseMinimumDelayMs, kMinimumDelayMs); + + EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMs)); + EXPECT_TRUE(dm_->SetMinimumDelay(kMinimumDelayMs)); + EXPECT_EQ(dm_->effective_minimum_delay_ms_for_test(), kBaseMinimumDelayMs); +} + +TEST_F(DelayManagerTest, BaseMinimumDelayGreaterThanBufferSize) { + SetPacketAudioLength(kFrameSizeMs); + constexpr int kBaseMinimumDelayMs = kMaxBufferSizeMs + 1; + constexpr int kMinimumDelayMs = 12; + constexpr int kMaximumDelayMs = 20; + constexpr int kMaxBufferSizeMsQ75 = 3 * kMaxBufferSizeMs / 4; + + EXPECT_TRUE(dm_->SetMaximumDelay(kMaximumDelayMs)); + + // Base minimum delay is greater than minimum delay, that is why we clamp + // it to current the highest possible value which is maximum delay. + RTC_DCHECK_GT(kBaseMinimumDelayMs, kMinimumDelayMs); + RTC_DCHECK_GT(kBaseMinimumDelayMs, kMaxBufferSizeMs); + RTC_DCHECK_GT(kBaseMinimumDelayMs, kMaximumDelayMs); + RTC_DCHECK_LT(kMaximumDelayMs, kMaxBufferSizeMsQ75); + + EXPECT_TRUE(dm_->SetMinimumDelay(kMinimumDelayMs)); + EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMs)); + + // Unset maximum value. + EXPECT_TRUE(dm_->SetMaximumDelay(0)); + + // With maximum value unset, the highest possible value now is 75% of + // currently possible maximum buffer size. + EXPECT_EQ(dm_->effective_minimum_delay_ms_for_test(), kMaxBufferSizeMsQ75); +} + +TEST_F(DelayManagerTest, BaseMinimumDelayGreaterThanMaximumDelay) { + SetPacketAudioLength(kFrameSizeMs); + constexpr int kMaximumDelayMs = 400; + constexpr int kBaseMinimumDelayMs = kMaximumDelayMs + 1; + constexpr int kMinimumDelayMs = 20; + + // Base minimum delay is greater than minimum delay, that is why we clamp + // it to current the highest possible value which is kMaximumDelayMs. + RTC_DCHECK_GT(kBaseMinimumDelayMs, kMinimumDelayMs); + RTC_DCHECK_GT(kBaseMinimumDelayMs, kMaximumDelayMs); + RTC_DCHECK_LT(kMaximumDelayMs, kMaxBufferSizeMs); + + EXPECT_TRUE(dm_->SetMaximumDelay(kMaximumDelayMs)); + EXPECT_TRUE(dm_->SetMinimumDelay(kMinimumDelayMs)); + EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMs)); + EXPECT_EQ(dm_->effective_minimum_delay_ms_for_test(), kMaximumDelayMs); +} + +TEST_F(DelayManagerTest, BaseMinimumDelayLowerThanMaxSize) { + SetPacketAudioLength(kFrameSizeMs); + constexpr int kMaximumDelayMs = 400; + constexpr int kBaseMinimumDelayMs = kMaximumDelayMs - 1; + constexpr int kMinimumDelayMs = 20; + + // Base minimum delay is greater than minimum delay, and lower than maximum + // delays that is why it is used. + RTC_DCHECK_GT(kBaseMinimumDelayMs, kMinimumDelayMs); + RTC_DCHECK_LT(kBaseMinimumDelayMs, kMaximumDelayMs); + + EXPECT_TRUE(dm_->SetMaximumDelay(kMaximumDelayMs)); + EXPECT_TRUE(dm_->SetMinimumDelay(kMinimumDelayMs)); + EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMs)); + EXPECT_EQ(dm_->effective_minimum_delay_ms_for_test(), kBaseMinimumDelayMs); +} + +TEST_F(DelayManagerTest, MinimumDelayMemorization) { + // Check that when we increase base minimum delay to value higher than + // minimum delay then minimum delay is still memorized. This allows to + // restore effective minimum delay to memorized minimum delay value when we + // decrease base minimum delay. + SetPacketAudioLength(kFrameSizeMs); + + constexpr int kBaseMinimumDelayMsLow = 10; + constexpr int kMinimumDelayMs = 20; + constexpr int kBaseMinimumDelayMsHigh = 30; + + EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMsLow)); + EXPECT_TRUE(dm_->SetMinimumDelay(kMinimumDelayMs)); + // Minimum delay is used as it is higher than base minimum delay. + EXPECT_EQ(dm_->effective_minimum_delay_ms_for_test(), kMinimumDelayMs); + + EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMsHigh)); + // Base minimum delay is used as it is now higher than minimum delay. + EXPECT_EQ(dm_->effective_minimum_delay_ms_for_test(), + kBaseMinimumDelayMsHigh); + + EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMsLow)); + // Check that minimum delay is memorized and is used again. + EXPECT_EQ(dm_->effective_minimum_delay_ms_for_test(), kMinimumDelayMs); +} + +TEST_F(DelayManagerTest, BaseMinimumDelay) { + const int kExpectedTarget = 5; + const int kTimeIncrement = kExpectedTarget * kFrameSizeMs; + SetPacketAudioLength(kFrameSizeMs); + // First packet arrival. + InsertNextPacket(); + // Second packet arrival. + // Expect detector update method to be called once with inter-arrival time + // equal to |kExpectedTarget| packet. Return true to indicate peaks found. + EXPECT_CALL(detector_, Update(kExpectedTarget, false, _)) + .WillRepeatedly(Return(true)); + EXPECT_CALL(detector_, MaxPeakHeight()) + .WillRepeatedly(Return(kExpectedTarget)); + IncreaseTime(kTimeIncrement); + InsertNextPacket(); + + // No limit is applied. + EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel()); + + constexpr int kBaseMinimumDelayPackets = kExpectedTarget + 2; + constexpr int kBaseMinimumDelayMs = kBaseMinimumDelayPackets * kFrameSizeMs; + EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMs)); + EXPECT_EQ(dm_->GetBaseMinimumDelay(), kBaseMinimumDelayMs); + + IncreaseTime(kTimeIncrement); + InsertNextPacket(); + EXPECT_EQ(dm_->GetBaseMinimumDelay(), kBaseMinimumDelayMs); + EXPECT_EQ(kBaseMinimumDelayPackets << 8, dm_->TargetLevel()); +} + +TEST_F(DelayManagerTest, BaseMinimumDealyAffectTargetLevel) { + const int kExpectedTarget = 5; + const int kTimeIncrement = kExpectedTarget * kFrameSizeMs; + SetPacketAudioLength(kFrameSizeMs); + // First packet arrival. + InsertNextPacket(); + // Second packet arrival. + // Expect detector update method to be called once with inter-arrival time + // equal to |kExpectedTarget|. Return true to indicate peaks found. + EXPECT_CALL(detector_, Update(kExpectedTarget, false, _)) + .WillRepeatedly(Return(true)); + EXPECT_CALL(detector_, MaxPeakHeight()) + .WillRepeatedly(Return(kExpectedTarget)); + IncreaseTime(kTimeIncrement); + InsertNextPacket(); + + // No limit is applied. + EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel()); + + // Minimum delay is lower than base minimum delay, that is why base minimum + // delay is used to calculate target level. + constexpr int kMinimumDelayPackets = kExpectedTarget + 1; + constexpr int kBaseMinimumDelayPackets = kExpectedTarget + 2; + + constexpr int kMinimumDelayMs = kMinimumDelayPackets * kFrameSizeMs; + constexpr int kBaseMinimumDelayMs = kBaseMinimumDelayPackets * kFrameSizeMs; + + EXPECT_TRUE(kMinimumDelayMs < kBaseMinimumDelayMs); + EXPECT_TRUE(dm_->SetMinimumDelay(kMinimumDelayMs)); + EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMs)); + EXPECT_EQ(dm_->GetBaseMinimumDelay(), kBaseMinimumDelayMs); + + IncreaseTime(kTimeIncrement); + InsertNextPacket(); + EXPECT_EQ(dm_->GetBaseMinimumDelay(), kBaseMinimumDelayMs); + EXPECT_EQ(kBaseMinimumDelayPackets << 8, dm_->TargetLevel()); +} + +TEST_F(DelayManagerTest, UpdateReorderedPacket) { + SetPacketAudioLength(kFrameSizeMs); + InsertNextPacket(); + + // Insert packet that was sent before the previous packet. + EXPECT_CALL(detector_, Update(_, true, _)); + EXPECT_EQ(0, dm_->Update(seq_no_ - 1, ts_ - kFrameSizeMs, kFs)); +} + +TEST_F(DelayManagerTest, EnableRtxHandling) { + enable_rtx_handling_ = true; + use_mock_histogram_ = true; + RecreateDelayManager(); + EXPECT_TRUE(mock_histogram_); + + // Insert first packet. + SetPacketAudioLength(kFrameSizeMs); + InsertNextPacket(); + + // Insert reordered packet. + EXPECT_CALL(*mock_histogram_, Add(3)); + EXPECT_EQ(0, dm_->Update(seq_no_ - 3, ts_ - 3 * kFrameSizeMs, kFs)); + + // Insert another reordered packet. + EXPECT_CALL(*mock_histogram_, Add(2)); + EXPECT_EQ(0, dm_->Update(seq_no_ - 2, ts_ - 2 * kFrameSizeMs, kFs)); + + // Insert the next packet in order and verify that the inter-arrival time is + // estimated correctly. + IncreaseTime(kFrameSizeMs); + EXPECT_CALL(*mock_histogram_, Add(1)); + InsertNextPacket(); +} + // Tests that skipped sequence numbers (simulating empty packets) are handled // correctly. TEST_F(DelayManagerTest, EmptyPacketsReported) { @@ -285,7 +534,7 @@ // Expect detector update method to be called once with inter-arrival time // equal to 1 packet, and (base) target level equal to 1 as well. // Return false to indicate no peaks found. - EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false)); + EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(false)); InsertNextPacket(); EXPECT_EQ(1 << 8, dm_->TargetLevel()); // In Q8. @@ -309,7 +558,7 @@ // Expect detector update method to be called once with inter-arrival time // equal to 1 packet, and (base) target level equal to 1 as well. // Return false to indicate no peaks found. - EXPECT_CALL(detector_, Update(10, 10)).WillOnce(Return(false)); + EXPECT_CALL(detector_, Update(10, false, 10)).WillOnce(Return(false)); InsertNextPacket(); // Note 10 times higher target value. @@ -337,8 +586,7 @@ test::ScopedFieldTrials field_trial( "WebRTC-Audio-NetEqForceTargetDelayPercentile/Enabled-0/"); RecreateDelayManager(); - EXPECT_EQ(absl::make_optional<int>(1 << 30), - dm_->forced_limit_probability_for_test()); + EXPECT_EQ(0, dm_->histogram_quantile()); SetPacketAudioLength(kFrameSizeMs); // First packet arrival. @@ -348,7 +596,7 @@ // Second packet arrival. // Expect detector update method to be called once with inter-arrival time // equal to 1 packet. - EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false)); + EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(false)); InsertNextPacket(); constexpr int kExpectedTarget = 1; EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel()); // In Q8. @@ -359,145 +607,122 @@ test::ScopedFieldTrials field_trial( "WebRTC-Audio-NetEqForceTargetDelayPercentile/Enabled-95/"); RecreateDelayManager(); - EXPECT_EQ(absl::make_optional<int>(53687091), - dm_->forced_limit_probability_for_test()); // 1/20 in Q30 + EXPECT_EQ(kDefaultHistogramQuantile, dm_->histogram_quantile()); } { test::ScopedFieldTrials field_trial( "WebRTC-Audio-NetEqForceTargetDelayPercentile/Enabled-99.95/"); RecreateDelayManager(); - EXPECT_EQ(absl::make_optional<int>(536871), - dm_->forced_limit_probability_for_test()); // 1/2000 in Q30 + EXPECT_EQ(1073204953, dm_->histogram_quantile()); // 0.9995 in Q30. } { test::ScopedFieldTrials field_trial( "WebRTC-Audio-NetEqForceTargetDelayPercentile/Disabled/"); RecreateDelayManager(); - EXPECT_EQ(absl::nullopt, dm_->forced_limit_probability_for_test()); + EXPECT_EQ(kDefaultHistogramQuantile, dm_->histogram_quantile()); } { test::ScopedFieldTrials field_trial( "WebRTC-Audio-NetEqForceTargetDelayPercentile/Enabled--1/"); - EXPECT_EQ(absl::nullopt, dm_->forced_limit_probability_for_test()); + EXPECT_EQ(kDefaultHistogramQuantile, dm_->histogram_quantile()); } { test::ScopedFieldTrials field_trial( "WebRTC-Audio-NetEqForceTargetDelayPercentile/Enabled-100.1/"); RecreateDelayManager(); - EXPECT_EQ(absl::nullopt, dm_->forced_limit_probability_for_test()); + EXPECT_EQ(kDefaultHistogramQuantile, dm_->histogram_quantile()); } } -// Test if the histogram is stretched correctly if the packet size is decreased. -TEST(DelayManagerIATScalingTest, StretchTest) { - using IATVector = DelayManager::IATVector; - // Test a straightforward 60ms to 20ms change. - IATVector iat = {12, 0, 0, 0, 0, 0}; - IATVector expected_result = {4, 4, 4, 0, 0, 0}; - IATVector stretched_iat = DelayManager::ScaleHistogram(iat, 60, 20); - EXPECT_EQ(stretched_iat, expected_result); - - // Test an example where the last bin in the stretched histogram should - // contain the sum of the elements that don't fit into the new histogram. - iat = {18, 15, 12, 9, 6, 3, 0}; - expected_result = {6, 6, 6, 5, 5, 5, 30}; - stretched_iat = DelayManager::ScaleHistogram(iat, 60, 20); - EXPECT_EQ(stretched_iat, expected_result); - - // Test a 120ms to 60ms change. - iat = {18, 16, 14, 4, 0}; - expected_result = {9, 9, 8, 8, 18}; - stretched_iat = DelayManager::ScaleHistogram(iat, 120, 60); - EXPECT_EQ(stretched_iat, expected_result); - - // Test a 120ms to 20ms change. - iat = {19, 12, 0, 0, 0, 0, 0, 0}; - expected_result = {3, 3, 3, 3, 3, 3, 2, 11}; - stretched_iat = DelayManager::ScaleHistogram(iat, 120, 20); - EXPECT_EQ(stretched_iat, expected_result); - - // Test a 70ms to 40ms change. - iat = {13, 7, 5, 3, 1, 5, 12, 11, 3, 0, 0, 0}; - expected_result = {7, 5, 5, 3, 3, 2, 2, 1, 2, 2, 6, 22}; - stretched_iat = DelayManager::ScaleHistogram(iat, 70, 40); - EXPECT_EQ(stretched_iat, expected_result); - - // Test a 30ms to 20ms change. - iat = {13, 7, 5, 3, 1, 5, 12, 11, 3, 0, 0, 0}; - expected_result = {8, 6, 6, 3, 2, 2, 1, 3, 3, 8, 7, 11}; - stretched_iat = DelayManager::ScaleHistogram(iat, 30, 20); - EXPECT_EQ(stretched_iat, expected_result); +TEST_F(DelayManagerTest, DelayHistogramFieldTrial) { + { + test::ScopedFieldTrials field_trial( + "WebRTC-Audio-NetEqDelayHistogram/Enabled-96-0.998/"); + RecreateDelayManager(); + EXPECT_EQ(DelayManager::HistogramMode::RELATIVE_ARRIVAL_DELAY, + dm_->histogram_mode()); + EXPECT_EQ(1030792151, dm_->histogram_quantile()); // 0.96 in Q30. + EXPECT_EQ(32702, dm_->histogram_forget_factor()); // 0.998 in Q15. + } + { + test::ScopedFieldTrials field_trial( + "WebRTC-Audio-NetEqDelayHistogram/Enabled-97.5-0.998/"); + RecreateDelayManager(); + EXPECT_EQ(DelayManager::HistogramMode::RELATIVE_ARRIVAL_DELAY, + dm_->histogram_mode()); + EXPECT_EQ(1046898278, dm_->histogram_quantile()); // 0.975 in Q30. + EXPECT_EQ(32702, dm_->histogram_forget_factor()); // 0.998 in Q15. + } + { + // NetEqDelayHistogram should take precedence over + // NetEqForceTargetDelayPercentile. + test::ScopedFieldTrials field_trial( + "WebRTC-Audio-NetEqForceTargetDelayPercentile/Enabled-99.95/" + "WebRTC-Audio-NetEqDelayHistogram/Enabled-96-0.998/"); + RecreateDelayManager(); + EXPECT_EQ(DelayManager::HistogramMode::RELATIVE_ARRIVAL_DELAY, + dm_->histogram_mode()); + EXPECT_EQ(1030792151, dm_->histogram_quantile()); // 0.96 in Q30. + EXPECT_EQ(32702, dm_->histogram_forget_factor()); // 0.998 in Q15. + } + { + // Invalid parameters. + test::ScopedFieldTrials field_trial( + "WebRTC-Audio-NetEqDelayHistogram/Enabled-96/"); + RecreateDelayManager(); + EXPECT_EQ(DelayManager::HistogramMode::RELATIVE_ARRIVAL_DELAY, + dm_->histogram_mode()); + EXPECT_EQ(kDefaultHistogramQuantile, + dm_->histogram_quantile()); // 0.95 in Q30. + EXPECT_EQ(kForgetFactor, dm_->histogram_forget_factor()); // 0.9993 in Q15. + } + { + test::ScopedFieldTrials field_trial( + "WebRTC-Audio-NetEqDelayHistogram/Disabled/"); + RecreateDelayManager(); + EXPECT_EQ(DelayManager::HistogramMode::INTER_ARRIVAL_TIME, + dm_->histogram_mode()); + EXPECT_EQ(kDefaultHistogramQuantile, + dm_->histogram_quantile()); // 0.95 in Q30. + EXPECT_EQ(kForgetFactor, dm_->histogram_forget_factor()); // 0.9993 in Q15. + } } -// Test if the histogram is compressed correctly if the packet size is -// increased. -TEST(DelayManagerIATScalingTest, CompressionTest) { - using IATVector = DelayManager::IATVector; - // Test a 20 to 60 ms change. - IATVector iat = {12, 11, 10, 3, 2, 1}; - IATVector expected_result = {33, 6, 0, 0, 0, 0}; - IATVector compressed_iat = DelayManager::ScaleHistogram(iat, 20, 60); - EXPECT_EQ(compressed_iat, expected_result); +TEST_F(DelayManagerTest, RelativeArrivalDelayMode) { + histogram_mode_ = DelayManager::HistogramMode::RELATIVE_ARRIVAL_DELAY; + use_mock_histogram_ = true; + RecreateDelayManager(); - // Test a 60ms to 120ms change. - iat = {18, 16, 14, 4, 1}; - expected_result = {34, 18, 1, 0, 0}; - compressed_iat = DelayManager::ScaleHistogram(iat, 60, 120); - EXPECT_EQ(compressed_iat, expected_result); + SetPacketAudioLength(kFrameSizeMs); + InsertNextPacket(); - // Test a 20ms to 120ms change. - iat = {18, 12, 5, 4, 4, 3, 5, 1}; - expected_result = {46, 6, 0, 0, 0, 0, 0, 0}; - compressed_iat = DelayManager::ScaleHistogram(iat, 20, 120); - EXPECT_EQ(compressed_iat, expected_result); + IncreaseTime(kFrameSizeMs); + EXPECT_CALL(*mock_histogram_, Add(0)); // Not delayed. + InsertNextPacket(); - // Test a 70ms to 80ms change. - iat = {13, 7, 5, 3, 1, 5, 12, 11, 3}; - expected_result = {11, 8, 6, 2, 5, 12, 13, 3, 0}; - compressed_iat = DelayManager::ScaleHistogram(iat, 70, 80); - EXPECT_EQ(compressed_iat, expected_result); + IncreaseTime(2 * kFrameSizeMs); + EXPECT_CALL(*mock_histogram_, Add(1)); // 20ms delayed. + EXPECT_EQ(0, dm_->Update(seq_no_, ts_, kFs)); - // Test a 50ms to 110ms change. - iat = {13, 7, 5, 3, 1, 5, 12, 11, 3}; - expected_result = {18, 8, 16, 16, 2, 0, 0, 0, 0}; - compressed_iat = DelayManager::ScaleHistogram(iat, 50, 110); - EXPECT_EQ(compressed_iat, expected_result); + IncreaseTime(2 * kFrameSizeMs); + EXPECT_CALL(*mock_histogram_, Add(2)); // 40ms delayed. + EXPECT_EQ(0, dm_->Update(seq_no_ + 1, ts_ + kTsIncrement, kFs)); + + EXPECT_CALL(*mock_histogram_, Add(1)); // Reordered, 20ms delayed. + EXPECT_EQ(0, dm_->Update(seq_no_, ts_, kFs)); } -// Test if the histogram scaling function handles overflows correctly. -TEST(DelayManagerIATScalingTest, OverflowTest) { - using IATVector = DelayManager::IATVector; - // Test a compression operation that can cause overflow. - IATVector iat = {733544448, 0, 0, 0, 0, 0, 0, 340197376, 0, 0, 0, 0, 0, 0}; - IATVector expected_result = {733544448, 340197376, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0}; - IATVector scaled_iat = DelayManager::ScaleHistogram(iat, 10, 60); - EXPECT_EQ(scaled_iat, expected_result); +TEST_F(DelayManagerTest, RelativeArrivalDelayStatistic) { + SetPacketAudioLength(kFrameSizeMs); + InsertNextPacket(); - iat = {655591163, 39962288, 360736736, 1930514, 4003853, 1782764, - 114119, 2072996, 0, 2149354, 0}; - expected_result = {1056290187, 7717131, 2187115, 2149354, 0, 0, - 0, 0, 0, 0, 0}; - scaled_iat = DelayManager::ScaleHistogram(iat, 20, 60); - EXPECT_EQ(scaled_iat, expected_result); + IncreaseTime(kFrameSizeMs); + EXPECT_CALL(stats_, RelativePacketArrivalDelay(0)); + InsertNextPacket(); - // In this test case we will not be able to add everything to the final bin in - // the scaled histogram. Check that the last bin doesn't overflow. - iat = {2000000000, 2000000000, 2000000000, - 2000000000, 2000000000, 2000000000}; - expected_result = {666666666, 666666666, 666666666, - 666666667, 666666667, 2147483647}; - scaled_iat = DelayManager::ScaleHistogram(iat, 60, 20); - EXPECT_EQ(scaled_iat, expected_result); - - // In this test case we will not be able to add enough to each of the bins, - // so the values should be smeared out past the end of the normal range. - iat = {2000000000, 2000000000, 2000000000, - 2000000000, 2000000000, 2000000000}; - expected_result = {2147483647, 2147483647, 2147483647, - 2147483647, 2147483647, 1262581765}; - scaled_iat = DelayManager::ScaleHistogram(iat, 20, 60); - EXPECT_EQ(scaled_iat, expected_result); + IncreaseTime(2 * kFrameSizeMs); + EXPECT_CALL(stats_, RelativePacketArrivalDelay(20)); + InsertNextPacket(); } } // namespace webrtc
diff --git a/modules/audio_coding/neteq/delay_peak_detector.cc b/modules/audio_coding/neteq/delay_peak_detector.cc index 893ce3e..5669d72 100644 --- a/modules/audio_coding/neteq/delay_peak_detector.cc +++ b/modules/audio_coding/neteq/delay_peak_detector.cc
@@ -26,10 +26,12 @@ DelayPeakDetector::~DelayPeakDetector() = default; -DelayPeakDetector::DelayPeakDetector(const TickTimer* tick_timer) +DelayPeakDetector::DelayPeakDetector(const TickTimer* tick_timer, + bool ignore_reordered_packets) : peak_found_(false), peak_detection_threshold_(0), tick_timer_(tick_timer), + ignore_reordered_packets_(ignore_reordered_packets), frame_length_change_experiment_( field_trial::IsEnabled("WebRTC-Audio-NetEqFramelengthExperiment")) { RTC_DCHECK(!peak_period_stopwatch_); @@ -79,7 +81,12 @@ return max_period_element->period_ms; } -bool DelayPeakDetector::Update(int inter_arrival_time, int target_level) { +bool DelayPeakDetector::Update(int inter_arrival_time, + bool reordered, + int target_level) { + if (ignore_reordered_packets_ && reordered) { + return CheckPeakConditions(); + } if (inter_arrival_time > target_level + peak_detection_threshold_ || inter_arrival_time > 2 * target_level) { // A delay peak is observed.
diff --git a/modules/audio_coding/neteq/delay_peak_detector.h b/modules/audio_coding/neteq/delay_peak_detector.h index 272d50e..8cd198d 100644 --- a/modules/audio_coding/neteq/delay_peak_detector.h +++ b/modules/audio_coding/neteq/delay_peak_detector.h
@@ -17,13 +17,13 @@ #include <memory> #include "modules/audio_coding/neteq/tick_timer.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { class DelayPeakDetector { public: - DelayPeakDetector(const TickTimer* tick_timer); + DelayPeakDetector(const TickTimer* tick_timer, bool ignore_reordered_packets); virtual ~DelayPeakDetector(); virtual void Reset(); @@ -43,10 +43,11 @@ // larger than 0), or 0 if no delay peaks have been observed recently. virtual uint64_t MaxPeakPeriod() const; - // Updates the DelayPeakDetector with a new inter-arrival time (in packets) - // and the current target buffer level (needed to decide if a peak is observed - // or not). Returns true if peak-mode is active, false if not. - virtual bool Update(int inter_arrival_time, int target_level); + // Updates the DelayPeakDetector with a new inter-arrival time (in packets), + // the current target buffer level (needed to decide if a peak is observed or + // not) and if the new inter-arrival time includes a compensation for + // reordering. Returns true if peak-mode is active, false if not. + virtual bool Update(int inter_arrival_time, bool reordered, int target_level); private: static const size_t kMaxNumPeaks = 8; @@ -66,6 +67,7 @@ int peak_detection_threshold_; const TickTimer* tick_timer_; std::unique_ptr<TickTimer::Stopwatch> peak_period_stopwatch_; + const bool ignore_reordered_packets_; const bool frame_length_change_experiment_; RTC_DISALLOW_COPY_AND_ASSIGN(DelayPeakDetector);
diff --git a/modules/audio_coding/neteq/delay_peak_detector_unittest.cc b/modules/audio_coding/neteq/delay_peak_detector_unittest.cc index fd4dded..6590dc2 100644 --- a/modules/audio_coding/neteq/delay_peak_detector_unittest.cc +++ b/modules/audio_coding/neteq/delay_peak_detector_unittest.cc
@@ -18,14 +18,14 @@ TEST(DelayPeakDetector, CreateAndDestroy) { TickTimer tick_timer; - DelayPeakDetector* detector = new DelayPeakDetector(&tick_timer); + DelayPeakDetector* detector = new DelayPeakDetector(&tick_timer, false); EXPECT_FALSE(detector->peak_found()); delete detector; } TEST(DelayPeakDetector, EmptyHistory) { TickTimer tick_timer; - DelayPeakDetector detector(&tick_timer); + DelayPeakDetector detector(&tick_timer, false); EXPECT_EQ(-1, detector.MaxPeakHeight()); EXPECT_EQ(0u, detector.MaxPeakPeriod()); } @@ -35,7 +35,7 @@ // start. This should then continue until it is disengaged due to lack of peaks. TEST(DelayPeakDetector, TriggerPeakMode) { TickTimer tick_timer; - DelayPeakDetector detector(&tick_timer); + DelayPeakDetector detector(&tick_timer, false); const int kPacketSizeMs = 30; detector.SetPacketAudioLength(kPacketSizeMs); @@ -69,9 +69,9 @@ (arrival_times_ms[next] - arrival_times_ms[next - 1]) / kPacketSizeMs; const int kTargetBufferLevel = 1; // Define peaks to be iat > 2. if (time < peak_mode_start_ms || time > peak_mode_end_ms) { - EXPECT_FALSE(detector.Update(iat_packets, kTargetBufferLevel)); + EXPECT_FALSE(detector.Update(iat_packets, false, kTargetBufferLevel)); } else { - EXPECT_TRUE(detector.Update(iat_packets, kTargetBufferLevel)); + EXPECT_TRUE(detector.Update(iat_packets, false, kTargetBufferLevel)); EXPECT_EQ(kWorstPeakPeriod, detector.MaxPeakPeriod()); EXPECT_EQ(kPeakDelayMs / kPacketSizeMs + 1, detector.MaxPeakHeight()); } @@ -87,7 +87,7 @@ // The delay pattern has peaks with delay = 3, thus should not trigger. TEST(DelayPeakDetector, DoNotTriggerPeakMode) { TickTimer tick_timer; - DelayPeakDetector detector(&tick_timer); + DelayPeakDetector detector(&tick_timer, false); const int kPacketSizeMs = 30; detector.SetPacketAudioLength(kPacketSizeMs); @@ -115,7 +115,7 @@ int iat_packets = (arrival_times_ms[next] - arrival_times_ms[next - 1]) / kPacketSizeMs; const int kTargetBufferLevel = 2; // Define peaks to be iat > 4. - EXPECT_FALSE(detector.Update(iat_packets, kTargetBufferLevel)); + EXPECT_FALSE(detector.Update(iat_packets, false, kTargetBufferLevel)); ++next; } tick_timer.Increment(); @@ -129,15 +129,33 @@ // problems. TEST(DelayPeakDetector, ZeroDistancePeaks) { TickTimer tick_timer; - DelayPeakDetector detector(&tick_timer); + DelayPeakDetector detector(&tick_timer, false); const int kPacketSizeMs = 30; detector.SetPacketAudioLength(kPacketSizeMs); const int kTargetBufferLevel = 2; // Define peaks to be iat > 4. - const int kInterArrivalTime = 3 * kTargetBufferLevel; // Will trigger a peak. - EXPECT_FALSE(detector.Update(kInterArrivalTime, kTargetBufferLevel)); - EXPECT_FALSE(detector.Update(kInterArrivalTime, kTargetBufferLevel)); - EXPECT_FALSE(detector.Update(kInterArrivalTime, kTargetBufferLevel)); + const int kInterArrivalTime = + 3 * kTargetBufferLevel; // Above peak threshold. + EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel)); + tick_timer.Increment(); + EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel)); + // The following would fail if there were non-zero time between the updates. + EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel)); +} + +TEST(DelayPeakDetector, IgnoreReorderedPacket) { + TickTimer tick_timer; + DelayPeakDetector detector(&tick_timer, true); + + const int kTargetBufferLevel = 2; // Define peaks to be iat > 4. + const int kInterArrivalTime = + 3 * kTargetBufferLevel; // Above peak threshold. + EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel)); + tick_timer.Increment(); + EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel)); + tick_timer.Increment(); + // The following would fail if the packet was not reordered. + EXPECT_FALSE(detector.Update(kInterArrivalTime, true, kTargetBufferLevel)); } } // namespace webrtc
diff --git a/modules/audio_coding/neteq/dsp_helper.h b/modules/audio_coding/neteq/dsp_helper.h index 8379461..82fe14e 100644 --- a/modules/audio_coding/neteq/dsp_helper.h +++ b/modules/audio_coding/neteq/dsp_helper.h
@@ -16,7 +16,7 @@ #include "modules/audio_coding/neteq/audio_multi_vector.h" #include "modules/audio_coding/neteq/audio_vector.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/dtmf_buffer.h b/modules/audio_coding/neteq/dtmf_buffer.h index 24b14ec..a994e3a 100644 --- a/modules/audio_coding/neteq/dtmf_buffer.h +++ b/modules/audio_coding/neteq/dtmf_buffer.h
@@ -15,7 +15,7 @@ #include <stdint.h> #include <list> -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/dtmf_tone_generator.h b/modules/audio_coding/neteq/dtmf_tone_generator.h index 22e166e..968bc7f 100644 --- a/modules/audio_coding/neteq/dtmf_tone_generator.h +++ b/modules/audio_coding/neteq/dtmf_tone_generator.h
@@ -15,7 +15,7 @@ #include <stdint.h> #include "modules/audio_coding/neteq/audio_multi_vector.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/expand.h b/modules/audio_coding/neteq/expand.h index 30c34a2..7c041b8 100644 --- a/modules/audio_coding/neteq/expand.h +++ b/modules/audio_coding/neteq/expand.h
@@ -15,7 +15,7 @@ #include <memory> #include "modules/audio_coding/neteq/audio_vector.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/expand_uma_logger.h b/modules/audio_coding/neteq/expand_uma_logger.h index bd079c6..7cb11b1 100644 --- a/modules/audio_coding/neteq/expand_uma_logger.h +++ b/modules/audio_coding/neteq/expand_uma_logger.h
@@ -16,7 +16,7 @@ #include "absl/types/optional.h" #include "modules/audio_coding/neteq/tick_timer.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/expand_unittest.cc b/modules/audio_coding/neteq/expand_unittest.cc index 09914da..4c8c174 100644 --- a/modules/audio_coding/neteq/expand_unittest.cc +++ b/modules/audio_coding/neteq/expand_unittest.cc
@@ -20,7 +20,7 @@ #include "modules/audio_coding/neteq/tools/resample_input_audio_file.h" #include "rtc_base/numerics/safe_conversions.h" #include "test/gtest.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/histogram.cc b/modules/audio_coding/neteq/histogram.cc new file mode 100644 index 0000000..b8e4e52 --- /dev/null +++ b/modules/audio_coding/neteq/histogram.cc
@@ -0,0 +1,174 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <algorithm> +#include <numeric> + +#include "modules/audio_coding/neteq/histogram.h" +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_conversions.h" + +namespace webrtc { + +Histogram::Histogram(size_t num_buckets, int forget_factor) + : buckets_(num_buckets, 0), + forget_factor_(0), + base_forget_factor_(forget_factor) {} + +Histogram::~Histogram() {} + +// Each element in the vector is first multiplied by the forgetting factor +// |forget_factor_|. Then the vector element indicated by |iat_packets| is then +// increased (additive) by 1 - |forget_factor_|. This way, the probability of +// |iat_packets| is slightly increased, while the sum of the histogram remains +// constant (=1). +// Due to inaccuracies in the fixed-point arithmetic, the histogram may no +// longer sum up to 1 (in Q30) after the update. To correct this, a correction +// term is added or subtracted from the first element (or elements) of the +// vector. +// The forgetting factor |forget_factor_| is also updated. When the DelayManager +// is reset, the factor is set to 0 to facilitate rapid convergence in the +// beginning. With each update of the histogram, the factor is increased towards +// the steady-state value |kIatFactor_|. +void Histogram::Add(int value) { + RTC_DCHECK(value >= 0); + RTC_DCHECK(value < static_cast<int>(buckets_.size())); + int vector_sum = 0; // Sum up the vector elements as they are processed. + // Multiply each element in |buckets_| with |forget_factor_|. + for (int& bucket : buckets_) { + bucket = (static_cast<int64_t>(bucket) * forget_factor_) >> 15; + vector_sum += bucket; + } + + // Increase the probability for the currently observed inter-arrival time + // by 1 - |forget_factor_|. The factor is in Q15, |buckets_| in Q30. + // Thus, left-shift 15 steps to obtain result in Q30. + buckets_[value] += (32768 - forget_factor_) << 15; + vector_sum += (32768 - forget_factor_) << 15; // Add to vector sum. + + // |buckets_| should sum up to 1 (in Q30), but it may not due to + // fixed-point rounding errors. + vector_sum -= 1 << 30; // Should be zero. Compensate if not. + if (vector_sum != 0) { + // Modify a few values early in |buckets_|. + int flip_sign = vector_sum > 0 ? -1 : 1; + for (int& bucket : buckets_) { + // Add/subtract 1/16 of the element, but not more than |vector_sum|. + int correction = flip_sign * std::min(abs(vector_sum), bucket >> 4); + bucket += correction; + vector_sum += correction; + if (abs(vector_sum) == 0) { + break; + } + } + } + RTC_DCHECK(vector_sum == 0); // Verify that the above is correct. + + // Update |forget_factor_| (changes only during the first seconds after a + // reset). The factor converges to |base_forget_factor_|. + forget_factor_ += (base_forget_factor_ - forget_factor_ + 3) >> 2; +} + +int Histogram::Quantile(int probability) { + // Find the bucket for which the probability of observing an + // inter-arrival time larger than or equal to |index| is larger than or + // equal to |probability|. The sought probability is estimated using + // the histogram as the reverse cumulant PDF, i.e., the sum of elements from + // the end up until |index|. Now, since the sum of all elements is 1 + // (in Q30) by definition, and since the solution is often a low value for + // |iat_index|, it is more efficient to start with |sum| = 1 and subtract + // elements from the start of the histogram. + int inverse_probability = (1 << 30) - probability; + size_t index = 0; // Start from the beginning of |buckets_|. + int sum = 1 << 30; // Assign to 1 in Q30. + sum -= buckets_[index]; // Ensure that target level is >= 1. + + do { + // Subtract the probabilities one by one until the sum is no longer greater + // than |inverse_probability|. + ++index; + sum -= buckets_[index]; + } while ((sum > inverse_probability) && (index < buckets_.size() - 1)); + return static_cast<int>(index); +} + +// Set the histogram vector to an exponentially decaying distribution +// buckets_[i] = 0.5^(i+1), i = 0, 1, 2, ... +// buckets_ is in Q30. +void Histogram::Reset() { + // Set temp_prob to (slightly more than) 1 in Q14. This ensures that the sum + // of buckets_ is 1. + uint16_t temp_prob = 0x4002; // 16384 + 2 = 100000000000010 binary. + for (int& bucket : buckets_) { + temp_prob >>= 1; + bucket = temp_prob << 16; + } + forget_factor_ = 0; // Adapt the histogram faster for the first few packets. +} + +int Histogram::NumBuckets() const { + return buckets_.size(); +} + +void Histogram::Scale(int old_bucket_width, int new_bucket_width) { + buckets_ = ScaleBuckets(buckets_, old_bucket_width, new_bucket_width); +} + +std::vector<int> Histogram::ScaleBuckets(const std::vector<int>& buckets, + int old_bucket_width, + int new_bucket_width) { + RTC_DCHECK_GT(old_bucket_width, 0); + RTC_DCHECK_GT(new_bucket_width, 0); + RTC_DCHECK_EQ(old_bucket_width % 10, 0); + RTC_DCHECK_EQ(new_bucket_width % 10, 0); + std::vector<int> new_histogram(buckets.size(), 0); + int64_t acc = 0; + int time_counter = 0; + size_t new_histogram_idx = 0; + for (size_t i = 0; i < buckets.size(); i++) { + acc += buckets[i]; + time_counter += old_bucket_width; + // The bins should be scaled, to ensure the histogram still sums to one. + const int64_t scaled_acc = acc * new_bucket_width / time_counter; + int64_t actually_used_acc = 0; + while (time_counter >= new_bucket_width) { + const int64_t old_histogram_val = new_histogram[new_histogram_idx]; + new_histogram[new_histogram_idx] = + rtc::saturated_cast<int>(old_histogram_val + scaled_acc); + actually_used_acc += new_histogram[new_histogram_idx] - old_histogram_val; + new_histogram_idx = + std::min(new_histogram_idx + 1, new_histogram.size() - 1); + time_counter -= new_bucket_width; + } + // Only subtract the part that was succesfully written to the new histogram. + acc -= actually_used_acc; + } + // If there is anything left in acc (due to rounding errors), add it to the + // last bin. If we cannot add everything to the last bin we need to add as + // much as possible to the bins after the last bin (this is only possible + // when compressing a histogram). + while (acc > 0 && new_histogram_idx < new_histogram.size()) { + const int64_t old_histogram_val = new_histogram[new_histogram_idx]; + new_histogram[new_histogram_idx] = + rtc::saturated_cast<int>(old_histogram_val + acc); + acc -= new_histogram[new_histogram_idx] - old_histogram_val; + new_histogram_idx++; + } + RTC_DCHECK_EQ(buckets.size(), new_histogram.size()); + if (acc == 0) { + // If acc is non-zero, we were not able to add everything to the new + // histogram, so this check will not hold. + RTC_DCHECK_EQ(accumulate(buckets.begin(), buckets.end(), 0ll), + accumulate(new_histogram.begin(), new_histogram.end(), 0ll)); + } + return new_histogram; +} + +} // namespace webrtc
diff --git a/modules/audio_coding/neteq/histogram.h b/modules/audio_coding/neteq/histogram.h new file mode 100644 index 0000000..fc8f612 --- /dev/null +++ b/modules/audio_coding/neteq/histogram.h
@@ -0,0 +1,61 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_AUDIO_CODING_NETEQ_HISTOGRAM_H_ +#define MODULES_AUDIO_CODING_NETEQ_HISTOGRAM_H_ + +#include <string.h> // Provide access to size_t. + +#include <vector> + +namespace webrtc { + +class Histogram { + public: + // Creates histogram with capacity |num_buckets| and |forget_factor| in Q15. + Histogram(size_t num_buckets, int forget_factor); + + virtual ~Histogram(); + + // Resets the histogram to the default start distribution. + virtual void Reset(); + + // Add entry in bucket |index|. + virtual void Add(int index); + + // Calculates the quantile at |probability| (in Q30) of the histogram + // distribution. + virtual int Quantile(int probability); + + // Apply compression or stretching to the histogram. + virtual void Scale(int old_bucket_width, int new_bucket_width); + + // Returns the number of buckets in the histogram. + virtual int NumBuckets() const; + + // Returns the probability for each bucket in Q30. + std::vector<int> buckets() const { return buckets_; } + + int forget_factor() const { return base_forget_factor_; } + + // Made public for testing. + static std::vector<int> ScaleBuckets(const std::vector<int>& buckets, + int old_bucket_width, + int new_bucket_width); + + private: + std::vector<int> buckets_; + int forget_factor_; // Q15 + const int base_forget_factor_; +}; + +} // namespace webrtc + +#endif // MODULES_AUDIO_CODING_NETEQ_HISTOGRAM_H_
diff --git a/modules/audio_coding/neteq/histogram_unittest.cc b/modules/audio_coding/neteq/histogram_unittest.cc new file mode 100644 index 0000000..7a887c8 --- /dev/null +++ b/modules/audio_coding/neteq/histogram_unittest.cc
@@ -0,0 +1,171 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <cmath> + +#include "modules/audio_coding/neteq/histogram.h" +#include "test/gtest.h" + +namespace webrtc { + +TEST(HistogramTest, Initialization) { + Histogram histogram(65, 32440); + histogram.Reset(); + const auto& buckets = histogram.buckets(); + double sum = 0.0; + for (size_t i = 0; i < buckets.size(); i++) { + EXPECT_NEAR(ldexp(std::pow(0.5, static_cast<int>(i + 1)), 30), buckets[i], + 65537); + // Tolerance 65537 in Q30 corresponds to a delta of approximately 0.00006. + sum += buckets[i]; + } + EXPECT_EQ(1 << 30, static_cast<int>(sum)); // Should be 1 in Q30. +} + +TEST(HistogramTest, Add) { + Histogram histogram(10, 32440); + histogram.Reset(); + const std::vector<int> before = histogram.buckets(); + const int index = 5; + histogram.Add(index); + const std::vector<int> after = histogram.buckets(); + EXPECT_GT(after[index], before[index]); + int sum = 0; + for (int bucket : after) { + sum += bucket; + } + EXPECT_EQ(1 << 30, sum); +} + +TEST(HistogramTest, ForgetFactor) { + Histogram histogram(10, 32440); + histogram.Reset(); + const std::vector<int> before = histogram.buckets(); + const int index = 4; + histogram.Add(index); + const std::vector<int> after = histogram.buckets(); + for (int i = 0; i < histogram.NumBuckets(); ++i) { + if (i != index) { + EXPECT_LT(after[i], before[i]); + } + } +} + +// Test if the histogram is scaled correctly if the bucket width is decreased. +TEST(HistogramTest, DownScale) { + // Test a straightforward 60 to 20 change. + std::vector<int> buckets = {12, 0, 0, 0, 0, 0}; + std::vector<int> expected_result = {4, 4, 4, 0, 0, 0}; + std::vector<int> stretched_buckets = Histogram::ScaleBuckets(buckets, 60, 20); + EXPECT_EQ(stretched_buckets, expected_result); + + // Test an example where the last bin in the stretched histogram should + // contain the sum of the elements that don't fit into the new histogram. + buckets = {18, 15, 12, 9, 6, 3, 0}; + expected_result = {6, 6, 6, 5, 5, 5, 30}; + stretched_buckets = Histogram::ScaleBuckets(buckets, 60, 20); + EXPECT_EQ(stretched_buckets, expected_result); + + // Test a 120 to 60 change. + buckets = {18, 16, 14, 4, 0}; + expected_result = {9, 9, 8, 8, 18}; + stretched_buckets = Histogram::ScaleBuckets(buckets, 120, 60); + EXPECT_EQ(stretched_buckets, expected_result); + + // Test a 120 to 20 change. + buckets = {19, 12, 0, 0, 0, 0, 0, 0}; + expected_result = {3, 3, 3, 3, 3, 3, 2, 11}; + stretched_buckets = Histogram::ScaleBuckets(buckets, 120, 20); + EXPECT_EQ(stretched_buckets, expected_result); + + // Test a 70 to 40 change. + buckets = {13, 7, 5, 3, 1, 5, 12, 11, 3, 0, 0, 0}; + expected_result = {7, 5, 5, 3, 3, 2, 2, 1, 2, 2, 6, 22}; + stretched_buckets = Histogram::ScaleBuckets(buckets, 70, 40); + EXPECT_EQ(stretched_buckets, expected_result); + + // Test a 30 to 20 change. + buckets = {13, 7, 5, 3, 1, 5, 12, 11, 3, 0, 0, 0}; + expected_result = {8, 6, 6, 3, 2, 2, 1, 3, 3, 8, 7, 11}; + stretched_buckets = Histogram::ScaleBuckets(buckets, 30, 20); + EXPECT_EQ(stretched_buckets, expected_result); +} + +// Test if the histogram is scaled correctly if the bucket width is increased. +TEST(HistogramTest, UpScale) { + // Test a 20 to 60 change. + std::vector<int> buckets = {12, 11, 10, 3, 2, 1}; + std::vector<int> expected_result = {33, 6, 0, 0, 0, 0}; + std::vector<int> compressed_buckets = + Histogram::ScaleBuckets(buckets, 20, 60); + EXPECT_EQ(compressed_buckets, expected_result); + + // Test a 60 to 120 change. + buckets = {18, 16, 14, 4, 1}; + expected_result = {34, 18, 1, 0, 0}; + compressed_buckets = Histogram::ScaleBuckets(buckets, 60, 120); + EXPECT_EQ(compressed_buckets, expected_result); + + // Test a 20 to 120 change. + buckets = {18, 12, 5, 4, 4, 3, 5, 1}; + expected_result = {46, 6, 0, 0, 0, 0, 0, 0}; + compressed_buckets = Histogram::ScaleBuckets(buckets, 20, 120); + EXPECT_EQ(compressed_buckets, expected_result); + + // Test a 70 to 80 change. + buckets = {13, 7, 5, 3, 1, 5, 12, 11, 3}; + expected_result = {11, 8, 6, 2, 5, 12, 13, 3, 0}; + compressed_buckets = Histogram::ScaleBuckets(buckets, 70, 80); + EXPECT_EQ(compressed_buckets, expected_result); + + // Test a 50 to 110 change. + buckets = {13, 7, 5, 3, 1, 5, 12, 11, 3}; + expected_result = {18, 8, 16, 16, 2, 0, 0, 0, 0}; + compressed_buckets = Histogram::ScaleBuckets(buckets, 50, 110); + EXPECT_EQ(compressed_buckets, expected_result); +} + +// Test if the histogram scaling function handles overflows correctly. +TEST(HistogramTest, OverflowTest) { + // Test a upscale operation that can cause overflow. + std::vector<int> buckets = {733544448, 0, 0, 0, 0, 0, 0, + 340197376, 0, 0, 0, 0, 0, 0}; + std::vector<int> expected_result = {733544448, 340197376, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0}; + std::vector<int> scaled_buckets = Histogram::ScaleBuckets(buckets, 10, 60); + EXPECT_EQ(scaled_buckets, expected_result); + + buckets = {655591163, 39962288, 360736736, 1930514, 4003853, 1782764, + 114119, 2072996, 0, 2149354, 0}; + expected_result = {1056290187, 7717131, 2187115, 2149354, 0, 0, + 0, 0, 0, 0, 0}; + scaled_buckets = Histogram::ScaleBuckets(buckets, 20, 60); + EXPECT_EQ(scaled_buckets, expected_result); + + // In this test case we will not be able to add everything to the final bin in + // the scaled histogram. Check that the last bin doesn't overflow. + buckets = {2000000000, 2000000000, 2000000000, + 2000000000, 2000000000, 2000000000}; + expected_result = {666666666, 666666666, 666666666, + 666666667, 666666667, 2147483647}; + scaled_buckets = Histogram::ScaleBuckets(buckets, 60, 20); + EXPECT_EQ(scaled_buckets, expected_result); + + // In this test case we will not be able to add enough to each of the bins, + // so the values should be smeared out past the end of the normal range. + buckets = {2000000000, 2000000000, 2000000000, + 2000000000, 2000000000, 2000000000}; + expected_result = {2147483647, 2147483647, 2147483647, + 2147483647, 2147483647, 1262581765}; + scaled_buckets = Histogram::ScaleBuckets(buckets, 20, 60); + EXPECT_EQ(scaled_buckets, expected_result); +} + +} // namespace webrtc
diff --git a/modules/audio_coding/neteq/include/neteq.h b/modules/audio_coding/neteq/include/neteq.h index 2820fd8..549d355 100644 --- a/modules/audio_coding/neteq/include/neteq.h +++ b/modules/audio_coding/neteq/include/neteq.h
@@ -13,18 +13,18 @@ #include <string.h> // Provide access to size_t. +#include <map> #include <string> #include <vector> #include "absl/types/optional.h" #include "api/audio_codecs/audio_codec_pair_id.h" #include "api/audio_codecs/audio_decoder.h" +#include "api/audio_codecs/audio_format.h" #include "api/rtp_headers.h" -#include "common_types.h" // NOLINT(build/include) +#include "api/scoped_refptr.h" #include "modules/audio_coding/neteq/defines.h" -#include "modules/audio_coding/neteq/neteq_decoder_enum.h" -#include "rtc_base/constructormagic.h" -#include "rtc_base/scoped_ref_ptr.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { @@ -70,9 +70,19 @@ uint64_t concealed_samples = 0; uint64_t concealment_events = 0; uint64_t jitter_buffer_delay_ms = 0; - // Below stat is not part of the spec. + uint64_t jitter_buffer_emitted_count = 0; + // Below stats are not part of the spec. uint64_t voice_concealed_samples = 0; uint64_t delayed_packet_outage_samples = 0; + // This is sum of relative packet arrival delays of received packets so far. + // Since end-to-end delay of a packet is difficult to measure and is not + // necessarily useful for measuring jitter buffer performance, we report a + // relative packet arrival delay. The relative packet arrival delay of a + // packet is defined as the arrival delay compared to the first packet + // received, given that it had zero delay. To avoid clock drift, the "first" + // packet can be made dynamic. + uint64_t relative_packet_arrival_delay_ms = 0; + uint64_t jitter_buffer_packets_received = 0; }; // Metrics that describe the operations performed in NetEq, and the internal @@ -85,6 +95,8 @@ uint64_t accelerate_samples = 0; // Count of the number of buffer flushes. uint64_t packet_buffer_flushes = 0; + // The number of primary packets that were discarded. + uint64_t discarded_primary_packets = 0; // The statistics below are not cumulative. // The waiting time of the last decoded packet. uint64_t last_waiting_time_ms = 0; @@ -111,11 +123,12 @@ int sample_rate_hz = 16000; // Initial value. Will change with input data. bool enable_post_decode_vad = false; - size_t max_packets_in_buffer = 50; - int max_delay_ms = 2000; + size_t max_packets_in_buffer = 200; + int max_delay_ms = 0; int min_delay_ms = 0; bool enable_fast_accelerate = false; bool enable_muted_state = false; + bool enable_rtx_handling = false; absl::optional<AudioCodecPairId> codec_pair_id; bool for_test_no_time_stretching = false; // Use only for testing. }; @@ -165,25 +178,6 @@ // Replaces the current set of decoders with the given one. virtual void SetCodecs(const std::map<int, SdpAudioFormat>& codecs) = 0; - // Associates |rtp_payload_type| with |codec| and |codec_name|, and stores the - // information in the codec database. Returns 0 on success, -1 on failure. - // The name is only used to provide information back to the caller about the - // decoders. Hence, the name is arbitrary, and may be empty. - virtual int RegisterPayloadType(NetEqDecoder codec, - const std::string& codec_name, - uint8_t rtp_payload_type) = 0; - - // Provides an externally created decoder object |decoder| to insert in the - // decoder database. The decoder implements a decoder of type |codec| and - // associates it with |rtp_payload_type| and |codec_name|. Returns kOK on - // success, kFail on failure. The name is only used to provide information - // back to the caller about the decoders. Hence, the name is arbitrary, and - // may be empty. - virtual int RegisterExternalDecoder(AudioDecoder* decoder, - NetEqDecoder codec, - const std::string& codec_name, - uint8_t rtp_payload_type) = 0; - // Associates |rtp_payload_type| with the given codec, which NetEq will // instantiate when it needs it. Returns true iff successful. virtual bool RegisterPayloadType(int rtp_payload_type, @@ -209,13 +203,20 @@ // the |max_delay_ms| value in the NetEq::Config struct. virtual bool SetMaximumDelay(int delay_ms) = 0; + // Sets a base minimum delay in milliseconds for packet buffer. The minimum + // delay which is set via |SetMinimumDelay| can't be lower than base minimum + // delay. Calling this method is similar to setting the |min_delay_ms| value + // in the NetEq::Config struct. Returns true if the base minimum is + // successfully applied, otherwise false is returned. + virtual bool SetBaseMinimumDelayMs(int delay_ms) = 0; + + // Returns current value of base minimum delay in milliseconds. + virtual int GetBaseMinimumDelayMs() const = 0; + // Returns the current target delay in ms. This includes any extra delay // requested through SetMinimumDelay. virtual int TargetDelayMs() const = 0; - // Returns the current total delay (packet buffer and sync buffer) in ms. - virtual int CurrentDelayMs() const = 0; - // Returns the current total delay (packet buffer and sync buffer) in ms, // with smoothing applied to even out short-time fluctuations due to jitter. // The packet buffer part of the delay is not updated during DTX/CNG periods. @@ -249,11 +250,7 @@ // (Config::sample_rate_hz) is returned. virtual int last_output_sample_rate_hz() const = 0; - // Returns info about the decoder for the given payload type, or an empty - // value if we have no decoder for that payload type. - virtual absl::optional<CodecInst> GetDecoder(int payload_type) const = 0; - - // Returns the decoder format for the given payload type. Returns empty if no + // Returns the decoder info for the given payload type. Returns empty if no // such payload type was registered. virtual absl::optional<SdpAudioFormat> GetDecoderFormat( int payload_type) const = 0;
diff --git a/modules/audio_coding/neteq/merge.h b/modules/audio_coding/neteq/merge.h index e7e0bf9..a062a95 100644 --- a/modules/audio_coding/neteq/merge.h +++ b/modules/audio_coding/neteq/merge.h
@@ -12,7 +12,7 @@ #define MODULES_AUDIO_CODING_NETEQ_MERGE_H_ #include "modules/audio_coding/neteq/audio_multi_vector.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/mock/mock_decoder_database.h b/modules/audio_coding/neteq/mock/mock_decoder_database.h index b1d8151..d1db213 100644 --- a/modules/audio_coding/neteq/mock/mock_decoder_database.h +++ b/modules/audio_coding/neteq/mock/mock_decoder_database.h
@@ -29,17 +29,8 @@ MOCK_CONST_METHOD0(Empty, bool()); MOCK_CONST_METHOD0(Size, int()); MOCK_METHOD0(Reset, void()); - MOCK_METHOD3(RegisterPayload, - int(uint8_t rtp_payload_type, - NetEqDecoder codec_type, - const std::string& name)); MOCK_METHOD2(RegisterPayload, int(int rtp_payload_type, const SdpAudioFormat& audio_format)); - MOCK_METHOD4(InsertExternal, - int(uint8_t rtp_payload_type, - NetEqDecoder codec_type, - const std::string& codec_name, - AudioDecoder* decoder)); MOCK_METHOD1(Remove, int(uint8_t rtp_payload_type)); MOCK_METHOD0(RemoveAll, void()); MOCK_CONST_METHOD1(GetDecoderInfo,
diff --git a/modules/audio_coding/neteq/mock/mock_delay_manager.h b/modules/audio_coding/neteq/mock/mock_delay_manager.h index 206cea7..3a128ce 100644 --- a/modules/audio_coding/neteq/mock/mock_delay_manager.h +++ b/modules/audio_coding/neteq/mock/mock_delay_manager.h
@@ -11,8 +11,11 @@ #ifndef MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_DELAY_MANAGER_H_ #define MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_DELAY_MANAGER_H_ -#include "modules/audio_coding/neteq/delay_manager.h" +#include <algorithm> +#include "modules/audio_coding/neteq/delay_manager.h" +#include "modules/audio_coding/neteq/histogram.h" +#include "modules/audio_coding/neteq/statistics_calculator.h" #include "test/gmock.h" namespace webrtc { @@ -21,26 +24,37 @@ public: MockDelayManager(size_t max_packets_in_buffer, int base_min_target_delay_ms, + int histogram_quantile, + HistogramMode histogram_mode, + bool enable_rtx_handling, DelayPeakDetector* peak_detector, - const TickTimer* tick_timer) + const TickTimer* tick_timer, + StatisticsCalculator* stats, + std::unique_ptr<Histogram> histogram) : DelayManager(max_packets_in_buffer, base_min_target_delay_ms, + histogram_quantile, + histogram_mode, + enable_rtx_handling, peak_detector, - tick_timer) {} + tick_timer, + stats, + std::move(histogram)) {} virtual ~MockDelayManager() { Die(); } MOCK_METHOD0(Die, void()); - MOCK_CONST_METHOD0(iat_vector, const IATVector&()); MOCK_METHOD3(Update, int(uint16_t sequence_number, uint32_t timestamp, int sample_rate_hz)); - MOCK_METHOD1(CalculateTargetLevel, int(int iat_packets)); + MOCK_METHOD2(CalculateTargetLevel, int(int iat_packets, bool reordered)); MOCK_METHOD1(SetPacketAudioLength, int(int length_ms)); MOCK_METHOD0(Reset, void()); MOCK_CONST_METHOD0(PeakFound, bool()); MOCK_METHOD1(UpdateCounters, void(int elapsed_time_ms)); MOCK_METHOD0(ResetPacketIatCount, void()); MOCK_CONST_METHOD2(BufferLimits, void(int* lower_limit, int* higher_limit)); + MOCK_METHOD1(SetBaseMinimumDelay, bool(int delay_ms)); + MOCK_CONST_METHOD0(GetBaseMinimumDelay, int()); MOCK_CONST_METHOD0(TargetLevel, int()); MOCK_METHOD0(RegisterEmptyPacket, void()); MOCK_METHOD1(set_extra_delay_ms, void(int16_t delay));
diff --git a/modules/audio_coding/neteq/mock/mock_delay_peak_detector.h b/modules/audio_coding/neteq/mock/mock_delay_peak_detector.h index f6cdea0..f7f0465 100644 --- a/modules/audio_coding/neteq/mock/mock_delay_peak_detector.h +++ b/modules/audio_coding/neteq/mock/mock_delay_peak_detector.h
@@ -19,8 +19,9 @@ class MockDelayPeakDetector : public DelayPeakDetector { public: - MockDelayPeakDetector(const TickTimer* tick_timer) - : DelayPeakDetector(tick_timer) {} + MockDelayPeakDetector(const TickTimer* tick_timer, + bool ignore_reordered_packets) + : DelayPeakDetector(tick_timer, ignore_reordered_packets) {} virtual ~MockDelayPeakDetector() { Die(); } MOCK_METHOD0(Die, void()); MOCK_METHOD0(Reset, void()); @@ -28,7 +29,8 @@ MOCK_METHOD0(peak_found, bool()); MOCK_CONST_METHOD0(MaxPeakHeight, int()); MOCK_CONST_METHOD0(MaxPeakPeriod, uint64_t()); - MOCK_METHOD2(Update, bool(int inter_arrival_time, int target_level)); + MOCK_METHOD3(Update, + bool(int inter_arrival_time, bool reordered, int target_level)); }; } // namespace webrtc
diff --git a/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h b/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h deleted file mode 100644 index 1fb3db5..0000000 --- a/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h +++ /dev/null
@@ -1,96 +0,0 @@ -/* - * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_EXTERNAL_DECODER_PCM16B_H_ -#define MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_EXTERNAL_DECODER_PCM16B_H_ - -#include "api/audio_codecs/audio_decoder.h" -#include "modules/audio_coding/codecs/pcm16b/pcm16b.h" -#include "rtc_base/constructormagic.h" -#include "test/gmock.h" - -namespace webrtc { - -using ::testing::_; -using ::testing::Invoke; - -// Implement an external version of the PCM16b decoder. -class ExternalPcm16B : public AudioDecoder { - public: - explicit ExternalPcm16B(int sample_rate_hz) - : sample_rate_hz_(sample_rate_hz) {} - void Reset() override {} - - int DecodeInternal(const uint8_t* encoded, - size_t encoded_len, - int sample_rate_hz, - int16_t* decoded, - SpeechType* speech_type) override { - EXPECT_EQ(sample_rate_hz_, sample_rate_hz); - size_t ret = WebRtcPcm16b_Decode(encoded, encoded_len, decoded); - *speech_type = ConvertSpeechType(1); - return static_cast<int>(ret); - } - int SampleRateHz() const override { return sample_rate_hz_; } - size_t Channels() const override { return 1; } - - private: - const int sample_rate_hz_; - RTC_DISALLOW_COPY_AND_ASSIGN(ExternalPcm16B); -}; - -// Create a mock of ExternalPcm16B which delegates all calls to the real object. -// The reason is that we can then track that the correct calls are being made. -class MockExternalPcm16B : public AudioDecoder { - public: - explicit MockExternalPcm16B(int sample_rate_hz) : real_(sample_rate_hz) { - // By default, all calls are delegated to the real object. - ON_CALL(*this, DecodeInternal(_, _, _, _, _)) - .WillByDefault(Invoke(&real_, &ExternalPcm16B::DecodeInternal)); - ON_CALL(*this, HasDecodePlc()) - .WillByDefault(Invoke(&real_, &ExternalPcm16B::HasDecodePlc)); - ON_CALL(*this, DecodePlc(_, _)) - .WillByDefault(Invoke(&real_, &ExternalPcm16B::DecodePlc)); - ON_CALL(*this, Reset()) - .WillByDefault(Invoke(&real_, &ExternalPcm16B::Reset)); - ON_CALL(*this, IncomingPacket(_, _, _, _, _)) - .WillByDefault(Invoke(&real_, &ExternalPcm16B::IncomingPacket)); - ON_CALL(*this, ErrorCode()) - .WillByDefault(Invoke(&real_, &ExternalPcm16B::ErrorCode)); - } - virtual ~MockExternalPcm16B() { Die(); } - - MOCK_METHOD0(Die, void()); - MOCK_METHOD5(DecodeInternal, - int(const uint8_t* encoded, - size_t encoded_len, - int sample_rate_hz, - int16_t* decoded, - SpeechType* speech_type)); - MOCK_CONST_METHOD0(HasDecodePlc, bool()); - MOCK_METHOD2(DecodePlc, size_t(size_t num_frames, int16_t* decoded)); - MOCK_METHOD0(Reset, void()); - MOCK_METHOD5(IncomingPacket, - int(const uint8_t* payload, - size_t payload_len, - uint16_t rtp_sequence_number, - uint32_t rtp_timestamp, - uint32_t arrival_timestamp)); - MOCK_METHOD0(ErrorCode, int()); - - int SampleRateHz() const /* override */ { return real_.SampleRateHz(); } - size_t Channels() const /* override */ { return real_.Channels(); } - - private: - ExternalPcm16B real_; -}; - -} // namespace webrtc -#endif // MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_EXTERNAL_DECODER_PCM16B_H_
diff --git a/modules/audio_coding/neteq/mock/mock_histogram.h b/modules/audio_coding/neteq/mock/mock_histogram.h new file mode 100644 index 0000000..09b1b89 --- /dev/null +++ b/modules/audio_coding/neteq/mock/mock_histogram.h
@@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_HISTOGRAM_H_ +#define MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_HISTOGRAM_H_ + +#include "modules/audio_coding/neteq/histogram.h" + +#include "test/gmock.h" + +namespace webrtc { + +class MockHistogram : public Histogram { + public: + MockHistogram(size_t num_buckets, int forget_factor) + : Histogram(num_buckets, forget_factor) {} + virtual ~MockHistogram() {} + + MOCK_METHOD1(Add, void(int)); + MOCK_METHOD1(Quantile, int(int)); +}; + +} // namespace webrtc +#endif // MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_HISTOGRAM_H_
diff --git a/modules/audio_coding/neteq/mock/mock_statistics_calculator.h b/modules/audio_coding/neteq/mock/mock_statistics_calculator.h index 85f2620..aedb1df 100644 --- a/modules/audio_coding/neteq/mock/mock_statistics_calculator.h +++ b/modules/audio_coding/neteq/mock/mock_statistics_calculator.h
@@ -21,6 +21,7 @@ public: MOCK_METHOD1(PacketsDiscarded, void(size_t num_packets)); MOCK_METHOD1(SecondaryPacketsDiscarded, void(size_t num_packets)); + MOCK_METHOD1(RelativePacketArrivalDelay, void(size_t delay_ms)); }; } // namespace webrtc
diff --git a/modules/audio_coding/neteq/neteq.cc b/modules/audio_coding/neteq/neteq.cc index 0e6147e..a84c942 100644 --- a/modules/audio_coding/neteq/neteq.cc +++ b/modules/audio_coding/neteq/neteq.cc
@@ -28,9 +28,10 @@ ss << "sample_rate_hz=" << sample_rate_hz << ", enable_post_decode_vad=" << (enable_post_decode_vad ? "true" : "false") << ", max_packets_in_buffer=" << max_packets_in_buffer - << ", enable_fast_accelerate=" - << (enable_fast_accelerate ? " true" : "false") - << ", enable_muted_state=" << (enable_muted_state ? " true" : "false"); + << ", min_delay_ms=" << min_delay_ms << ", enable_fast_accelerate=" + << (enable_fast_accelerate ? "true" : "false") + << ", enable_muted_state=" << (enable_muted_state ? "true" : "false") + << ", enable_rtx_handling=" << (enable_rtx_handling ? "true" : "false"); return ss.str(); }
diff --git a/modules/audio_coding/neteq/neteq_decoder_enum.cc b/modules/audio_coding/neteq/neteq_decoder_enum.cc deleted file mode 100644 index e3b633e..0000000 --- a/modules/audio_coding/neteq/neteq_decoder_enum.cc +++ /dev/null
@@ -1,85 +0,0 @@ -/* - * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include <map> -#include <string> - -#include "modules/audio_coding/neteq/neteq_decoder_enum.h" - -namespace webrtc { - -absl::optional<SdpAudioFormat> NetEqDecoderToSdpAudioFormat(NetEqDecoder nd) { - switch (nd) { - case NetEqDecoder::kDecoderPCMu: - return SdpAudioFormat("pcmu", 8000, 1); - case NetEqDecoder::kDecoderPCMa: - return SdpAudioFormat("pcma", 8000, 1); - case NetEqDecoder::kDecoderPCMu_2ch: - return SdpAudioFormat("pcmu", 8000, 2); - case NetEqDecoder::kDecoderPCMa_2ch: - return SdpAudioFormat("pcma", 8000, 2); - case NetEqDecoder::kDecoderILBC: - return SdpAudioFormat("ilbc", 8000, 1); - case NetEqDecoder::kDecoderISAC: - return SdpAudioFormat("isac", 16000, 1); - case NetEqDecoder::kDecoderISACswb: - return SdpAudioFormat("isac", 32000, 1); - case NetEqDecoder::kDecoderPCM16B: - return SdpAudioFormat("l16", 8000, 1); - case NetEqDecoder::kDecoderPCM16Bwb: - return SdpAudioFormat("l16", 16000, 1); - case NetEqDecoder::kDecoderPCM16Bswb32kHz: - return SdpAudioFormat("l16", 32000, 1); - case NetEqDecoder::kDecoderPCM16Bswb48kHz: - return SdpAudioFormat("l16", 48000, 1); - case NetEqDecoder::kDecoderPCM16B_2ch: - return SdpAudioFormat("l16", 8000, 2); - case NetEqDecoder::kDecoderPCM16Bwb_2ch: - return SdpAudioFormat("l16", 16000, 2); - case NetEqDecoder::kDecoderPCM16Bswb32kHz_2ch: - return SdpAudioFormat("l16", 32000, 2); - case NetEqDecoder::kDecoderPCM16Bswb48kHz_2ch: - return SdpAudioFormat("l16", 48000, 2); - case NetEqDecoder::kDecoderPCM16B_5ch: - return SdpAudioFormat("l16", 8000, 5); - case NetEqDecoder::kDecoderG722: - return SdpAudioFormat("g722", 8000, 1); - case NetEqDecoder::kDecoderG722_2ch: - return SdpAudioFormat("g722", 8000, 2); - case NetEqDecoder::kDecoderOpus: - return SdpAudioFormat("opus", 48000, 2); - case NetEqDecoder::kDecoderOpus_2ch: - return SdpAudioFormat( - "opus", 48000, 2, - std::map<std::string, std::string>{{"stereo", "1"}}); - case NetEqDecoder::kDecoderRED: - return SdpAudioFormat("red", 8000, 1); - case NetEqDecoder::kDecoderAVT: - return SdpAudioFormat("telephone-event", 8000, 1); - case NetEqDecoder::kDecoderAVT16kHz: - return SdpAudioFormat("telephone-event", 16000, 1); - case NetEqDecoder::kDecoderAVT32kHz: - return SdpAudioFormat("telephone-event", 32000, 1); - case NetEqDecoder::kDecoderAVT48kHz: - return SdpAudioFormat("telephone-event", 48000, 1); - case NetEqDecoder::kDecoderCNGnb: - return SdpAudioFormat("cn", 8000, 1); - case NetEqDecoder::kDecoderCNGwb: - return SdpAudioFormat("cn", 16000, 1); - case NetEqDecoder::kDecoderCNGswb32kHz: - return SdpAudioFormat("cn", 32000, 1); - case NetEqDecoder::kDecoderCNGswb48kHz: - return SdpAudioFormat("cn", 48000, 1); - default: - return absl::nullopt; - } -} - -} // namespace webrtc
diff --git a/modules/audio_coding/neteq/neteq_decoder_enum.h b/modules/audio_coding/neteq/neteq_decoder_enum.h deleted file mode 100644 index 00629bc..0000000 --- a/modules/audio_coding/neteq/neteq_decoder_enum.h +++ /dev/null
@@ -1,56 +0,0 @@ -/* - * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef MODULES_AUDIO_CODING_NETEQ_NETEQ_DECODER_ENUM_H_ -#define MODULES_AUDIO_CODING_NETEQ_NETEQ_DECODER_ENUM_H_ - -#include "absl/types/optional.h" -#include "api/audio_codecs/audio_format.h" - -namespace webrtc { - -enum class NetEqDecoder { - kDecoderPCMu, - kDecoderPCMa, - kDecoderPCMu_2ch, - kDecoderPCMa_2ch, - kDecoderILBC, - kDecoderISAC, - kDecoderISACswb, - kDecoderPCM16B, - kDecoderPCM16Bwb, - kDecoderPCM16Bswb32kHz, - kDecoderPCM16Bswb48kHz, - kDecoderPCM16B_2ch, - kDecoderPCM16Bwb_2ch, - kDecoderPCM16Bswb32kHz_2ch, - kDecoderPCM16Bswb48kHz_2ch, - kDecoderPCM16B_5ch, - kDecoderG722, - kDecoderG722_2ch, - kDecoderRED, - kDecoderAVT, - kDecoderAVT16kHz, - kDecoderAVT32kHz, - kDecoderAVT48kHz, - kDecoderCNGnb, - kDecoderCNGwb, - kDecoderCNGswb32kHz, - kDecoderCNGswb48kHz, - kDecoderArbitrary, - kDecoderOpus, - kDecoderOpus_2ch, -}; - -absl::optional<SdpAudioFormat> NetEqDecoderToSdpAudioFormat(NetEqDecoder nd); - -} // namespace webrtc - -#endif // MODULES_AUDIO_CODING_NETEQ_NETEQ_DECODER_ENUM_H_
diff --git a/modules/audio_coding/neteq/neteq_decoder_plc_unittest.cc b/modules/audio_coding/neteq/neteq_decoder_plc_unittest.cc index 8d0972c..21b15a9 100644 --- a/modules/audio_coding/neteq/neteq_decoder_plc_unittest.cc +++ b/modules/audio_coding/neteq/neteq_decoder_plc_unittest.cc
@@ -14,6 +14,7 @@ #include <utility> #include <vector> +#include "absl/memory/memory.h" #include "absl/types/optional.h" #include "modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h" #include "modules/audio_coding/neteq/tools/audio_checksum.h" @@ -23,8 +24,10 @@ #include "modules/audio_coding/neteq/tools/input_audio_file.h" #include "modules/audio_coding/neteq/tools/neteq_test.h" #include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/ref_counted_object.h" +#include "test/audio_decoder_proxy_factory.h" #include "test/gtest.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" namespace webrtc { namespace test { @@ -174,10 +177,7 @@ webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm")); AudioDecoderPlc dec(std::move(input_file), kSampleRateHz); // Masquerading as a PCM16b decoder. - NetEqTest::ExternalDecoderInfo dec_info = { - &dec, NetEqDecoder::kDecoderPCM16Bswb32kHz, "pcm16b_PLC"}; - NetEqTest::ExtDecoderMap external_decoders; - external_decoders.insert(std::make_pair(kPayloadType, dec_info)); + decoders.emplace(kPayloadType, SdpAudioFormat("l16", 32000, 1)); // Output is simply a checksum calculator. auto output = absl::make_unique<AudioChecksumWithOutput>(checksum); @@ -185,8 +185,9 @@ // No callback objects. NetEqTest::Callbacks callbacks; - NetEqTest neteq_test(config, decoders, external_decoders, - std::move(lossy_input), std::move(output), callbacks); + NetEqTest neteq_test( + config, new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&dec), + decoders, nullptr, std::move(lossy_input), std::move(output), callbacks); EXPECT_LE(kRunTimeMs, neteq_test.Run()); auto lifetime_stats = neteq_test.LifetimeStats();
diff --git a/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc b/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc index 872829c..8214ed2 100644 --- a/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc +++ b/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc
@@ -14,14 +14,13 @@ #include "api/audio/audio_frame.h" #include "api/audio_codecs/builtin_audio_decoder_factory.h" -#include "common_types.h" // NOLINT(build/include) #include "modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h" #include "modules/audio_coding/neteq/tools/input_audio_file.h" #include "modules/audio_coding/neteq/tools/neteq_external_decoder_test.h" #include "modules/audio_coding/neteq/tools/rtp_generator.h" #include "rtc_base/strings/string_builder.h" #include "test/gmock.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/neteq_impl.cc b/modules/audio_coding/neteq/neteq_impl.cc index 2a025f3..f1e8527 100644 --- a/modules/audio_coding/neteq/neteq_impl.cc +++ b/modules/audio_coding/neteq/neteq_impl.cc
@@ -41,6 +41,7 @@ #include "modules/audio_coding/neteq/post_decode_vad.h" #include "modules/audio_coding/neteq/preemptive_expand.h" #include "modules/audio_coding/neteq/red_payload_splitter.h" +#include "modules/audio_coding/neteq/statistics_calculator.h" #include "modules/audio_coding/neteq/sync_buffer.h" #include "modules/audio_coding/neteq/tick_timer.h" #include "modules/audio_coding/neteq/time_stretch.h" @@ -58,14 +59,18 @@ const NetEq::Config& config, const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) : tick_timer(new TickTimer), + stats(new StatisticsCalculator), buffer_level_filter(new BufferLevelFilter), decoder_database( new DecoderDatabase(decoder_factory, config.codec_pair_id)), - delay_peak_detector(new DelayPeakDetector(tick_timer.get())), - delay_manager(new DelayManager(config.max_packets_in_buffer, - config.min_delay_ms, - delay_peak_detector.get(), - tick_timer.get())), + delay_peak_detector( + new DelayPeakDetector(tick_timer.get(), config.enable_rtx_handling)), + delay_manager(DelayManager::Create(config.max_packets_in_buffer, + config.min_delay_ms, + config.enable_rtx_handling, + delay_peak_detector.get(), + tick_timer.get(), + stats.get())), dtmf_buffer(new DtmfBuffer(config.sample_rate_hz)), dtmf_tone_generator(new DtmfToneGenerator), packet_buffer( @@ -95,6 +100,7 @@ expand_factory_(std::move(deps.expand_factory)), accelerate_factory_(std::move(deps.accelerate_factory)), preemptive_expand_factory_(std::move(deps.preemptive_expand_factory)), + stats_(std::move(deps.stats)), last_mode_(kModeNormal), decoded_buffer_length_(kMaxFrameSize), decoded_buffer_(new int16_t[decoded_buffer_length_]), @@ -102,7 +108,6 @@ new_codec_(false), timestamp_(0), reset_decoder_(false), - ssrc_(0), first_packet_(true), enable_fast_accelerate_(config.enable_fast_accelerate), nack_enabled_(false), @@ -113,7 +118,8 @@ speech_expand_uma_logger_("WebRTC.Audio.SpeechExpandRatePercent", 10, // Report once every 10 s. tick_timer_.get()), - no_time_stretching_(config.for_test_no_time_stretching) { + no_time_stretching_(config.for_test_no_time_stretching), + enable_rtx_handling_(config.enable_rtx_handling) { RTC_LOG(LS_INFO) << "NetEq config: " << config.ToString(); int fs = config.sample_rate_hz; if (fs != 8000 && fs != 16000 && fs != 32000 && fs != 48000) { @@ -231,44 +237,10 @@ const std::vector<int> changed_payload_types = decoder_database_->SetCodecs(codecs); for (const int pt : changed_payload_types) { - packet_buffer_->DiscardPacketsWithPayloadType(pt, &stats_); + packet_buffer_->DiscardPacketsWithPayloadType(pt, stats_.get()); } } -int NetEqImpl::RegisterPayloadType(NetEqDecoder codec, - const std::string& name, - uint8_t rtp_payload_type) { - rtc::CritScope lock(&crit_sect_); - RTC_LOG(LS_VERBOSE) << "RegisterPayloadType " - << static_cast<int>(rtp_payload_type) << " " - << static_cast<int>(codec); - if (decoder_database_->RegisterPayload(rtp_payload_type, codec, name) != - DecoderDatabase::kOK) { - return kFail; - } - return kOK; -} - -int NetEqImpl::RegisterExternalDecoder(AudioDecoder* decoder, - NetEqDecoder codec, - const std::string& codec_name, - uint8_t rtp_payload_type) { - rtc::CritScope lock(&crit_sect_); - RTC_LOG(LS_VERBOSE) << "RegisterExternalDecoder " - << static_cast<int>(rtp_payload_type) << " " - << static_cast<int>(codec); - if (!decoder) { - RTC_LOG(LS_ERROR) << "Cannot register external decoder with NULL pointer"; - assert(false); - return kFail; - } - if (decoder_database_->InsertExternal(rtp_payload_type, codec, codec_name, - decoder) != DecoderDatabase::kOK) { - return kFail; - } - return kOK; -} - bool NetEqImpl::RegisterPayloadType(int rtp_payload_type, const SdpAudioFormat& audio_format) { RTC_LOG(LS_VERBOSE) << "NetEqImpl::RegisterPayloadType: payload type " @@ -283,7 +255,8 @@ rtc::CritScope lock(&crit_sect_); int ret = decoder_database_->Remove(rtp_payload_type); if (ret == DecoderDatabase::kOK || ret == DecoderDatabase::kDecoderNotFound) { - packet_buffer_->DiscardPacketsWithPayloadType(rtp_payload_type, &stats_); + packet_buffer_->DiscardPacketsWithPayloadType(rtp_payload_type, + stats_.get()); return kOK; } return kFail; @@ -312,6 +285,19 @@ return false; } +bool NetEqImpl::SetBaseMinimumDelayMs(int delay_ms) { + rtc::CritScope lock(&crit_sect_); + if (delay_ms >= 0 && delay_ms <= 10000) { + return delay_manager_->SetBaseMinimumDelay(delay_ms); + } + return false; +} + +int NetEqImpl::GetBaseMinimumDelayMs() const { + rtc::CritScope lock(&crit_sect_); + return delay_manager_->GetBaseMinimumDelay(); +} + int NetEqImpl::TargetDelayMs() const { rtc::CritScope lock(&crit_sect_); RTC_DCHECK(delay_manager_.get()); @@ -322,21 +308,6 @@ rtc::CheckedDivExact(fs_hz_, 1000); } -int NetEqImpl::CurrentDelayMs() const { - rtc::CritScope lock(&crit_sect_); - if (fs_hz_ == 0) - return 0; - // Sum up the samples in the packet buffer with the future length of the sync - // buffer, and divide the sum by the sample rate. - const size_t delay_samples = - packet_buffer_->NumSamplesInBuffer(decoder_frame_length_) + - sync_buffer_->FutureLength(); - // The division below will truncate. - const int delay_ms = - static_cast<int>(delay_samples) / rtc::CheckedDivExact(fs_hz_, 1000); - return delay_ms; -} - int NetEqImpl::FilteredCurrentDelayMs() const { rtc::CritScope lock(&crit_sect_); // Calculate the filtered packet buffer level in samples. The value from @@ -363,20 +334,21 @@ assert(decision_logic_.get()); const int ms_per_packet = rtc::dchecked_cast<int>( decision_logic_->packet_length_samples() / (fs_hz_ / 1000)); - stats_.PopulateDelayManagerStats(ms_per_packet, *delay_manager_.get(), stats); - stats_.GetNetworkStatistics(fs_hz_, total_samples_in_buffers, - decoder_frame_length_, stats); + stats_->PopulateDelayManagerStats(ms_per_packet, *delay_manager_.get(), + stats); + stats_->GetNetworkStatistics(fs_hz_, total_samples_in_buffers, + decoder_frame_length_, stats); return 0; } NetEqLifetimeStatistics NetEqImpl::GetLifetimeStatistics() const { rtc::CritScope lock(&crit_sect_); - return stats_.GetLifetimeStatistics(); + return stats_->GetLifetimeStatistics(); } NetEqOperationsAndState NetEqImpl::GetOperationsAndState() const { rtc::CritScope lock(&crit_sect_); - auto result = stats_.GetOperationsAndState(); + auto result = stats_->GetOperationsAndState(); result.current_buffer_size_ms = (packet_buffer_->NumSamplesInBuffer(decoder_frame_length_) + sync_buffer_->FutureLength()) * @@ -417,27 +389,6 @@ return last_output_sample_rate_hz_; } -absl::optional<CodecInst> NetEqImpl::GetDecoder(int payload_type) const { - rtc::CritScope lock(&crit_sect_); - const DecoderDatabase::DecoderInfo* di = - decoder_database_->GetDecoderInfo(payload_type); - if (!di) { - return absl::nullopt; - } - - // Create a CodecInst with some fields set. The remaining fields are zeroed, - // but we tell MSan to consider them uninitialized. - CodecInst ci = {0}; - rtc::MsanMarkUninitialized(rtc::MakeArrayView(&ci, 1)); - ci.pltype = payload_type; - std::strncpy(ci.plname, di->get_name().c_str(), sizeof(ci.plname)); - ci.plname[sizeof(ci.plname) - 1] = '\0'; - ci.plfreq = di->IsRed() ? 8000 : di->SampleRateHz(); - AudioDecoder* const decoder = di->GetDecoder(); - ci.channels = decoder ? decoder->Channels() : 1; - return ci; -} - absl::optional<SdpAudioFormat> NetEqImpl::GetDecoderFormat( int payload_type) const { rtc::CritScope lock(&crit_sect_); @@ -446,7 +397,13 @@ if (!di) { return absl::nullopt; // Payload type not registered. } - return di->GetFormat(); + + SdpAudioFormat format = di->GetFormat(); + // TODO(solenberg): This is legacy but messed up - mixing RTP rate and SR. + format.clockrate_hz = di->IsRed() ? 8000 : di->SampleRateHz(); + const AudioDecoder* const decoder = di->GetDecoder(); + format.num_channels = decoder ? decoder->Channels() : 1; + return format; } void NetEqImpl::FlushBuffers() { @@ -518,6 +475,7 @@ RTC_LOG_F(LS_ERROR) << "payload is empty"; return kInvalidPointer; } + stats_->ReceivedPacket(); PacketList packet_list; // Insert packet in a packet list. @@ -533,8 +491,7 @@ return packet; }()); - bool update_sample_rate_and_channels = - first_packet_ || (rtp_header.ssrc != ssrc_); + bool update_sample_rate_and_channels = first_packet_; if (update_sample_rate_and_channels) { // Reset timestamp scaling. @@ -561,9 +518,6 @@ packet_buffer_->Flush(); dtmf_buffer_->Flush(); - // Store new SSRC. - ssrc_ = rtp_header.ssrc; - // Update audio buffer timestamp. sync_buffer_->IncreaseEndTimestamp(main_timestamp - timestamp_); @@ -707,7 +661,7 @@ // Insert packets in buffer. const int ret = packet_buffer_->InsertPacketList( &parsed_packet_list, *decoder_database_, ¤t_rtp_payload_type_, - ¤t_cng_rtp_payload_type_, &stats_); + ¤t_cng_rtp_payload_type_, stats_.get()); if (ret == PacketBuffer::kFlushed) { // Reset DSP timestamp etc. if packet buffer flushed. new_codec_ = true; @@ -777,9 +731,11 @@ } // Update statistics. - if ((int32_t)(main_timestamp - timestamp_) >= 0 && !new_codec_) { + if ((enable_rtx_handling_ || (int32_t)(main_timestamp - timestamp_) >= 0) && + !new_codec_) { // Only update statistics if incoming packet is not older than last played - // out packet, and if new codec flag is not set. + // out packet or RTX handling is enabled, and if new codec flag is not + // set. delay_manager_->Update(main_sequence_number, main_timestamp, fs_hz_); } } else if (delay_manager_->last_pack_cng_or_dtmf() == -1) { @@ -802,8 +758,8 @@ *muted = false; last_decoded_timestamps_.clear(); tick_timer_->Increment(); - stats_.IncreaseCounter(output_size_samples_, fs_hz_); - const auto lifetime_stats = stats_.GetLifetimeStatistics(); + stats_->IncreaseCounter(output_size_samples_, fs_hz_); + const auto lifetime_stats = stats_->GetLifetimeStatistics(); expand_uma_logger_.UpdateSampleCounter(lifetime_stats.concealed_samples, fs_hz_); speech_expand_uma_logger_.UpdateSampleCounter( @@ -823,7 +779,7 @@ : timestamp_scaler_->ToExternal(playout_timestamp_) - static_cast<uint32_t>(audio_frame->samples_per_channel_); audio_frame->num_channels_ = sync_buffer_->Channels(); - stats_.ExpandedNoiseSamples(output_size_samples_, false); + stats_->ExpandedNoiseSamples(output_size_samples_, false); *muted = true; return 0; } @@ -1032,7 +988,7 @@ if (!new_codec_) { const uint32_t five_seconds_samples = 5 * fs_hz_; packet_buffer_->DiscardOldPackets(end_timestamp, five_seconds_samples, - &stats_); + stats_.get()); } const Packet* packet = packet_buffer_->PeekNextPacket(); @@ -1052,12 +1008,14 @@ (end_timestamp >= packet->timestamp || end_timestamp + generated_noise_samples > packet->timestamp)) { // Don't use this packet, discard it. - if (packet_buffer_->DiscardNextPacket(&stats_) != PacketBuffer::kOK) { + if (packet_buffer_->DiscardNextPacket(stats_.get()) != + PacketBuffer::kOK) { assert(false); // Must be ok by design. } // Check buffer again. if (!new_codec_) { - packet_buffer_->DiscardOldPackets(end_timestamp, 5 * fs_hz_, &stats_); + packet_buffer_->DiscardOldPackets(end_timestamp, 5 * fs_hz_, + stats_.get()); } packet = packet_buffer_->PeekNextPacket(); } @@ -1139,7 +1097,7 @@ decision_logic_->SoftReset(); buffer_level_filter_->Reset(); delay_manager_->Reset(); - stats_.ResetMcu(); + stats_->ResetMcu(); } size_t required_samples = output_size_samples_; @@ -1244,7 +1202,7 @@ // if comfort noise is not played. If comfort noise was just played, // this adjustment of timestamp is only done to get back in sync with the // stream timestamp; no loss to report. - stats_.LostSamples(packet->timestamp - end_timestamp); + stats_->LostSamples(packet->timestamp - end_timestamp); } if (*operation != kRfc3389Cng) { @@ -1511,10 +1469,10 @@ // Update in-call and post-call statistics. if (expand_->MuteFactor(0) == 0) { // Expand generates only noise. - stats_.ExpandedNoiseSamplesCorrection(expand_length_correction); + stats_->ExpandedNoiseSamplesCorrection(expand_length_correction); } else { // Expansion generates more than only noise. - stats_.ExpandedVoiceSamplesCorrection(expand_length_correction); + stats_->ExpandedVoiceSamplesCorrection(expand_length_correction); } last_mode_ = kModeMerge; @@ -1555,12 +1513,12 @@ if (std::all_of(concealment_audio_.cbegin(), concealment_audio_.cend(), [](int16_t i) { return i == 0; })) { // Expand operation generates only noise. - stats_.ExpandedNoiseSamples(concealed_samples_per_channel, - is_new_concealment_event); + stats_->ExpandedNoiseSamples(concealed_samples_per_channel, + is_new_concealment_event); } else { // Expand operation generates more than only noise. - stats_.ExpandedVoiceSamples(concealed_samples_per_channel, - is_new_concealment_event); + stats_->ExpandedVoiceSamples(concealed_samples_per_channel, + is_new_concealment_event); } last_mode_ = kModeCodecPlc; if (!generated_noise_stopwatch_) { @@ -1581,10 +1539,10 @@ // Update in-call and post-call statistics. if (expand_->MuteFactor(0) == 0) { // Expand operation generates only noise. - stats_.ExpandedNoiseSamples(length, is_new_concealment_event); + stats_->ExpandedNoiseSamples(length, is_new_concealment_event); } else { // Expand operation generates more than only noise. - stats_.ExpandedVoiceSamples(length, is_new_concealment_event); + stats_->ExpandedVoiceSamples(length, is_new_concealment_event); } last_mode_ = kModeExpand; @@ -1633,7 +1591,7 @@ Accelerate::ReturnCodes return_code = accelerate_->Process(decoded_buffer, decoded_length, fast_accelerate, algorithm_buffer_.get(), &samples_removed); - stats_.AcceleratedSamples(samples_removed); + stats_->AcceleratedSamples(samples_removed); switch (return_code) { case Accelerate::kSuccess: last_mode_ = kModeAccelerateSuccess; @@ -1711,7 +1669,7 @@ PreemptiveExpand::ReturnCodes return_code = preemptive_expand_->Process( decoded_buffer, decoded_length, old_borrowed_samples_per_channel, algorithm_buffer_.get(), &samples_added); - stats_.PreemptiveExpandedSamples(samples_added); + stats_->PreemptiveExpandedSamples(samples_added); switch (return_code) { case PreemptiveExpand::kSuccess: last_mode_ = kModePreemptiveExpandSuccess; @@ -1926,7 +1884,7 @@ return -1; } const uint64_t waiting_time_ms = packet->waiting_time->ElapsedMs(); - stats_.StoreWaitingTime(waiting_time_ms); + stats_->StoreWaitingTime(waiting_time_ms); RTC_DCHECK(!packet->empty()); if (first_packet) { @@ -1950,7 +1908,7 @@ packet_duration = packet->frame->Duration(); // TODO(ossu): Is this the correct way to track Opus FEC packets? if (packet->priority.codec_level > 0) { - stats_.SecondaryDecodedSamples( + stats_->SecondaryDecodedSamples( rtc::dchecked_cast<int>(packet_duration)); } } else if (!has_cng_packet) { @@ -1966,7 +1924,7 @@ } extracted_samples = packet->timestamp - first_timestamp + packet_duration; - stats_.JitterBufferDelay(extracted_samples, waiting_time_ms); + stats_->JitterBufferDelay(packet_duration, waiting_time_ms); packet_list->push_back(std::move(*packet)); // Store packet in list. packet = absl::nullopt; // Ensure it's never used after the move. @@ -1978,13 +1936,14 @@ !has_cng_packet) { int16_t seq_no_diff = next_packet->sequence_number - prev_sequence_number; size_t ts_diff = next_packet->timestamp - prev_timestamp; - if (seq_no_diff == 1 || - (seq_no_diff == 0 && ts_diff == decoder_frame_length_)) { + if ((seq_no_diff == 1 || seq_no_diff == 0) && + ts_diff <= packet_duration) { // The next sequence number is available, or the next part of a packet // that was split into pieces upon insertion. next_packet_available = true; } prev_sequence_number = next_packet->sequence_number; + prev_timestamp = next_packet->timestamp; } } while (extracted_samples < required_samples && next_packet_available); @@ -1993,7 +1952,7 @@ // we could end up in the situation where we never decode anything, since // all incoming packets are considered too old but the buffer will also // never be flooded and flushed. - packet_buffer_->DiscardAllOldPackets(timestamp_, &stats_); + packet_buffer_->DiscardAllOldPackets(timestamp_, stats_.get()); } return rtc::dchecked_cast<int>(extracted_samples); @@ -2003,7 +1962,7 @@ // Delete objects and create new ones. expand_.reset(expand_factory_->Create(background_noise_.get(), sync_buffer_.get(), &random_vector_, - &stats_, fs_hz, channels)); + stats_.get(), fs_hz, channels)); merge_.reset(new Merge(fs_hz, channels, expand_.get(), sync_buffer_.get())); }
diff --git a/modules/audio_coding/neteq/neteq_impl.h b/modules/audio_coding/neteq/neteq_impl.h index 525ae61..34a5c71 100644 --- a/modules/audio_coding/neteq/neteq_impl.h +++ b/modules/audio_coding/neteq/neteq_impl.h
@@ -24,8 +24,8 @@ #include "modules/audio_coding/neteq/random_vector.h" #include "modules/audio_coding/neteq/statistics_calculator.h" #include "modules/audio_coding/neteq/tick_timer.h" -#include "rtc_base/constructormagic.h" -#include "rtc_base/criticalsection.h" +#include "rtc_base/constructor_magic.h" +#include "rtc_base/critical_section.h" #include "rtc_base/thread_annotations.h" namespace webrtc { @@ -99,6 +99,7 @@ ~Dependencies(); std::unique_ptr<TickTimer> tick_timer; + std::unique_ptr<StatisticsCalculator> stats; std::unique_ptr<BufferLevelFilter> buffer_level_filter; std::unique_ptr<DecoderDatabase> decoder_database; std::unique_ptr<DelayPeakDetector> delay_peak_detector; @@ -137,15 +138,6 @@ void SetCodecs(const std::map<int, SdpAudioFormat>& codecs) override; - int RegisterPayloadType(NetEqDecoder codec, - const std::string& codec_name, - uint8_t rtp_payload_type) override; - - int RegisterExternalDecoder(AudioDecoder* decoder, - NetEqDecoder codec, - const std::string& codec_name, - uint8_t rtp_payload_type) override; - bool RegisterPayloadType(int rtp_payload_type, const SdpAudioFormat& audio_format) override; @@ -159,9 +151,11 @@ bool SetMaximumDelay(int delay_ms) override; - int TargetDelayMs() const override; + bool SetBaseMinimumDelayMs(int delay_ms) override; - int CurrentDelayMs() const override; + int GetBaseMinimumDelayMs() const override; + + int TargetDelayMs() const override; int FilteredCurrentDelayMs() const override; @@ -184,8 +178,6 @@ int last_output_sample_rate_hz() const override; - absl::optional<CodecInst> GetDecoder(int payload_type) const override; - absl::optional<SdpAudioFormat> GetDecoderFormat( int payload_type) const override; @@ -370,6 +362,7 @@ RTC_GUARDED_BY(crit_sect_); const std::unique_ptr<PreemptiveExpandFactory> preemptive_expand_factory_ RTC_GUARDED_BY(crit_sect_); + const std::unique_ptr<StatisticsCalculator> stats_ RTC_GUARDED_BY(crit_sect_); std::unique_ptr<BackgroundNoise> background_noise_ RTC_GUARDED_BY(crit_sect_); std::unique_ptr<DecisionLogic> decision_logic_ RTC_GUARDED_BY(crit_sect_); @@ -384,7 +377,6 @@ RTC_GUARDED_BY(crit_sect_); RandomVector random_vector_ RTC_GUARDED_BY(crit_sect_); std::unique_ptr<ComfortNoise> comfort_noise_ RTC_GUARDED_BY(crit_sect_); - StatisticsCalculator stats_ RTC_GUARDED_BY(crit_sect_); int fs_hz_ RTC_GUARDED_BY(crit_sect_); int fs_mult_ RTC_GUARDED_BY(crit_sect_); int last_output_sample_rate_hz_ RTC_GUARDED_BY(crit_sect_); @@ -401,7 +393,6 @@ absl::optional<uint8_t> current_rtp_payload_type_ RTC_GUARDED_BY(crit_sect_); absl::optional<uint8_t> current_cng_rtp_payload_type_ RTC_GUARDED_BY(crit_sect_); - uint32_t ssrc_ RTC_GUARDED_BY(crit_sect_); bool first_packet_ RTC_GUARDED_BY(crit_sect_); bool enable_fast_accelerate_ RTC_GUARDED_BY(crit_sect_); std::unique_ptr<NackTracker> nack_ RTC_GUARDED_BY(crit_sect_); @@ -416,6 +407,7 @@ ExpandUmaLogger speech_expand_uma_logger_ RTC_GUARDED_BY(crit_sect_); bool no_time_stretching_ RTC_GUARDED_BY(crit_sect_); // Only used for test. rtc::BufferT<int16_t> concealment_audio_ RTC_GUARDED_BY(crit_sect_); + const bool enable_rtx_handling_ RTC_GUARDED_BY(crit_sect_); private: RTC_DISALLOW_COPY_AND_ASSIGN(NetEqImpl);
diff --git a/modules/audio_coding/neteq/neteq_impl_unittest.cc b/modules/audio_coding/neteq/neteq_impl_unittest.cc index 0e087c8..5875493 100644 --- a/modules/audio_coding/neteq/neteq_impl_unittest.cc +++ b/modules/audio_coding/neteq/neteq_impl_unittest.cc
@@ -10,10 +10,11 @@ #include <memory> +#include "absl/memory/memory.h" #include "api/audio_codecs/builtin_audio_decoder_factory.h" -#include "common_types.h" // NOLINT(build/include) #include "modules/audio_coding/neteq/accelerate.h" #include "modules/audio_coding/neteq/expand.h" +#include "modules/audio_coding/neteq/histogram.h" #include "modules/audio_coding/neteq/include/neteq.h" #include "modules/audio_coding/neteq/mock/mock_buffer_level_filter.h" #include "modules/audio_coding/neteq/mock/mock_decoder_database.h" @@ -25,9 +26,12 @@ #include "modules/audio_coding/neteq/mock/mock_red_payload_splitter.h" #include "modules/audio_coding/neteq/neteq_impl.h" #include "modules/audio_coding/neteq/preemptive_expand.h" +#include "modules/audio_coding/neteq/statistics_calculator.h" #include "modules/audio_coding/neteq/sync_buffer.h" #include "modules/audio_coding/neteq/timestamp_scaler.h" #include "rtc_base/numerics/safe_conversions.h" +#include "test/audio_decoder_proxy_factory.h" +#include "test/function_audio_decoder_factory.h" #include "test/gmock.h" #include "test/gtest.h" #include "test/mock_audio_decoder.h" @@ -59,8 +63,10 @@ protected: NetEqImplTest() { config_.sample_rate_hz = 8000; } - void CreateInstance() { - NetEqImpl::Dependencies deps(config_, CreateBuiltinAudioDecoderFactory()); + void CreateInstance( + const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) { + ASSERT_TRUE(decoder_factory); + NetEqImpl::Dependencies deps(config_, decoder_factory); // Get a local pointer to NetEq's TickTimer object. tick_timer_ = deps.tick_timer.get(); @@ -83,7 +89,7 @@ if (use_mock_delay_peak_detector_) { std::unique_ptr<MockDelayPeakDetector> mock( - new MockDelayPeakDetector(tick_timer_)); + new MockDelayPeakDetector(tick_timer_, config_.enable_rtx_handling)); mock_delay_peak_detector_ = mock.get(); EXPECT_CALL(*mock_delay_peak_detector_, Reset()).Times(1); deps.delay_peak_detector = std::move(mock); @@ -92,8 +98,10 @@ if (use_mock_delay_manager_) { std::unique_ptr<MockDelayManager> mock(new MockDelayManager( - config_.max_packets_in_buffer, config_.min_delay_ms, - delay_peak_detector_, tick_timer_)); + config_.max_packets_in_buffer, config_.min_delay_ms, 1020054733, + DelayManager::HistogramMode::INTER_ARRIVAL_TIME, + config_.enable_rtx_handling, delay_peak_detector_, tick_timer_, + deps.stats.get(), absl::make_unique<Histogram>(50, 32745))); mock_delay_manager_ = mock.get(); EXPECT_CALL(*mock_delay_manager_, set_streaming_mode(false)).Times(1); deps.delay_manager = std::move(mock); @@ -137,6 +145,8 @@ ASSERT_TRUE(neteq_ != NULL); } + void CreateInstance() { CreateInstance(CreateBuiltinAudioDecoderFactory()); } + void UseNoMocks() { ASSERT_TRUE(neteq_ == NULL) << "Must call UseNoMocks before CreateInstance"; use_mock_buffer_level_filter_ = false; @@ -173,7 +183,7 @@ } } - void TestDtmfPacket(NetEqDecoder decoder_type) { + void TestDtmfPacket(int sample_rate_hz) { const size_t kPayloadLength = 4; const uint8_t kPayloadType = 110; const uint32_t kReceiveTime = 17; @@ -189,8 +199,8 @@ rtp_header.timestamp = 0x12345678; rtp_header.ssrc = 0x87654321; - EXPECT_EQ(NetEq::kOK, neteq_->RegisterPayloadType( - decoder_type, "telephone-event", kPayloadType)); + EXPECT_TRUE(neteq_->RegisterPayloadType( + kPayloadType, SdpAudioFormat("telephone-event", sample_rate_hz, 1))); // Insert first packet. EXPECT_EQ(NetEq::kOK, @@ -257,16 +267,6 @@ delete neteq; } -TEST_F(NetEqImplTest, RegisterPayloadTypeNetEqDecoder) { - CreateInstance(); - uint8_t rtp_payload_type = 0; - NetEqDecoder codec_type = NetEqDecoder::kDecoderPCMu; - const std::string kCodecName = "Robert\'); DROP TABLE Students;"; - EXPECT_CALL(*mock_decoder_database_, - RegisterPayload(rtp_payload_type, codec_type, kCodecName)); - neteq_->RegisterPayloadType(codec_type, kCodecName, rtp_payload_type); -} - TEST_F(NetEqImplTest, RegisterPayloadType) { CreateInstance(); constexpr int rtp_payload_type = 0; @@ -335,8 +335,8 @@ *dec = std::move(mock_decoder); })); - DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu, absl::nullopt, - mock_decoder_factory); + DecoderDatabase::DecoderInfo info(SdpAudioFormat("pcmu", 8000, 1), + absl::nullopt, mock_decoder_factory); // Expectations for decoder database. EXPECT_CALL(*mock_decoder_database_, GetDecoderInfo(kPayloadType)) @@ -405,8 +405,8 @@ rtp_header.timestamp = 0x12345678; rtp_header.ssrc = 0x87654321; - EXPECT_EQ(NetEq::kOK, neteq_->RegisterPayloadType( - NetEqDecoder::kDecoderPCM16B, "", kPayloadType)); + EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType, + SdpAudioFormat("l16", 8000, 1))); // Insert packets. The buffer should not flush. for (size_t i = 1; i <= config_.max_packets_in_buffer; ++i) { @@ -428,27 +428,24 @@ } TEST_F(NetEqImplTest, TestDtmfPacketAVT) { - TestDtmfPacket(NetEqDecoder::kDecoderAVT); + TestDtmfPacket(8000); } TEST_F(NetEqImplTest, TestDtmfPacketAVT16kHz) { - TestDtmfPacket(NetEqDecoder::kDecoderAVT16kHz); + TestDtmfPacket(16000); } TEST_F(NetEqImplTest, TestDtmfPacketAVT32kHz) { - TestDtmfPacket(NetEqDecoder::kDecoderAVT32kHz); + TestDtmfPacket(32000); } TEST_F(NetEqImplTest, TestDtmfPacketAVT48kHz) { - TestDtmfPacket(NetEqDecoder::kDecoderAVT48kHz); + TestDtmfPacket(48000); } // This test verifies that timestamps propagate from the incoming packets // through to the sync buffer and to the playout timestamp. TEST_F(NetEqImplTest, VerifyTimestampPropagation) { - UseNoMocks(); - CreateInstance(); - const uint8_t kPayloadType = 17; // Just an arbitrary number. const uint32_t kReceiveTime = 17; // Value doesn't matter for this test. const int kSampleRateHz = 8000; @@ -494,9 +491,14 @@ int16_t next_value_; } decoder_; - EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder( - &decoder_, NetEqDecoder::kDecoderPCM16B, - "dummy name", kPayloadType)); + rtc::scoped_refptr<AudioDecoderFactory> decoder_factory = + new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&decoder_); + + UseNoMocks(); + CreateInstance(decoder_factory); + + EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType, + SdpAudioFormat("L16", 8000, 1))); // Insert one packet. EXPECT_EQ(NetEq::kOK, @@ -541,7 +543,11 @@ TEST_F(NetEqImplTest, ReorderedPacket) { UseNoMocks(); - CreateInstance(); + // Create a mock decoder object. + MockAudioDecoder mock_decoder; + + CreateInstance( + new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&mock_decoder)); const uint8_t kPayloadType = 17; // Just an arbitrary number. const uint32_t kReceiveTime = 17; // Value doesn't matter for this test. @@ -556,8 +562,6 @@ rtp_header.timestamp = 0x12345678; rtp_header.ssrc = 0x87654321; - // Create a mock decoder object. - MockAudioDecoder mock_decoder; EXPECT_CALL(mock_decoder, Reset()).WillRepeatedly(Return()); EXPECT_CALL(mock_decoder, SampleRateHz()) .WillRepeatedly(Return(kSampleRateHz)); @@ -575,9 +579,8 @@ dummy_output + kPayloadLengthSamples), SetArgPointee<4>(AudioDecoder::kSpeech), Return(rtc::checked_cast<int>(kPayloadLengthSamples)))); - EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder( - &mock_decoder, NetEqDecoder::kDecoderPCM16B, - "dummy name", kPayloadType)); + EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType, + SdpAudioFormat("L16", 8000, 1))); // Insert one packet. EXPECT_EQ(NetEq::kOK, @@ -662,8 +665,8 @@ EXPECT_EQ(AudioFrame::kPLC, output.speech_type_); // Register the payload type. - EXPECT_EQ(NetEq::kOK, neteq_->RegisterPayloadType( - NetEqDecoder::kDecoderPCM16B, "", kPayloadType)); + EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType, + SdpAudioFormat("l16", 8000, 1))); // Insert 10 packets. for (size_t i = 0; i < 10; ++i) { @@ -689,7 +692,10 @@ // internal CNG mode properly. TEST_F(NetEqImplTest, CodecInternalCng) { UseNoMocks(); - CreateInstance(); + // Create a mock decoder object. + MockAudioDecoder mock_decoder; + CreateInstance( + new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&mock_decoder)); const uint8_t kPayloadType = 17; // Just an arbitrary number. const uint32_t kReceiveTime = 17; // Value doesn't matter for this test. @@ -706,8 +712,6 @@ rtp_header.timestamp = 0x12345678; rtp_header.ssrc = 0x87654321; - // Create a mock decoder object. - MockAudioDecoder mock_decoder; EXPECT_CALL(mock_decoder, Reset()).WillRepeatedly(Return()); EXPECT_CALL(mock_decoder, SampleRateHz()) .WillRepeatedly(Return(kSampleRateKhz * 1000)); @@ -751,9 +755,8 @@ SetArgPointee<4>(AudioDecoder::kSpeech), Return(rtc::checked_cast<int>(kPayloadLengthSamples)))); - EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder( - &mock_decoder, NetEqDecoder::kDecoderOpus, - "dummy name", kPayloadType)); + EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType, + SdpAudioFormat("opus", 48000, 2))); // Insert one packet (decoder will return speech). EXPECT_EQ(NetEq::kOK, @@ -834,7 +837,10 @@ TEST_F(NetEqImplTest, UnsupportedDecoder) { UseNoMocks(); - CreateInstance(); + ::testing::NiceMock<MockAudioDecoder> decoder; + + CreateInstance( + new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&decoder)); static const size_t kNetEqMaxFrameSize = 5760; // 120 ms @ 48 kHz. static const size_t kChannels = 2; @@ -853,8 +859,6 @@ rtp_header.timestamp = 0x12345678; rtp_header.ssrc = 0x87654321; - ::testing::NiceMock<MockAudioDecoder> decoder; - const uint8_t kFirstPayloadValue = 1; const uint8_t kSecondPayloadValue = 2; @@ -886,9 +890,8 @@ EXPECT_CALL(decoder, Channels()) .WillRepeatedly(Return(kChannels)); - EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder( - &decoder, NetEqDecoder::kDecoderPCM16B, - "dummy name", kPayloadType)); + EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType, + SdpAudioFormat("L16", 8000, 1))); // Insert one packet. payload[0] = kFirstPayloadValue; // This will make Decode() fail. @@ -945,8 +948,8 @@ rtp_header.timestamp = 0x12345678; rtp_header.ssrc = 0x87654321; - EXPECT_EQ(NetEq::kOK, neteq_->RegisterPayloadType( - NetEqDecoder::kDecoderPCM16B, "", kPayloadType)); + EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType, + SdpAudioFormat("l16", 8000, 1))); // Insert packets until the buffer flushes. for (size_t i = 0; i <= config_.max_packets_in_buffer; ++i) { @@ -965,7 +968,11 @@ TEST_F(NetEqImplTest, DecodedPayloadTooShort) { UseNoMocks(); - CreateInstance(); + // Create a mock decoder object. + MockAudioDecoder mock_decoder; + + CreateInstance( + new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&mock_decoder)); const uint8_t kPayloadType = 17; // Just an arbitrary number. const uint32_t kReceiveTime = 17; // Value doesn't matter for this test. @@ -980,8 +987,6 @@ rtp_header.timestamp = 0x12345678; rtp_header.ssrc = 0x87654321; - // Create a mock decoder object. - MockAudioDecoder mock_decoder; EXPECT_CALL(mock_decoder, Reset()).WillRepeatedly(Return()); EXPECT_CALL(mock_decoder, SampleRateHz()) .WillRepeatedly(Return(kSampleRateHz)); @@ -1001,9 +1006,8 @@ dummy_output + kPayloadLengthSamples - 5), SetArgPointee<4>(AudioDecoder::kSpeech), Return(rtc::checked_cast<int>(kPayloadLengthSamples - 5)))); - EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder( - &mock_decoder, NetEqDecoder::kDecoderPCM16B, - "dummy name", kPayloadType)); + EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType, + SdpAudioFormat("L16", 8000, 1))); // Insert one packet. EXPECT_EQ(NetEq::kOK, @@ -1026,7 +1030,11 @@ // This test checks the behavior of NetEq when audio decoder fails. TEST_F(NetEqImplTest, DecodingError) { UseNoMocks(); - CreateInstance(); + // Create a mock decoder object. + MockAudioDecoder mock_decoder; + + CreateInstance( + new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&mock_decoder)); const uint8_t kPayloadType = 17; // Just an arbitrary number. const uint32_t kReceiveTime = 17; // Value doesn't matter for this test. @@ -1047,8 +1055,6 @@ rtp_header.timestamp = 0x12345678; rtp_header.ssrc = 0x87654321; - // Create a mock decoder object. - MockAudioDecoder mock_decoder; EXPECT_CALL(mock_decoder, Reset()).WillRepeatedly(Return()); EXPECT_CALL(mock_decoder, SampleRateHz()) .WillRepeatedly(Return(kSampleRateHz)); @@ -1094,9 +1100,8 @@ Return(rtc::checked_cast<int>(kFrameLengthSamples)))); } - EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder( - &mock_decoder, NetEqDecoder::kDecoderPCM16B, - "dummy name", kPayloadType)); + EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType, + SdpAudioFormat("L16", 8000, 1))); // Insert packets. for (int i = 0; i < 6; ++i) { @@ -1140,7 +1145,11 @@ // This test checks the behavior of NetEq when audio decoder fails during CNG. TEST_F(NetEqImplTest, DecodingErrorDuringInternalCng) { UseNoMocks(); - CreateInstance(); + + // Create a mock decoder object. + MockAudioDecoder mock_decoder; + CreateInstance( + new rtc::RefCountedObject<test::AudioDecoderProxyFactory>(&mock_decoder)); const uint8_t kPayloadType = 17; // Just an arbitrary number. const uint32_t kReceiveTime = 17; // Value doesn't matter for this test. @@ -1161,8 +1170,6 @@ rtp_header.timestamp = 0x12345678; rtp_header.ssrc = 0x87654321; - // Create a mock decoder object. - MockAudioDecoder mock_decoder; EXPECT_CALL(mock_decoder, Reset()).WillRepeatedly(Return()); EXPECT_CALL(mock_decoder, SampleRateHz()) .WillRepeatedly(Return(kSampleRateHz)); @@ -1204,9 +1211,8 @@ Return(rtc::checked_cast<int>(kFrameLengthSamples)))); } - EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder( - &mock_decoder, NetEqDecoder::kDecoderPCM16B, - "dummy name", kPayloadType)); + EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType, + SdpAudioFormat("l16", 8000, 1))); // Insert 2 packets. This will make netEq into codec internal CNG mode. for (int i = 0; i < 2; ++i) { @@ -1261,6 +1267,34 @@ EXPECT_EQ(1u, tick_timer_->ticks()); } +TEST_F(NetEqImplTest, SetBaseMinimumDelay) { + UseNoMocks(); + use_mock_delay_manager_ = true; + CreateInstance(); + + EXPECT_CALL(*mock_delay_manager_, SetBaseMinimumDelay(_)) + .WillOnce(Return(true)) + .WillOnce(Return(false)); + + const int delay_ms = 200; + + EXPECT_EQ(true, neteq_->SetBaseMinimumDelayMs(delay_ms)); + EXPECT_EQ(false, neteq_->SetBaseMinimumDelayMs(delay_ms)); +} + +TEST_F(NetEqImplTest, GetBaseMinimumDelayMs) { + UseNoMocks(); + use_mock_delay_manager_ = true; + CreateInstance(); + + const int delay_ms = 200; + + EXPECT_CALL(*mock_delay_manager_, GetBaseMinimumDelay()) + .WillOnce(Return(delay_ms)); + + EXPECT_EQ(delay_ms, neteq_->GetBaseMinimumDelayMs()); +} + TEST_F(NetEqImplTest, TargetDelayMs) { UseNoMocks(); use_mock_delay_manager_ = true; @@ -1289,6 +1323,43 @@ neteq_->InsertEmptyPacket(rtp_header); } +TEST_F(NetEqImplTest, EnableRtxHandling) { + UseNoMocks(); + use_mock_delay_manager_ = true; + config_.enable_rtx_handling = true; + CreateInstance(); + EXPECT_CALL(*mock_delay_manager_, BufferLimits(_, _)) + .Times(1) + .WillOnce(DoAll(SetArgPointee<0>(0), SetArgPointee<1>(0))); + + const int kPayloadLengthSamples = 80; + const size_t kPayloadLengthBytes = 2 * kPayloadLengthSamples; // PCM 16-bit. + const uint8_t kPayloadType = 17; // Just an arbitrary number. + const uint32_t kReceiveTime = 17; + uint8_t payload[kPayloadLengthBytes] = {0}; + RTPHeader rtp_header; + rtp_header.payloadType = kPayloadType; + rtp_header.sequenceNumber = 0x1234; + rtp_header.timestamp = 0x12345678; + rtp_header.ssrc = 0x87654321; + + EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType, + SdpAudioFormat("l16", 8000, 1))); + EXPECT_EQ(NetEq::kOK, + neteq_->InsertPacket(rtp_header, payload, kReceiveTime)); + AudioFrame output; + bool muted; + EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted)); + + // Insert second packet that was sent before the first packet. + rtp_header.sequenceNumber -= 1; + rtp_header.timestamp -= kPayloadLengthSamples; + EXPECT_CALL(*mock_delay_manager_, + Update(rtp_header.sequenceNumber, rtp_header.timestamp, _)); + EXPECT_EQ(NetEq::kOK, + neteq_->InsertPacket(rtp_header, payload, kReceiveTime)); +} + class Decoder120ms : public AudioDecoder { public: Decoder120ms(int sample_rate_hz, SpeechType speech_type) @@ -1328,13 +1399,17 @@ void CreateInstanceNoMocks() { UseNoMocks(); - CreateInstance(); + CreateInstance(decoder_factory_); + EXPECT_TRUE(neteq_->RegisterPayloadType( + kPayloadType, SdpAudioFormat("opus", 48000, 2, {{"stereo", "1"}}))); } void CreateInstanceWithDelayManagerMock() { UseNoMocks(); use_mock_delay_manager_ = true; - CreateInstance(); + CreateInstance(decoder_factory_); + EXPECT_TRUE(neteq_->RegisterPayloadType( + kPayloadType, SdpAudioFormat("opus", 48000, 2, {{"stereo", "1"}}))); } uint32_t timestamp_diff_between_packets() const { @@ -1364,14 +1439,18 @@ } void Register120msCodec(AudioDecoder::SpeechType speech_type) { - decoder_.reset(new Decoder120ms(kSamplingFreq_, speech_type)); - ASSERT_EQ(2u, decoder_->Channels()); - EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder( - decoder_.get(), NetEqDecoder::kDecoderOpus_2ch, - "120ms codec", kPayloadType)); + const uint32_t sampling_freq = kSamplingFreq_; + decoder_factory_ = + new rtc::RefCountedObject<test::FunctionAudioDecoderFactory>( + [sampling_freq, speech_type]() { + std::unique_ptr<AudioDecoder> decoder = + absl::make_unique<Decoder120ms>(sampling_freq, speech_type); + RTC_CHECK_EQ(2, decoder->Channels()); + return decoder; + }); } - std::unique_ptr<Decoder120ms> decoder_; + rtc::scoped_refptr<AudioDecoderFactory> decoder_factory_; AudioFrame output_; const uint32_t kPayloadType = 17; const uint32_t kSamplingFreq_ = 48000; @@ -1379,8 +1458,8 @@ }; TEST_F(NetEqImplTest120ms, CodecInternalCng) { - CreateInstanceNoMocks(); Register120msCodec(AudioDecoder::kComfortNoise); + CreateInstanceNoMocks(); InsertPacket(first_timestamp()); GetFirstPacket(); @@ -1391,8 +1470,8 @@ } TEST_F(NetEqImplTest120ms, Normal) { - CreateInstanceNoMocks(); Register120msCodec(AudioDecoder::kSpeech); + CreateInstanceNoMocks(); InsertPacket(first_timestamp()); GetFirstPacket(); @@ -1401,9 +1480,9 @@ } TEST_F(NetEqImplTest120ms, Merge) { + Register120msCodec(AudioDecoder::kSpeech); CreateInstanceWithDelayManagerMock(); - Register120msCodec(AudioDecoder::kSpeech); InsertPacket(first_timestamp()); GetFirstPacket(); @@ -1420,8 +1499,8 @@ } TEST_F(NetEqImplTest120ms, Expand) { - CreateInstanceNoMocks(); Register120msCodec(AudioDecoder::kSpeech); + CreateInstanceNoMocks(); InsertPacket(first_timestamp()); GetFirstPacket(); @@ -1432,8 +1511,8 @@ } TEST_F(NetEqImplTest120ms, FastAccelerate) { - CreateInstanceWithDelayManagerMock(); Register120msCodec(AudioDecoder::kSpeech); + CreateInstanceWithDelayManagerMock(); InsertPacket(first_timestamp()); GetFirstPacket(); @@ -1450,8 +1529,8 @@ } TEST_F(NetEqImplTest120ms, PreemptiveExpand) { - CreateInstanceWithDelayManagerMock(); Register120msCodec(AudioDecoder::kSpeech); + CreateInstanceWithDelayManagerMock(); InsertPacket(first_timestamp()); GetFirstPacket(); @@ -1469,8 +1548,8 @@ } TEST_F(NetEqImplTest120ms, Accelerate) { - CreateInstanceWithDelayManagerMock(); Register120msCodec(AudioDecoder::kSpeech); + CreateInstanceWithDelayManagerMock(); InsertPacket(first_timestamp()); GetFirstPacket();
diff --git a/modules/audio_coding/neteq/neteq_network_stats_unittest.cc b/modules/audio_coding/neteq/neteq_network_stats_unittest.cc index 57fc682..79059b7 100644 --- a/modules/audio_coding/neteq/neteq_network_stats_unittest.cc +++ b/modules/audio_coding/neteq/neteq_network_stats_unittest.cc
@@ -10,10 +10,15 @@ #include <memory> +#include "absl/memory/memory.h" #include "api/audio/audio_frame.h" +#include "api/audio_codecs/audio_decoder.h" #include "common_types.h" // NOLINT(build/include) -#include "modules/audio_coding/neteq/tools/neteq_external_decoder_test.h" + +#include "modules/audio_coding/neteq/include/neteq.h" #include "modules/audio_coding/neteq/tools/rtp_generator.h" +#include "rtc_base/ref_counted_object.h" +#include "test/audio_decoder_proxy_factory.h" #include "test/gmock.h" namespace webrtc { @@ -118,10 +123,12 @@ bool fec_enabled_; }; -class NetEqNetworkStatsTest : public NetEqExternalDecoderTest { +class NetEqNetworkStatsTest { public: static const int kPayloadSizeByte = 30; static const int kFrameSizeMs = 20; + static const uint8_t kPayloadType = 95; + static const int kOutputLengthMs = 10; enum logic { kIgnore, @@ -146,17 +153,19 @@ NetEqNetworkStatistics stats_ref; }; - NetEqNetworkStatsTest(NetEqDecoder codec, - int sample_rate_hz, - MockAudioDecoder* decoder) - : NetEqExternalDecoderTest(codec, sample_rate_hz, decoder), - external_decoder_(decoder), - samples_per_ms_(sample_rate_hz / 1000), + NetEqNetworkStatsTest(const SdpAudioFormat& format, MockAudioDecoder* decoder) + : decoder_(decoder), + decoder_factory_( + new rtc::RefCountedObject<AudioDecoderProxyFactory>(decoder)), + samples_per_ms_(format.clockrate_hz / 1000), frame_size_samples_(kFrameSizeMs * samples_per_ms_), - rtp_generator_(new test::RtpGenerator(samples_per_ms_)), + rtp_generator_(new RtpGenerator(samples_per_ms_)), last_lost_time_(0), packet_loss_interval_(0xffffffff) { - Init(); + NetEq::Config config; + config.sample_rate_hz = format.clockrate_hz; + neteq_ = absl::WrapUnique(NetEq::Create(config, decoder_factory_)); + neteq_->RegisterPayloadType(kPayloadType, format); } bool Lost(uint32_t send_time) { @@ -180,7 +189,7 @@ // expects.x = 2, 'x' in current stats should > 'x' in |stats_ref| void CheckNetworkStatistics(NetEqNetworkStatsCheck expects) { NetEqNetworkStatistics stats; - neteq()->NetworkStatistics(&stats); + neteq_->NetworkStatistics(&stats); #define CHECK_NETEQ_NETWORK_STATS(x) \ switch (expects.x) { \ @@ -211,9 +220,6 @@ CHECK_NETEQ_NETWORK_STATS(added_zero_samples); #undef CHECK_NETEQ_NETWORK_STATS - - // Compare with CurrentDelay, which should be identical. - EXPECT_EQ(stats.current_buffer_size_ms, neteq()->CurrentDelayMs()); } void RunTest(int num_loops, NetEqNetworkStatsCheck expects) { @@ -230,18 +236,26 @@ kPayloadType, frame_size_samples_, &rtp_header_); if (!Lost(next_send_time)) { static const uint8_t payload[kPayloadSizeByte] = {0}; - InsertPacket(rtp_header_, payload, next_send_time); + ASSERT_EQ(NetEq::kOK, + neteq_->InsertPacket(rtp_header_, payload, next_send_time)); } } - GetOutputAudio(&output_frame_); + bool muted = true; + EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_frame_, &muted)); + ASSERT_FALSE(muted); + EXPECT_EQ(decoder_->Channels(), output_frame_.num_channels_); + EXPECT_EQ(static_cast<size_t>(kOutputLengthMs * samples_per_ms_), + output_frame_.samples_per_channel_); + EXPECT_EQ(48000, neteq_->last_output_sample_rate_hz()); + time_now += kOutputLengthMs; } CheckNetworkStatistics(expects); - neteq()->FlushBuffers(); + neteq_->FlushBuffers(); } void DecodeFecTest() { - external_decoder_->set_fec_enabled(false); + decoder_->set_fec_enabled(false); NetEqNetworkStatsCheck expects = {kIgnore, // current_buffer_size_ms kIgnore, // preferred_buffer_size_ms kIgnore, // jitter_peaks_found @@ -264,7 +278,7 @@ RunTest(50, expects); // Next we enable FEC. - external_decoder_->set_fec_enabled(true); + decoder_->set_fec_enabled(true); // If FEC fills in the lost packets, no packet loss will be counted. expects.stats_ref.packet_loss_rate = 0; expects.stats_ref.expand_rate = expects.stats_ref.speech_expand_rate = 0; @@ -296,10 +310,13 @@ } private: - MockAudioDecoder* external_decoder_; + MockAudioDecoder* decoder_; + rtc::scoped_refptr<AudioDecoderProxyFactory> decoder_factory_; + std::unique_ptr<NetEq> neteq_; + const int samples_per_ms_; const size_t frame_size_samples_; - std::unique_ptr<test::RtpGenerator> rtp_generator_; + std::unique_ptr<RtpGenerator> rtp_generator_; RTPHeader rtp_header_; uint32_t last_lost_time_; uint32_t packet_loss_interval_; @@ -308,21 +325,21 @@ TEST(NetEqNetworkStatsTest, DecodeFec) { MockAudioDecoder decoder(48000, 1); - NetEqNetworkStatsTest test(NetEqDecoder::kDecoderOpus, 48000, &decoder); + NetEqNetworkStatsTest test(SdpAudioFormat("opus", 48000, 2), &decoder); test.DecodeFecTest(); EXPECT_CALL(decoder, Die()).Times(1); } TEST(NetEqNetworkStatsTest, StereoDecodeFec) { MockAudioDecoder decoder(48000, 2); - NetEqNetworkStatsTest test(NetEqDecoder::kDecoderOpus, 48000, &decoder); + NetEqNetworkStatsTest test(SdpAudioFormat("opus", 48000, 2), &decoder); test.DecodeFecTest(); EXPECT_CALL(decoder, Die()).Times(1); } TEST(NetEqNetworkStatsTest, NoiseExpansionTest) { MockAudioDecoder decoder(48000, 1); - NetEqNetworkStatsTest test(NetEqDecoder::kDecoderOpus, 48000, &decoder); + NetEqNetworkStatsTest test(SdpAudioFormat("opus", 48000, 2), &decoder); test.NoiseExpansionTest(); EXPECT_CALL(decoder, Die()).Times(1); }
diff --git a/modules/audio_coding/neteq/neteq_stereo_unittest.cc b/modules/audio_coding/neteq/neteq_stereo_unittest.cc index 3f86944..d25e8d6 100644 --- a/modules/audio_coding/neteq/neteq_stereo_unittest.cc +++ b/modules/audio_coding/neteq/neteq_stereo_unittest.cc
@@ -17,14 +17,13 @@ #include "api/audio/audio_frame.h" #include "api/audio_codecs/builtin_audio_decoder_factory.h" -#include "common_types.h" // NOLINT(build/include) #include "modules/audio_coding/codecs/pcm16b/pcm16b.h" #include "modules/audio_coding/neteq/include/neteq.h" #include "modules/audio_coding/neteq/tools/input_audio_file.h" #include "modules/audio_coding/neteq/tools/rtp_generator.h" #include "rtc_base/strings/string_builder.h" #include "test/gtest.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" namespace webrtc { @@ -90,51 +89,12 @@ const std::string file_name = webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"); input_file_.reset(new test::InputAudioFile(file_name)); - NetEqDecoder mono_decoder; - NetEqDecoder multi_decoder; - switch (sample_rate_hz_) { - case 8000: - mono_decoder = NetEqDecoder::kDecoderPCM16B; - if (num_channels_ == 2) { - multi_decoder = NetEqDecoder::kDecoderPCM16B_2ch; - } else if (num_channels_ == 5) { - multi_decoder = NetEqDecoder::kDecoderPCM16B_5ch; - } else { - FAIL() << "Only 2 and 5 channels supported for 8000 Hz."; - } - break; - case 16000: - mono_decoder = NetEqDecoder::kDecoderPCM16Bwb; - if (num_channels_ == 2) { - multi_decoder = NetEqDecoder::kDecoderPCM16Bwb_2ch; - } else { - FAIL() << "More than 2 channels is not supported for 16000 Hz."; - } - break; - case 32000: - mono_decoder = NetEqDecoder::kDecoderPCM16Bswb32kHz; - if (num_channels_ == 2) { - multi_decoder = NetEqDecoder::kDecoderPCM16Bswb32kHz_2ch; - } else { - FAIL() << "More than 2 channels is not supported for 32000 Hz."; - } - break; - case 48000: - mono_decoder = NetEqDecoder::kDecoderPCM16Bswb48kHz; - if (num_channels_ == 2) { - multi_decoder = NetEqDecoder::kDecoderPCM16Bswb48kHz_2ch; - } else { - FAIL() << "More than 2 channels is not supported for 48000 Hz."; - } - break; - default: - FAIL() << "We shouldn't get here."; - } - ASSERT_EQ(NetEq::kOK, neteq_mono_->RegisterPayloadType(mono_decoder, "mono", - kPayloadTypeMono)); - ASSERT_EQ(NetEq::kOK, - neteq_->RegisterPayloadType(multi_decoder, "multi-channel", - kPayloadTypeMulti)); + RTC_CHECK_GE(num_channels_, 2); + ASSERT_TRUE(neteq_mono_->RegisterPayloadType( + kPayloadTypeMono, SdpAudioFormat("l16", sample_rate_hz_, 1))); + ASSERT_TRUE(neteq_->RegisterPayloadType( + kPayloadTypeMulti, + SdpAudioFormat("l16", sample_rate_hz_, num_channels_))); } virtual void TearDown() {} @@ -404,24 +364,24 @@ // Instantiate the tests. Each test is instantiated using the function above, // so that all different parameter combinations are tested. -INSTANTIATE_TEST_CASE_P(MultiChannel, - NetEqStereoTestNoJitter, - ::testing::ValuesIn(GetTestParameters())); +INSTANTIATE_TEST_SUITE_P(MultiChannel, + NetEqStereoTestNoJitter, + ::testing::ValuesIn(GetTestParameters())); -INSTANTIATE_TEST_CASE_P(MultiChannel, - NetEqStereoTestPositiveDrift, - ::testing::ValuesIn(GetTestParameters())); +INSTANTIATE_TEST_SUITE_P(MultiChannel, + NetEqStereoTestPositiveDrift, + ::testing::ValuesIn(GetTestParameters())); -INSTANTIATE_TEST_CASE_P(MultiChannel, - NetEqStereoTestNegativeDrift, - ::testing::ValuesIn(GetTestParameters())); +INSTANTIATE_TEST_SUITE_P(MultiChannel, + NetEqStereoTestNegativeDrift, + ::testing::ValuesIn(GetTestParameters())); -INSTANTIATE_TEST_CASE_P(MultiChannel, - NetEqStereoTestDelays, - ::testing::ValuesIn(GetTestParameters())); +INSTANTIATE_TEST_SUITE_P(MultiChannel, + NetEqStereoTestDelays, + ::testing::ValuesIn(GetTestParameters())); -INSTANTIATE_TEST_CASE_P(MultiChannel, - NetEqStereoTestLosses, - ::testing::ValuesIn(GetTestParameters())); +INSTANTIATE_TEST_SUITE_P(MultiChannel, + NetEqStereoTestLosses, + ::testing::ValuesIn(GetTestParameters())); } // namespace webrtc
diff --git a/modules/audio_coding/neteq/neteq_unittest.cc b/modules/audio_coding/neteq/neteq_unittest.cc index e8b5023..6c67ca8 100644 --- a/modules/audio_coding/neteq/neteq_unittest.cc +++ b/modules/audio_coding/neteq/neteq_unittest.cc
@@ -27,17 +27,18 @@ #include "modules/audio_coding/neteq/tools/neteq_packet_source_input.h" #include "modules/audio_coding/neteq/tools/neteq_test.h" #include "modules/audio_coding/neteq/tools/rtp_file_source.h" +#include "modules/include/module_common_types_public.h" #include "modules/rtp_rtcp/include/rtcp_statistics.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "rtc_base/ignore_wundef.h" -#include "rtc_base/messagedigest.h" +#include "rtc_base/message_digest.h" #include "rtc_base/numerics/safe_conversions.h" -#include "rtc_base/protobuf_utils.h" -#include "rtc_base/stringencode.h" +#include "rtc_base/string_encode.h" #include "rtc_base/strings/string_builder.h" #include "rtc_base/system/arch.h" #include "test/field_trial.h" #include "test/gtest.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" // This must come after test/gtest.h #include "rtc_base/flags.h" // NOLINT(build/include) @@ -129,10 +130,8 @@ void LoadDecoders(webrtc::NetEq* neteq) { ASSERT_EQ(true, neteq->RegisterPayloadType(0, SdpAudioFormat("pcmu", 8000, 1))); - // Use non-SdpAudioFormat argument when registering PCMa, so that we get test - // coverage for that as well. - ASSERT_EQ(0, neteq->RegisterPayloadType(webrtc::NetEqDecoder::kDecoderPCMa, - "pcma", 8)); + ASSERT_EQ(true, + neteq->RegisterPayloadType(8, SdpAudioFormat("pcma", 8000, 1))); #ifdef WEBRTC_CODEC_ILBC ASSERT_EQ(true, neteq->RegisterPayloadType(102, SdpAudioFormat("ilbc", 8000, 1))); @@ -208,7 +207,7 @@ neteq_unittest::NetEqNetworkStatistics stats; Convert(stats_raw, &stats); - ProtoString stats_string; + std::string stats_string; ASSERT_TRUE(stats.SerializeToString(&stats_string)); AddMessage(output_fp_, digest_.get(), stats_string); #else @@ -221,7 +220,7 @@ neteq_unittest::RtcpStatistics stats; Convert(stats_raw, &stats); - ProtoString stats_string; + std::string stats_string; ASSERT_TRUE(stats.SerializeToString(&stats_string)); AddMessage(output_fp_, digest_.get(), stats_string); #else @@ -258,7 +257,6 @@ NetEqDecodingTest(); virtual void SetUp(); virtual void TearDown(); - void SelectDecoders(NetEqDecoder* used_codec); void OpenInputFile(const std::string& rtp_file); void Process(); @@ -402,10 +400,6 @@ ASSERT_EQ(0, neteq_->NetworkStatistics(¤t_network_stats)); ASSERT_NO_FATAL_FAILURE(network_stats.AddResult(current_network_stats)); - // Compare with CurrentDelay, which should be identical. - EXPECT_EQ(current_network_stats.current_buffer_size_ms, - neteq_->CurrentDelayMs()); - // Verify that liftime stats and network stats report similar loss // concealment rates. auto lifetime_stats = neteq_->GetLifetimeStatistics(); @@ -464,16 +458,16 @@ webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp"); const std::string output_checksum = - PlatformChecksum("0c6dc227f781c81a229970f8fceda1a012498cba", - "15c4a2202877a414515e218bdb7992f0ad53e5af", "not used", - "0c6dc227f781c81a229970f8fceda1a012498cba", - "25fc4c863caa499aa447a5b8d059f5452cbcc500"); + PlatformChecksum("9652cee1d6771a9cbfda821ae1bbdb41b0dd4dee", + "54a7e32f163663c0af35bf70bf45cefc24ad62ef", "not used", + "9652cee1d6771a9cbfda821ae1bbdb41b0dd4dee", + "79496b0a1ef0a3824f3ee04789748a461bed643f"); const std::string network_stats_checksum = - PlatformChecksum("4b2370f5c794741d2a46be5c7935c66ef3fb53e9", - "e339cb2adf5ab3dfc21cb7205d670a34751e8336", "not used", - "4b2370f5c794741d2a46be5c7935c66ef3fb53e9", - "4b2370f5c794741d2a46be5c7935c66ef3fb53e9"); + PlatformChecksum("c59b1f9f282b6d8733cdff975e3c150ca4a47d51", + "bca95e565996a4ffd6e2ac15736e08843bdca93b", "not used", + "c59b1f9f282b6d8733cdff975e3c150ca4a47d51", + "c59b1f9f282b6d8733cdff975e3c150ca4a47d51"); DecodeAndCompare(input_rtp_file, output_checksum, network_stats_checksum, FLAG_gen_ref); @@ -1661,6 +1655,7 @@ int packets_sent = 0; int packets_received = 0; int expected_delay = 0; + uint64_t expected_emitted_count = 0; while (packets_received < kNumPackets) { // Insert packet. if (packets_sent < kNumPackets) { @@ -1684,6 +1679,7 @@ // number of samples that are sent for play out. int current_delay_ms = packets_delay * kPacketLenMs; expected_delay += current_delay_ms * kSamples; + expected_emitted_count += kSamples; } } @@ -1695,6 +1691,7 @@ // Check jitter buffer delay. NetEqLifetimeStatistics stats = neteq_->GetLifetimeStatistics(); EXPECT_EQ(expected_delay, static_cast<int>(stats.jitter_buffer_delay_ms)); + EXPECT_EQ(expected_emitted_count, stats.jitter_buffer_emitted_count); } TEST_F(NetEqDecodingTestFaxMode, TestJitterBufferDelayWithoutLoss) { @@ -1705,12 +1702,43 @@ TestJitterBufferDelay(true); } +TEST_F(NetEqDecodingTestFaxMode, TestJitterBufferDelayWithAcceleration) { + const int kPacketLenMs = 10; // All packets are of 10 ms size. + const size_t kSamples = kPacketLenMs * 16; + const size_t kPayloadBytes = kSamples * 2; + RTPHeader rtp_info; + rtp_info.ssrc = 0x1234; // Just an arbitrary SSRC. + rtp_info.payloadType = 94; // PCM16b WB codec. + rtp_info.markerBit = 0; + const uint8_t payload[kPayloadBytes] = {0}; + + neteq_->InsertPacket(rtp_info, payload, 0); + + bool muted; + neteq_->GetAudio(&out_frame_, &muted); + + rtp_info.sequenceNumber += 1; + rtp_info.timestamp += kSamples; + neteq_->InsertPacket(rtp_info, payload, 0); + rtp_info.sequenceNumber += 1; + rtp_info.timestamp += kSamples; + neteq_->InsertPacket(rtp_info, payload, 0); + + // We have two packets in the buffer and kAccelerate operation will + // extract 20 ms of data. + neteq_->GetAudio(&out_frame_, &muted, Operations::kAccelerate); + + // Check jitter buffer delay. + NetEqLifetimeStatistics stats = neteq_->GetLifetimeStatistics(); + EXPECT_EQ(10 * kSamples * 3, stats.jitter_buffer_delay_ms); + EXPECT_EQ(kSamples * 3, stats.jitter_buffer_emitted_count); +} + namespace test { TEST(NetEqNoTimeStretchingMode, RunTest) { NetEq::Config config; config.for_test_no_time_stretching = true; auto codecs = NetEqTest::StandardDecoderMap(); - NetEqTest::ExtDecoderMap ext_codecs; NetEqPacketSourceInput::RtpHeaderExtensionMap rtp_ext_map = { {1, kRtpExtensionAudioLevel}, {3, kRtpExtensionAbsoluteSendTime}, @@ -1724,8 +1752,8 @@ new TimeLimitedNetEqInput(std::move(input), 20000)); std::unique_ptr<AudioSink> output(new VoidAudioSink); NetEqTest::Callbacks callbacks; - NetEqTest test(config, codecs, ext_codecs, std::move(input_time_limit), - std::move(output), callbacks); + NetEqTest test(config, CreateBuiltinAudioDecoderFactory(), codecs, nullptr, + std::move(input_time_limit), std::move(output), callbacks); test.Run(); const auto stats = test.SimulationStats(); EXPECT_EQ(0, stats.accelerate_rate);
diff --git a/modules/audio_coding/neteq/normal.h b/modules/audio_coding/neteq/normal.h index 80451b5..2059c5a 100644 --- a/modules/audio_coding/neteq/normal.h +++ b/modules/audio_coding/neteq/normal.h
@@ -16,7 +16,7 @@ #include "modules/audio_coding/neteq/defines.h" #include "rtc_base/checks.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" #include "rtc_base/numerics/safe_conversions.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/packet_buffer.cc b/modules/audio_coding/neteq/packet_buffer.cc index 343763b..e90fadc 100644 --- a/modules/audio_coding/neteq/packet_buffer.cc +++ b/modules/audio_coding/neteq/packet_buffer.cc
@@ -287,6 +287,20 @@ return num_samples; } +size_t PacketBuffer::GetSpanSamples(size_t last_decoded_length) const { + if (buffer_.size() == 0) { + return 0; + } + + size_t span = buffer_.back().timestamp - buffer_.front().timestamp; + if (buffer_.back().frame && buffer_.back().frame->Duration() > 0) { + span += buffer_.back().frame->Duration(); + } else { + span += last_decoded_length; + } + return span; +} + bool PacketBuffer::ContainsDtxOrCngPacket( const DecoderDatabase* decoder_database) const { RTC_DCHECK(decoder_database);
diff --git a/modules/audio_coding/neteq/packet_buffer.h b/modules/audio_coding/neteq/packet_buffer.h index 0f5cd7f..0837027 100644 --- a/modules/audio_coding/neteq/packet_buffer.h +++ b/modules/audio_coding/neteq/packet_buffer.h
@@ -15,7 +15,7 @@ #include "modules/audio_coding/neteq/decoder_database.h" #include "modules/audio_coding/neteq/packet.h" #include "modules/include/module_common_types_public.h" // IsNewerTimestamp -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { @@ -121,6 +121,10 @@ // duplicate and redundant packets. virtual size_t NumSamplesInBuffer(size_t last_decoded_length) const; + // Returns the total duration in samples that the packets in the buffer spans + // across. + virtual size_t GetSpanSamples(size_t last_decoded_length) const; + // Returns true if the packet buffer contains any DTX or CNG packets. virtual bool ContainsDtxOrCngPacket( const DecoderDatabase* decoder_database) const;
diff --git a/modules/audio_coding/neteq/packet_buffer_unittest.cc b/modules/audio_coding/neteq/packet_buffer_unittest.cc index cb40d7d..7a381ee 100644 --- a/modules/audio_coding/neteq/packet_buffer_unittest.cc +++ b/modules/audio_coding/neteq/packet_buffer_unittest.cc
@@ -175,7 +175,7 @@ MockDecoderDatabase decoder_database; auto factory = CreateBuiltinAudioDecoderFactory(); - const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu, + const DecoderDatabase::DecoderInfo info(SdpAudioFormat("pcmu", 8000, 1), absl::nullopt, factory); EXPECT_CALL(decoder_database, GetDecoderInfo(0)) .WillRepeatedly(Return(&info)); @@ -220,11 +220,11 @@ MockDecoderDatabase decoder_database; auto factory = CreateBuiltinAudioDecoderFactory(); - const DecoderDatabase::DecoderInfo info0(NetEqDecoder::kDecoderPCMu, + const DecoderDatabase::DecoderInfo info0(SdpAudioFormat("pcmu", 8000, 1), absl::nullopt, factory); EXPECT_CALL(decoder_database, GetDecoderInfo(0)) .WillRepeatedly(Return(&info0)); - const DecoderDatabase::DecoderInfo info1(NetEqDecoder::kDecoderPCMa, + const DecoderDatabase::DecoderInfo info1(SdpAudioFormat("pcma", 8000, 1), absl::nullopt, factory); EXPECT_CALL(decoder_database, GetDecoderInfo(1)) .WillRepeatedly(Return(&info1)); @@ -407,7 +407,7 @@ MockDecoderDatabase decoder_database; auto factory = CreateBuiltinAudioDecoderFactory(); - const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu, + const DecoderDatabase::DecoderInfo info(SdpAudioFormat("pcmu", 8000, 1), absl::nullopt, factory); EXPECT_CALL(decoder_database, GetDecoderInfo(0)) .WillRepeatedly(Return(&info)); @@ -447,12 +447,12 @@ MockDecoderDatabase decoder_database; auto factory = CreateBuiltinAudioDecoderFactory(); - const DecoderDatabase::DecoderInfo info_cng(NetEqDecoder::kDecoderCNGnb, + const DecoderDatabase::DecoderInfo info_cng(SdpAudioFormat("cn", 8000, 1), absl::nullopt, factory); EXPECT_CALL(decoder_database, GetDecoderInfo(kCngPt)) .WillRepeatedly(Return(&info_cng)); - const DecoderDatabase::DecoderInfo info_speech(NetEqDecoder::kDecoderPCM16Bwb, - absl::nullopt, factory); + const DecoderDatabase::DecoderInfo info_speech( + SdpAudioFormat("l16", 16000, 1), absl::nullopt, factory); EXPECT_CALL(decoder_database, GetDecoderInfo(kSpeechPt)) .WillRepeatedly(Return(&info_speech)); @@ -549,7 +549,7 @@ list.push_back(gen.NextPacket(payload_len)); // Valid packet. MockDecoderDatabase decoder_database; auto factory = CreateBuiltinAudioDecoderFactory(); - const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu, + const DecoderDatabase::DecoderInfo info(SdpAudioFormat("pcmu", 8000, 1), absl::nullopt, factory); EXPECT_CALL(decoder_database, GetDecoderInfo(0)) .WillRepeatedly(Return(&info));
diff --git a/modules/audio_coding/neteq/post_decode_vad.h b/modules/audio_coding/neteq/post_decode_vad.h index 27d69a6..ca7cabf 100644 --- a/modules/audio_coding/neteq/post_decode_vad.h +++ b/modules/audio_coding/neteq/post_decode_vad.h
@@ -16,7 +16,7 @@ #include "api/audio_codecs/audio_decoder.h" #include "common_audio/vad/include/webrtc_vad.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/preemptive_expand.h b/modules/audio_coding/neteq/preemptive_expand.h index 0f7b3bc..e7d2bad 100644 --- a/modules/audio_coding/neteq/preemptive_expand.h +++ b/modules/audio_coding/neteq/preemptive_expand.h
@@ -15,7 +15,7 @@ #include <stdint.h> #include "modules/audio_coding/neteq/time_stretch.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/random_vector.h b/modules/audio_coding/neteq/random_vector.h index e8c7ba8..1d37600 100644 --- a/modules/audio_coding/neteq/random_vector.h +++ b/modules/audio_coding/neteq/random_vector.h
@@ -14,7 +14,7 @@ #include <stddef.h> #include <stdint.h> -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/red_payload_splitter.h b/modules/audio_coding/neteq/red_payload_splitter.h index 55063e7..c2e0a44 100644 --- a/modules/audio_coding/neteq/red_payload_splitter.h +++ b/modules/audio_coding/neteq/red_payload_splitter.h
@@ -12,7 +12,7 @@ #define MODULES_AUDIO_CODING_NETEQ_RED_PAYLOAD_SPLITTER_H_ #include "modules/audio_coding/neteq/packet.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/red_payload_splitter_unittest.cc b/modules/audio_coding/neteq/red_payload_splitter_unittest.cc index 52fc1ba..b4cd8d7 100644 --- a/modules/audio_coding/neteq/red_payload_splitter_unittest.cc +++ b/modules/audio_coding/neteq/red_payload_splitter_unittest.cc
@@ -18,7 +18,7 @@ #include <utility> // pair #include "api/audio_codecs/builtin_audio_decoder_factory.h" -#include "modules/audio_coding/neteq/mock/mock_decoder_database.h" +#include "modules/audio_coding/neteq/decoder_database.h" #include "modules/audio_coding/neteq/packet.h" #include "rtc_base/numerics/safe_conversions.h" #include "test/gtest.h" @@ -300,10 +300,11 @@ // do its job. DecoderDatabase decoder_database( new rtc::RefCountedObject<MockAudioDecoderFactory>, absl::nullopt); - decoder_database.RegisterPayload(0, NetEqDecoder::kDecoderCNGnb, "cng-nb"); - decoder_database.RegisterPayload(1, NetEqDecoder::kDecoderPCMu, "pcmu"); - decoder_database.RegisterPayload(2, NetEqDecoder::kDecoderAVT, "avt"); - decoder_database.RegisterPayload(3, NetEqDecoder::kDecoderILBC, "ilbc"); + decoder_database.RegisterPayload(0, SdpAudioFormat("cn", 8000, 1)); + decoder_database.RegisterPayload(1, SdpAudioFormat("pcmu", 8000, 1)); + decoder_database.RegisterPayload(2, + SdpAudioFormat("telephone-event", 8000, 1)); + decoder_database.RegisterPayload(3, SdpAudioFormat("ilbc", 8000, 1)); RedPayloadSplitter splitter; splitter.CheckRedPayloads(&packet_list, decoder_database); @@ -334,8 +335,8 @@ // do its job. DecoderDatabase decoder_database( new rtc::RefCountedObject<MockAudioDecoderFactory>, absl::nullopt); - decoder_database.RegisterPayload(kRedPayloadType, NetEqDecoder::kDecoderRED, - "red"); + decoder_database.RegisterPayload(kRedPayloadType, + SdpAudioFormat("red", 8000, 1)); RedPayloadSplitter splitter; splitter.CheckRedPayloads(&packet_list, decoder_database);
diff --git a/modules/audio_coding/neteq/statistics_calculator.cc b/modules/audio_coding/neteq/statistics_calculator.cc index 50521fb..a0e9bca 100644 --- a/modules/audio_coding/neteq/statistics_calculator.cc +++ b/modules/audio_coding/neteq/statistics_calculator.cc
@@ -216,7 +216,7 @@ } void StatisticsCalculator::PacketsDiscarded(size_t num_packets) { - discarded_packets_ += num_packets; + operations_and_state_.discarded_primary_packets += num_packets; } void StatisticsCalculator::SecondaryPacketsDiscarded(size_t num_packets) { @@ -246,6 +246,7 @@ void StatisticsCalculator::JitterBufferDelay(size_t num_samples, uint64_t waiting_time_ms) { lifetime_stats_.jitter_buffer_delay_ms += waiting_time_ms * num_samples; + lifetime_stats_.jitter_buffer_emitted_count += num_samples; } void StatisticsCalculator::SecondaryDecodedSamples(int num_samples) { @@ -257,6 +258,14 @@ buffer_full_counter_.RegisterSample(); } +void StatisticsCalculator::ReceivedPacket() { + ++lifetime_stats_.jitter_buffer_packets_received; +} + +void StatisticsCalculator::RelativePacketArrivalDelay(size_t delay_ms) { + lifetime_stats_.relative_packet_arrival_delay_ms += delay_ms; +} + void StatisticsCalculator::LogDelayedPacketOutageEvent(int num_samples, int fs_hz) { int outage_duration_ms = num_samples / (fs_hz / 1000);
diff --git a/modules/audio_coding/neteq/statistics_calculator.h b/modules/audio_coding/neteq/statistics_calculator.h index 49b74a0..cb92f37 100644 --- a/modules/audio_coding/neteq/statistics_calculator.h +++ b/modules/audio_coding/neteq/statistics_calculator.h
@@ -15,7 +15,7 @@ #include <string> #include "modules/audio_coding/neteq/include/neteq.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { @@ -83,9 +83,15 @@ // Reports that |num_samples| samples were decoded from secondary packets. void SecondaryDecodedSamples(int num_samples); - // Rerport that the packet buffer was flushed. + // Reports that the packet buffer was flushed. void FlushedPacketBuffer(); + // Reports that the jitter buffer received a packet. + void ReceivedPacket(); + + // Reports that a received packet was delayed by |delay_ms| milliseconds. + virtual void RelativePacketArrivalDelay(size_t delay_ms); + // Logs a delayed packet outage event of |num_samples| expanded at a sample // rate of |fs_hz|. A delayed packet outage event is defined as an expand // period caused not by an actual packet loss, but by a delayed packet.
diff --git a/modules/audio_coding/neteq/statistics_calculator_unittest.cc b/modules/audio_coding/neteq/statistics_calculator_unittest.cc index 0a4901d..1fb8e1c 100644 --- a/modules/audio_coding/neteq/statistics_calculator_unittest.cc +++ b/modules/audio_coding/neteq/statistics_calculator_unittest.cc
@@ -104,4 +104,28 @@ EXPECT_EQ((50u << 14) / k10MsSamples, stats_output.speech_expand_rate); } +TEST(StatisticsCalculator, RelativePacketArrivalDelay) { + StatisticsCalculator stats; + + stats.RelativePacketArrivalDelay(50); + NetEqLifetimeStatistics stats_output = stats.GetLifetimeStatistics(); + EXPECT_EQ(50u, stats_output.relative_packet_arrival_delay_ms); + + stats.RelativePacketArrivalDelay(20); + stats_output = stats.GetLifetimeStatistics(); + EXPECT_EQ(70u, stats_output.relative_packet_arrival_delay_ms); +} + +TEST(StatisticsCalculator, ReceivedPacket) { + StatisticsCalculator stats; + + stats.ReceivedPacket(); + NetEqLifetimeStatistics stats_output = stats.GetLifetimeStatistics(); + EXPECT_EQ(1u, stats_output.jitter_buffer_packets_received); + + stats.ReceivedPacket(); + stats_output = stats.GetLifetimeStatistics(); + EXPECT_EQ(2u, stats_output.jitter_buffer_packets_received); +} + } // namespace webrtc
diff --git a/modules/audio_coding/neteq/sync_buffer.h b/modules/audio_coding/neteq/sync_buffer.h index d645e91..7f6c111 100644 --- a/modules/audio_coding/neteq/sync_buffer.h +++ b/modules/audio_coding/neteq/sync_buffer.h
@@ -19,7 +19,7 @@ #include "modules/audio_coding/neteq/audio_multi_vector.h" #include "modules/audio_coding/neteq/audio_vector.h" #include "rtc_base/buffer.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/tick_timer.h b/modules/audio_coding/neteq/tick_timer.h index 02f083e..724dd12 100644 --- a/modules/audio_coding/neteq/tick_timer.h +++ b/modules/audio_coding/neteq/tick_timer.h
@@ -15,7 +15,7 @@ #include <memory> #include "rtc_base/checks.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/time_stretch.h b/modules/audio_coding/neteq/time_stretch.h index 13ad2c8..9f86649 100644 --- a/modules/audio_coding/neteq/time_stretch.h +++ b/modules/audio_coding/neteq/time_stretch.h
@@ -15,7 +15,7 @@ #include <string.h> // memset, size_t #include "modules/audio_coding/neteq/audio_multi_vector.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/time_stretch_unittest.cc b/modules/audio_coding/neteq/time_stretch_unittest.cc index c96c7d4..6fced38 100644 --- a/modules/audio_coding/neteq/time_stretch_unittest.cc +++ b/modules/audio_coding/neteq/time_stretch_unittest.cc
@@ -21,7 +21,7 @@ #include "modules/audio_coding/neteq/tools/input_audio_file.h" #include "rtc_base/checks.h" #include "test/gtest.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/timestamp_scaler.h b/modules/audio_coding/neteq/timestamp_scaler.h index 62f535c..93cb953 100644 --- a/modules/audio_coding/neteq/timestamp_scaler.h +++ b/modules/audio_coding/neteq/timestamp_scaler.h
@@ -12,7 +12,7 @@ #define MODULES_AUDIO_CODING_NETEQ_TIMESTAMP_SCALER_H_ #include "modules/audio_coding/neteq/packet.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/timestamp_scaler_unittest.cc b/modules/audio_coding/neteq/timestamp_scaler_unittest.cc index 1f1445a..5b14189 100644 --- a/modules/audio_coding/neteq/timestamp_scaler_unittest.cc +++ b/modules/audio_coding/neteq/timestamp_scaler_unittest.cc
@@ -25,7 +25,7 @@ MockDecoderDatabase db; auto factory = CreateBuiltinAudioDecoderFactory(); // Use PCMu, because it doesn't use scaled timestamps. - const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu, + const DecoderDatabase::DecoderInfo info(SdpAudioFormat("pcmu", 8000, 1), absl::nullopt, factory); static const uint8_t kRtpPayloadType = 0; EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType)) @@ -47,7 +47,7 @@ MockDecoderDatabase db; auto factory = CreateBuiltinAudioDecoderFactory(); // Use PCMu, because it doesn't use scaled timestamps. - const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu, + const DecoderDatabase::DecoderInfo info(SdpAudioFormat("pcmu", 8000, 1), absl::nullopt, factory); static const uint8_t kRtpPayloadType = 0; EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType)) @@ -74,7 +74,7 @@ MockDecoderDatabase db; auto factory = CreateBuiltinAudioDecoderFactory(); // Use G722, which has a factor 2 scaling. - const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderG722, + const DecoderDatabase::DecoderInfo info(SdpAudioFormat("g722", 8000, 1), absl::nullopt, factory); static const uint8_t kRtpPayloadType = 17; EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType)) @@ -100,7 +100,7 @@ MockDecoderDatabase db; auto factory = CreateBuiltinAudioDecoderFactory(); // Use G722, which has a factor 2 scaling. - const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderG722, + const DecoderDatabase::DecoderInfo info(SdpAudioFormat("g722", 8000, 1), absl::nullopt, factory); static const uint8_t kRtpPayloadType = 17; EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType)) @@ -130,9 +130,9 @@ MockDecoderDatabase db; auto factory = CreateBuiltinAudioDecoderFactory(); // Use G722, which has a factor 2 scaling. - const DecoderDatabase::DecoderInfo info_g722(NetEqDecoder::kDecoderG722, + const DecoderDatabase::DecoderInfo info_g722(SdpAudioFormat("g722", 8000, 1), absl::nullopt, factory); - const DecoderDatabase::DecoderInfo info_cng(NetEqDecoder::kDecoderCNGwb, + const DecoderDatabase::DecoderInfo info_cng(SdpAudioFormat("cn", 16000, 1), absl::nullopt, factory); static const uint8_t kRtpPayloadTypeG722 = 17; static const uint8_t kRtpPayloadTypeCng = 13; @@ -174,7 +174,7 @@ MockDecoderDatabase db; auto factory = CreateBuiltinAudioDecoderFactory(); // Use G722, which has a factor 2 scaling. - const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderG722, + const DecoderDatabase::DecoderInfo info(SdpAudioFormat("g722", 8000, 1), absl::nullopt, factory); static const uint8_t kRtpPayloadType = 17; EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType)) @@ -204,7 +204,7 @@ MockDecoderDatabase db; auto factory = CreateBuiltinAudioDecoderFactory(); // Use G722, which has a factor 2 scaling. - const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderG722, + const DecoderDatabase::DecoderInfo info(SdpAudioFormat("g722", 8000, 1), absl::nullopt, factory); static const uint8_t kRtpPayloadType = 17; EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType)) @@ -238,7 +238,7 @@ MockDecoderDatabase db; auto factory = CreateBuiltinAudioDecoderFactory(); // Use G722, which has a factor 2 scaling. - const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderG722, + const DecoderDatabase::DecoderInfo info(SdpAudioFormat("g722", 8000, 1), absl::nullopt, factory); static const uint8_t kRtpPayloadType = 17; EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType)) @@ -279,7 +279,7 @@ TEST(TimestampScaler, TestOpusLargeStep) { MockDecoderDatabase db; auto factory = CreateBuiltinAudioDecoderFactory(); - const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderOpus, + const DecoderDatabase::DecoderInfo info(SdpAudioFormat("opus", 48000, 2), absl::nullopt, factory); static const uint8_t kRtpPayloadType = 17; EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
diff --git a/modules/audio_coding/neteq/tools/audio_checksum.h b/modules/audio_coding/neteq/tools/audio_checksum.h index ee8c582..e4306fa 100644 --- a/modules/audio_coding/neteq/tools/audio_checksum.h +++ b/modules/audio_coding/neteq/tools/audio_checksum.h
@@ -16,9 +16,9 @@ #include "modules/audio_coding/neteq/tools/audio_sink.h" #include "rtc_base/buffer.h" -#include "rtc_base/constructormagic.h" -#include "rtc_base/messagedigest.h" -#include "rtc_base/stringencode.h" +#include "rtc_base/constructor_magic.h" +#include "rtc_base/message_digest.h" +#include "rtc_base/string_encode.h" #include "rtc_base/system/arch.h" namespace webrtc {
diff --git a/modules/audio_coding/neteq/tools/audio_loop.h b/modules/audio_coding/neteq/tools/audio_loop.h index c7788a6..cd764cc 100644 --- a/modules/audio_coding/neteq/tools/audio_loop.h +++ b/modules/audio_coding/neteq/tools/audio_loop.h
@@ -15,7 +15,7 @@ #include <string> #include "api/array_view.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { namespace test {
diff --git a/modules/audio_coding/neteq/tools/audio_sink.h b/modules/audio_coding/neteq/tools/audio_sink.h index be2a315..68825eb 100644 --- a/modules/audio_coding/neteq/tools/audio_sink.h +++ b/modules/audio_coding/neteq/tools/audio_sink.h
@@ -12,7 +12,7 @@ #define MODULES_AUDIO_CODING_NETEQ_TOOLS_AUDIO_SINK_H_ #include "api/audio/audio_frame.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { namespace test {
diff --git a/modules/audio_coding/neteq/tools/constant_pcm_packet_source.h b/modules/audio_coding/neteq/tools/constant_pcm_packet_source.h index 4e216e4..7adb15b 100644 --- a/modules/audio_coding/neteq/tools/constant_pcm_packet_source.h +++ b/modules/audio_coding/neteq/tools/constant_pcm_packet_source.h
@@ -14,9 +14,8 @@ #include <stdio.h> #include <string> -#include "common_types.h" // NOLINT(build/include) #include "modules/audio_coding/neteq/tools/packet_source.h" -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { namespace test {
diff --git a/modules/audio_coding/neteq/tools/input_audio_file.cc b/modules/audio_coding/neteq/tools/input_audio_file.cc index 6d11064..d5e2862 100644 --- a/modules/audio_coding/neteq/tools/input_audio_file.cc +++ b/modules/audio_coding/neteq/tools/input_audio_file.cc
@@ -18,9 +18,11 @@ InputAudioFile::InputAudioFile(const std::string file_name, bool loop_at_end) : loop_at_end_(loop_at_end) { fp_ = fopen(file_name.c_str(), "rb"); + RTC_DCHECK(fp_) << file_name << " could not be opened."; } InputAudioFile::~InputAudioFile() { + RTC_DCHECK(fp_); fclose(fp_); }
diff --git a/modules/audio_coding/neteq/tools/input_audio_file.h b/modules/audio_coding/neteq/tools/input_audio_file.h index b36dc24..4335a99 100644 --- a/modules/audio_coding/neteq/tools/input_audio_file.h +++ b/modules/audio_coding/neteq/tools/input_audio_file.h
@@ -15,7 +15,7 @@ #include <string> -#include "rtc_base/constructormagic.h" +#include "rtc_base/constructor_magic.h" namespace webrtc { namespace test {
diff --git a/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc b/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc deleted file mode 100644 index 3bd218b..0000000 --- a/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc +++ /dev/null
@@ -1,58 +0,0 @@ -/* - * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "modules/audio_coding/neteq/tools/neteq_external_decoder_test.h" - -#include "api/audio/audio_frame.h" -#include "api/audio_codecs/builtin_audio_decoder_factory.h" -#include "rtc_base/format_macros.h" -#include "test/gtest.h" - -namespace webrtc { -namespace test { - -NetEqExternalDecoderTest::NetEqExternalDecoderTest(NetEqDecoder codec, - int sample_rate_hz, - AudioDecoder* decoder) - : codec_(codec), - decoder_(decoder), - sample_rate_hz_(sample_rate_hz), - channels_(decoder_->Channels()) { - NetEq::Config config; - config.sample_rate_hz = sample_rate_hz_; - neteq_.reset(NetEq::Create(config, CreateBuiltinAudioDecoderFactory())); -} - -void NetEqExternalDecoderTest::Init() { - ASSERT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder(decoder_, codec_, name_, - kPayloadType)); -} - -void NetEqExternalDecoderTest::InsertPacket( - RTPHeader rtp_header, - rtc::ArrayView<const uint8_t> payload, - uint32_t receive_timestamp) { - ASSERT_EQ(NetEq::kOK, - neteq_->InsertPacket(rtp_header, payload, receive_timestamp)); -} - -void NetEqExternalDecoderTest::GetOutputAudio(AudioFrame* output) { - // Get audio from regular instance. - bool muted; - EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(output, &muted)); - ASSERT_FALSE(muted); - EXPECT_EQ(channels_, output->num_channels_); - EXPECT_EQ(static_cast<size_t>(kOutputLengthMs * sample_rate_hz_ / 1000), - output->samples_per_channel_); - EXPECT_EQ(sample_rate_hz_, neteq_->last_output_sample_rate_hz()); -} - -} // namespace test -} // namespace webrtc
diff --git a/modules/audio_coding/neteq/tools/neteq_external_decoder_test.h b/modules/audio_coding/neteq/tools/neteq_external_decoder_test.h deleted file mode 100644 index 78f0085..0000000 --- a/modules/audio_coding/neteq/tools/neteq_external_decoder_test.h +++ /dev/null
@@ -1,64 +0,0 @@ -/* - * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_EXTERNAL_DECODER_TEST_H_ -#define MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_EXTERNAL_DECODER_TEST_H_ - -#include <memory> -#include <string> - -#include "api/audio_codecs/audio_decoder.h" -#include "common_types.h" // NOLINT(build/include) -#include "modules/audio_coding/neteq/include/neteq.h" - -namespace webrtc { -namespace test { -// This test class provides a way run NetEQ with an external decoder. -class NetEqExternalDecoderTest { - protected: - static const uint8_t kPayloadType = 95; - static const int kOutputLengthMs = 10; - - // The external decoder |decoder| is suppose to be of type |codec|. - NetEqExternalDecoderTest(NetEqDecoder codec, - int sample_rate_hz, - AudioDecoder* decoder); - - virtual ~NetEqExternalDecoderTest() {} - - // In Init(), we register the external decoder. - void Init(); - - // Inserts a new packet with |rtp_header| and |payload| of - // |payload_size_bytes| bytes. The |receive_timestamp| is an indication - // of the time when the packet was received, and should be measured with - // the same tick rate as the RTP timestamp of the current payload. - virtual void InsertPacket(RTPHeader rtp_header, - rtc::ArrayView<const uint8_t> payload, - uint32_t receive_timestamp); - - // Get 10 ms of audio data. - void GetOutputAudio(AudioFrame* output); - - NetEq* neteq() { return neteq_.get(); } - - private: - NetEqDecoder codec_; - std::string name_ = "dummy name"; - AudioDecoder* decoder_; - int sample_rate_hz_; - size_t channels_; - std::unique_ptr<NetEq> neteq_; -}; - -} // namespace test -} // namespace webrtc - -#endif // MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_EXTERNAL_DECODER_TEST_H_
diff --git a/modules/audio_coding/neteq/tools/neteq_input.h b/modules/audio_coding/neteq/tools/neteq_input.h index b9cba09..732b807 100644 --- a/modules/audio_coding/neteq/tools/neteq_input.h +++ b/modules/audio_coding/neteq/tools/neteq_input.h
@@ -16,7 +16,6 @@ #include <string> #include "absl/types/optional.h" -#include "common_types.h" // NOLINT(build/include) #include "modules/audio_coding/neteq/tools/packet.h" #include "modules/audio_coding/neteq/tools/packet_source.h" #include "rtc_base/buffer.h"
diff --git a/modules/audio_coding/neteq/tools/neteq_performance_test.cc b/modules/audio_coding/neteq/tools/neteq_performance_test.cc index 52524fe..61f52bb 100644 --- a/modules/audio_coding/neteq/tools/neteq_performance_test.cc +++ b/modules/audio_coding/neteq/tools/neteq_performance_test.cc
@@ -12,14 +12,13 @@ #include "api/audio/audio_frame.h" #include "api/audio_codecs/builtin_audio_decoder_factory.h" -#include "common_types.h" // NOLINT(build/include) #include "modules/audio_coding/codecs/pcm16b/pcm16b.h" #include "modules/audio_coding/neteq/include/neteq.h" #include "modules/audio_coding/neteq/tools/audio_loop.h" #include "modules/audio_coding/neteq/tools/rtp_generator.h" #include "rtc_base/checks.h" #include "system_wrappers/include/clock.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" using webrtc::NetEq; using webrtc::test::AudioLoop; @@ -34,8 +33,6 @@ const std::string kInputFileName = webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"); const int kSampRateHz = 32000; - const webrtc::NetEqDecoder kDecoderType = - webrtc::NetEqDecoder::kDecoderPCM16Bswb32kHz; const std::string kDecoderName = "pcm16-swb32"; const int kPayloadType = 95; @@ -44,7 +41,8 @@ config.sample_rate_hz = kSampRateHz; NetEq* neteq = NetEq::Create(config, CreateBuiltinAudioDecoderFactory()); // Register decoder in |neteq|. - if (neteq->RegisterPayloadType(kDecoderType, kDecoderName, kPayloadType) != 0) + if (!neteq->RegisterPayloadType(kPayloadType, + SdpAudioFormat("l16", kSampRateHz, 1))) return -1; // Set up AudioLoop object.
diff --git a/modules/audio_coding/neteq/tools/neteq_quality_test.cc b/modules/audio_coding/neteq/tools/neteq_quality_test.cc index 2ee6779..a0e7667 100644 --- a/modules/audio_coding/neteq/tools/neteq_quality_test.cc +++ b/modules/audio_coding/neteq/tools/neteq_quality_test.cc
@@ -17,7 +17,7 @@ #include "modules/audio_coding/neteq/tools/output_wav_file.h" #include "modules/audio_coding/neteq/tools/resample_input_audio_file.h" #include "rtc_base/checks.h" -#include "test/testsupport/fileutils.h" +#include "test/testsupport/file_utils.h" namespace webrtc { namespace test { @@ -135,8 +135,8 @@ NetEqQualityTest::NetEqQualityTest(int block_duration_ms, int in_sampling_khz, int out_sampling_khz, - NetEqDecoder decoder_type) - : decoder_type_(decoder_type), + const SdpAudioFormat& format) + : audio_format_(format), channels_(static_cast<size_t>(FLAG_channels)), decoded_time_ms_(0), decodable_time_ms_(0), @@ -271,8 +271,7 @@ } void NetEqQualityTest::SetUp() { - ASSERT_EQ(0, - neteq_->RegisterPayloadType(decoder_type_, "noname", kPayloadType)); + ASSERT_TRUE(neteq_->RegisterPayloadType(kPayloadType, audio_format_)); rtp_generator_->set_drift_factor(drift_factor_); int units = block_duration_ms_ / kPacketLossTimeUnitMs;
diff --git a/modules/audio_coding/neteq/tools/neteq_quality_test.h b/modules/audio_coding/neteq/tools/neteq_quality_test.h index 3d7760e..82a6a64 100644 --- a/modules/audio_coding/neteq/tools/neteq_quality_test.h +++ b/modules/audio_coding/neteq/tools/neteq_quality_test.h
@@ -14,7 +14,6 @@ #include <fstream> #include <memory> -#include "common_types.h" // NOLINT(build/include) #include "modules/audio_coding/neteq/include/neteq.h" #include "modules/audio_coding/neteq/tools/audio_sink.h" #include "modules/audio_coding/neteq/tools/input_audio_file.h" @@ -35,7 +34,7 @@ class LossModel { public: - virtual ~LossModel(){}; + virtual ~LossModel() {} virtual bool Lost(int now_ms) = 0; }; @@ -99,7 +98,7 @@ NetEqQualityTest(int block_duration_ms, int in_sampling_khz, int out_sampling_khz, - NetEqDecoder decoder_type); + const SdpAudioFormat& format); ~NetEqQualityTest() override; void SetUp() override; @@ -133,7 +132,7 @@ // Write to log file. Usage Log() << ... std::ofstream& Log(); - NetEqDecoder decoder_type_; + SdpAudioFormat audio_format_; const size_t channels_; private:
diff --git a/modules/audio_coding/neteq/tools/neteq_rtpplay.cc b/modules/audio_coding/neteq/tools/neteq_rtpplay.cc index c2726eb..36c03b8 100644 --- a/modules/audio_coding/neteq/tools/neteq_rtpplay.cc +++ b/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
@@ -17,6 +17,10 @@ #include "system_wrappers/include/field_trial.h" #include "test/field_trial.h" +namespace { + +using TestConfig = webrtc::test::NetEqTestFactory::Config; + WEBRTC_DEFINE_bool(codec_map, false, "Prints the mapping between RTP payload type and " @@ -28,6 +32,185 @@ "E.g. running with --force_fieldtrials=WebRTC-FooFeature/Enable/" " will assign the group Enable to field trial WebRTC-FooFeature."); WEBRTC_DEFINE_bool(help, false, "Prints this message"); +// Define command line flags. +WEBRTC_DEFINE_int(pcmu, + TestConfig::default_pcmu(), + "RTP payload type for PCM-u"); +WEBRTC_DEFINE_int(pcma, + TestConfig::default_pcma(), + "RTP payload type for PCM-a"); +WEBRTC_DEFINE_int(ilbc, + TestConfig::default_ilbc(), + "RTP payload type for iLBC"); +WEBRTC_DEFINE_int(isac, + TestConfig::default_isac(), + "RTP payload type for iSAC"); +WEBRTC_DEFINE_int(isac_swb, + TestConfig::default_isac_swb(), + "RTP payload type for iSAC-swb (32 kHz)"); +WEBRTC_DEFINE_int(opus, + TestConfig::default_opus(), + "RTP payload type for Opus"); +WEBRTC_DEFINE_int(pcm16b, + TestConfig::default_pcm16b(), + "RTP payload type for PCM16b-nb (8 kHz)"); +WEBRTC_DEFINE_int(pcm16b_wb, + TestConfig::default_pcm16b_wb(), + "RTP payload type for PCM16b-wb (16 kHz)"); +WEBRTC_DEFINE_int(pcm16b_swb32, + TestConfig::default_pcm16b_swb32(), + "RTP payload type for PCM16b-swb32 (32 kHz)"); +WEBRTC_DEFINE_int(pcm16b_swb48, + TestConfig::default_pcm16b_swb48(), + "RTP payload type for PCM16b-swb48 (48 kHz)"); +WEBRTC_DEFINE_int(g722, + TestConfig::default_g722(), + "RTP payload type for G.722"); +WEBRTC_DEFINE_int(avt, + TestConfig::default_avt(), + "RTP payload type for AVT/DTMF (8 kHz)"); +WEBRTC_DEFINE_int(avt_16, + TestConfig::default_avt_16(), + "RTP payload type for AVT/DTMF (16 kHz)"); +WEBRTC_DEFINE_int(avt_32, + TestConfig::default_avt_32(), + "RTP payload type for AVT/DTMF (32 kHz)"); +WEBRTC_DEFINE_int(avt_48, + TestConfig::default_avt_48(), + "RTP payload type for AVT/DTMF (48 kHz)"); +WEBRTC_DEFINE_int(red, + TestConfig::default_red(), + "RTP payload type for redundant audio (RED)"); +WEBRTC_DEFINE_int(cn_nb, + TestConfig::default_cn_nb(), + "RTP payload type for comfort noise (8 kHz)"); +WEBRTC_DEFINE_int(cn_wb, + TestConfig::default_cn_wb(), + "RTP payload type for comfort noise (16 kHz)"); +WEBRTC_DEFINE_int(cn_swb32, + TestConfig::default_cn_swb32(), + "RTP payload type for comfort noise (32 kHz)"); +WEBRTC_DEFINE_int(cn_swb48, + TestConfig::default_cn_swb48(), + "RTP payload type for comfort noise (48 kHz)"); +WEBRTC_DEFINE_string(replacement_audio_file, + "", + "A PCM file that will be used to populate dummy" + " RTP packets"); +WEBRTC_DEFINE_string( + ssrc, + "", + "Only use packets with this SSRC (decimal or hex, the latter " + "starting with 0x)"); +WEBRTC_DEFINE_int(audio_level, + TestConfig::default_audio_level(), + "Extension ID for audio level (RFC 6464)"); +WEBRTC_DEFINE_int(abs_send_time, + TestConfig::default_abs_send_time(), + "Extension ID for absolute sender time"); +WEBRTC_DEFINE_int(transport_seq_no, + TestConfig::default_transport_seq_no(), + "Extension ID for transport sequence number"); +WEBRTC_DEFINE_int(video_content_type, + TestConfig::default_video_content_type(), + "Extension ID for video content type"); +WEBRTC_DEFINE_int(video_timing, + TestConfig::default_video_timing(), + "Extension ID for video timing"); +WEBRTC_DEFINE_bool(matlabplot, + false, + "Generates a matlab script for plotting the delay profile"); +WEBRTC_DEFINE_bool(pythonplot, + false, + "Generates a python script for plotting the delay profile"); +WEBRTC_DEFINE_bool(textlog, + false, + "Generates a text log describing the simulation on a " + "step-by-step basis."); +WEBRTC_DEFINE_bool(concealment_events, false, "Prints concealment events"); +WEBRTC_DEFINE_int(max_nr_packets_in_buffer, + TestConfig::default_max_nr_packets_in_buffer(), + "Maximum allowed number of packets in the buffer"); +WEBRTC_DEFINE_bool(enable_fast_accelerate, + false, + "Enables jitter buffer fast accelerate"); + +// Parses the input string for a valid SSRC (at the start of the string). If a +// valid SSRC is found, it is written to the output variable |ssrc|, and true is +// returned. Otherwise, false is returned. +bool ParseSsrc(const std::string& str, uint32_t* ssrc) { + if (str.empty()) + return true; + int base = 10; + // Look for "0x" or "0X" at the start and change base to 16 if found. + if ((str.compare(0, 2, "0x") == 0) || (str.compare(0, 2, "0X") == 0)) + base = 16; + errno = 0; + char* end_ptr; + unsigned long value = strtoul(str.c_str(), &end_ptr, base); // NOLINT + if (value == ULONG_MAX && errno == ERANGE) + return false; // Value out of range for unsigned long. + if (sizeof(unsigned long) > sizeof(uint32_t) && value > 0xFFFFFFFF) // NOLINT + return false; // Value out of range for uint32_t. + if (end_ptr - str.c_str() < static_cast<ptrdiff_t>(str.length())) + return false; // Part of the string was not parsed. + *ssrc = static_cast<uint32_t>(value); + return true; +} + +static bool ValidateExtensionId(int value) { + if (value > 0 && value <= 255) // Value is ok. + return true; + printf("Extension ID must be between 1 and 255, not %d\n", + static_cast<int>(value)); + return false; +} + +// Flag validators. +bool ValidatePayloadType(int value) { + if (value >= 0 && value <= 127) // Value is ok. + return true; + printf("Payload type must be between 0 and 127, not %d\n", + static_cast<int>(value)); + return false; +} + +bool ValidateSsrcValue(const std::string& str) { + uint32_t dummy_ssrc; + if (ParseSsrc(str, &dummy_ssrc)) // Value is ok. + return true; + printf("Invalid SSRC: %s\n", str.c_str()); + return false; +} + +void PrintCodecMappingEntry(const char* codec, int flag) { + std::cout << codec << ": " << flag << std::endl; +} + +void PrintCodecMapping() { + PrintCodecMappingEntry("PCM-u", FLAG_pcmu); + PrintCodecMappingEntry("PCM-a", FLAG_pcma); + PrintCodecMappingEntry("iLBC", FLAG_ilbc); + PrintCodecMappingEntry("iSAC", FLAG_isac); + PrintCodecMappingEntry("iSAC-swb (32 kHz)", FLAG_isac_swb); + PrintCodecMappingEntry("Opus", FLAG_opus); + PrintCodecMappingEntry("PCM16b-nb (8 kHz)", FLAG_pcm16b); + PrintCodecMappingEntry("PCM16b-wb (16 kHz)", FLAG_pcm16b_wb); + PrintCodecMappingEntry("PCM16b-swb32 (32 kHz)", FLAG_pcm16b_swb32); + PrintCodecMappingEntry("PCM16b-swb48 (48 kHz)", FLAG_pcm16b_swb48); + PrintCodecMappingEntry("G.722", FLAG_g722); + PrintCodecMappingEntry("AVT/DTMF (8 kHz)", FLAG_avt); + PrintCodecMappingEntry("AVT/DTMF (16 kHz)", FLAG_avt_16); + PrintCodecMappingEntry("AVT/DTMF (32 kHz)", FLAG_avt_32); + PrintCodecMappingEntry("AVT/DTMF (48 kHz)", FLAG_avt_48); + PrintCodecMappingEntry("redundant audio (RED)", FLAG_red); + PrintCodecMappingEntry("comfort noise (8 kHz)", FLAG_cn_nb); + PrintCodecMappingEntry("comfort noise (16 kHz)", FLAG_cn_wb); + PrintCodecMappingEntry("comfort noise (32 kHz)", FLAG_cn_swb32); + PrintCodecMappingEntry("comfort noise (48 kHz)", FLAG_cn_swb48); +} + +} // namespace int main(int argc, char* argv[]) { webrtc::test::NetEqTestFactory factory; @@ -48,21 +231,85 @@ exit(0); } if (FLAG_codec_map) { - factory.PrintCodecMap(); + PrintCodecMapping(); + exit(0); } if (argc != 3) { - if (FLAG_codec_map) { - // We have already printed the codec map. Just end the program. - exit(0); - } // Print usage information. std::cout << usage; exit(0); } + RTC_CHECK(ValidatePayloadType(FLAG_pcmu)); + RTC_CHECK(ValidatePayloadType(FLAG_pcma)); + RTC_CHECK(ValidatePayloadType(FLAG_ilbc)); + RTC_CHECK(ValidatePayloadType(FLAG_isac)); + RTC_CHECK(ValidatePayloadType(FLAG_isac_swb)); + RTC_CHECK(ValidatePayloadType(FLAG_opus)); + RTC_CHECK(ValidatePayloadType(FLAG_pcm16b)); + RTC_CHECK(ValidatePayloadType(FLAG_pcm16b_wb)); + RTC_CHECK(ValidatePayloadType(FLAG_pcm16b_swb32)); + RTC_CHECK(ValidatePayloadType(FLAG_pcm16b_swb48)); + RTC_CHECK(ValidatePayloadType(FLAG_g722)); + RTC_CHECK(ValidatePayloadType(FLAG_avt)); + RTC_CHECK(ValidatePayloadType(FLAG_avt_16)); + RTC_CHECK(ValidatePayloadType(FLAG_avt_32)); + RTC_CHECK(ValidatePayloadType(FLAG_avt_48)); + RTC_CHECK(ValidatePayloadType(FLAG_red)); + RTC_CHECK(ValidatePayloadType(FLAG_cn_nb)); + RTC_CHECK(ValidatePayloadType(FLAG_cn_wb)); + RTC_CHECK(ValidatePayloadType(FLAG_cn_swb32)); + RTC_CHECK(ValidatePayloadType(FLAG_cn_swb48)); + RTC_CHECK(ValidateSsrcValue(FLAG_ssrc)); + RTC_CHECK(ValidateExtensionId(FLAG_audio_level)); + RTC_CHECK(ValidateExtensionId(FLAG_abs_send_time)); + RTC_CHECK(ValidateExtensionId(FLAG_transport_seq_no)); + RTC_CHECK(ValidateExtensionId(FLAG_video_content_type)); + RTC_CHECK(ValidateExtensionId(FLAG_video_timing)); + webrtc::test::ValidateFieldTrialsStringOrDie(FLAG_force_fieldtrials); webrtc::field_trial::InitFieldTrialsFromString(FLAG_force_fieldtrials); + webrtc::test::NetEqTestFactory::Config config; + config.pcmu = FLAG_pcmu; + config.pcma = FLAG_pcma; + config.ilbc = FLAG_ilbc; + config.isac = FLAG_isac; + config.isac_swb = FLAG_isac_swb; + config.opus = FLAG_opus; + config.pcm16b = FLAG_pcm16b; + config.pcm16b_wb = FLAG_pcm16b_wb; + config.pcm16b_swb32 = FLAG_pcm16b_swb32; + config.pcm16b_swb48 = FLAG_pcm16b_swb48; + config.g722 = FLAG_g722; + config.avt = FLAG_avt; + config.avt_16 = FLAG_avt_16; + config.avt_32 = FLAG_avt_32; + config.avt_48 = FLAG_avt_48; + config.red = FLAG_red; + config.cn_nb = FLAG_cn_nb; + config.cn_wb = FLAG_cn_wb; + config.cn_swb32 = FLAG_cn_swb32; + config.cn_swb48 = FLAG_cn_swb48; + config.replacement_audio_file = FLAG_replacement_audio_file; + config.audio_level = FLAG_audio_level; + config.abs_send_time = FLAG_abs_send_time; + config.transport_seq_no = FLAG_transport_seq_no; + config.video_content_type = FLAG_video_content_type; + config.video_timing = FLAG_video_timing; + config.matlabplot = FLAG_matlabplot; + config.pythonplot = FLAG_pythonplot; + config.textlog = FLAG_textlog; + config.concealment_events = FLAG_concealment_events; + config.max_nr_packets_in_buffer = FLAG_max_nr_packets_in_buffer; + config.enable_fast_accelerate = FLAG_enable_fast_accelerate; + // Check if an SSRC value was provided. + if (strlen(FLAG_ssrc) > 0) { + uint32_t ssrc; + RTC_CHECK(ParseSsrc(FLAG_ssrc, &ssrc)) << "Flag verification has failed."; + config.ssrc_filter = absl::make_optional(ssrc); + } + std::unique_ptr<webrtc::test::NetEqTest> test = - factory.InitializeTest(argv[1], argv[2]); + factory.InitializeTest(argv[1], argv[2], config); test->Run(); return 0; }
diff --git a/modules/audio_coding/neteq/tools/neteq_stats_getter.cc b/modules/audio_coding/neteq/tools/neteq_stats_getter.cc index 1a52176..291fc24 100644 --- a/modules/audio_coding/neteq/tools/neteq_stats_getter.cc +++ b/modules/audio_coding/neteq/tools/neteq_stats_getter.cc
@@ -16,7 +16,7 @@ #include "rtc_base/checks.h" #include "rtc_base/strings/string_builder.h" -#include "rtc_base/timeutils.h" +#include "rtc_base/time_utils.h" namespace webrtc { namespace test {
diff --git a/modules/audio_coding/neteq/tools/neteq_test.cc b/modules/audio_coding/neteq/tools/neteq_test.cc index 421f380..97e71bf 100644 --- a/modules/audio_coding/neteq/tools/neteq_test.cc +++ b/modules/audio_coding/neteq/tools/neteq_test.cc
@@ -10,9 +10,10 @@ #include "modules/audio_coding/neteq/tools/neteq_test.h" +#include <iomanip> #include <iostream> -#include "api/audio_codecs/builtin_audio_decoder_factory.h" +#include "modules/rtp_rtcp/source/byte_io.h" namespace webrtc { namespace test { @@ -50,20 +51,21 @@ } NetEqTest::NetEqTest(const NetEq::Config& config, + rtc::scoped_refptr<AudioDecoderFactory> decoder_factory, const DecoderMap& codecs, - const ExtDecoderMap& ext_codecs, + std::unique_ptr<std::ofstream> text_log, std::unique_ptr<NetEqInput> input, std::unique_ptr<AudioSink> output, Callbacks callbacks) - : neteq_(NetEq::Create(config, CreateBuiltinAudioDecoderFactory())), + : neteq_(NetEq::Create(config, decoder_factory)), input_(std::move(input)), output_(std::move(output)), callbacks_(callbacks), - sample_rate_hz_(config.sample_rate_hz) { + sample_rate_hz_(config.sample_rate_hz), + text_log_(std::move(text_log)) { RTC_CHECK(!config.enable_muted_state) << "The code does not handle enable_muted_state"; RegisterDecoders(codecs); - RegisterExternalDecoders(ext_codecs); } NetEqTest::~NetEqTest() = default; @@ -117,7 +119,36 @@ current_state_.packet_iat_ms.push_back(time_now_ms - *last_packet_time_ms_); } + if (text_log_) { + const auto ops_state = neteq_->GetOperationsAndState(); + const auto delta_wallclock = + last_packet_time_ms_ ? (time_now_ms - *last_packet_time_ms_) : -1; + const auto delta_timestamp = + last_packet_timestamp_ + ? (static_cast<int64_t>(packet_data->header.timestamp) - + *last_packet_timestamp_) * + 1000 / sample_rate_hz_ + : -1; + const auto packet_size_bytes = + packet_data->payload.size() == 12 + ? ByteReader<uint32_t>::ReadLittleEndian( + &packet_data->payload[8]) + : -1; + *text_log_ << "Packet - wallclock: " << std::setw(5) << time_now_ms + << ", delta wc: " << std::setw(4) << delta_wallclock + << ", seq_no: " << packet_data->header.sequenceNumber + << ", timestamp: " << std::setw(10) + << packet_data->header.timestamp + << ", delta ts: " << std::setw(4) << delta_timestamp + << ", size: " << std::setw(5) << packet_size_bytes + << ", frame size: " << std::setw(3) + << ops_state.current_frame_size_ms + << ", buffer size: " << std::setw(4) + << ops_state.current_buffer_size_ms << std::endl; + } last_packet_time_ms_ = absl::make_optional<int>(time_now_ms); + last_packet_timestamp_ = + absl::make_optional<uint32_t>(packet_data->header.timestamp); } // Check if it is time to get output audio. @@ -186,6 +217,39 @@ // Consider the whole frame to be the result of normal playout. result.action_times_ms[Action::kNormal] = 10; } + auto lifetime_stats = LifetimeStats(); + if (text_log_) { + const bool plc = + (out_frame.speech_type_ == AudioFrame::SpeechType::kPLC) || + (out_frame.speech_type_ == AudioFrame::SpeechType::kPLCCNG); + const bool cng = out_frame.speech_type_ == AudioFrame::SpeechType::kCNG; + const bool voice_concealed = + lifetime_stats.voice_concealed_samples > + prev_lifetime_stats_.voice_concealed_samples; + *text_log_ << "GetAudio - wallclock: " << std::setw(5) << time_now_ms + << ", delta wc: " << std::setw(4) + << (input_->NextEventTime().value_or(time_now_ms) - + start_time_ms) + << ", CNG: " << cng << ", PLC: " << plc + << ", voice concealed: " << voice_concealed + << ", buffer size: " << std::setw(4) + << current_state_.current_delay_ms << std::endl; + if (operations_state.discarded_primary_packets > + prev_ops_state_.discarded_primary_packets) { + *text_log_ << "Discarded " + << (operations_state.discarded_primary_packets - + prev_ops_state_.discarded_primary_packets) + << " primary packets." << std::endl; + } + if (operations_state.packet_buffer_flushes > + prev_ops_state_.packet_buffer_flushes) { + *text_log_ << "Flushed packet buffer " + << (operations_state.packet_buffer_flushes - + prev_ops_state_.packet_buffer_flushes) + << " times." << std::endl; + } + } + prev_lifetime_stats_ = lifetime_stats; result.is_simulation_finished = input_->ended(); prev_ops_state_ = operations_state; return result; @@ -217,53 +281,40 @@ NetEqTest::DecoderMap NetEqTest::StandardDecoderMap() { DecoderMap codecs = { - {0, std::make_pair(NetEqDecoder::kDecoderPCMu, "pcmu")}, - {8, std::make_pair(NetEqDecoder::kDecoderPCMa, "pcma")}, + {0, SdpAudioFormat("pcmu", 8000, 1)}, + {8, SdpAudioFormat("pcma", 8000, 1)}, #ifdef WEBRTC_CODEC_ILBC - {102, std::make_pair(NetEqDecoder::kDecoderILBC, "ilbc")}, + {102, SdpAudioFormat("ilbc", 8000, 1)}, #endif - {103, std::make_pair(NetEqDecoder::kDecoderISAC, "isac")}, + {103, SdpAudioFormat("isac", 16000, 1)}, #if !defined(WEBRTC_ANDROID) - {104, std::make_pair(NetEqDecoder::kDecoderISACswb, "isac-swb")}, + {104, SdpAudioFormat("isac", 32000, 1)}, #endif #ifdef WEBRTC_CODEC_OPUS - {111, std::make_pair(NetEqDecoder::kDecoderOpus, "opus")}, + {111, SdpAudioFormat("opus", 48000, 2)}, #endif - {93, std::make_pair(NetEqDecoder::kDecoderPCM16B, "pcm16-nb")}, - {94, std::make_pair(NetEqDecoder::kDecoderPCM16Bwb, "pcm16-wb")}, - {95, std::make_pair(NetEqDecoder::kDecoderPCM16Bswb32kHz, "pcm16-swb32")}, - {96, std::make_pair(NetEqDecoder::kDecoderPCM16Bswb48kHz, "pcm16-swb48")}, - {9, std::make_pair(NetEqDecoder::kDecoderG722, "g722")}, - {106, std::make_pair(NetEqDecoder::kDecoderAVT, "avt")}, - {114, std::make_pair(NetEqDecoder::kDecoderAVT16kHz, "avt-16")}, - {115, std::make_pair(NetEqDecoder::kDecoderAVT32kHz, "avt-32")}, - {116, std::make_pair(NetEqDecoder::kDecoderAVT48kHz, "avt-48")}, - {117, std::make_pair(NetEqDecoder::kDecoderRED, "red")}, - {13, std::make_pair(NetEqDecoder::kDecoderCNGnb, "cng-nb")}, - {98, std::make_pair(NetEqDecoder::kDecoderCNGwb, "cng-wb")}, - {99, std::make_pair(NetEqDecoder::kDecoderCNGswb32kHz, "cng-swb32")}, - {100, std::make_pair(NetEqDecoder::kDecoderCNGswb48kHz, "cng-swb48")} + {93, SdpAudioFormat("l16", 8000, 1)}, + {94, SdpAudioFormat("l16", 16000, 1)}, + {95, SdpAudioFormat("l16", 32000, 1)}, + {96, SdpAudioFormat("l16", 48000, 1)}, + {9, SdpAudioFormat("g722", 8000, 1)}, + {106, SdpAudioFormat("telephone-event", 8000, 1)}, + {114, SdpAudioFormat("telephone-event", 16000, 1)}, + {115, SdpAudioFormat("telephone-event", 32000, 1)}, + {116, SdpAudioFormat("telephone-event", 48000, 1)}, + {117, SdpAudioFormat("red", 8000, 1)}, + {13, SdpAudioFormat("cn", 8000, 1)}, + {98, SdpAudioFormat("cn", 16000, 1)}, + {99, SdpAudioFormat("cn", 32000, 1)}, + {100, SdpAudioFormat("cn", 48000, 1)} }; return codecs; } void NetEqTest::RegisterDecoders(const DecoderMap& codecs) { for (const auto& c : codecs) { - RTC_CHECK_EQ( - neteq_->RegisterPayloadType(c.second.first, c.second.second, c.first), - NetEq::kOK) - << "Cannot register " << c.second.second << " to payload type " - << c.first; - } -} - -void NetEqTest::RegisterExternalDecoders(const ExtDecoderMap& codecs) { - for (const auto& c : codecs) { - RTC_CHECK_EQ( - neteq_->RegisterExternalDecoder(c.second.decoder, c.second.codec, - c.second.codec_name, c.first), - NetEq::kOK) - << "Cannot register " << c.second.codec_name << " to payload type " + RTC_CHECK(neteq_->RegisterPayloadType(c.first, c.second)) + << "Cannot register " << c.second.name << " to payload type " << c.first; } }
diff --git a/modules/audio_coding/neteq/tools/neteq_test.h b/modules/audio_coding/neteq/tools/neteq_test.h index 23d7c22..5261dd7 100644 --- a/modules/audio_coding/neteq/tools/neteq_test.h +++ b/modules/audio_coding/neteq/tools/neteq_test.h
@@ -11,12 +11,14 @@ #ifndef MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_TEST_H_ #define MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_TEST_H_ +#include <fstream> #include <map> #include <memory> #include <string> #include <utility> #include "absl/types/optional.h" +#include "api/audio_codecs/audio_decoder_factory.h" #include "api/test/neteq_simulator.h" #include "modules/audio_coding/neteq/include/neteq.h" #include "modules/audio_coding/neteq/tools/audio_sink.h" @@ -65,15 +67,7 @@ // directed to an AudioSink object. class NetEqTest : public NetEqSimulator { public: - using DecoderMap = std::map<int, std::pair<NetEqDecoder, std::string> >; - - struct ExternalDecoderInfo { - AudioDecoder* decoder; - NetEqDecoder codec; - std::string codec_name; - }; - - using ExtDecoderMap = std::map<int, ExternalDecoderInfo>; + using DecoderMap = std::map<int, SdpAudioFormat>; struct Callbacks { NetEqTestErrorCallback* error_callback = nullptr; @@ -85,8 +79,9 @@ // Sets up the test with given configuration, codec mappings, input, ouput, // and callback objects for error reporting. NetEqTest(const NetEq::Config& config, + rtc::scoped_refptr<AudioDecoderFactory> decoder_factory, const DecoderMap& codecs, - const ExtDecoderMap& ext_codecs, + std::unique_ptr<std::ofstream> text_log, std::unique_ptr<NetEqInput> input, std::unique_ptr<AudioSink> output, Callbacks callbacks); @@ -111,7 +106,6 @@ private: void RegisterDecoders(const DecoderMap& codecs); - void RegisterExternalDecoders(const ExtDecoderMap& codecs); absl::optional<Action> next_action_; absl::optional<int> last_packet_time_ms_; std::unique_ptr<NetEq> neteq_; @@ -121,6 +115,9 @@ int sample_rate_hz_; NetEqState current_state_; NetEqOperationsAndState prev_ops_state_; + NetEqLifetimeStatistics prev_lifetime_stats_; + absl::optional<uint32_t> last_packet_timestamp_; + std::unique_ptr<std::ofstream> text_log_; }; } // namespace test
diff --git a/modules/audio_coding/neteq/tools/neteq_test_factory.cc b/modules/audio_coding/neteq/tools/neteq_test_factory.cc index aa956ce..1d38bc4 100644 --- a/modules/audio_coding/neteq/tools/neteq_test_factory.cc +++ b/modules/audio_coding/neteq/tools/neteq_test_factory.cc
@@ -14,6 +14,7 @@ #include <limits.h> // For ULONG_MAX returned by strtoul. #include <stdio.h> #include <stdlib.h> // For strto