diff options
37 files changed, 1879 insertions, 349 deletions
diff --git a/WORKSPACE b/WORKSPACE index 064459306de3..9c9506508723 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -13,20 +13,20 @@ http_archive( # GoogleTest/GoogleMock framework. Used by most unit-tests. http_archive( name = "com_google_googletest", - urls = ["https://github.com/google/googletest/archive/master.zip"], - strip_prefix = "googletest-master", + urls = ["https://github.com/google/googletest/archive/4e4df226fc197c0dda6e37f5c8c3845ca1e73a49.zip"], + strip_prefix = "googletest-4e4df226fc197c0dda6e37f5c8c3845ca1e73a49", ) # Google benchmark. http_archive( name = "com_github_google_benchmark", - urls = ["https://github.com/google/benchmark/archive/master.zip"], - strip_prefix = "benchmark-master", + urls = ["https://github.com/google/benchmark/archive/16703ff83c1ae6d53e5155df3bb3ab0bc96083be.zip"], + strip_prefix = "benchmark-16703ff83c1ae6d53e5155df3bb3ab0bc96083be", ) # RE2 regular-expression framework. Used by some unit-tests. http_archive( name = "com_googlesource_code_re2", - urls = ["https://github.com/google/re2/archive/master.zip"], - strip_prefix = "re2-master", + urls = ["https://github.com/google/re2/archive/6cf8ccd82dbaab2668e9b13596c68183c9ecd13f.zip"], + strip_prefix = "re2-6cf8ccd82dbaab2668e9b13596c68183c9ecd13f", ) diff --git a/absl/algorithm/BUILD.bazel b/absl/algorithm/BUILD.bazel index 3b24ce12029c..d04dc71206e8 100644 --- a/absl/algorithm/BUILD.bazel +++ b/absl/algorithm/BUILD.bazel @@ -49,7 +49,7 @@ cc_test( deps = [ ":algorithm", "//absl/base:core_headers", - "@com_github_google_benchmark//:benchmark", + "@com_github_google_benchmark//:benchmark_main", ], ) diff --git a/absl/algorithm/equal_benchmark.cc b/absl/algorithm/equal_benchmark.cc index 9af36ce79f6c..19c0780ccd17 100644 --- a/absl/algorithm/equal_benchmark.cc +++ b/absl/algorithm/equal_benchmark.cc @@ -124,5 +124,3 @@ BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, EightBits) ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); } // namespace - -BENCHMARK_MAIN(); diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index 748f2f9f2154..1e93d97ebd40 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel @@ -392,11 +392,6 @@ cc_test( "//absl:windows": [], "//conditions:default": ["-pthread"], }), - tags = [ - "no_test_android_arm", - "no_test_android_arm64", - "no_test_android_x86", - ], deps = [":malloc_internal"], ) @@ -426,6 +421,6 @@ cc_test( deps = [ ":base", "//absl/synchronization", - "@com_github_google_benchmark//:benchmark", + "@com_github_google_benchmark//:benchmark_main", ], ) diff --git a/absl/base/internal/hide_ptr.h b/absl/base/internal/hide_ptr.h index 2c2e11f679a0..45cf438912c2 100644 --- a/absl/base/internal/hide_ptr.h +++ b/absl/base/internal/hide_ptr.h @@ -23,9 +23,7 @@ namespace base_internal { // Arbitrary value with high bits set. Xor'ing with it is unlikely // to map one valid pointer to another valid pointer. constexpr uintptr_t HideMask() { - static_assert(sizeof(uintptr_t) == 4 || sizeof(uintptr_t) == 8, - "uintptr_t must be 32 or 64 bits"); - return sizeof(uintptr_t) == 8 ? 0xF03A5F7BF03A5F7BULL : 0xF03A5F7BUL; + return (uintptr_t{0xF03A5F7BU} << (sizeof(uintptr_t) - 4) * 8) | 0xF03A5F7BU; } // Hide a pointer from the leak checker. For internal use only. diff --git a/absl/base/internal/thread_identity_benchmark.cc b/absl/base/internal/thread_identity_benchmark.cc index fe22e4cff172..242522b4418a 100644 --- a/absl/base/internal/thread_identity_benchmark.cc +++ b/absl/base/internal/thread_identity_benchmark.cc @@ -36,5 +36,3 @@ void BM_UnsafeCurrentThreadIdentity(benchmark::State& state) { BENCHMARK(BM_UnsafeCurrentThreadIdentity); } // namespace - -BENCHMARK_MAIN(); diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel index 897be90fc9e4..119d5c88de2a 100644 --- a/absl/container/BUILD.bazel +++ b/absl/container/BUILD.bazel @@ -42,11 +42,6 @@ cc_test( name = "fixed_array_test", srcs = ["fixed_array_test.cc"], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, - tags = [ - "no_test_android_arm", - "no_test_android_arm64", - "no_test_android_x86", - ], deps = [ ":fixed_array", "//absl/base:exception_testing", @@ -74,7 +69,7 @@ cc_test( tags = ["benchmark"], deps = [ ":fixed_array", - "@com_github_google_benchmark//:benchmark", + "@com_github_google_benchmark//:benchmark_main", ], ) @@ -131,7 +126,7 @@ cc_test( ":inlined_vector", "//absl/base", "//absl/strings", - "@com_github_google_benchmark//:benchmark", + "@com_github_google_benchmark//:benchmark_main", ], ) diff --git a/absl/container/fixed_array_benchmark.cc b/absl/container/fixed_array_benchmark.cc index 2d39898d8a5f..b4f0cf2aeb04 100644 --- a/absl/container/fixed_array_benchmark.cc +++ b/absl/container/fixed_array_benchmark.cc @@ -64,5 +64,3 @@ BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 256)->Range(0, 1 << 16); BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 65536)->Range(0, 1 << 16); } // namespace - -BENCHMARK_MAIN(); diff --git a/absl/container/inlined_vector_benchmark.cc b/absl/container/inlined_vector_benchmark.cc index c6bc5cd96dc8..5977bc934f0e 100644 --- a/absl/container/inlined_vector_benchmark.cc +++ b/absl/container/inlined_vector_benchmark.cc @@ -372,5 +372,3 @@ void BM_StdVectorEmpty(benchmark::State& state) { BENCHMARK(BM_StdVectorEmpty); } // namespace - -BENCHMARK_MAIN(); diff --git a/absl/memory/memory.h b/absl/memory/memory.h index 055d88e001b3..cd818cff4ffa 100644 --- a/absl/memory/memory.h +++ b/absl/memory/memory.h @@ -179,9 +179,9 @@ typename memory_internal::MakeUniqueResult<T>::invalid make_unique( // useful within templates that need to handle a complement of raw pointers, // `std::nullptr_t`, and smart pointers. template <typename T> -auto RawPtr(T&& ptr) -> decltype(&*ptr) { +auto RawPtr(T&& ptr) -> decltype(std::addressof(*ptr)) { // ptr is a forwarding reference to support Ts with non-const operators. - return (ptr != nullptr) ? &*ptr : nullptr; + return (ptr != nullptr) ? std::addressof(*ptr) : nullptr; } inline std::nullptr_t RawPtr(std::nullptr_t) { return nullptr; } diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index e6bb7ff530e4..d1c6878c41e4 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -111,7 +111,7 @@ cc_test( size = "small", srcs = [ "escaping_test.cc", - "internal/escaping_test_common.inc", + "internal/escaping_test_common.h", ], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], @@ -127,7 +127,7 @@ cc_test( name = "escaping_benchmark", srcs = [ "escaping_benchmark.cc", - "internal/escaping_test_common.inc", + "internal/escaping_test_common.h", ], copts = ABSL_TEST_COPTS, tags = ["benchmark"], @@ -135,7 +135,7 @@ cc_test( deps = [ ":strings", "//absl/base", - "@com_github_google_benchmark//:benchmark", + "@com_github_google_benchmark//:benchmark_main", ], ) @@ -199,7 +199,7 @@ cc_test( ":strings", "//absl/base", "//absl/base:core_headers", - "@com_github_google_benchmark//:benchmark", + "@com_github_google_benchmark//:benchmark_main", ], ) @@ -240,7 +240,7 @@ cc_test( deps = [ ":strings", "//absl/base", - "@com_github_google_benchmark//:benchmark", + "@com_github_google_benchmark//:benchmark_main", ], ) @@ -278,7 +278,7 @@ cc_test( deps = [ ":strings", "//absl/base", - "@com_github_google_benchmark//:benchmark", + "@com_github_google_benchmark//:benchmark_main", ], ) @@ -295,6 +295,18 @@ cc_test( ) cc_test( + name = "ostringstream_benchmark", + srcs = ["internal/ostringstream_benchmark.cc"], + copts = ABSL_TEST_COPTS, + tags = ["benchmark"], + visibility = ["//visibility:private"], + deps = [ + ":internal", + "@com_github_google_benchmark//:benchmark_main", + ], +) + +cc_test( name = "resize_uninitialized_test", size = "small", srcs = [ @@ -333,7 +345,7 @@ cc_test( deps = [ ":strings", "//absl/memory", - "@com_github_google_benchmark//:benchmark", + "@com_github_google_benchmark//:benchmark_main", ], ) @@ -358,7 +370,7 @@ cc_test( visibility = ["//visibility:private"], deps = [ ":strings", - "@com_github_google_benchmark//:benchmark", + "@com_github_google_benchmark//:benchmark_main", ], ) @@ -366,7 +378,7 @@ cc_test( name = "numbers_test", size = "small", srcs = [ - "internal/numbers_test_common.inc", + "internal/numbers_test_common.h", "numbers_test.cc", ], copts = ABSL_TEST_COPTS, @@ -411,3 +423,14 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "char_map_benchmark", + srcs = ["internal/char_map_benchmark.cc"], + copts = ABSL_TEST_COPTS, + tags = ["benchmark"], + deps = [ + ":internal", + "@com_github_google_benchmark//:benchmark_main", + ], +) diff --git a/absl/strings/escaping_benchmark.cc b/absl/strings/escaping_benchmark.cc index 26ddc2d5f318..0f791f4e8750 100644 --- a/absl/strings/escaping_benchmark.cc +++ b/absl/strings/escaping_benchmark.cc @@ -20,7 +20,7 @@ #include "benchmark/benchmark.h" #include "absl/base/internal/raw_logging.h" -#include "absl/strings/internal/escaping_test_common.inc" +#include "absl/strings/internal/escaping_test_common.h" namespace { @@ -39,7 +39,7 @@ BENCHMARK(BM_CUnescapeHexString); void BM_WebSafeBase64Escape_string(benchmark::State& state) { std::string raw; for (int i = 0; i < 10; ++i) { - for (const auto& test_set : base64_strings) { + for (const auto& test_set : absl::strings_internal::base64_strings()) { raw += std::string(test_set.plaintext); } } @@ -92,5 +92,3 @@ void BM_CEscape_MostEscaped(benchmark::State& state) { BENCHMARK(BM_CEscape_MostEscaped)->Range(1, 1 << 14); } // namespace - -BENCHMARK_MAIN(); diff --git a/absl/strings/escaping_test.cc b/absl/strings/escaping_test.cc index 982989b8b4a4..3f65ec107f45 100644 --- a/absl/strings/escaping_test.cc +++ b/absl/strings/escaping_test.cc @@ -25,7 +25,7 @@ #include "absl/container/fixed_array.h" #include "absl/strings/str_cat.h" -#include "absl/strings/internal/escaping_test_common.inc" +#include "absl/strings/internal/escaping_test_common.h" namespace { @@ -575,7 +575,7 @@ TEST(Base64, EscapeAndUnescape) { } // Now try the long strings, this tests the streaming - for (const auto& tc : base64_strings) { + for (const auto& tc : absl::strings_internal::base64_strings()) { std::string buffer; absl::WebSafeBase64Escape(tc.plaintext, &buffer); EXPECT_EQ(tc.cyphertext, buffer); diff --git a/absl/strings/internal/char_map_benchmark.cc b/absl/strings/internal/char_map_benchmark.cc new file mode 100644 index 000000000000..c45f3157c291 --- /dev/null +++ b/absl/strings/internal/char_map_benchmark.cc @@ -0,0 +1,61 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/strings/internal/char_map.h" + +#include <cstdint> + +#include "benchmark/benchmark.h" + +namespace { + +absl::strings_internal::Charmap MakeBenchmarkMap() { + absl::strings_internal::Charmap m; + uint32_t x[] = {0x0, 0x1, 0x2, 0x3, 0xf, 0xe, 0xd, 0xc}; + for (uint32_t& t : x) t *= static_cast<uint32_t>(0x11111111UL); + for (uint32_t i = 0; i < 256; ++i) { + if ((x[i / 32] >> (i % 32)) & 1) + m = m | absl::strings_internal::Charmap::Char(i); + } + return m; +} + +// Micro-benchmark for Charmap::contains. +void BM_Contains(benchmark::State& state) { + // Loop-body replicated 10 times to increase time per iteration. + // Argument continuously changed to avoid generating common subexpressions. + const absl::strings_internal::Charmap benchmark_map = MakeBenchmarkMap(); + unsigned char c = 0; + int ops = 0; + for (auto _ : state) { + ops += benchmark_map.contains(c++); + ops += benchmark_map.contains(c++); + ops += benchmark_map.contains(c++); + ops += benchmark_map.contains(c++); + ops += benchmark_map.contains(c++); + ops += benchmark_map.contains(c++); + ops += benchmark_map.contains(c++); + ops += benchmark_map.contains(c++); + ops += benchmark_map.contains(c++); + ops += benchmark_map.contains(c++); + } + benchmark::DoNotOptimize(ops); +} +BENCHMARK(BM_Contains); + +// We don't bother benchmarking Charmap::IsZero or Charmap::IntersectsWith; +// their running time is data-dependent and it is not worth characterizing +// "typical" data. + +} // namespace diff --git a/absl/strings/internal/escaping_test_common.h b/absl/strings/internal/escaping_test_common.h new file mode 100644 index 000000000000..cc41f4312c7c --- /dev/null +++ b/absl/strings/internal/escaping_test_common.h @@ -0,0 +1,131 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This test contains common things needed by both escaping_test.cc and +// escaping_benchmark.cc. + +#ifndef ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_ +#define ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_ + +#include <array> +#include "absl/strings/string_view.h" + +namespace absl { +namespace strings_internal { + +struct base64_testcase { + absl::string_view plaintext; + absl::string_view cyphertext; +}; + +inline const std::array<base64_testcase, 5>& base64_strings() { + static const std::array<base64_testcase, 5> testcase{{ + // Some google quotes + // Cyphertext created with "uuencode (GNU sharutils) 4.6.3" + // (Note that we're testing the websafe encoding, though, so if + // you add messages, be sure to run "tr -- '+/' '-_'" on the output) + { "I was always good at math and science, and I never realized " + "that was unusual or somehow undesirable. So one of the things " + "I care a lot about is helping to remove that stigma, " + "to show girls that you can be feminine, you can like the things " + "that girls like, but you can also be really good at technology. " + "You can be really good at building things." + " - Marissa Meyer, Newsweek, 2010-12-22" "\n", + + "SSB3YXMgYWx3YXlzIGdvb2QgYXQgbWF0aCBhbmQgc2NpZW5jZSwgYW5kIEkg" + "bmV2ZXIgcmVhbGl6ZWQgdGhhdCB3YXMgdW51c3VhbCBvciBzb21laG93IHVu" + "ZGVzaXJhYmxlLiBTbyBvbmUgb2YgdGhlIHRoaW5ncyBJIGNhcmUgYSBsb3Qg" + "YWJvdXQgaXMgaGVscGluZyB0byByZW1vdmUgdGhhdCBzdGlnbWEsIHRvIHNo" + "b3cgZ2lybHMgdGhhdCB5b3UgY2FuIGJlIGZlbWluaW5lLCB5b3UgY2FuIGxp" + "a2UgdGhlIHRoaW5ncyB0aGF0IGdpcmxzIGxpa2UsIGJ1dCB5b3UgY2FuIGFs" + "c28gYmUgcmVhbGx5IGdvb2QgYXQgdGVjaG5vbG9neS4gWW91IGNhbiBiZSBy" + "ZWFsbHkgZ29vZCBhdCBidWlsZGluZyB0aGluZ3MuIC0gTWFyaXNzYSBNZXll" + "ciwgTmV3c3dlZWssIDIwMTAtMTItMjIK" }, + + { "Typical first year for a new cluster: " + "~0.5 overheating " + "~1 PDU failure " + "~1 rack-move " + "~1 network rewiring " + "~20 rack failures " + "~5 racks go wonky " + "~8 network maintenances " + "~12 router reloads " + "~3 router failures " + "~dozens of minor 30-second blips for dns " + "~1000 individual machine failures " + "~thousands of hard drive failures " + "slow disks, bad memory, misconfigured machines, flaky machines, etc." + " - Jeff Dean, The Joys of Real Hardware" "\n", + + "VHlwaWNhbCBmaXJzdCB5ZWFyIGZvciBhIG5ldyBjbHVzdGVyOiB-MC41IG92" + "ZXJoZWF0aW5nIH4xIFBEVSBmYWlsdXJlIH4xIHJhY2stbW92ZSB-MSBuZXR3" + "b3JrIHJld2lyaW5nIH4yMCByYWNrIGZhaWx1cmVzIH41IHJhY2tzIGdvIHdv" + "bmt5IH44IG5ldHdvcmsgbWFpbnRlbmFuY2VzIH4xMiByb3V0ZXIgcmVsb2Fk" + "cyB-MyByb3V0ZXIgZmFpbHVyZXMgfmRvemVucyBvZiBtaW5vciAzMC1zZWNv" + "bmQgYmxpcHMgZm9yIGRucyB-MTAwMCBpbmRpdmlkdWFsIG1hY2hpbmUgZmFp" + "bHVyZXMgfnRob3VzYW5kcyBvZiBoYXJkIGRyaXZlIGZhaWx1cmVzIHNsb3cg" + "ZGlza3MsIGJhZCBtZW1vcnksIG1pc2NvbmZpZ3VyZWQgbWFjaGluZXMsIGZs" + "YWt5IG1hY2hpbmVzLCBldGMuIC0gSmVmZiBEZWFuLCBUaGUgSm95cyBvZiBS" + "ZWFsIEhhcmR3YXJlCg" }, + + { "I'm the head of the webspam team at Google. " + "That means that if you type your name into Google and get porn back, " + "it's my fault. Unless you're a porn star, in which case porn is a " + "completely reasonable response." + " - Matt Cutts, Google Plus" "\n", + + "SSdtIHRoZSBoZWFkIG9mIHRoZSB3ZWJzcGFtIHRlYW0gYXQgR29vZ2xlLiAg" + "VGhhdCBtZWFucyB0aGF0IGlmIHlvdSB0eXBlIHlvdXIgbmFtZSBpbnRvIEdv" + "b2dsZSBhbmQgZ2V0IHBvcm4gYmFjaywgaXQncyBteSBmYXVsdC4gVW5sZXNz" + "IHlvdSdyZSBhIHBvcm4gc3RhciwgaW4gd2hpY2ggY2FzZSBwb3JuIGlzIGEg" + "Y29tcGxldGVseSByZWFzb25hYmxlIHJlc3BvbnNlLiAtIE1hdHQgQ3V0dHMs" + "IEdvb2dsZSBQbHVzCg" }, + + { "It will still be a long time before machines approach human " + "intelligence. " + "But luckily, machines don't actually have to be intelligent; " + "they just have to fake it. Access to a wealth of information, " + "combined with a rudimentary decision-making capacity, " + "can often be almost as useful. Of course, the results are better yet " + "when coupled with intelligence. A reference librarian with access to " + "a good search engine is a formidable tool." + " - Craig Silverstein, Siemens Pictures of the Future, Spring 2004" + "\n", + + "SXQgd2lsbCBzdGlsbCBiZSBhIGxvbmcgdGltZSBiZWZvcmUgbWFjaGluZXMg" + "YXBwcm9hY2ggaHVtYW4gaW50ZWxsaWdlbmNlLiBCdXQgbHVja2lseSwgbWFj" + "aGluZXMgZG9uJ3QgYWN0dWFsbHkgaGF2ZSB0byBiZSBpbnRlbGxpZ2VudDsg" + "dGhleSBqdXN0IGhhdmUgdG8gZmFrZSBpdC4gQWNjZXNzIHRvIGEgd2VhbHRo" + "IG9mIGluZm9ybWF0aW9uLCBjb21iaW5lZCB3aXRoIGEgcnVkaW1lbnRhcnkg" + "ZGVjaXNpb24tbWFraW5nIGNhcGFjaXR5LCBjYW4gb2Z0ZW4gYmUgYWxtb3N0" + "IGFzIHVzZWZ1bC4gT2YgY291cnNlLCB0aGUgcmVzdWx0cyBhcmUgYmV0dGVy" + "IHlldCB3aGVuIGNvdXBsZWQgd2l0aCBpbnRlbGxpZ2VuY2UuIEEgcmVmZXJl" + "bmNlIGxpYnJhcmlhbiB3aXRoIGFjY2VzcyB0byBhIGdvb2Qgc2VhcmNoIGVu" + "Z2luZSBpcyBhIGZvcm1pZGFibGUgdG9vbC4gLSBDcmFpZyBTaWx2ZXJzdGVp" + "biwgU2llbWVucyBQaWN0dXJlcyBvZiB0aGUgRnV0dXJlLCBTcHJpbmcgMjAw" + "NAo" }, + + // Degenerate edge case + { "", + "" }, + }}; + + return testcase; +} + +} // namespace strings_internal +} // namespace absl + +#endif // ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_ diff --git a/absl/strings/internal/escaping_test_common.inc b/absl/strings/internal/escaping_test_common.inc deleted file mode 100644 index 6f29140e3584..000000000000 --- a/absl/strings/internal/escaping_test_common.inc +++ /dev/null @@ -1,113 +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 test contains common things needed by both escaping_test.cc and -// escaping_benchmark.cc. - -namespace { - -struct { - absl::string_view plaintext; - absl::string_view cyphertext; -} const base64_strings[] = { - // Some google quotes - // Cyphertext created with "uuencode (GNU sharutils) 4.6.3" - // (Note that we're testing the websafe encoding, though, so if - // you add messages, be sure to run "tr -- '+/' '-_'" on the output) - { "I was always good at math and science, and I never realized " - "that was unusual or somehow undesirable. So one of the things " - "I care a lot about is helping to remove that stigma, " - "to show girls that you can be feminine, you can like the things " - "that girls like, but you can also be really good at technology. " - "You can be really good at building things." - " - Marissa Meyer, Newsweek, 2010-12-22" "\n", - - "SSB3YXMgYWx3YXlzIGdvb2QgYXQgbWF0aCBhbmQgc2NpZW5jZSwgYW5kIEkg" - "bmV2ZXIgcmVhbGl6ZWQgdGhhdCB3YXMgdW51c3VhbCBvciBzb21laG93IHVu" - "ZGVzaXJhYmxlLiBTbyBvbmUgb2YgdGhlIHRoaW5ncyBJIGNhcmUgYSBsb3Qg" - "YWJvdXQgaXMgaGVscGluZyB0byByZW1vdmUgdGhhdCBzdGlnbWEsIHRvIHNo" - "b3cgZ2lybHMgdGhhdCB5b3UgY2FuIGJlIGZlbWluaW5lLCB5b3UgY2FuIGxp" - "a2UgdGhlIHRoaW5ncyB0aGF0IGdpcmxzIGxpa2UsIGJ1dCB5b3UgY2FuIGFs" - "c28gYmUgcmVhbGx5IGdvb2QgYXQgdGVjaG5vbG9neS4gWW91IGNhbiBiZSBy" - "ZWFsbHkgZ29vZCBhdCBidWlsZGluZyB0aGluZ3MuIC0gTWFyaXNzYSBNZXll" - "ciwgTmV3c3dlZWssIDIwMTAtMTItMjIK" }, - - { "Typical first year for a new cluster: " - "~0.5 overheating " - "~1 PDU failure " - "~1 rack-move " - "~1 network rewiring " - "~20 rack failures " - "~5 racks go wonky " - "~8 network maintenances " - "~12 router reloads " - "~3 router failures " - "~dozens of minor 30-second blips for dns " - "~1000 individual machine failures " - "~thousands of hard drive failures " - "slow disks, bad memory, misconfigured machines, flaky machines, etc." - " - Jeff Dean, The Joys of Real Hardware" "\n", - - "VHlwaWNhbCBmaXJzdCB5ZWFyIGZvciBhIG5ldyBjbHVzdGVyOiB-MC41IG92" - "ZXJoZWF0aW5nIH4xIFBEVSBmYWlsdXJlIH4xIHJhY2stbW92ZSB-MSBuZXR3" - "b3JrIHJld2lyaW5nIH4yMCByYWNrIGZhaWx1cmVzIH41IHJhY2tzIGdvIHdv" - "bmt5IH44IG5ldHdvcmsgbWFpbnRlbmFuY2VzIH4xMiByb3V0ZXIgcmVsb2Fk" - "cyB-MyByb3V0ZXIgZmFpbHVyZXMgfmRvemVucyBvZiBtaW5vciAzMC1zZWNv" - "bmQgYmxpcHMgZm9yIGRucyB-MTAwMCBpbmRpdmlkdWFsIG1hY2hpbmUgZmFp" - "bHVyZXMgfnRob3VzYW5kcyBvZiBoYXJkIGRyaXZlIGZhaWx1cmVzIHNsb3cg" - "ZGlza3MsIGJhZCBtZW1vcnksIG1pc2NvbmZpZ3VyZWQgbWFjaGluZXMsIGZs" - "YWt5IG1hY2hpbmVzLCBldGMuIC0gSmVmZiBEZWFuLCBUaGUgSm95cyBvZiBS" - "ZWFsIEhhcmR3YXJlCg" }, - - { "I'm the head of the webspam team at Google. " - "That means that if you type your name into Google and get porn back, " - "it's my fault. Unless you're a porn star, in which case porn is a " - "completely reasonable response." - " - Matt Cutts, Google Plus" "\n", - - "SSdtIHRoZSBoZWFkIG9mIHRoZSB3ZWJzcGFtIHRlYW0gYXQgR29vZ2xlLiAg" - "VGhhdCBtZWFucyB0aGF0IGlmIHlvdSB0eXBlIHlvdXIgbmFtZSBpbnRvIEdv" - "b2dsZSBhbmQgZ2V0IHBvcm4gYmFjaywgaXQncyBteSBmYXVsdC4gVW5sZXNz" - "IHlvdSdyZSBhIHBvcm4gc3RhciwgaW4gd2hpY2ggY2FzZSBwb3JuIGlzIGEg" - "Y29tcGxldGVseSByZWFzb25hYmxlIHJlc3BvbnNlLiAtIE1hdHQgQ3V0dHMs" - "IEdvb2dsZSBQbHVzCg" }, - - { "It will still be a long time before machines approach human intelligence. " - "But luckily, machines don't actually have to be intelligent; " - "they just have to fake it. Access to a wealth of information, " - "combined with a rudimentary decision-making capacity, " - "can often be almost as useful. Of course, the results are better yet " - "when coupled with intelligence. A reference librarian with access to " - "a good search engine is a formidable tool." - " - Craig Silverstein, Siemens Pictures of the Future, Spring 2004" "\n", - - "SXQgd2lsbCBzdGlsbCBiZSBhIGxvbmcgdGltZSBiZWZvcmUgbWFjaGluZXMg" - "YXBwcm9hY2ggaHVtYW4gaW50ZWxsaWdlbmNlLiBCdXQgbHVja2lseSwgbWFj" - "aGluZXMgZG9uJ3QgYWN0dWFsbHkgaGF2ZSB0byBiZSBpbnRlbGxpZ2VudDsg" - "dGhleSBqdXN0IGhhdmUgdG8gZmFrZSBpdC4gQWNjZXNzIHRvIGEgd2VhbHRo" - "IG9mIGluZm9ybWF0aW9uLCBjb21iaW5lZCB3aXRoIGEgcnVkaW1lbnRhcnkg" - "ZGVjaXNpb24tbWFraW5nIGNhcGFjaXR5LCBjYW4gb2Z0ZW4gYmUgYWxtb3N0" - "IGFzIHVzZWZ1bC4gT2YgY291cnNlLCB0aGUgcmVzdWx0cyBhcmUgYmV0dGVy" - "IHlldCB3aGVuIGNvdXBsZWQgd2l0aCBpbnRlbGxpZ2VuY2UuIEEgcmVmZXJl" - "bmNlIGxpYnJhcmlhbiB3aXRoIGFjY2VzcyB0byBhIGdvb2Qgc2VhcmNoIGVu" - "Z2luZSBpcyBhIGZvcm1pZGFibGUgdG9vbC4gLSBDcmFpZyBTaWx2ZXJzdGVp" - "biwgU2llbWVucyBQaWN0dXJlcyBvZiB0aGUgRnV0dXJlLCBTcHJpbmcgMjAw" - "NAo" }, - - // Degenerate edge case - { "", - "" }, -}; - -} // namespace diff --git a/absl/strings/internal/numbers_test_common.h b/absl/strings/internal/numbers_test_common.h new file mode 100644 index 000000000000..20e3af51141e --- /dev/null +++ b/absl/strings/internal/numbers_test_common.h @@ -0,0 +1,178 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This file contains common things needed by numbers_test.cc, +// numbers_legacy_test.cc and numbers_benchmark.cc. + +#ifndef ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_ +#define ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_ + +#include <array> +#include <cstdint> +#include <limits> +#include <string> + +namespace absl { +namespace strings_internal { + +template <typename IntType> +inline bool Itoa(IntType value, int base, std::string* destination) { + destination->clear(); + if (base <= 1 || base > 36) { + return false; + } + + if (value == 0) { + destination->push_back('0'); + return true; + } + + bool negative = value < 0; + while (value != 0) { + const IntType next_value = value / base; + // Can't use std::abs here because of problems when IntType is unsigned. + int remainder = value > next_value * base ? value - next_value * base + : next_value * base - value; + char c = remainder < 10 ? '0' + remainder : 'A' + remainder - 10; + destination->insert(0, 1, c); + value = next_value; + } + + if (negative) { + destination->insert(0, 1, '-'); + } + return true; +} + +struct uint32_test_case { + const char* str; + bool expect_ok; + int base; // base to pass to the conversion function + uint32_t expected; +}; + +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()}, + {"0x34234324", true, 16, 0x34234324}, + {"34234324", true, 16, 0x34234324}, + {"0", true, 16, 0}, + {" \t\n 0xffffffff", true, 16, std::numeric_limits<uint32_t>::max()}, + {" \f\v 46", true, 10, 46}, // must accept weird whitespace + {" \t\n 72717222", true, 8, 072717222}, + {" \t\n 072717222", true, 8, 072717222}, + {" \t\n 072717228", false, 8, 07271722}, + {"0", true, 0, 0}, + + // Base-10 version. + {"34234324", true, 0, 34234324}, + {"4294967295", true, 0, std::numeric_limits<uint32_t>::max()}, + {"34234324 \n\t", true, 10, 34234324}, + + // Unusual base + {"0", true, 3, 0}, + {"2", true, 3, 2}, + {"11", true, 3, 4}, + + // Invalid uints. + {"", false, 0, 0}, + {" ", false, 0, 0}, + {"abc", false, 0, 0}, // would be valid hex, but prefix is missing + {"34234324a", false, 0, 34234324}, + {"34234.3", false, 0, 34234}, + {"-1", false, 0, 0}, + {" -123", false, 0, 0}, + {" \t\n -123", false, 0, 0}, + + // Out of bounds. + {"4294967296", false, 0, std::numeric_limits<uint32_t>::max()}, + {"0x100000000", false, 0, std::numeric_limits<uint32_t>::max()}, + {nullptr, false, 0, 0}, + }}; + return test_cases; +} + +struct uint64_test_case { + const char* str; + bool expect_ok; + int base; + uint64_t expected; +}; + +inline const std::array<uint64_test_case, 34>& strtouint64_test_cases() { + static const std::array<uint64_test_case, 34> test_cases{{ + {"0x3423432448783446", true, 16, int64_t{0x3423432448783446}}, + {"3423432448783446", true, 16, int64_t{0x3423432448783446}}, + + {"0", true, 16, 0}, + {"000", true, 0, 0}, + {"0", true, 0, 0}, + {" \t\n 0xffffffffffffffff", true, 16, + std::numeric_limits<uint64_t>::max()}, + + {"012345670123456701234", true, 8, int64_t{012345670123456701234}}, + {"12345670123456701234", true, 8, int64_t{012345670123456701234}}, + + {"12845670123456701234", false, 8, 0}, + + // Base-10 version. + {"34234324487834466", true, 0, int64_t{34234324487834466}}, + + {" \t\n 18446744073709551615", true, 0, + std::numeric_limits<uint64_t>::max()}, + + {"34234324487834466 \n\t ", true, 0, int64_t{34234324487834466}}, + + {" \f\v 46", true, 10, 46}, // must accept weird whitespace + + // Unusual base + {"0", true, 3, 0}, + {"2", true, 3, 2}, + {"11", true, 3, 4}, + + {"0", true, 0, 0}, + + // Invalid uints. + {"", false, 0, 0}, + {" ", false, 0, 0}, + {"abc", false, 0, 0}, + {"34234324487834466a", false, 0, 0}, + {"34234487834466.3", false, 0, 0}, + {"-1", false, 0, 0}, + {" -123", false, 0, 0}, + {" \t\n -123", false, 0, 0}, + + // Out of bounds. + {"18446744073709551616", false, 10, 0}, + {"18446744073709551616", false, 0, 0}, + {"0x10000000000000000", false, 16, std::numeric_limits<uint64_t>::max()}, + {"0X10000000000000000", false, 16, + std::numeric_limits<uint64_t>::max()}, // 0X versus 0x. + {"0x10000000000000000", false, 0, std::numeric_limits<uint64_t>::max()}, + {"0X10000000000000000", false, 0, + std::numeric_limits<uint64_t>::max()}, // 0X versus 0x. + + {"0x1234", true, 16, 0x1234}, + + // Base-10 std::string version. + {"1234", true, 0, 1234}, + {nullptr, false, 0, 0}, + }}; + return test_cases; +} + +} // namespace strings_internal +} // namespace absl + +#endif // ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_ diff --git a/absl/strings/internal/numbers_test_common.inc b/absl/strings/internal/numbers_test_common.inc deleted file mode 100644 index 81d2a1b70510..000000000000 --- a/absl/strings/internal/numbers_test_common.inc +++ /dev/null @@ -1,156 +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 common things needed by numbers_test.cc, -// numbers_legacy_test.cc and numbers_benchmark.cc. - -namespace { - -template <typename IntType> -bool Itoa(IntType value, int base, std::string* destination) { - destination->clear(); - if (base <= 1 || base > 36) { - return false; - } - - if (value == 0) { - destination->push_back('0'); - return true; - } - - bool negative = value < 0; - while (value != 0) { - const IntType next_value = value / base; - // Can't use std::abs here because of problems when IntType is unsigned. - int remainder = value > next_value * base ? value - next_value * base - : next_value * base - value; - char c = remainder < 10 ? '0' + remainder : 'A' + remainder - 10; - destination->insert(0, 1, c); - value = next_value; - } - - if (negative) { - destination->insert(0, 1, '-'); - } - return true; -} - -struct uint32_test_case { - const char* str; - bool expect_ok; - int base; // base to pass to the conversion function - uint32_t expected; -} const strtouint32_test_cases[] = { - {"0xffffffff", true, 16, std::numeric_limits<uint32_t>::max()}, - {"0x34234324", true, 16, 0x34234324}, - {"34234324", true, 16, 0x34234324}, - {"0", true, 16, 0}, - {" \t\n 0xffffffff", true, 16, std::numeric_limits<uint32_t>::max()}, - {" \f\v 46", true, 10, 46}, // must accept weird whitespace - {" \t\n 72717222", true, 8, 072717222}, - {" \t\n 072717222", true, 8, 072717222}, - {" \t\n 072717228", false, 8, 07271722}, - {"0", true, 0, 0}, - - // Base-10 version. - {"34234324", true, 0, 34234324}, - {"4294967295", true, 0, std::numeric_limits<uint32_t>::max()}, - {"34234324 \n\t", true, 10, 34234324}, - - // Unusual base - {"0", true, 3, 0}, - {"2", true, 3, 2}, - {"11", true, 3, 4}, - - // Invalid uints. - {"", false, 0, 0}, - {" ", false, 0, 0}, - {"abc", false, 0, 0}, // would be valid hex, but prefix is missing - {"34234324a", false, 0, 34234324}, - {"34234.3", false, 0, 34234}, - {"-1", false, 0, 0}, - {" -123", false, 0, 0}, - {" \t\n -123", false, 0, 0}, - - // Out of bounds. - {"4294967296", false, 0, std::numeric_limits<uint32_t>::max()}, - {"0x100000000", false, 0, std::numeric_limits<uint32_t>::max()}, - {nullptr, false, 0, 0}, -}; - -struct uint64_test_case { - const char* str; - bool expect_ok; - int base; - uint64_t expected; -} const strtouint64_test_cases[] = { - {"0x3423432448783446", true, 16, int64_t{0x3423432448783446}}, - {"3423432448783446", true, 16, int64_t{0x3423432448783446}}, - - {"0", true, 16, 0}, - {"000", true, 0, 0}, - {"0", true, 0, 0}, - {" \t\n 0xffffffffffffffff", true, 16, - std::numeric_limits<uint64_t>::max()}, - - {"012345670123456701234", true, 8, int64_t{012345670123456701234}}, - {"12345670123456701234", true, 8, int64_t{012345670123456701234}}, - - {"12845670123456701234", false, 8, 0}, - - // Base-10 version. - {"34234324487834466", true, 0, int64_t{34234324487834466}}, - - {" \t\n 18446744073709551615", true, 0, - std::numeric_limits<uint64_t>::max()}, - - {"34234324487834466 \n\t ", true, 0, int64_t{34234324487834466}}, - - {" \f\v 46", true, 10, 46}, // must accept weird whitespace - - // Unusual base - {"0", true, 3, 0}, - {"2", true, 3, 2}, - {"11", true, 3, 4}, - - {"0", true, 0, 0}, - - // Invalid uints. - {"", false, 0, 0}, - {" ", false, 0, 0}, - {"abc", false, 0, 0}, - {"34234324487834466a", false, 0, 0}, - {"34234487834466.3", false, 0, 0}, - {"-1", false, 0, 0}, - {" -123", false, 0, 0}, - {" \t\n -123", false, 0, 0}, - - // Out of bounds. - {"18446744073709551616", false, 10, 0}, - {"18446744073709551616", false, 0, 0}, - {"0x10000000000000000", false, 16, std::numeric_limits<uint64_t>::max()}, - {"0X10000000000000000", false, 16, - std::numeric_limits<uint64_t>::max()}, // 0X versus 0x. - {"0x10000000000000000", false, 0, std::numeric_limits<uint64_t>::max()}, - {"0X10000000000000000", false, 0, - std::numeric_limits<uint64_t>::max()}, // 0X versus 0x. - - {"0x1234", true, 16, 0x1234}, - - // Base-10 std::string version. - {"1234", true, 0, 1234}, - {nullptr, false, 0, 0}, -}; - -} // namespace diff --git a/absl/strings/internal/ostringstream_benchmark.cc b/absl/strings/internal/ostringstream_benchmark.cc new file mode 100644 index 000000000000..c93f96909d8b --- /dev/null +++ b/absl/strings/internal/ostringstream_benchmark.cc @@ -0,0 +1,106 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/strings/internal/ostringstream.h" + +#include <sstream> +#include <string> + +#include "benchmark/benchmark.h" + +namespace { + +enum StringType { + kNone, + kStdString, +}; + +// Benchmarks for std::ostringstream. +template <StringType kOutput> +void BM_StdStream(benchmark::State& state) { + const int num_writes = state.range(0); + const int bytes_per_write = state.range(1); + const std::string payload(bytes_per_write, 'x'); + for (auto _ : state) { + std::ostringstream strm; + benchmark::DoNotOptimize(strm); + for (int i = 0; i != num_writes; ++i) { + strm << payload; + } + switch (kOutput) { + case kNone: { + break; + } + case kStdString: { + std::string s = strm.str(); + benchmark::DoNotOptimize(s); + break; + } + } + } +} + +// Create the stream, optionally write to it, then destroy it. +BENCHMARK_TEMPLATE(BM_StdStream, kNone) + ->ArgPair(0, 0) + ->ArgPair(1, 16) // 16 bytes is small enough for SSO + ->ArgPair(1, 256) // 256 bytes requires heap allocation + ->ArgPair(1024, 256); +// Create the stream, write to it, get std::string out, then destroy. +BENCHMARK_TEMPLATE(BM_StdStream, kStdString) + ->ArgPair(1, 16) // 16 bytes is small enough for SSO + ->ArgPair(1, 256) // 256 bytes requires heap allocation + ->ArgPair(1024, 256); + +// Benchmarks for OStringStream. +template <StringType kOutput> +void BM_CustomStream(benchmark::State& state) { + const int num_writes = state.range(0); + const int bytes_per_write = state.range(1); + const std::string payload(bytes_per_write, 'x'); + for (auto _ : state) { + std::string out; + absl::strings_internal::OStringStream strm(&out); + benchmark::DoNotOptimize(strm); + for (int i = 0; i != num_writes; ++i) { + strm << payload; + } + switch (kOutput) { + case kNone: { + break; + } + case kStdString: { + std::string s = out; + benchmark::DoNotOptimize(s); + break; + } + } + } +} + +// Create the stream, optionally write to it, then destroy it. +BENCHMARK_TEMPLATE(BM_CustomStream, kNone) + ->ArgPair(0, 0) + ->ArgPair(1, 16) // 16 bytes is small enough for SSO + ->ArgPair(1, 256) // 256 bytes requires heap allocation + ->ArgPair(1024, 256); +// Create the stream, write to it, get std::string out, then destroy. +// It's not useful in practice to extract std::string from OStringStream; we +// measure it for completeness. +BENCHMARK_TEMPLATE(BM_CustomStream, kStdString) + ->ArgPair(1, 16) // 16 bytes is small enough for SSO + ->ArgPair(1, 256) // 256 bytes requires heap allocation + ->ArgPair(1024, 256); + +} // namespace diff --git a/absl/strings/numbers.h b/absl/strings/numbers.h index 75925e61f2c0..cf3c597266cf 100644 --- a/absl/strings/numbers.h +++ b/absl/strings/numbers.h @@ -52,12 +52,16 @@ ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view s, int_type* out); // // Converts the given std::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/std::string/byte/strtof for details about the +// allowed formats for `str`. ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* value); // SimpleAtod() // // Converts the given std::string (optionally followed or preceded by ASCII // whitespace) into a double, which may be rounded on overflow or underflow. +// See http://en.cppreference.com/w/c/std::string/byte/strtof for details about the +// allowed formats for `str`. ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str, double* value); // SimpleAtob() diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc index e372eea14ca8..24e7138cfae2 100644 --- a/absl/strings/numbers_test.cc +++ b/absl/strings/numbers_test.cc @@ -38,7 +38,7 @@ #include "absl/base/internal/raw_logging.h" #include "absl/strings/str_cat.h" -#include "absl/strings/internal/numbers_test_common.inc" +#include "absl/strings/internal/numbers_test_common.h" namespace { @@ -48,6 +48,9 @@ using absl::numbers_internal::safe_strto64_base; using absl::numbers_internal::safe_strtou32_base; using absl::numbers_internal::safe_strtou64_base; using absl::numbers_internal::SixDigitsToBuffer; +using absl::strings_internal::Itoa; +using absl::strings_internal::strtouint32_test_cases; +using absl::strings_internal::strtouint64_test_cases; using absl::SimpleAtoi; using testing::Eq; using testing::MatchesRegex; @@ -654,8 +657,8 @@ TEST(stringtest, safe_strtou64_random) { } TEST(stringtest, safe_strtou32_base) { - for (int i = 0; strtouint32_test_cases[i].str != nullptr; ++i) { - const auto& e = strtouint32_test_cases[i]; + for (int i = 0; strtouint32_test_cases()[i].str != nullptr; ++i) { + const auto& e = strtouint32_test_cases()[i]; uint32_t value; EXPECT_EQ(e.expect_ok, safe_strtou32_base(e.str, &value, e.base)) << "str=\"" << e.str << "\" base=" << e.base; @@ -667,8 +670,8 @@ TEST(stringtest, safe_strtou32_base) { } TEST(stringtest, safe_strtou32_base_length_delimited) { - for (int i = 0; strtouint32_test_cases[i].str != nullptr; ++i) { - const auto& e = strtouint32_test_cases[i]; + for (int i = 0; strtouint32_test_cases()[i].str != nullptr; ++i) { + const auto& e = strtouint32_test_cases()[i]; std::string tmp(e.str); tmp.append("12"); // Adds garbage at the end. @@ -685,8 +688,8 @@ TEST(stringtest, safe_strtou32_base_length_delimited) { } TEST(stringtest, safe_strtou64_base) { - for (int i = 0; strtouint64_test_cases[i].str != nullptr; ++i) { - const auto& e = strtouint64_test_cases[i]; + for (int i = 0; strtouint64_test_cases()[i].str != nullptr; ++i) { + const auto& e = strtouint64_test_cases()[i]; uint64_t value; EXPECT_EQ(e.expect_ok, safe_strtou64_base(e.str, &value, e.base)) << "str=\"" << e.str << "\" base=" << e.base; @@ -697,8 +700,8 @@ TEST(stringtest, safe_strtou64_base) { } TEST(stringtest, safe_strtou64_base_length_delimited) { - for (int i = 0; strtouint64_test_cases[i].str != nullptr; ++i) { - const auto& e = strtouint64_test_cases[i]; + for (int i = 0; strtouint64_test_cases()[i].str != nullptr; ++i) { + const auto& e = strtouint64_test_cases()[i]; std::string tmp(e.str); tmp.append("12"); // Adds garbage at the end. diff --git a/absl/strings/str_cat_benchmark.cc b/absl/strings/str_cat_benchmark.cc index 1791410c6e3a..b6df9e309c4f 100644 --- a/absl/strings/str_cat_benchmark.cc +++ b/absl/strings/str_cat_benchmark.cc @@ -138,5 +138,3 @@ void BM_DoubleToString_By_SixDigits(benchmark::State& state) { BENCHMARK(BM_DoubleToString_By_SixDigits); } // namespace - -BENCHMARK_MAIN(); diff --git a/absl/strings/str_join_benchmark.cc b/absl/strings/str_join_benchmark.cc index 79cad5e39300..7fb0e4973cb4 100644 --- a/absl/strings/str_join_benchmark.cc +++ b/absl/strings/str_join_benchmark.cc @@ -94,5 +94,3 @@ BENCHMARK(BM_JoinStreamable) ->ArgPair(256, 256); } // namespace - -BENCHMARK_MAIN(); diff --git a/absl/strings/str_replace_benchmark.cc b/absl/strings/str_replace_benchmark.cc index 9dd72eb6e77c..e608de8d19e4 100644 --- a/absl/strings/str_replace_benchmark.cc +++ b/absl/strings/str_replace_benchmark.cc @@ -120,5 +120,3 @@ void BM_StrReplaceAll(benchmark::State& state) { BENCHMARK(BM_StrReplaceAll); } // namespace - -BENCHMARK_MAIN(); diff --git a/absl/strings/str_split_benchmark.cc b/absl/strings/str_split_benchmark.cc index c35787b7ef4b..326ff744ebd9 100644 --- a/absl/strings/str_split_benchmark.cc +++ b/absl/strings/str_split_benchmark.cc @@ -154,5 +154,3 @@ BENCHMARK_TEMPLATE(BM_SplitStringWithOneCharNoVector, OneCharLiteral); BENCHMARK_TEMPLATE(BM_SplitStringWithOneCharNoVector, OneCharStringLiteral); } // namespace - -BENCHMARK_MAIN(); diff --git a/absl/strings/string_view_benchmark.cc b/absl/strings/string_view_benchmark.cc index c66f0fbd5430..fb46db18b3c3 100644 --- a/absl/strings/string_view_benchmark.cc +++ b/absl/strings/string_view_benchmark.cc @@ -327,5 +327,3 @@ void BM_AppendToStringNative(benchmark::State& state) { BENCHMARK(BM_AppendToStringNative)->Range(1 << 3, 1 << 12); } // namespace - -BENCHMARK_MAIN(); diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h index 5747d384d34e..c4b25ba70952 100644 --- a/absl/strings/substitute.h +++ b/absl/strings/substitute.h @@ -99,7 +99,10 @@ class Arg { // Explicitly overload `const char*` so the compiler doesn't cast to `bool`. Arg(const char* value) // NOLINT(runtime/explicit) : piece_(absl::NullSafeStringView(value)) {} - Arg(const std::string& value) // NOLINT(runtime/explicit) + template <typename Allocator> + Arg( // NOLINT + const std::basic_string<char, std::char_traits<char>, Allocator>& + value) noexcept : piece_(value) {} Arg(absl::string_view value) // NOLINT(runtime/explicit) : piece_(value) {} diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel index 2502c53fff2b..123536ea4d10 100644 --- a/absl/synchronization/BUILD.bazel +++ b/absl/synchronization/BUILD.bazel @@ -130,7 +130,7 @@ cc_test( deps = [ ":graphcycles_internal", "//absl/base", - "@com_github_google_benchmark//:benchmark", + "@com_github_google_benchmark//:benchmark_main", ], ) @@ -176,7 +176,7 @@ cc_test( ":synchronization", ":thread_pool", "//absl/base", - "@com_github_google_benchmark//:benchmark", + "@com_github_google_benchmark//:benchmark_main", ], ) diff --git a/absl/synchronization/internal/graphcycles_benchmark.cc b/absl/synchronization/internal/graphcycles_benchmark.cc index b4a1debe752e..a239c25c3a81 100644 --- a/absl/synchronization/internal/graphcycles_benchmark.cc +++ b/absl/synchronization/internal/graphcycles_benchmark.cc @@ -42,5 +42,3 @@ void BM_StressTest(benchmark::State& state) { BENCHMARK(BM_StressTest)->Range(2048, 1048576); } // namespace - -BENCHMARK_MAIN(); diff --git a/absl/synchronization/mutex_benchmark.cc b/absl/synchronization/mutex_benchmark.cc index d91071b71bdd..30a523556c3d 100644 --- a/absl/synchronization/mutex_benchmark.cc +++ b/absl/synchronization/mutex_benchmark.cc @@ -92,5 +92,3 @@ BENCHMARK(BM_ContendedMutex)->Threads(1); BENCHMARK(BM_ContendedMutex)->ThreadPerCpu(); } // namespace - -BENCHMARK_MAIN(); diff --git a/absl/time/BUILD.bazel b/absl/time/BUILD.bazel index 7126f1410f8f..64cb99f73716 100644 --- a/absl/time/BUILD.bazel +++ b/absl/time/BUILD.bazel @@ -81,10 +81,6 @@ cc_test( ], copts = ABSL_TEST_COPTS, tags = [ - "no_test_android_arm", - "no_test_android_arm64", - "no_test_android_x86", - "no_test_ios_x86_64", "no_test_loonix", ], deps = [ diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel index 468470b4fb63..9f1ba21cf7e2 100644 --- a/absl/time/internal/cctz/BUILD.bazel +++ b/absl/time/internal/cctz/BUILD.bazel @@ -81,6 +81,11 @@ cc_test( size = "small", srcs = ["src/time_zone_format_test.cc"], data = [":zoneinfo"], + tags = [ + "no_test_android_arm", + "no_test_android_arm64", + "no_test_android_x86", + ], deps = [ ":civil_time", ":time_zone", @@ -93,6 +98,11 @@ cc_test( size = "small", srcs = ["src/time_zone_lookup_test.cc"], data = [":zoneinfo"], + tags = [ + "no_test_android_arm", + "no_test_android_arm64", + "no_test_android_x86", + ], deps = [ ":civil_time", ":time_zone", @@ -102,6 +112,24 @@ cc_test( ### benchmarks +cc_test( + name = "cctz_benchmark", + srcs = [ + "src/cctz_benchmark.cc", + "src/time_zone_if.h", + "src/time_zone_impl.h", + "src/time_zone_info.h", + "src/tzfile.h", + ], + linkstatic = 1, + tags = ["benchmark"], + deps = [ + ":civil_time", + ":time_zone", + "@com_github_google_benchmark//:benchmark_main", + ], +) + ### examples ### binaries diff --git a/absl/time/internal/cctz/src/cctz_benchmark.cc b/absl/time/internal/cctz/src/cctz_benchmark.cc new file mode 100644 index 000000000000..f13cb4ee6b5f --- /dev/null +++ b/absl/time/internal/cctz/src/cctz_benchmark.cc @@ -0,0 +1,982 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <algorithm> +#include <cassert> +#include <chrono> +#include <ctime> +#include <random> +#include <string> +#include <vector> + +#include "benchmark/benchmark.h" +#include "absl/time/internal/cctz/include/cctz/civil_time.h" +#include "absl/time/internal/cctz/include/cctz/time_zone.h" +#include "time_zone_impl.h" + +namespace { + +namespace cctz = absl::time_internal::cctz; + +void BM_Difference_Days(benchmark::State& state) { + const cctz::civil_day c(2014, 8, 22); + const cctz::civil_day epoch(1970, 1, 1); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(c - epoch); + } +} +BENCHMARK(BM_Difference_Days); + +void BM_Step_Days(benchmark::State& state) { + const cctz::civil_day kStart(2014, 8, 22); + cctz::civil_day c = kStart; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(++c); + } +} +BENCHMARK(BM_Step_Days); + +const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez"; +const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez"; + +const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z"; +const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z"; + +// A list of known time-zone names. +// TODO: Refactor with src/time_zone_lookup_test.cc. +const char* const kTimeZoneNames[] = { + "Africa/Abidjan", + "Africa/Accra", + "Africa/Addis_Ababa", + "Africa/Algiers", + "Africa/Asmara", + "Africa/Asmera", + "Africa/Bamako", + "Africa/Bangui", + "Africa/Banjul", + "Africa/Bissau", + "Africa/Blantyre", + "Africa/Brazzaville", + "Africa/Bujumbura", + "Africa/Cairo", + "Africa/Casablanca", + "Africa/Ceuta", + "Africa/Conakry", + "Africa/Dakar", + "Africa/Dar_es_Salaam", + "Africa/Djibouti", + "Africa/Douala", + "Africa/El_Aaiun", + "Africa/Freetown", + "Africa/Gaborone", + "Africa/Harare", + "Africa/Johannesburg", + "Africa/Juba", + "Africa/Kampala", + "Africa/Khartoum", + "Africa/Kigali", + "Africa/Kinshasa", + "Africa/Lagos", + "Africa/Libreville", + "Africa/Lome", + "Africa/Luanda", + "Africa/Lubumbashi", + "Africa/Lusaka", + "Africa/Malabo", + "Africa/Maputo", + "Africa/Maseru", + "Africa/Mbabane", + "Africa/Mogadishu", + "Africa/Monrovia", + "Africa/Nairobi", + "Africa/Ndjamena", + "Africa/Niamey", + "Africa/Nouakchott", + "Africa/Ouagadougou", + "Africa/Porto-Novo", + "Africa/Sao_Tome", + "Africa/Timbuktu", + "Africa/Tripoli", + "Africa/Tunis", + "Africa/Windhoek", + "America/Adak", + "America/Anchorage", + "America/Anguilla", + "America/Antigua", + "America/Araguaina", + "America/Argentina/Buenos_Aires", + "America/Argentina/Catamarca", + "America/Argentina/ComodRivadavia", + "America/Argentina/Cordoba", + "America/Argentina/Jujuy", + "America/Argentina/La_Rioja", + "America/Argentina/Mendoza", + "America/Argentina/Rio_Gallegos", + "America/Argentina/Salta", + "America/Argentina/San_Juan", + "America/Argentina/San_Luis", + "America/Argentina/Tucuman", + "America/Argentina/Ushuaia", + "America/Aruba", + "America/Asuncion", + "America/Atikokan", + "America/Atka", + "America/Bahia", + "America/Bahia_Banderas", + "America/Barbados", + "America/Belem", + "America/Belize", + "America/Blanc-Sablon", + "America/Boa_Vista", + "America/Bogota", + "America/Boise", + "America/Buenos_Aires", + "America/Cambridge_Bay", + "America/Campo_Grande", + "America/Cancun", + "America/Caracas", + "America/Catamarca", + "America/Cayenne", + "America/Cayman", + "America/Chicago", + "America/Chihuahua", + "America/Coral_Harbour", + "America/Cordoba", + "America/Costa_Rica", + "America/Creston", + "America/Cuiaba", + "America/Curacao", + "America/Danmarkshavn", + "America/Dawson", + "America/Dawson_Creek", + "America/Denver", + "America/Detroit", + "America/Dominica", + "America/Edmonton", + "America/Eirunepe", + "America/El_Salvador", + "America/Ensenada", + "America/Fort_Nelson", + "America/Fort_Wayne", + "America/Fortaleza", + "America/Glace_Bay", + "America/Godthab", + "America/Goose_Bay", + "America/Grand_Turk", + "America/Grenada", + "America/Guadeloupe", + "America/Guatemala", + "America/Guayaquil", + "America/Guyana", + "America/Halifax", + "America/Havana", + "America/Hermosillo", + "America/Indiana/Indianapolis", + "America/Indiana/Knox", + "America/Indiana/Marengo", + "America/Indiana/Petersburg", + "America/Indiana/Tell_City", + "America/Indiana/Vevay", + "America/Indiana/Vincennes", + "America/Indiana/Winamac", + "America/Indianapolis", + "America/Inuvik", + "America/Iqaluit", + "America/Jamaica", + "America/Jujuy", + "America/Juneau", + "America/Kentucky/Louisville", + "America/Kentucky/Monticello", + "America/Knox_IN", + "America/Kralendijk", + "America/La_Paz", + "America/Lima", + "America/Los_Angeles", + "America/Louisville", + "America/Lower_Princes", + "America/Maceio", + "America/Managua", + "America/Manaus", + "America/Marigot", + "America/Martinique", + "America/Matamoros", + "America/Mazatlan", + "America/Mendoza", + "America/Menominee", + "America/Merida", + "America/Metlakatla", + "America/Mexico_City", + "America/Miquelon", + "America/Moncton", + "America/Monterrey", + "America/Montevideo", + "America/Montreal", + "America/Montserrat", + "America/Nassau", + "America/New_York", + "America/Nipigon", + "America/Nome", + "America/Noronha", + "America/North_Dakota/Beulah", + "America/North_Dakota/Center", + "America/North_Dakota/New_Salem", + "America/Ojinaga", + "America/Panama", + "America/Pangnirtung", + "America/Paramaribo", + "America/Phoenix", + "America/Port-au-Prince", + "America/Port_of_Spain", + "America/Porto_Acre", + "America/Porto_Velho", + "America/Puerto_Rico", + "America/Punta_Arenas", + "America/Rainy_River", + "America/Rankin_Inlet", + "America/Recife", + "America/Regina", + "America/Resolute", + "America/Rio_Branco", + "America/Rosario", + "America/Santa_Isabel", + "America/Santarem", + "America/Santiago", + "America/Santo_Domingo", + "America/Sao_Paulo", + "America/Scoresbysund", + "America/Shiprock", + "America/Sitka", + "America/St_Barthelemy", + "America/St_Johns", + "America/St_Kitts", + "America/St_Lucia", + "America/St_Thomas", + "America/St_Vincent", + "America/Swift_Current", + "America/Tegucigalpa", + "America/Thule", + "America/Thunder_Bay", + "America/Tijuana", + "America/Toronto", + "America/Tortola", + "America/Vancouver", + "America/Virgin", + "America/Whitehorse", + "America/Winnipeg", + "America/Yakutat", + "America/Yellowknife", + "Antarctica/Casey", + "Antarctica/Davis", + "Antarctica/DumontDUrville", + "Antarctica/Macquarie", + "Antarctica/Mawson", + "Antarctica/McMurdo", + "Antarctica/Palmer", + "Antarctica/Rothera", + "Antarctica/South_Pole", + "Antarctica/Syowa", + "Antarctica/Troll", + "Antarctica/Vostok", + "Arctic/Longyearbyen", + "Asia/Aden", + "Asia/Almaty", + "Asia/Amman", + "Asia/Anadyr", + "Asia/Aqtau", + "Asia/Aqtobe", + "Asia/Ashgabat", + "Asia/Ashkhabad", + "Asia/Atyrau", + "Asia/Baghdad", + "Asia/Bahrain", + "Asia/Baku", + "Asia/Bangkok", + "Asia/Barnaul", + "Asia/Beirut", + "Asia/Bishkek", + "Asia/Brunei", + "Asia/Calcutta", + "Asia/Chita", + "Asia/Choibalsan", + "Asia/Chongqing", + "Asia/Chungking", + "Asia/Colombo", + "Asia/Dacca", + "Asia/Damascus", + "Asia/Dhaka", + "Asia/Dili", + "Asia/Dubai", + "Asia/Dushanbe", + "Asia/Famagusta", + "Asia/Gaza", + "Asia/Harbin", + "Asia/Hebron", + "Asia/Ho_Chi_Minh", + "Asia/Hong_Kong", + "Asia/Hovd", + "Asia/Irkutsk", + "Asia/Istanbul", + "Asia/Jakarta", + "Asia/Jayapura", + "Asia/Jerusalem", + "Asia/Kabul", + "Asia/Kamchatka", + "Asia/Karachi", + "Asia/Kashgar", + "Asia/Kathmandu", + "Asia/Katmandu", + "Asia/Khandyga", + "Asia/Kolkata", + "Asia/Krasnoyarsk", + "Asia/Kuala_Lumpur", + "Asia/Kuching", + "Asia/Kuwait", + "Asia/Macao", + "Asia/Macau", + "Asia/Magadan", + "Asia/Makassar", + "Asia/Manila", + "Asia/Muscat", + "Asia/Nicosia", + "Asia/Novokuznetsk", + "Asia/Novosibirsk", + "Asia/Omsk", + "Asia/Oral", + "Asia/Phnom_Penh", + "Asia/Pontianak", + "Asia/Pyongyang", + "Asia/Qatar", + "Asia/Qyzylorda", + "Asia/Rangoon", + "Asia/Riyadh", + "Asia/Saigon", + "Asia/Sakhalin", + "Asia/Samarkand", + "Asia/Seoul", + "Asia/Shanghai", + "Asia/Singapore", + "Asia/Srednekolymsk", + "Asia/Taipei", + "Asia/Tashkent", + "Asia/Tbilisi", + "Asia/Tehran", + "Asia/Tel_Aviv", + "Asia/Thimbu", + "Asia/Thimphu", + "Asia/Tokyo", + "Asia/Tomsk", + "Asia/Ujung_Pandang", + "Asia/Ulaanbaatar", + "Asia/Ulan_Bator", + "Asia/Urumqi", + "Asia/Ust-Nera", + "Asia/Vientiane", + "Asia/Vladivostok", + "Asia/Yakutsk", + "Asia/Yangon", + "Asia/Yekaterinburg", + "Asia/Yerevan", + "Atlantic/Azores", + "Atlantic/Bermuda", + "Atlantic/Canary", + "Atlantic/Cape_Verde", + "Atlantic/Faeroe", + "Atlantic/Faroe", + "Atlantic/Jan_Mayen", + "Atlantic/Madeira", + "Atlantic/Reykjavik", + "Atlantic/South_Georgia", + "Atlantic/St_Helena", + "Atlantic/Stanley", + "Australia/ACT", + "Australia/Adelaide", + "Australia/Brisbane", + "Australia/Broken_Hill", + "Australia/Canberra", + "Australia/Currie", + "Australia/Darwin", + "Australia/Eucla", + "Australia/Hobart", + "Australia/LHI", + "Australia/Lindeman", + "Australia/Lord_Howe", + "Australia/Melbourne", + "Australia/NSW", + "Australia/North", + "Australia/Perth", + "Australia/Queensland", + "Australia/South", + "Australia/Sydney", + "Australia/Tasmania", + "Australia/Victoria", + "Australia/West", + "Australia/Yancowinna", + "Brazil/Acre", + "Brazil/DeNoronha", + "Brazil/East", + "Brazil/West", + "CET", + "CST6CDT", + "Canada/Atlantic", + "Canada/Central", + "Canada/Eastern", + "Canada/Mountain", + "Canada/Newfoundland", + "Canada/Pacific", + "Canada/Saskatchewan", + "Canada/Yukon", + "Chile/Continental", + "Chile/EasterIsland", + "Cuba", + "EET", + "EST", + "EST5EDT", + "Egypt", + "Eire", + "Etc/GMT", + "Etc/GMT+0", + "Etc/GMT+1", + "Etc/GMT+10", + "Etc/GMT+11", + "Etc/GMT+12", + "Etc/GMT+2", + "Etc/GMT+3", + "Etc/GMT+4", + "Etc/GMT+5", + "Etc/GMT+6", + "Etc/GMT+7", + "Etc/GMT+8", + "Etc/GMT+9", + "Etc/GMT-0", + "Etc/GMT-1", + "Etc/GMT-10", + "Etc/GMT-11", + "Etc/GMT-12", + "Etc/GMT-13", + "Etc/GMT-14", + "Etc/GMT-2", + "Etc/GMT-3", + "Etc/GMT-4", + "Etc/GMT-5", + "Etc/GMT-6", + "Etc/GMT-7", + "Etc/GMT-8", + "Etc/GMT-9", + "Etc/GMT0", + "Etc/Greenwich", + "Etc/UCT", + "Etc/UTC", + "Etc/Universal", + "Etc/Zulu", + "Europe/Amsterdam", + "Europe/Andorra", + "Europe/Astrakhan", + "Europe/Athens", + "Europe/Belfast", + "Europe/Belgrade", + "Europe/Berlin", + "Europe/Bratislava", + "Europe/Brussels", + "Europe/Bucharest", + "Europe/Budapest", + "Europe/Busingen", + "Europe/Chisinau", + "Europe/Copenhagen", + "Europe/Dublin", + "Europe/Gibraltar", + "Europe/Guernsey", + "Europe/Helsinki", + "Europe/Isle_of_Man", + "Europe/Istanbul", + "Europe/Jersey", + "Europe/Kaliningrad", + "Europe/Kiev", + "Europe/Kirov", + "Europe/Lisbon", + "Europe/Ljubljana", + "Europe/London", + "Europe/Luxembourg", + "Europe/Madrid", + "Europe/Malta", + "Europe/Mariehamn", + "Europe/Minsk", + "Europe/Monaco", + "Europe/Moscow", + "Europe/Nicosia", + "Europe/Oslo", + "Europe/Paris", + "Europe/Podgorica", + "Europe/Prague", + "Europe/Riga", + "Europe/Rome", + "Europe/Samara", + "Europe/San_Marino", + "Europe/Sarajevo", + "Europe/Saratov", + "Europe/Simferopol", + "Europe/Skopje", + "Europe/Sofia", + "Europe/Stockholm", + "Europe/Tallinn", + "Europe/Tirane", + "Europe/Tiraspol", + "Europe/Ulyanovsk", + "Europe/Uzhgorod", + "Europe/Vaduz", + "Europe/Vatican", + "Europe/Vienna", + "Europe/Vilnius", + "Europe/Volgograd", + "Europe/Warsaw", + "Europe/Zagreb", + "Europe/Zaporozhye", + "Europe/Zurich", + "GB", + "GB-Eire", + "GMT", + "GMT+0", + "GMT-0", + "GMT0", + "Greenwich", + "HST", + "Hongkong", + "Iceland", + "Indian/Antananarivo", + "Indian/Chagos", + "Indian/Christmas", + "Indian/Cocos", + "Indian/Comoro", + "Indian/Kerguelen", + "Indian/Mahe", + "Indian/Maldives", + "Indian/Mauritius", + "Indian/Mayotte", + "Indian/Reunion", + "Iran", + "Israel", + "Jamaica", + "Japan", + "Kwajalein", + "Libya", + "MET", + "MST", + "MST7MDT", + "Mexico/BajaNorte", + "Mexico/BajaSur", + "Mexico/General", + "NZ", + "NZ-CHAT", + "Navajo", + "PRC", + "PST8PDT", + "Pacific/Apia", + "Pacific/Auckland", + "Pacific/Bougainville", + "Pacific/Chatham", + "Pacific/Chuuk", + "Pacific/Easter", + "Pacific/Efate", + "Pacific/Enderbury", + "Pacific/Fakaofo", + "Pacific/Fiji", + "Pacific/Funafuti", + "Pacific/Galapagos", + "Pacific/Gambier", + "Pacific/Guadalcanal", + "Pacific/Guam", + "Pacific/Honolulu", + "Pacific/Johnston", + "Pacific/Kiritimati", + "Pacific/Kosrae", + "Pacific/Kwajalein", + "Pacific/Majuro", + "Pacific/Marquesas", + "Pacific/Midway", + "Pacific/Nauru", + "Pacific/Niue", + "Pacific/Norfolk", + "Pacific/Noumea", + "Pacific/Pago_Pago", + "Pacific/Palau", + "Pacific/Pitcairn", + "Pacific/Pohnpei", + "Pacific/Ponape", + "Pacific/Port_Moresby", + "Pacific/Rarotonga", + "Pacific/Saipan", + "Pacific/Samoa", + "Pacific/Tahiti", + "Pacific/Tarawa", + "Pacific/Tongatapu", + "Pacific/Truk", + "Pacific/Wake", + "Pacific/Wallis", + "Pacific/Yap", + "Poland", + "Portugal", + "ROC", + "ROK", + "Singapore", + "Turkey", + "UCT", + "US/Alaska", + "US/Aleutian", + "US/Arizona", + "US/Central", + "US/East-Indiana", + "US/Eastern", + "US/Hawaii", + "US/Indiana-Starke", + "US/Michigan", + "US/Mountain", + "US/Pacific", + "US/Samoa", + "UTC", + "Universal", + "W-SU", + "WET", + "Zulu", + nullptr +}; + +std::vector<std::string> AllTimeZoneNames() { + std::vector<std::string> names; + for (const char* const* namep = kTimeZoneNames; *namep != nullptr; ++namep) { + names.push_back(std::string("file:") + *namep); + } + assert(!names.empty()); + + std::mt19937 urbg(42); // a UniformRandomBitGenerator with fixed seed + std::shuffle(names.begin(), names.end(), urbg); + return names; +} + +cctz::time_zone TestTimeZone() { + cctz::time_zone tz; + cctz::load_time_zone("America/Los_Angeles", &tz); + return tz; +} + +void BM_Zone_LoadUTCTimeZoneFirst(benchmark::State& state) { + cctz::time_zone tz; + cctz::load_time_zone("UTC", &tz); // in case we're first + cctz::time_zone::Impl::ClearTimeZoneMapTestOnly(); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(cctz::load_time_zone("UTC", &tz)); + } +} +BENCHMARK(BM_Zone_LoadUTCTimeZoneFirst); + +void BM_Zone_LoadUTCTimeZoneLast(benchmark::State& state) { + cctz::time_zone tz; + for (const auto& name : AllTimeZoneNames()) { + cctz::load_time_zone(name, &tz); // prime cache + } + while (state.KeepRunning()) { + benchmark::DoNotOptimize(cctz::load_time_zone("UTC", &tz)); + } +} +BENCHMARK(BM_Zone_LoadUTCTimeZoneLast); + +void BM_Zone_LoadTimeZoneFirst(benchmark::State& state) { + cctz::time_zone tz = cctz::utc_time_zone(); // in case we're first + const std::string name = "file:America/Los_Angeles"; + while (state.KeepRunning()) { + state.PauseTiming(); + cctz::time_zone::Impl::ClearTimeZoneMapTestOnly(); + state.ResumeTiming(); + benchmark::DoNotOptimize(cctz::load_time_zone(name, &tz)); + } +} +BENCHMARK(BM_Zone_LoadTimeZoneFirst); + +void BM_Zone_LoadTimeZoneCached(benchmark::State& state) { + cctz::time_zone tz = cctz::utc_time_zone(); // in case we're first + cctz::time_zone::Impl::ClearTimeZoneMapTestOnly(); + const std::string name = "file:America/Los_Angeles"; + cctz::load_time_zone(name, &tz); // prime cache + while (state.KeepRunning()) { + benchmark::DoNotOptimize(cctz::load_time_zone(name, &tz)); + } +} +BENCHMARK(BM_Zone_LoadTimeZoneCached); + +void BM_Zone_LoadLocalTimeZoneCached(benchmark::State& state) { + cctz::utc_time_zone(); // in case we're first + cctz::time_zone::Impl::ClearTimeZoneMapTestOnly(); + cctz::local_time_zone(); // prime cache + while (state.KeepRunning()) { + benchmark::DoNotOptimize(cctz::local_time_zone()); + } +} +BENCHMARK(BM_Zone_LoadLocalTimeZoneCached); + +void BM_Zone_LoadAllTimeZonesFirst(benchmark::State& state) { + cctz::time_zone tz; + const std::vector<std::string> names = AllTimeZoneNames(); + for (auto index = names.size(); state.KeepRunning(); ++index) { + if (index == names.size()) { + index = 0; + } + if (index == 0) { + state.PauseTiming(); + cctz::time_zone::Impl::ClearTimeZoneMapTestOnly(); + state.ResumeTiming(); + } + benchmark::DoNotOptimize(cctz::load_time_zone(names[index], &tz)); + } +} +BENCHMARK(BM_Zone_LoadAllTimeZonesFirst); + +void BM_Zone_LoadAllTimeZonesCached(benchmark::State& state) { + cctz::time_zone tz; + const std::vector<std::string> names = AllTimeZoneNames(); + for (const auto& name : names) { + cctz::load_time_zone(name, &tz); // prime cache + } + for (auto index = names.size(); state.KeepRunning(); ++index) { + if (index == names.size()) { + index = 0; + } + benchmark::DoNotOptimize(cctz::load_time_zone(names[index], &tz)); + } +} +BENCHMARK(BM_Zone_LoadAllTimeZonesCached); + +void BM_Zone_TimeZoneImplGetImplicit(benchmark::State& state) { + cctz::time_zone tz; // implicit UTC + cctz::time_zone::Impl::get(tz); + while (state.KeepRunning()) { + cctz::time_zone::Impl::get(tz); + } +} +BENCHMARK(BM_Zone_TimeZoneImplGetImplicit); + +void BM_Zone_TimeZoneImplGetExplicit(benchmark::State& state) { + cctz::time_zone tz = cctz::utc_time_zone(); // explicit UTC + cctz::time_zone::Impl::get(tz); + while (state.KeepRunning()) { + cctz::time_zone::Impl::get(tz); + } +} +BENCHMARK(BM_Zone_TimeZoneImplGetExplicit); + +void BM_Zone_UTCTimeZone(benchmark::State& state) { + cctz::time_zone tz; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(cctz::utc_time_zone()); + } +} +BENCHMARK(BM_Zone_UTCTimeZone); + +// In each "ToDateTime" benchmark we switch between two instants +// separated by at least one transition in order to defeat any +// internal caching of previous results (e.g., see local_time_hint_). +// +// The "UTC" variants use UTC instead of the Google/local time zone. + +void BM_Time_ToDateTime_CCTZ(benchmark::State& state) { + const cctz::time_zone tz = TestTimeZone(); + std::chrono::system_clock::time_point tp = + std::chrono::system_clock::from_time_t(1384569027); + std::chrono::system_clock::time_point tp2 = + std::chrono::system_clock::from_time_t(1418962578); + while (state.KeepRunning()) { + std::swap(tp, tp2); + tp += std::chrono::seconds(1); + benchmark::DoNotOptimize(cctz::convert(tp, tz)); + } +} +BENCHMARK(BM_Time_ToDateTime_CCTZ); + +void BM_Time_ToDateTime_Libc(benchmark::State& state) { + // No timezone support, so just use localtime. + time_t t = 1384569027; + time_t t2 = 1418962578; + struct tm tm; + while (state.KeepRunning()) { + std::swap(t, t2); + t += 1; +#if defined(_WIN32) || defined(_WIN64) + benchmark::DoNotOptimize(localtime_s(&tm, &t)); +#else + benchmark::DoNotOptimize(localtime_r(&t, &tm)); +#endif + } +} +BENCHMARK(BM_Time_ToDateTime_Libc); + +void BM_Time_ToDateTimeUTC_CCTZ(benchmark::State& state) { + const cctz::time_zone tz = cctz::utc_time_zone(); + std::chrono::system_clock::time_point tp = + std::chrono::system_clock::from_time_t(1384569027); + while (state.KeepRunning()) { + tp += std::chrono::seconds(1); + benchmark::DoNotOptimize(cctz::convert(tp, tz)); + } +} +BENCHMARK(BM_Time_ToDateTimeUTC_CCTZ); + +void BM_Time_ToDateTimeUTC_Libc(benchmark::State& state) { + time_t t = 1384569027; + struct tm tm; + while (state.KeepRunning()) { + t += 1; +#if defined(_WIN32) || defined(_WIN64) + benchmark::DoNotOptimize(gmtime_s(&tm, &t)); +#else + benchmark::DoNotOptimize(gmtime_r(&t, &tm)); +#endif + } +} +BENCHMARK(BM_Time_ToDateTimeUTC_Libc); + +// 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_). +// +// 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_CCTZ(benchmark::State& state) { + const cctz::time_zone tz = TestTimeZone(); + int i = 0; + while (state.KeepRunning()) { + if ((i++ & 1) == 0) { + benchmark::DoNotOptimize( + cctz::convert(cctz::civil_second(2014, 12, 18, 20, 16, 18), tz)); + } else { + benchmark::DoNotOptimize( + cctz::convert(cctz::civil_second(2013, 11, 15, 18, 30, 27), tz)); + } + } +} +BENCHMARK(BM_Time_FromDateTime_CCTZ); + +void BM_Time_FromDateTime_Libc(benchmark::State& state) { + // No timezone support, so just use localtime. + int i = 0; + while (state.KeepRunning()) { + struct tm tm; + if ((i++ & 1) == 0) { + tm.tm_year = 2014 - 1900; + tm.tm_mon = 12 - 1; + tm.tm_mday = 18; + tm.tm_hour = 20; + tm.tm_min = 16; + tm.tm_sec = 18; + } else { + tm.tm_year = 2013 - 1900; + tm.tm_mon = 11 - 1; + tm.tm_mday = 15; + tm.tm_hour = 18; + tm.tm_min = 30; + tm.tm_sec = 27; + } + tm.tm_isdst = -1; + benchmark::DoNotOptimize(mktime(&tm)); + } +} +BENCHMARK(BM_Time_FromDateTime_Libc); + +void BM_Time_FromDateTimeUTC_CCTZ(benchmark::State& state) { + const cctz::time_zone tz = cctz::utc_time_zone(); + while (state.KeepRunning()) { + benchmark::DoNotOptimize( + cctz::convert(cctz::civil_second(2014, 12, 18, 20, 16, 18), tz)); + } +} +BENCHMARK(BM_Time_FromDateTimeUTC_CCTZ); + +// There is no BM_Time_FromDateTimeUTC_Libc. + +void BM_Time_FromDateTimeDay0_CCTZ(benchmark::State& state) { + const cctz::time_zone tz = TestTimeZone(); + int i = 0; + while (state.KeepRunning()) { + if ((i++ & 1) == 0) { + benchmark::DoNotOptimize( + cctz::convert(cctz::civil_second(2014, 12, 0, 20, 16, 18), tz)); + } else { + benchmark::DoNotOptimize( + cctz::convert(cctz::civil_second(2013, 11, 0, 18, 30, 27), tz)); + } + } +} +BENCHMARK(BM_Time_FromDateTimeDay0_CCTZ); + +void BM_Time_FromDateTimeDay0_Libc(benchmark::State& state) { + // No timezone support, so just use localtime. + int i = 0; + while (state.KeepRunning()) { + struct tm tm; + if ((i++ & 1) == 0) { + tm.tm_year = 2014 - 1900; + tm.tm_mon = 12 - 1; + tm.tm_mday = 0; + tm.tm_hour = 20; + tm.tm_min = 16; + tm.tm_sec = 18; + } else { + tm.tm_year = 2013 - 1900; + tm.tm_mon = 11 - 1; + tm.tm_mday = 0; + tm.tm_hour = 18; + tm.tm_min = 30; + tm.tm_sec = 27; + } + tm.tm_isdst = -1; + benchmark::DoNotOptimize(mktime(&tm)); + } +} +BENCHMARK(BM_Time_FromDateTimeDay0_Libc); + +const char* const kFormats[] = { + RFC1123_full, // 0 + RFC1123_no_wday, // 1 + RFC3339_full, // 2 + RFC3339_sec, // 3 + "%Y-%m-%dT%H:%M:%S", // 4 + "%Y-%m-%d", // 5 +}; +const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]); + +void BM_Format_FormatTime(benchmark::State& state) { + const std::string fmt = kFormats[state.range(0)]; + state.SetLabel(fmt); + const cctz::time_zone tz = TestTimeZone(); + const std::chrono::system_clock::time_point tp = + cctz::convert(cctz::civil_second(1977, 6, 28, 9, 8, 7), tz) + + std::chrono::microseconds(1); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(cctz::format(fmt, tp, tz)); + } +} +BENCHMARK(BM_Format_FormatTime)->DenseRange(0, kNumFormats - 1); + +void BM_Format_ParseTime(benchmark::State& state) { + const std::string fmt = kFormats[state.range(0)]; + state.SetLabel(fmt); + const cctz::time_zone tz = TestTimeZone(); + std::chrono::system_clock::time_point tp = + cctz::convert(cctz::civil_second(1977, 6, 28, 9, 8, 7), tz) + + std::chrono::microseconds(1); + const std::string when = cctz::format(fmt, tp, tz); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(cctz::parse(fmt, when, tz, &tp)); + } +} +BENCHMARK(BM_Format_ParseTime)->DenseRange(0, kNumFormats - 1); + +} // namespace 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 6cea0360dd0e..3a5f19ac8b1f 100644 --- a/absl/time/internal/cctz/src/time_zone_format_test.cc +++ b/absl/time/internal/cctz/src/time_zone_format_test.cc @@ -463,8 +463,13 @@ TEST(Format, ExtendedSecondOffset) { EXPECT_TRUE(load_time_zone("Europe/Moscow", &tz)); tp = convert(civil_second(1919, 6, 30, 23, 59, 59), utc); - TestFormatSpecifier(tp, tz, "%E*z", "+04:31:19"); - TestFormatSpecifier(tp, tz, "%Ez", "+04:31"); + if (tz.lookup(tp).offset == 4 * 60 * 60) { + // We're likely dealing with zoneinfo that doesn't support really old + // timestamps, so Europe/Moscow never looks to be on local mean time. + } else { + TestFormatSpecifier(tp, tz, "%E*z", "+04:31:19"); + TestFormatSpecifier(tp, tz, "%Ez", "+04:31"); + } tp += seconds(1); TestFormatSpecifier(tp, tz, "%E*z", "+04:00:00"); } diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel index f8d53c263bab..c26c68d0b35f 100644 --- a/absl/types/BUILD.bazel +++ b/absl/types/BUILD.bazel @@ -193,6 +193,20 @@ cc_test( ], ) +cc_test( + name = "optional_exception_safety_test", + srcs = [ + "optional_exception_safety_test.cc", + ], + copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, + deps = [ + ":optional", + "//absl/base:exception_safety_testing", + "@com_google_googletest//:gtest_main", + ], +) + + cc_library( name = "variant", srcs = ["internal/variant.h"], diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt index fbd8374031da..2f2e3a778089 100644 --- a/absl/types/CMakeLists.txt +++ b/absl/types/CMakeLists.txt @@ -209,3 +209,20 @@ absl_test( ) +# 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_EXCEPTIONS_FLAG} +) diff --git a/absl/types/optional_exception_safety_test.cc b/absl/types/optional_exception_safety_test.cc new file mode 100644 index 000000000000..7f6348e1b8e1 --- /dev/null +++ b/absl/types/optional_exception_safety_test.cc @@ -0,0 +1,284 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/types/optional.h" + +#include "gtest/gtest.h" +#include "absl/base/internal/exception_safety_testing.h" + +namespace absl { + +namespace { + +using ::testing::AssertionFailure; +using ::testing::AssertionResult; +using ::testing::AssertionSuccess; +using ::testing::MakeExceptionSafetyTester; + +using Thrower = testing::ThrowingValue<testing::TypeSpec::kEverythingThrows>; +using Optional = absl::optional<Thrower>; + +using MoveThrower = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>; +using MoveOptional = absl::optional<MoveThrower>; + +constexpr int kInitialInteger = 5; +constexpr int kUpdatedInteger = 10; + +template <typename OptionalT> +bool ValueThrowsBadOptionalAccess(const OptionalT& optional) try { + return (static_cast<void>(optional.value()), false); +} catch (absl::bad_optional_access) { + return true; +} + +template <typename OptionalT> +AssertionResult CheckInvariants(OptionalT* optional_ptr) { + // Check the current state post-throw for validity + auto& optional = *optional_ptr; + + if (optional.has_value() && ValueThrowsBadOptionalAccess(optional)) { + return AssertionFailure() + << "Optional with value should not throw bad_optional_access when " + "accessing the value."; + } + if (!optional.has_value() && !ValueThrowsBadOptionalAccess(optional)) { + return AssertionFailure() + << "Optional without a value should throw bad_optional_access when " + "accessing the value."; + } + + // Reset to a known state + optional.reset(); + + // Confirm that the known post-reset state is valid + if (optional.has_value()) { + return AssertionFailure() + << "Optional should not contain a value after being reset."; + } + if (!ValueThrowsBadOptionalAccess(optional)) { + return AssertionFailure() << "Optional should throw bad_optional_access " + "when accessing the value after being reset."; + } + + return AssertionSuccess(); +} + +template <typename OptionalT> +AssertionResult CheckDisengaged(OptionalT* optional_ptr) { + auto& optional = *optional_ptr; + + if (optional.has_value()) { + return AssertionFailure() + << "Expected optional to not contain a value but a value was found."; + } + + return AssertionSuccess(); +} + +template <typename OptionalT> +AssertionResult CheckEngaged(OptionalT* optional_ptr) { + auto& optional = *optional_ptr; + + if (!optional.has_value()) { + return AssertionFailure() + << "Expected optional to contain a value but no value was found."; + } + + return AssertionSuccess(); +} + +TEST(OptionalExceptionSafety, ThrowingConstructors) { + auto thrower_nonempty = Optional(Thrower(kInitialInteger)); + testing::TestThrowingCtor<Optional>(thrower_nonempty); + + auto integer_nonempty = absl::optional<int>(kInitialInteger); + testing::TestThrowingCtor<Optional>(integer_nonempty); + testing::TestThrowingCtor<Optional>(std::move(integer_nonempty)); // NOLINT + + testing::TestThrowingCtor<Optional>(kInitialInteger); + using ThrowerVec = std::vector<Thrower, testing::ThrowingAllocator<Thrower>>; + testing::TestThrowingCtor<absl::optional<ThrowerVec>>( + absl::in_place, + std::initializer_list<Thrower>{Thrower(), Thrower(), Thrower()}, + testing::ThrowingAllocator<Thrower>()); +} + +TEST(OptionalExceptionSafety, NothrowConstructors) { + // This constructor is marked noexcept. If it throws, the program will + // terminate. + testing::TestThrowingCtor<MoveOptional>(MoveOptional(kUpdatedInteger)); +} + +TEST(OptionalExceptionSafety, Emplace) { + // Test the basic guarantee plus test the result of optional::has_value() + // is false in all cases + auto disengaged_test = MakeExceptionSafetyTester().WithInvariants( + CheckInvariants<Optional>, CheckDisengaged<Optional>); + auto disengaged_test_empty = disengaged_test.WithInitialValue(Optional()); + auto disengaged_test_nonempty = + disengaged_test.WithInitialValue(Optional(kInitialInteger)); + + auto emplace_thrower_directly = [](Optional* optional_ptr) { + optional_ptr->emplace(kUpdatedInteger); + }; + EXPECT_TRUE(disengaged_test_empty.Test(emplace_thrower_directly)); + EXPECT_TRUE(disengaged_test_nonempty.Test(emplace_thrower_directly)); + + auto emplace_thrower_copy = [](Optional* optional_ptr) { + auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor); + optional_ptr->emplace(thrower); + }; + EXPECT_TRUE(disengaged_test_empty.Test(emplace_thrower_copy)); + EXPECT_TRUE(disengaged_test_nonempty.Test(emplace_thrower_copy)); +} + +TEST(OptionalExceptionSafety, EverythingThrowsSwap) { + // Test the basic guarantee plus test the result of optional::has_value() + // remains the same + auto test = + MakeExceptionSafetyTester().WithInvariants(CheckInvariants<Optional>); + auto disengaged_test_empty = test.WithInitialValue(Optional()) + .WithInvariants(CheckDisengaged<Optional>); + auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger)) + .WithInvariants(CheckEngaged<Optional>); + + auto swap_empty = [](Optional* optional_ptr) { + auto empty = Optional(); + optional_ptr->swap(empty); + }; + EXPECT_TRUE(engaged_test_nonempty.Test(swap_empty)); + + auto swap_nonempty = [](Optional* optional_ptr) { + auto nonempty = + Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor); + optional_ptr->swap(nonempty); + }; + EXPECT_TRUE(disengaged_test_empty.Test(swap_nonempty)); + EXPECT_TRUE(engaged_test_nonempty.Test(swap_nonempty)); +} + +TEST(OptionalExceptionSafety, NoThrowMoveSwap) { + // Tests the nothrow guarantee for optional of T with non-throwing move + auto nothrow_test = + MakeExceptionSafetyTester().WithInvariants(testing::nothrow_guarantee); + auto nothrow_test_empty = nothrow_test.WithInitialValue(MoveOptional()); + auto nothrow_test_nonempty = + nothrow_test.WithInitialValue(MoveOptional(kInitialInteger)); + + auto swap_empty = [](MoveOptional* optional_ptr) { + auto empty = MoveOptional(); + optional_ptr->swap(empty); + }; + EXPECT_TRUE(nothrow_test_nonempty.Test(swap_empty)); + + auto swap_nonempty = [](MoveOptional* optional_ptr) { + auto nonempty = + MoveOptional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor); + optional_ptr->swap(nonempty); + }; + EXPECT_TRUE(nothrow_test_empty.Test(swap_nonempty)); + EXPECT_TRUE(nothrow_test_nonempty.Test(swap_nonempty)); +} + +TEST(OptionalExceptionSafety, CopyAssign) { + // Test the basic guarantee plus test the result of optional::has_value() + // remains the same + auto test = + MakeExceptionSafetyTester().WithInvariants(CheckInvariants<Optional>); + auto disengaged_test_empty = test.WithInitialValue(Optional()) + .WithInvariants(CheckDisengaged<Optional>); + auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger)) + .WithInvariants(CheckEngaged<Optional>); + + auto copyassign_nonempty = [](Optional* optional_ptr) { + auto nonempty = + Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor); + *optional_ptr = nonempty; + }; + EXPECT_TRUE(disengaged_test_empty.Test(copyassign_nonempty)); + EXPECT_TRUE(engaged_test_nonempty.Test(copyassign_nonempty)); + + auto copyassign_thrower = [](Optional* optional_ptr) { + auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor); + *optional_ptr = thrower; + }; + EXPECT_TRUE(disengaged_test_empty.Test(copyassign_thrower)); + EXPECT_TRUE(engaged_test_nonempty.Test(copyassign_thrower)); +} + +TEST(OptionalExceptionSafety, MoveAssign) { + // Test the basic guarantee plus test the result of optional::has_value() + // remains the same + auto test = + MakeExceptionSafetyTester().WithInvariants(CheckInvariants<Optional>); + auto disengaged_test_empty = test.WithInitialValue(Optional()) + .WithInvariants(CheckDisengaged<Optional>); + auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger)) + .WithInvariants(CheckEngaged<Optional>); + + auto moveassign_empty = [](Optional* optional_ptr) { + auto empty = Optional(); + *optional_ptr = std::move(empty); + }; + EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_empty)); + + auto moveassign_nonempty = [](Optional* optional_ptr) { + auto nonempty = + Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor); + *optional_ptr = std::move(nonempty); + }; + EXPECT_TRUE(disengaged_test_empty.Test(moveassign_nonempty)); + EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_nonempty)); + + auto moveassign_thrower = [](Optional* optional_ptr) { + auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor); + *optional_ptr = std::move(thrower); + }; + EXPECT_TRUE(disengaged_test_empty.Test(moveassign_thrower)); + EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_thrower)); +} + +TEST(OptionalExceptionSafety, NothrowMoveAssign) { + // Tests the nothrow guarantee for optional of T with non-throwing move + auto nothrow_test = + MakeExceptionSafetyTester().WithInvariants(testing::nothrow_guarantee); + auto nothrow_test_empty = nothrow_test.WithInitialValue(MoveOptional()); + auto nothrow_test_nonempty = + nothrow_test.WithInitialValue(MoveOptional(kInitialInteger)); + + auto moveassign_empty = [](MoveOptional* optional_ptr) { + auto empty = MoveOptional(); + *optional_ptr = std::move(empty); + }; + EXPECT_TRUE(nothrow_test_nonempty.Test(moveassign_empty)); + + auto moveassign_nonempty = [](MoveOptional* optional_ptr) { + auto nonempty = + MoveOptional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor); + *optional_ptr = std::move(nonempty); + }; + EXPECT_TRUE(nothrow_test_empty.Test(moveassign_nonempty)); + EXPECT_TRUE(nothrow_test_nonempty.Test(moveassign_nonempty)); + + auto moveassign_thrower = [](MoveOptional* optional_ptr) { + auto thrower = MoveThrower(kUpdatedInteger, testing::nothrow_ctor); + *optional_ptr = std::move(thrower); + }; + EXPECT_TRUE(nothrow_test_empty.Test(moveassign_thrower)); + EXPECT_TRUE(nothrow_test_nonempty.Test(moveassign_thrower)); +} + +} // namespace + +} // namespace absl |