Commit 92020a04 by Abseil Team Committed by Gennadiy Civil

- abacaab4b11a69dd4db627bd183571d7cabb8def Refinement to previous time.h edit…

  - abacaab4b11a69dd4db627bd183571d7cabb8def Refinement to previous time.h edit (in this same github p... by Greg Falcon <gfalcon@google.com>
  - 64db19b773134c6c8004e3b23c9ca892efbf8bae Move SpinLock's adaptive spin count computation from a st... by Derek Mauro <dmauro@google.com>
  - 6f9533fb44a52485a7c2bbb9b4efc7bf8d6c359a Import of CCTZ from GitHub. by Abseil Team <absl-team@google.com>
  - a211d7255c986e8dd4ceada362c0d054a6a1969a Cleanup exception flags by Abseil Team <absl-team@google.com>
  - babdb29c590126fe9bba5229fe91034b5b5c358a Release time benchmarks. by Alex Strelnikov <strel@google.com>
  - 5803b32a3ff123d1fb57a0c471d199c818357c9f Release memutil microbenchmarks. by Alex Strelnikov <strel@google.com>
  - 5357d4890d30e80c53beb05af32500fb20e9402b Add parens around expansion of ABSL_PREDICT_{FALSE,TRUE} ... by Abseil Team <absl-team@google.com>
  - 32023f61a239a5f6b1c59e577bfe81b179bbcd2d Reformat build rule tag. by Alex Strelnikov <strel@google.com>
  - 833758ecf2b0cf7a42bbd50b5b127e416425c168 Release uint128 microbenchmarks. by Alex Strelnikov <strel@google.com>
  - c115a9bca1f944b90fdc78a56b2de176466b124f Disambiguate bitwise-not of size_type by Abseil Team <absl-team@google.com>
  - f6905f5b5f6e425792de646edafde440548d9346 Updates ConstructorTracker and TrackedObjects with 1) a m... by Abseil Team <absl-team@google.com>
  - 147c553bdd5d2db20a38f75c4d1ef973d6c709c5 Changes the absl::Duration factory functions to disallow ... by Greg Miller <jgm@google.com>
  - dba2b96d11b5264546b283ba452f2de1303b0f07 White space fix by Alex Strelnikov <strel@google.com>

GitOrigin-RevId: abacaab4b11a69dd4db627bd183571d7cabb8def
Change-Id: I6fa34f20d0b2f898e7b5475a603111413bb80a67
parent 7aacab8a
...@@ -168,8 +168,58 @@ TEST(ThrowingValueTest, ThrowingCompoundAssignmentOps) { ...@@ -168,8 +168,58 @@ TEST(ThrowingValueTest, ThrowingCompoundAssignmentOps) {
TEST(ThrowingValueTest, ThrowingStreamOps) { TEST(ThrowingValueTest, ThrowingStreamOps) {
ThrowingValue<> bomb; ThrowingValue<> bomb;
TestOp([&]() { std::cin >> bomb; }); TestOp([&]() {
TestOp([&]() { std::cout << bomb; }); std::istringstream stream;
stream >> bomb;
});
TestOp([&]() {
std::stringstream stream;
stream << bomb;
});
}
// Tests the operator<< of ThrowingValue by forcing ConstructorTracker to emit
// a nonfatal failure that contains the std::string representation of the Thrower
TEST(ThrowingValueTest, StreamOpsOutput) {
using ::testing::TypeSpec;
exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
// Test default spec list (kEverythingThrows)
EXPECT_NONFATAL_FAILURE(
{
using Thrower = ThrowingValue<TypeSpec{}>;
auto thrower = Thrower(123);
thrower.~Thrower();
},
"ThrowingValue<>(123)");
// Test with one item in spec list (kNoThrowCopy)
EXPECT_NONFATAL_FAILURE(
{
using Thrower = ThrowingValue<TypeSpec::kNoThrowCopy>;
auto thrower = Thrower(234);
thrower.~Thrower();
},
"ThrowingValue<kNoThrowCopy>(234)");
// Test with multiple items in spec list (kNoThrowMove, kNoThrowNew)
EXPECT_NONFATAL_FAILURE(
{
using Thrower =
ThrowingValue<TypeSpec::kNoThrowMove | TypeSpec::kNoThrowNew>;
auto thrower = Thrower(345);
thrower.~Thrower();
},
"ThrowingValue<kNoThrowMove | kNoThrowNew>(345)");
// Test with all items in spec list (kNoThrowCopy, kNoThrowMove, kNoThrowNew)
EXPECT_NONFATAL_FAILURE(
{
using Thrower = ThrowingValue<static_cast<TypeSpec>(-1)>;
auto thrower = Thrower(456);
thrower.~Thrower();
},
"ThrowingValue<kNoThrowCopy | kNoThrowMove | kNoThrowNew>(456)");
} }
template <typename F> template <typename F>
...@@ -653,20 +703,20 @@ struct BasicGuaranteeWithExtraInvariants : public NonNegative { ...@@ -653,20 +703,20 @@ struct BasicGuaranteeWithExtraInvariants : public NonNegative {
}; };
constexpr int BasicGuaranteeWithExtraInvariants::kExceptionSentinel; constexpr int BasicGuaranteeWithExtraInvariants::kExceptionSentinel;
TEST(ExceptionCheckTest, BasicGuaranteeWithInvariants) { TEST(ExceptionCheckTest, BasicGuaranteeWithExtraInvariants) {
auto tester_with_val = auto tester_with_val =
tester.WithInitialValue(BasicGuaranteeWithExtraInvariants{}); tester.WithInitialValue(BasicGuaranteeWithExtraInvariants{});
EXPECT_TRUE(tester_with_val.Test()); EXPECT_TRUE(tester_with_val.Test());
EXPECT_TRUE( EXPECT_TRUE(
tester_with_val tester_with_val
.WithInvariants([](BasicGuaranteeWithExtraInvariants* w) { .WithInvariants([](BasicGuaranteeWithExtraInvariants* o) {
if (w->i == BasicGuaranteeWithExtraInvariants::kExceptionSentinel) { if (o->i == BasicGuaranteeWithExtraInvariants::kExceptionSentinel) {
return testing::AssertionSuccess(); return testing::AssertionSuccess();
} }
return testing::AssertionFailure() return testing::AssertionFailure()
<< "i should be " << "i should be "
<< BasicGuaranteeWithExtraInvariants::kExceptionSentinel << BasicGuaranteeWithExtraInvariants::kExceptionSentinel
<< ", but is " << w->i; << ", but is " << o->i;
}) })
.Test()); .Test());
} }
...@@ -846,29 +896,28 @@ TEST(ConstructorTrackerTest, NotDestroyedAfter) { ...@@ -846,29 +896,28 @@ TEST(ConstructorTrackerTest, NotDestroyedAfter) {
new (&storage) Tracked; new (&storage) Tracked;
}, },
"not destroyed"); "not destroyed");
// Manual destruction of the Tracked instance is not required because
// ~ConstructorTracker() handles that automatically when a leak is found
} }
TEST(ConstructorTrackerTest, DestroyedTwice) { TEST(ConstructorTrackerTest, DestroyedTwice) {
exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
EXPECT_NONFATAL_FAILURE( EXPECT_NONFATAL_FAILURE(
{ {
Tracked t; Tracked t;
t.~Tracked(); t.~Tracked();
}, },
"destroyed improperly"); "re-destroyed");
} }
TEST(ConstructorTrackerTest, ConstructedTwice) { TEST(ConstructorTrackerTest, ConstructedTwice) {
exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage; absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage;
EXPECT_NONFATAL_FAILURE( EXPECT_NONFATAL_FAILURE(
{ {
new (&storage) Tracked; new (&storage) Tracked;
new (&storage) Tracked; new (&storage) Tracked;
reinterpret_cast<Tracked*>(&storage)->~Tracked();
}, },
"re-constructed"); "re-constructed");
reinterpret_cast<Tracked*>(&storage)->~Tracked();
} }
TEST(ThrowingValueTraitsTest, RelationalOperators) { TEST(ThrowingValueTraitsTest, RelationalOperators) {
......
...@@ -21,16 +21,14 @@ namespace testing { ...@@ -21,16 +21,14 @@ namespace testing {
exceptions_internal::NoThrowTag nothrow_ctor; exceptions_internal::NoThrowTag nothrow_ctor;
bool nothrow_guarantee(const void*) {
return ::testing::AssertionFailure()
<< "Exception thrown violating NoThrow Guarantee";
}
exceptions_internal::StrongGuaranteeTagType strong_guarantee; exceptions_internal::StrongGuaranteeTagType strong_guarantee;
namespace exceptions_internal { namespace exceptions_internal {
int countdown = -1; int countdown = -1;
ConstructorTracker* ConstructorTracker::current_tracker_instance_ = nullptr;
void MaybeThrow(absl::string_view msg, bool throw_bad_alloc) { void MaybeThrow(absl::string_view msg, bool throw_bad_alloc) {
if (countdown-- == 0) { if (countdown-- == 0) {
if (throw_bad_alloc) throw TestBadAllocException(msg); if (throw_bad_alloc) throw TestBadAllocException(msg);
...@@ -43,6 +41,31 @@ testing::AssertionResult FailureMessage(const TestException& e, ...@@ -43,6 +41,31 @@ testing::AssertionResult FailureMessage(const TestException& e,
return testing::AssertionFailure() << "Exception thrown from " << e.what(); return testing::AssertionFailure() << "Exception thrown from " << e.what();
} }
std::string GetSpecString(TypeSpec spec) {
std::string out;
absl::string_view sep;
const auto append = [&](absl::string_view s) {
absl::StrAppend(&out, sep, s);
sep = " | ";
};
if (static_cast<bool>(TypeSpec::kNoThrowCopy & spec)) {
append("kNoThrowCopy");
}
if (static_cast<bool>(TypeSpec::kNoThrowMove & spec)) {
append("kNoThrowMove");
}
if (static_cast<bool>(TypeSpec::kNoThrowNew & spec)) {
append("kNoThrowNew");
}
return out;
}
std::string GetSpecString(AllocSpec spec) {
return static_cast<bool>(AllocSpec::kNoThrowAllocate & spec)
? "kNoThrowAllocate"
: "";
}
} // namespace exceptions_internal } // namespace exceptions_internal
} // namespace testing } // namespace testing
...@@ -18,10 +18,12 @@ ...@@ -18,10 +18,12 @@
#include <atomic> #include <atomic>
#include <limits> #include <limits>
#include "absl/base/attributes.h"
#include "absl/base/internal/atomic_hook.h" #include "absl/base/internal/atomic_hook.h"
#include "absl/base/internal/cycleclock.h" #include "absl/base/internal/cycleclock.h"
#include "absl/base/internal/spinlock_wait.h" #include "absl/base/internal/spinlock_wait.h"
#include "absl/base/internal/sysinfo.h" /* For NumCPUs() */ #include "absl/base/internal/sysinfo.h" /* For NumCPUs() */
#include "absl/base/call_once.h"
// Description of lock-word: // Description of lock-word:
// 31..00: [............................3][2][1][0] // 31..00: [............................3][2][1][0]
...@@ -54,30 +56,10 @@ ...@@ -54,30 +56,10 @@
namespace absl { namespace absl {
namespace base_internal { namespace base_internal {
static int adaptive_spin_count = 0;
namespace {
struct SpinLock_InitHelper {
SpinLock_InitHelper() {
// On multi-cpu machines, spin for longer before yielding
// the processor or sleeping. Reduces idle time significantly.
if (base_internal::NumCPUs() > 1) {
adaptive_spin_count = 1000;
}
}
};
// Hook into global constructor execution:
// We do not do adaptive spinning before that,
// but nothing lock-intensive should be going on at that time.
static SpinLock_InitHelper init_helper;
ABSL_CONST_INIT static base_internal::AtomicHook<void (*)(const void *lock, ABSL_CONST_INIT static base_internal::AtomicHook<void (*)(const void *lock,
int64_t wait_cycles)> int64_t wait_cycles)>
submit_profile_data; submit_profile_data;
} // namespace
void RegisterSpinLockProfiler(void (*fn)(const void *contendedlock, void RegisterSpinLockProfiler(void (*fn)(const void *contendedlock,
int64_t wait_cycles)) { int64_t wait_cycles)) {
submit_profile_data.Store(fn); submit_profile_data.Store(fn);
...@@ -120,6 +102,14 @@ void SpinLock::InitLinkerInitializedAndCooperative() { ...@@ -120,6 +102,14 @@ void SpinLock::InitLinkerInitializedAndCooperative() {
// from the lock is returned from the method. // from the lock is returned from the method.
uint32_t SpinLock::SpinLoop(int64_t initial_wait_timestamp, uint32_t SpinLock::SpinLoop(int64_t initial_wait_timestamp,
uint32_t *wait_cycles) { uint32_t *wait_cycles) {
// We are already in the slow path of SpinLock, initialize the
// adaptive_spin_count here.
ABSL_CONST_INIT static absl::once_flag init_adaptive_spin_count;
ABSL_CONST_INIT static int adaptive_spin_count = 0;
base_internal::LowLevelCallOnce(&init_adaptive_spin_count, []() {
adaptive_spin_count = base_internal::NumCPUs() > 1 ? 1000 : 1;
});
int c = adaptive_spin_count; int c = adaptive_spin_count;
uint32_t lock_value; uint32_t lock_value;
do { do {
......
...@@ -158,8 +158,8 @@ ...@@ -158,8 +158,8 @@
#define ABSL_PREDICT_FALSE(x) (__builtin_expect(x, 0)) #define ABSL_PREDICT_FALSE(x) (__builtin_expect(x, 0))
#define ABSL_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) #define ABSL_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
#else #else
#define ABSL_PREDICT_FALSE(x) x #define ABSL_PREDICT_FALSE(x) (x)
#define ABSL_PREDICT_TRUE(x) x #define ABSL_PREDICT_TRUE(x) (x)
#endif #endif
#endif // ABSL_BASE_OPTIMIZATION_H_ #endif // ABSL_BASE_OPTIMIZATION_H_
...@@ -53,3 +53,15 @@ cc_test( ...@@ -53,3 +53,15 @@ cc_test(
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
) )
cc_test(
name = "int128_benchmark",
srcs = ["int128_benchmark.cc"],
copts = ABSL_TEST_COPTS,
tags = ["benchmark"],
deps = [
":int128",
"//absl/base:config",
"@com_github_google_benchmark//:benchmark_main",
],
)
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/numeric/int128.h"
#include <algorithm>
#include <cstdint>
#include <random>
#include <vector>
#include "benchmark/benchmark.h"
#include "absl/base/config.h"
namespace {
constexpr size_t kSampleSize = 1000000;
std::mt19937 MakeRandomEngine() {
std::random_device r;
std::seed_seq seed({r(), r(), r(), r(), r(), r(), r(), r()});
return std::mt19937(seed);
}
std::vector<std::pair<absl::uint128, absl::uint128>>
GetRandomClass128SampleUniformDivisor() {
std::vector<std::pair<absl::uint128, absl::uint128>> values;
std::mt19937 random = MakeRandomEngine();
std::uniform_int_distribution<uint64_t> uniform_uint64;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
absl::uint128 a =
absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
absl::uint128 b =
absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
values.emplace_back(std::max(a, b),
std::max(absl::uint128(2), std::min(a, b)));
}
return values;
}
void BM_DivideClass128UniformDivisor(benchmark::State& state) {
auto values = GetRandomClass128SampleUniformDivisor();
while (state.KeepRunningBatch(values.size())) {
for (const auto& pair : values) {
benchmark::DoNotOptimize(pair.first / pair.second);
}
}
}
BENCHMARK(BM_DivideClass128UniformDivisor);
std::vector<std::pair<absl::uint128, uint64_t>>
GetRandomClass128SampleSmallDivisor() {
std::vector<std::pair<absl::uint128, uint64_t>> values;
std::mt19937 random = MakeRandomEngine();
std::uniform_int_distribution<uint64_t> uniform_uint64;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
absl::uint128 a =
absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
uint64_t b = std::max(uint64_t{2}, uniform_uint64(random));
values.emplace_back(std::max(a, absl::uint128(b)), b);
}
return values;
}
void BM_DivideClass128SmallDivisor(benchmark::State& state) {
auto values = GetRandomClass128SampleSmallDivisor();
while (state.KeepRunningBatch(values.size())) {
for (const auto& pair : values) {
benchmark::DoNotOptimize(pair.first / pair.second);
}
}
}
BENCHMARK(BM_DivideClass128SmallDivisor);
std::vector<std::pair<absl::uint128, absl::uint128>> GetRandomClass128Sample() {
std::vector<std::pair<absl::uint128, absl::uint128>> values;
std::mt19937 random = MakeRandomEngine();
std::uniform_int_distribution<uint64_t> uniform_uint64;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
values.emplace_back(
absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)),
absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)));
}
return values;
}
void BM_MultiplyClass128(benchmark::State& state) {
auto values = GetRandomClass128Sample();
while (state.KeepRunningBatch(values.size())) {
for (const auto& pair : values) {
benchmark::DoNotOptimize(pair.first * pair.second);
}
}
}
BENCHMARK(BM_MultiplyClass128);
void BM_AddClass128(benchmark::State& state) {
auto values = GetRandomClass128Sample();
while (state.KeepRunningBatch(values.size())) {
for (const auto& pair : values) {
benchmark::DoNotOptimize(pair.first + pair.second);
}
}
}
BENCHMARK(BM_AddClass128);
#ifdef ABSL_HAVE_INTRINSIC_INT128
// Some implementations of <random> do not support __int128 when it is
// available, so we make our own uniform_int_distribution-like type.
class UniformIntDistribution128 {
public:
// NOLINTNEXTLINE: mimicking std::uniform_int_distribution API
unsigned __int128 operator()(std::mt19937& generator) {
return (static_cast<unsigned __int128>(dist64_(generator)) << 64) |
dist64_(generator);
}
private:
std::uniform_int_distribution<uint64_t> dist64_;
};
std::vector<std::pair<unsigned __int128, unsigned __int128>>
GetRandomIntrinsic128SampleUniformDivisor() {
std::vector<std::pair<unsigned __int128, unsigned __int128>> values;
std::mt19937 random = MakeRandomEngine();
UniformIntDistribution128 uniform_uint128;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
unsigned __int128 a = uniform_uint128(random);
unsigned __int128 b = uniform_uint128(random);
values.emplace_back(
std::max(a, b),
std::max(static_cast<unsigned __int128>(2), std::min(a, b)));
}
return values;
}
void BM_DivideIntrinsic128UniformDivisor(benchmark::State& state) {
auto values = GetRandomIntrinsic128SampleUniformDivisor();
while (state.KeepRunningBatch(values.size())) {
for (const auto& pair : values) {
benchmark::DoNotOptimize(pair.first / pair.second);
}
}
}
BENCHMARK(BM_DivideIntrinsic128UniformDivisor);
std::vector<std::pair<unsigned __int128, uint64_t>>
GetRandomIntrinsic128SampleSmallDivisor() {
std::vector<std::pair<unsigned __int128, uint64_t>> values;
std::mt19937 random = MakeRandomEngine();
UniformIntDistribution128 uniform_uint128;
std::uniform_int_distribution<uint64_t> uniform_uint64;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
unsigned __int128 a = uniform_uint128(random);
uint64_t b = std::max(uint64_t{2}, uniform_uint64(random));
values.emplace_back(std::max(a, static_cast<unsigned __int128>(b)), b);
}
return values;
}
void BM_DivideIntrinsic128SmallDivisor(benchmark::State& state) {
auto values = GetRandomIntrinsic128SampleSmallDivisor();
while (state.KeepRunningBatch(values.size())) {
for (const auto& pair : values) {
benchmark::DoNotOptimize(pair.first / pair.second);
}
}
}
BENCHMARK(BM_DivideIntrinsic128SmallDivisor);
std::vector<std::pair<unsigned __int128, unsigned __int128>>
GetRandomIntrinsic128Sample() {
std::vector<std::pair<unsigned __int128, unsigned __int128>> values;
std::mt19937 random = MakeRandomEngine();
UniformIntDistribution128 uniform_uint128;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
values.emplace_back(uniform_uint128(random), uniform_uint128(random));
}
return values;
}
void BM_MultiplyIntrinsic128(benchmark::State& state) {
auto values = GetRandomIntrinsic128Sample();
while (state.KeepRunningBatch(values.size())) {
for (const auto& pair : values) {
benchmark::DoNotOptimize(pair.first * pair.second);
}
}
}
BENCHMARK(BM_MultiplyIntrinsic128);
void BM_AddIntrinsic128(benchmark::State& state) {
auto values = GetRandomIntrinsic128Sample();
while (state.KeepRunningBatch(values.size())) {
for (const auto& pair : values) {
benchmark::DoNotOptimize(pair.first + pair.second);
}
}
}
BENCHMARK(BM_AddIntrinsic128);
#endif // ABSL_HAVE_INTRINSIC_INT128
} // namespace
...@@ -158,6 +158,22 @@ cc_test( ...@@ -158,6 +158,22 @@ cc_test(
) )
cc_test( cc_test(
name = "memutil_benchmark",
srcs = [
"internal/memutil.h",
"internal/memutil_benchmark.cc",
],
copts = ABSL_TEST_COPTS,
tags = ["benchmark"],
visibility = ["//visibility:private"],
deps = [
":strings",
"//absl/base:core_headers",
"@com_github_google_benchmark//:benchmark_main",
],
)
cc_test(
name = "memutil_test", name = "memutil_test",
size = "small", size = "small",
srcs = [ srcs = [
......
...@@ -93,3 +93,23 @@ cc_test( ...@@ -93,3 +93,23 @@ cc_test(
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
) )
cc_test(
name = "time_benchmark",
srcs = [
"clock_benchmark.cc",
"duration_benchmark.cc",
"format_benchmark.cc",
"time_benchmark.cc",
],
copts = ABSL_TEST_COPTS,
tags = [
"benchmark",
],
deps = [
":test_util",
":time",
"//absl/base",
"@com_github_google_benchmark//:benchmark_main",
],
)
// 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/time/clock.h"
#if !defined(_WIN32)
#include <sys/time.h>
#endif // _WIN32
#include <cstdio>
#include "absl/base/internal/cycleclock.h"
#include "benchmark/benchmark.h"
namespace {
void BM_Clock_Now_AbslTime(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::Now());
}
}
BENCHMARK(BM_Clock_Now_AbslTime);
void BM_Clock_Now_GetCurrentTimeNanos(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::GetCurrentTimeNanos());
}
}
BENCHMARK(BM_Clock_Now_GetCurrentTimeNanos);
void BM_Clock_Now_AbslTime_ToUnixNanos(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::ToUnixNanos(absl::Now()));
}
}
BENCHMARK(BM_Clock_Now_AbslTime_ToUnixNanos);
void BM_Clock_Now_CycleClock(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::base_internal::CycleClock::Now());
}
}
BENCHMARK(BM_Clock_Now_CycleClock);
#if !defined(_WIN32)
static void BM_Clock_Now_gettimeofday(benchmark::State& state) {
struct timeval tv;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(gettimeofday(&tv, nullptr));
}
}
BENCHMARK(BM_Clock_Now_gettimeofday);
static void BM_Clock_Now_clock_gettime(benchmark::State& state) {
struct timespec ts;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(clock_gettime(CLOCK_REALTIME, &ts));
}
}
BENCHMARK(BM_Clock_Now_clock_gettime);
#endif // _WIN32
} // namespace
...@@ -330,18 +330,10 @@ TEST(Duration, ToChrono) { ...@@ -330,18 +330,10 @@ TEST(Duration, ToChrono) {
EXPECT_EQ(hours::max(), absl::ToChronoHours(inf)); EXPECT_EQ(hours::max(), absl::ToChronoHours(inf));
} }
// Used for testing the factory overloads.
template <typename T>
struct ImplicitlyConvertible {
T n_;
explicit ImplicitlyConvertible(T n) : n_(n) {}
// Marking this conversion operator with 'explicit' will cause the test to
// fail (as desired).
operator T() { return n_; }
};
TEST(Duration, FactoryOverloads) { TEST(Duration, FactoryOverloads) {
enum E { kOne = 1 };
#define TEST_FACTORY_OVERLOADS(NAME) \ #define TEST_FACTORY_OVERLOADS(NAME) \
EXPECT_EQ(1, NAME(kOne) / NAME(kOne)); \
EXPECT_EQ(1, NAME(static_cast<int8_t>(1)) / NAME(1)); \ EXPECT_EQ(1, NAME(static_cast<int8_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(static_cast<int16_t>(1)) / NAME(1)); \ EXPECT_EQ(1, NAME(static_cast<int16_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(static_cast<int32_t>(1)) / NAME(1)); \ EXPECT_EQ(1, NAME(static_cast<int32_t>(1)) / NAME(1)); \
...@@ -350,14 +342,6 @@ TEST(Duration, FactoryOverloads) { ...@@ -350,14 +342,6 @@ TEST(Duration, FactoryOverloads) {
EXPECT_EQ(1, NAME(static_cast<uint16_t>(1)) / NAME(1)); \ EXPECT_EQ(1, NAME(static_cast<uint16_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(static_cast<uint32_t>(1)) / NAME(1)); \ EXPECT_EQ(1, NAME(static_cast<uint32_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(static_cast<uint64_t>(1)) / NAME(1)); \ EXPECT_EQ(1, NAME(static_cast<uint64_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(ImplicitlyConvertible<int8_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(ImplicitlyConvertible<int16_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(ImplicitlyConvertible<int32_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(ImplicitlyConvertible<int64_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(ImplicitlyConvertible<uint8_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(ImplicitlyConvertible<uint16_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(ImplicitlyConvertible<uint32_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(ImplicitlyConvertible<uint64_t>(1)) / NAME(1)); \
EXPECT_EQ(NAME(1) / 2, NAME(static_cast<float>(0.5))); \ EXPECT_EQ(NAME(1) / 2, NAME(static_cast<float>(0.5))); \
EXPECT_EQ(NAME(1) / 2, NAME(static_cast<double>(0.5))); \ EXPECT_EQ(NAME(1) / 2, NAME(static_cast<double>(0.5))); \
EXPECT_EQ(1.5, absl::FDivDuration(NAME(static_cast<float>(1.5)), NAME(1))); \ EXPECT_EQ(1.5, absl::FDivDuration(NAME(static_cast<float>(1.5)), NAME(1))); \
......
// 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 <cstddef>
#include <string>
#include "absl/time/internal/test_util.h"
#include "absl/time/time.h"
#include "benchmark/benchmark.h"
namespace {
namespace {
const char* const kFormats[] = {
absl::RFC1123_full, // 0
absl::RFC1123_no_wday, // 1
absl::RFC3339_full, // 2
absl::RFC3339_sec, // 3
"%Y-%m-%dT%H:%M:%S", // 4
"%Y-%m-%d", // 5
};
const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
} // namespace
void BM_Format_FormatTime(benchmark::State& state) {
const std::string fmt = kFormats[state.range(0)];
state.SetLabel(fmt);
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);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::FormatTime(fmt, t, lax).length());
}
}
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 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);
const std::string when = absl::FormatTime(fmt, t, lax);
std::string err;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::ParseTime(fmt, when, lax, &t, &err));
}
}
BENCHMARK(BM_Format_ParseTime)->DenseRange(0, kNumFormats - 1);
} // namespace
...@@ -463,13 +463,12 @@ TEST(Format, ExtendedSecondOffset) { ...@@ -463,13 +463,12 @@ TEST(Format, ExtendedSecondOffset) {
EXPECT_TRUE(load_time_zone("Europe/Moscow", &tz)); EXPECT_TRUE(load_time_zone("Europe/Moscow", &tz));
tp = convert(civil_second(1919, 6, 30, 23, 59, 59), utc); tp = convert(civil_second(1919, 6, 30, 23, 59, 59), utc);
if (tz.lookup(tp).offset == 4 * 60 * 60) { #if defined(__ANDROID__) && __ANDROID_API__ < 25
// We're likely dealing with zoneinfo that doesn't support really old // Only Android 'N'.1 and beyond have this tz2016g transition.
// timestamps, so Europe/Moscow never looks to be on local mean time. #else
} else {
TestFormatSpecifier(tp, tz, "%E*z", "+04:31:19"); TestFormatSpecifier(tp, tz, "%E*z", "+04:31:19");
TestFormatSpecifier(tp, tz, "%Ez", "+04:31"); TestFormatSpecifier(tp, tz, "%Ez", "+04:31");
} #endif
tp += seconds(1); tp += seconds(1);
TestFormatSpecifier(tp, tz, "%E*z", "+04:00:00"); TestFormatSpecifier(tp, tz, "%E*z", "+04:00:00");
} }
......
...@@ -693,7 +693,14 @@ TEST(TimeZones, LoadZonesConcurrently) { ...@@ -693,7 +693,14 @@ TEST(TimeZones, LoadZonesConcurrently) {
// Allow a small number of failures to account for skew between // Allow a small number of failures to account for skew between
// the contents of kTimeZoneNames and the zoneinfo data source. // the contents of kTimeZoneNames and the zoneinfo data source.
#if defined(__ANDROID__)
// Cater to the possibility of using an even older zoneinfo data
// source when running on Android, where it is difficult to override
// the bionic tzdata provided by the test environment.
const std::size_t max_failures = 20;
#else
const std::size_t max_failures = 3; const std::size_t max_failures = 3;
#endif
std::set<std::string> failures; std::set<std::string> failures;
for (const auto& thread_failure : thread_failures) { for (const auto& thread_failure : thread_failures) {
failures.insert(thread_failure.begin(), thread_failure.end()); failures.insert(thread_failure.begin(), thread_failure.end());
...@@ -839,7 +846,7 @@ TEST(TimeZoneImpl, LocalTimeInFixed) { ...@@ -839,7 +846,7 @@ TEST(TimeZoneImpl, LocalTimeInFixed) {
const time_zone tz = fixed_time_zone(offset); const time_zone tz = fixed_time_zone(offset);
const auto tp = system_clock::from_time_t(0); const auto tp = system_clock::from_time_t(0);
ExpectTime(tp, tz, 1969, 12, 31, 15, 26, 13, offset.count(), false, ExpectTime(tp, tz, 1969, 12, 31, 15, 26, 13, offset.count(), false,
"UTC-083347"); "-083347");
EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz)))); EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz))));
} }
...@@ -1098,6 +1105,9 @@ TEST(TimeZoneEdgeCase, PacificApia) { ...@@ -1098,6 +1105,9 @@ TEST(TimeZoneEdgeCase, PacificApia) {
TEST(TimeZoneEdgeCase, AfricaCairo) { TEST(TimeZoneEdgeCase, AfricaCairo) {
const time_zone tz = LoadZone("Africa/Cairo"); const time_zone tz = LoadZone("Africa/Cairo");
#if defined(__ANDROID__) && __ANDROID_API__ < 21
// Only Android 'L' and beyond have this tz2014c transition.
#else
// An interesting case of midnight not existing. // An interesting case of midnight not existing.
// //
// 1400191199 == Thu, 15 May 2014 23:59:59 +0200 (EET) // 1400191199 == Thu, 15 May 2014 23:59:59 +0200 (EET)
...@@ -1106,11 +1116,15 @@ TEST(TimeZoneEdgeCase, AfricaCairo) { ...@@ -1106,11 +1116,15 @@ TEST(TimeZoneEdgeCase, AfricaCairo) {
ExpectTime(tp, tz, 2014, 5, 15, 23, 59, 59, 2 * 3600, false, "EET"); ExpectTime(tp, tz, 2014, 5, 15, 23, 59, 59, 2 * 3600, false, "EET");
tp += seconds(1); tp += seconds(1);
ExpectTime(tp, tz, 2014, 5, 16, 1, 0, 0, 3 * 3600, true, "EEST"); ExpectTime(tp, tz, 2014, 5, 16, 1, 0, 0, 3 * 3600, true, "EEST");
#endif
} }
TEST(TimeZoneEdgeCase, AfricaMonrovia) { TEST(TimeZoneEdgeCase, AfricaMonrovia) {
const time_zone tz = LoadZone("Africa/Monrovia"); const time_zone tz = LoadZone("Africa/Monrovia");
#if defined(__ANDROID__) && __ANDROID_API__ < 26
// Only Android 'O' and beyond have this tz2017b transition.
#else
// Strange offset change -00:44:30 -> +00:00:00 (non-DST) // Strange offset change -00:44:30 -> +00:00:00 (non-DST)
// //
// 63593069 == Thu, 6 Jan 1972 23:59:59 -0044 (MMT) // 63593069 == Thu, 6 Jan 1972 23:59:59 -0044 (MMT)
...@@ -1119,6 +1133,7 @@ TEST(TimeZoneEdgeCase, AfricaMonrovia) { ...@@ -1119,6 +1133,7 @@ TEST(TimeZoneEdgeCase, AfricaMonrovia) {
ExpectTime(tp, tz, 1972, 1, 6, 23, 59, 59, -44.5 * 60, false, "MMT"); ExpectTime(tp, tz, 1972, 1, 6, 23, 59, 59, -44.5 * 60, false, "MMT");
tp += seconds(1); tp += seconds(1);
ExpectTime(tp, tz, 1972, 1, 7, 0, 44, 30, 0 * 60, false, "GMT"); ExpectTime(tp, tz, 1972, 1, 7, 0, 44, 30, 0 * 60, false, "GMT");
#endif
} }
TEST(TimeZoneEdgeCase, AmericaJamaica) { TEST(TimeZoneEdgeCase, AmericaJamaica) {
......
...@@ -82,8 +82,15 @@ constexpr Duration MakeDuration(int64_t hi, uint32_t lo); ...@@ -82,8 +82,15 @@ constexpr Duration MakeDuration(int64_t hi, uint32_t lo);
constexpr Duration MakeDuration(int64_t hi, int64_t lo); constexpr Duration MakeDuration(int64_t hi, int64_t lo);
constexpr int64_t kTicksPerNanosecond = 4; constexpr int64_t kTicksPerNanosecond = 4;
constexpr int64_t kTicksPerSecond = 1000 * 1000 * 1000 * kTicksPerNanosecond; constexpr int64_t kTicksPerSecond = 1000 * 1000 * 1000 * kTicksPerNanosecond;
template <std::intmax_t N>
constexpr Duration FromInt64(int64_t v, std::ratio<1, N>);
constexpr Duration FromInt64(int64_t v, std::ratio<60>);
constexpr Duration FromInt64(int64_t v, std::ratio<3600>);
template <typename T>
using EnableIfIntegral = typename std::enable_if<
std::is_integral<T>::value || std::is_enum<T>::value, int>::type;
template <typename T> template <typename T>
using IsFloatingPoint = using EnableIfFloat =
typename std::enable_if<std::is_floating_point<T>::value, int>::type; typename std::enable_if<std::is_floating_point<T>::value, int>::type;
} // namespace time_internal } // namespace time_internal
...@@ -178,15 +185,15 @@ inline Duration operator-(Duration lhs, Duration rhs) { return lhs -= rhs; } ...@@ -178,15 +185,15 @@ inline Duration operator-(Duration lhs, Duration rhs) { return lhs -= rhs; }
// Multiplicative Operators // Multiplicative Operators
template <typename T> template <typename T>
inline Duration operator*(Duration lhs, T rhs) { Duration operator*(Duration lhs, T rhs) {
return lhs *= rhs; return lhs *= rhs;
} }
template <typename T> template <typename T>
inline Duration operator*(T lhs, Duration rhs) { Duration operator*(T lhs, Duration rhs) {
return rhs *= lhs; return rhs *= lhs;
} }
template <typename T> template <typename T>
inline Duration operator/(Duration lhs, T rhs) { Duration operator/(Duration lhs, T rhs) {
return lhs /= rhs; return lhs /= rhs;
} }
inline int64_t operator/(Duration lhs, Duration rhs) { inline int64_t operator/(Duration lhs, Duration rhs) {
...@@ -322,27 +329,27 @@ constexpr Duration Hours(int64_t n); ...@@ -322,27 +329,27 @@ constexpr Duration Hours(int64_t n);
// Example: // Example:
// auto a = absl::Seconds(1.5); // OK // auto a = absl::Seconds(1.5); // OK
// auto b = absl::Milliseconds(1500); // BETTER // auto b = absl::Milliseconds(1500); // BETTER
template <typename T, time_internal::IsFloatingPoint<T> = 0> template <typename T, time_internal::EnableIfFloat<T> = 0>
Duration Nanoseconds(T n) { Duration Nanoseconds(T n) {
return n * Nanoseconds(1); return n * Nanoseconds(1);
} }
template <typename T, time_internal::IsFloatingPoint<T> = 0> template <typename T, time_internal::EnableIfFloat<T> = 0>
Duration Microseconds(T n) { Duration Microseconds(T n) {
return n * Microseconds(1); return n * Microseconds(1);
} }
template <typename T, time_internal::IsFloatingPoint<T> = 0> template <typename T, time_internal::EnableIfFloat<T> = 0>
Duration Milliseconds(T n) { Duration Milliseconds(T n) {
return n * Milliseconds(1); return n * Milliseconds(1);
} }
template <typename T, time_internal::IsFloatingPoint<T> = 0> template <typename T, time_internal::EnableIfFloat<T> = 0>
Duration Seconds(T n) { Duration Seconds(T n) {
return n * Seconds(1); return n * Seconds(1);
} }
template <typename T, time_internal::IsFloatingPoint<T> = 0> template <typename T, time_internal::EnableIfFloat<T> = 0>
Duration Minutes(T n) { Duration Minutes(T n) {
return n * Minutes(1); return n * Minutes(1);
} }
template <typename T, time_internal::IsFloatingPoint<T> = 0> template <typename T, time_internal::EnableIfFloat<T> = 0>
Duration Hours(T n) { Duration Hours(T n) {
return n * Hours(1); return n * Hours(1);
} }
...@@ -1154,10 +1161,16 @@ constexpr Duration FromInt64(int64_t v, std::ratio<1, N>) { ...@@ -1154,10 +1161,16 @@ constexpr Duration FromInt64(int64_t v, std::ratio<1, N>) {
v / N, v % N * kTicksPerNanosecond * 1000 * 1000 * 1000 / N); v / N, v % N * kTicksPerNanosecond * 1000 * 1000 * 1000 / N);
} }
constexpr Duration FromInt64(int64_t v, std::ratio<60>) { constexpr Duration FromInt64(int64_t v, std::ratio<60>) {
return Minutes(v); 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>) { constexpr Duration FromInt64(int64_t v, std::ratio<3600>) {
return Hours(v); return (v <= std::numeric_limits<int64_t>::max() / 3600 &&
v >= std::numeric_limits<int64_t>::min() / 3600)
? MakeDuration(v * 3600)
: v > 0 ? InfiniteDuration() : -InfiniteDuration();
} }
// IsValidRep64<T>(0) is true if the expression `int64_t{std::declval<T>()}` is // IsValidRep64<T>(0) is true if the expression `int64_t{std::declval<T>()}` is
...@@ -1220,6 +1233,24 @@ T ToChronoDuration(Duration d) { ...@@ -1220,6 +1233,24 @@ T ToChronoDuration(Duration d) {
} }
} // namespace time_internal } // namespace time_internal
constexpr Duration Nanoseconds(int64_t n) {
return time_internal::FromInt64(n, std::nano{});
}
constexpr Duration Microseconds(int64_t n) {
return time_internal::FromInt64(n, std::micro{});
}
constexpr Duration Milliseconds(int64_t n) {
return time_internal::FromInt64(n, std::milli{});
}
constexpr Duration Seconds(int64_t n) {
return time_internal::FromInt64(n, std::ratio<1>{});
}
constexpr Duration Minutes(int64_t n) {
return time_internal::FromInt64(n, std::ratio<60>{});
}
constexpr Duration Hours(int64_t n) {
return time_internal::FromInt64(n, std::ratio<3600>{});
}
constexpr bool operator<(Duration lhs, Duration rhs) { constexpr bool operator<(Duration lhs, Duration rhs) {
return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs) return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs)
...@@ -1261,39 +1292,6 @@ constexpr Duration operator-(Duration d) { ...@@ -1261,39 +1292,6 @@ constexpr Duration operator-(Duration d) {
time_internal::GetRepLo(d)); time_internal::GetRepLo(d));
} }
constexpr Duration Nanoseconds(int64_t n) {
return time_internal::MakeNormalizedDuration(
n / (1000 * 1000 * 1000),
n % (1000 * 1000 * 1000) * time_internal::kTicksPerNanosecond);
}
constexpr Duration Microseconds(int64_t n) {
return time_internal::MakeNormalizedDuration(
n / (1000 * 1000),
n % (1000 * 1000) * (1000 * time_internal::kTicksPerNanosecond));
}
constexpr Duration Milliseconds(int64_t n) {
return time_internal::MakeNormalizedDuration(
n / 1000, n % 1000 * (1000 * 1000 * time_internal::kTicksPerNanosecond));
}
constexpr Duration Seconds(int64_t n) { return time_internal::MakeDuration(n); }
constexpr Duration Minutes(int64_t n) {
return (n <= std::numeric_limits<int64_t>::max() / 60 &&
n >= std::numeric_limits<int64_t>::min() / 60)
? time_internal::MakeDuration(n * 60)
: n > 0 ? InfiniteDuration() : -InfiniteDuration();
}
constexpr Duration Hours(int64_t n) {
return (n <= std::numeric_limits<int64_t>::max() / 3600 &&
n >= std::numeric_limits<int64_t>::min() / 3600)
? time_internal::MakeDuration(n * 3600)
: n > 0 ? InfiniteDuration() : -InfiniteDuration();
}
constexpr Duration InfiniteDuration() { 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);
} }
......
// 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/time/time.h"
#if !defined(_WIN32)
#include <sys/time.h>
#endif // _WIN32
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <cstring>
#include <ctime>
#include <memory>
#include <string>
#include "absl/time/clock.h"
#include "absl/time/internal/test_util.h"
#include "benchmark/benchmark.h"
namespace {
//
// Addition/Subtraction of a duration
//
void BM_Time_Arithmetic(benchmark::State& state) {
const absl::Duration nano = absl::Nanoseconds(1);
const absl::Duration sec = absl::Seconds(1);
absl::Time t = absl::UnixEpoch();
while (state.KeepRunning()) {
benchmark::DoNotOptimize(t += nano);
benchmark::DoNotOptimize(t -= sec);
}
}
BENCHMARK(BM_Time_Arithmetic);
//
// Time difference
//
void BM_Time_Difference(benchmark::State& state) {
absl::Time start = absl::Now();
absl::Time end = start + absl::Nanoseconds(1);
absl::Duration diff;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(diff += end - start);
}
}
BENCHMARK(BM_Time_Difference);
//
// ToDateTime
//
// 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_Absl(benchmark::State& state) {
const absl::TimeZone tz =
absl::time_internal::LoadTimeZone("America/Los_Angeles");
absl::Time t = absl::FromUnixSeconds(1384569027);
absl::Time t2 = absl::FromUnixSeconds(1418962578);
while (state.KeepRunning()) {
std::swap(t, t2);
t += absl::Seconds(1);
benchmark::DoNotOptimize(t.In(tz));
}
}
BENCHMARK(BM_Time_ToDateTime_Absl);
void BM_Time_ToDateTime_Libc(benchmark::State& state) {
// No timezone support, so just use localtime.
time_t t = 1384569027;
time_t t2 = 1418962578;
while (state.KeepRunning()) {
std::swap(t, t2);
t += 1;
struct tm tm;
#if !defined(_WIN32)
benchmark::DoNotOptimize(localtime_r(&t, &tm));
#else // _WIN32
benchmark::DoNotOptimize(localtime_s(&tm, &t));
#endif // _WIN32
}
}
BENCHMARK(BM_Time_ToDateTime_Libc);
void BM_Time_ToDateTimeUTC_Absl(benchmark::State& state) {
const absl::TimeZone tz = absl::UTCTimeZone();
absl::Time t = absl::FromUnixSeconds(1384569027);
while (state.KeepRunning()) {
t += absl::Seconds(1);
benchmark::DoNotOptimize(t.In(tz));
}
}
BENCHMARK(BM_Time_ToDateTimeUTC_Absl);
void BM_Time_ToDateTimeUTC_Libc(benchmark::State& state) {
time_t t = 1384569027;
while (state.KeepRunning()) {
t += 1;
struct tm tm;
#if !defined(_WIN32)
benchmark::DoNotOptimize(gmtime_r(&t, &tm));
#else // _WIN32
benchmark::DoNotOptimize(gmtime_s(&tm, &t));
#endif // _WIN32
}
}
BENCHMARK(BM_Time_ToDateTimeUTC_Libc);
//
// FromUnixMicros
//
void BM_Time_FromUnixMicros(benchmark::State& state) {
int i = 0;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::FromUnixMicros(i));
++i;
}
}
BENCHMARK(BM_Time_FromUnixMicros);
void BM_Time_ToUnixNanos(benchmark::State& state) {
const absl::Time t = absl::UnixEpoch() + absl::Seconds(123);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(ToUnixNanos(t));
}
}
BENCHMARK(BM_Time_ToUnixNanos);
void BM_Time_ToUnixMicros(benchmark::State& state) {
const absl::Time t = absl::UnixEpoch() + absl::Seconds(123);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(ToUnixMicros(t));
}
}
BENCHMARK(BM_Time_ToUnixMicros);
void BM_Time_ToUnixMillis(benchmark::State& state) {
const absl::Time t = absl::UnixEpoch() + absl::Seconds(123);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(ToUnixMillis(t));
}
}
BENCHMARK(BM_Time_ToUnixMillis);
void BM_Time_ToUnixSeconds(benchmark::State& state) {
const absl::Time t = absl::UnixEpoch() + absl::Seconds(123);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::ToUnixSeconds(t));
}
}
BENCHMARK(BM_Time_ToUnixSeconds);
//
// FromDateTime
//
// 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_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);
} else {
absl::FromDateTime(2013, 11, 15, 18, 30, 27, tz);
}
++i;
}
}
BENCHMARK(BM_Time_FromDateTime_Absl);
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;
mktime(&tm);
++i;
}
}
BENCHMARK(BM_Time_FromDateTime_Libc);
void BM_Time_FromDateTimeUTC_Absl(benchmark::State& state) {
const absl::TimeZone tz = absl::UTCTimeZone();
while (state.KeepRunning()) {
FromDateTime(2014, 12, 18, 20, 16, 18, tz);
}
}
BENCHMARK(BM_Time_FromDateTimeUTC_Absl);
void BM_Time_FromDateTimeDay0_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);
} else {
absl::FromDateTime(2013, 11, 0, 18, 30, 27, tz);
}
++i;
}
}
BENCHMARK(BM_Time_FromDateTimeDay0_Absl);
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;
mktime(&tm);
++i;
}
}
BENCHMARK(BM_Time_FromDateTimeDay0_Libc);
//
// To/FromTimespec
//
void BM_Time_ToTimespec(benchmark::State& state) {
absl::Time now = absl::Now();
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::ToTimespec(now));
}
}
BENCHMARK(BM_Time_ToTimespec);
void BM_Time_FromTimespec(benchmark::State& state) {
timespec ts = absl::ToTimespec(absl::Now());
while (state.KeepRunning()) {
if (++ts.tv_nsec == 1000 * 1000 * 1000) {
++ts.tv_sec;
ts.tv_nsec = 0;
}
benchmark::DoNotOptimize(absl::TimeFromTimespec(ts));
}
}
BENCHMARK(BM_Time_FromTimespec);
//
// Comparison with InfiniteFuture/Past
//
void BM_Time_InfiniteFuture(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::InfiniteFuture());
}
}
BENCHMARK(BM_Time_InfiniteFuture);
void BM_Time_InfinitePast(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::InfinitePast());
}
}
BENCHMARK(BM_Time_InfinitePast);
} // namespace
...@@ -28,7 +28,7 @@ licenses(["notice"]) # Apache 2.0 ...@@ -28,7 +28,7 @@ licenses(["notice"]) # Apache 2.0
cc_library( cc_library(
name = "any", name = "any",
hdrs = ["any.h"], hdrs = ["any.h"],
copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG, copts = ABSL_DEFAULT_COPTS,
deps = [ deps = [
":bad_any_cast", ":bad_any_cast",
"//absl/base:config", "//absl/base:config",
...@@ -40,9 +40,19 @@ cc_library( ...@@ -40,9 +40,19 @@ cc_library(
cc_library( cc_library(
name = "bad_any_cast", name = "bad_any_cast",
srcs = ["bad_any_cast.cc"],
hdrs = ["bad_any_cast.h"], hdrs = ["bad_any_cast.h"],
copts = ABSL_DEFAULT_COPTS,
deps = [":bad_any_cast_impl"],
)
cc_library(
name = "bad_any_cast_impl",
srcs = [
"bad_any_cast.cc",
"bad_any_cast.h",
],
copts = ABSL_EXCEPTIONS_FLAG + ABSL_DEFAULT_COPTS, copts = ABSL_EXCEPTIONS_FLAG + ABSL_DEFAULT_COPTS,
visibility = ["//visibility:private"],
deps = [ deps = [
"//absl/base", "//absl/base",
"//absl/base:config", "//absl/base:config",
...@@ -206,7 +216,6 @@ cc_test( ...@@ -206,7 +216,6 @@ cc_test(
], ],
) )
cc_library( cc_library(
name = "variant", name = "variant",
srcs = ["internal/variant.h"], srcs = ["internal/variant.h"],
......
...@@ -170,25 +170,22 @@ TEST(OptionalExceptionSafety, EverythingThrowsSwap) { ...@@ -170,25 +170,22 @@ TEST(OptionalExceptionSafety, EverythingThrowsSwap) {
TEST(OptionalExceptionSafety, NoThrowMoveSwap) { TEST(OptionalExceptionSafety, NoThrowMoveSwap) {
// Tests the nothrow guarantee for optional of T with non-throwing move // 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(); auto empty = MoveOptional();
optional_ptr->swap(empty); auto nonempty = MoveOptional(kInitialInteger);
}; EXPECT_TRUE(testing::TestNothrowOp([&]() { nonempty.swap(empty); }));
EXPECT_TRUE(nothrow_test_nonempty.Test(swap_empty)); }
{
auto swap_nonempty = [](MoveOptional* optional_ptr) { auto nonempty = MoveOptional(kUpdatedInteger);
auto nonempty = auto empty = MoveOptional();
MoveOptional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor); EXPECT_TRUE(testing::TestNothrowOp([&]() { empty.swap(nonempty); }));
optional_ptr->swap(nonempty); }
}; {
EXPECT_TRUE(nothrow_test_empty.Test(swap_nonempty)); auto nonempty_from = MoveOptional(kUpdatedInteger);
EXPECT_TRUE(nothrow_test_nonempty.Test(swap_nonempty)); auto nonempty_to = MoveOptional(kInitialInteger);
EXPECT_TRUE(
testing::TestNothrowOp([&]() { nonempty_to.swap(nonempty_from); }));
}
} }
TEST(OptionalExceptionSafety, CopyAssign) { TEST(OptionalExceptionSafety, CopyAssign) {
...@@ -251,32 +248,33 @@ TEST(OptionalExceptionSafety, MoveAssign) { ...@@ -251,32 +248,33 @@ TEST(OptionalExceptionSafety, MoveAssign) {
TEST(OptionalExceptionSafety, NothrowMoveAssign) { TEST(OptionalExceptionSafety, NothrowMoveAssign) {
// Tests the nothrow guarantee for optional of T with non-throwing move // 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(); auto empty = MoveOptional();
*optional_ptr = std::move(empty); auto nonempty = MoveOptional(kInitialInteger);
}; EXPECT_TRUE(testing::TestNothrowOp([&]() { nonempty = std::move(empty); }));
EXPECT_TRUE(nothrow_test_nonempty.Test(moveassign_empty)); }
{
auto moveassign_nonempty = [](MoveOptional* optional_ptr) { auto nonempty = MoveOptional(kInitialInteger);
auto nonempty = auto empty = MoveOptional();
MoveOptional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor); EXPECT_TRUE(testing::TestNothrowOp([&]() { empty = std::move(nonempty); }));
*optional_ptr = std::move(nonempty); }
}; {
EXPECT_TRUE(nothrow_test_empty.Test(moveassign_nonempty)); auto nonempty_from = MoveOptional(kUpdatedInteger);
EXPECT_TRUE(nothrow_test_nonempty.Test(moveassign_nonempty)); auto nonempty_to = MoveOptional(kInitialInteger);
EXPECT_TRUE(testing::TestNothrowOp(
auto moveassign_thrower = [](MoveOptional* optional_ptr) { [&]() { nonempty_to = std::move(nonempty_from); }));
auto thrower = MoveThrower(kUpdatedInteger, testing::nothrow_ctor); }
*optional_ptr = std::move(thrower); {
}; auto thrower = MoveThrower(kUpdatedInteger);
EXPECT_TRUE(nothrow_test_empty.Test(moveassign_thrower)); auto empty = MoveOptional();
EXPECT_TRUE(nothrow_test_nonempty.Test(moveassign_thrower)); EXPECT_TRUE(testing::TestNothrowOp([&]() { empty = std::move(thrower); }));
}
{
auto thrower = MoveThrower(kUpdatedInteger);
auto nonempty = MoveOptional(kInitialInteger);
EXPECT_TRUE(
testing::TestNothrowOp([&]() { nonempty = std::move(thrower); }));
}
} }
} // namespace } // namespace
......
...@@ -279,7 +279,7 @@ class Span { ...@@ -279,7 +279,7 @@ class Span {
using size_type = size_t; using size_type = size_t;
using difference_type = ptrdiff_t; using difference_type = ptrdiff_t;
static const size_type npos = ~size_type{0}; static const size_type npos = ~(size_type(0));
constexpr Span() noexcept : Span(nullptr, 0) {} constexpr Span() noexcept : Span(nullptr, 0) {}
constexpr Span(pointer array, size_type length) noexcept constexpr Span(pointer array, size_type length) noexcept
......
...@@ -27,8 +27,8 @@ namespace absl { ...@@ -27,8 +27,8 @@ namespace absl {
namespace { namespace {
using ::testing::MakeExceptionSafetyTester; using ::testing::MakeExceptionSafetyTester;
using ::testing::nothrow_guarantee;
using ::testing::strong_guarantee; using ::testing::strong_guarantee;
using ::testing::TestNothrowOp;
using ::testing::TestThrowingCtor; using ::testing::TestThrowingCtor;
using Thrower = testing::ThrowingValue<>; using Thrower = testing::ThrowingValue<>;
...@@ -120,7 +120,11 @@ testing::AssertionResult CheckInvariants(ThrowingVariant* v) { ...@@ -120,7 +120,11 @@ testing::AssertionResult CheckInvariants(ThrowingVariant* v) {
return AssertionSuccess(); return AssertionSuccess();
} }
Thrower ExpectedThrower() { return Thrower(42); } template <typename... Args>
Thrower ExpectedThrower(Args&&... args) {
return Thrower(42, args...);
}
ThrowerVec ExpectedThrowerVec() { return {Thrower(100), Thrower(200)}; } ThrowerVec ExpectedThrowerVec() { return {Thrower(100), Thrower(200)}; }
ThrowingVariant ValuelessByException() { ThrowingVariant ValuelessByException() {
ThrowingVariant v; ThrowingVariant v;
...@@ -193,18 +197,14 @@ TEST(VariantExceptionSafetyTest, CopyAssign) { ...@@ -193,18 +197,14 @@ TEST(VariantExceptionSafetyTest, CopyAssign) {
{ {
// - neither *this nor rhs holds a value // - neither *this nor rhs holds a value
const ThrowingVariant rhs = ValuelessByException(); const ThrowingVariant rhs = ValuelessByException();
EXPECT_TRUE(MakeExceptionSafetyTester() ThrowingVariant lhs = ValuelessByException();
.WithInitialValue(ValuelessByException()) EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
.WithInvariants(nothrow_guarantee)
.Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
} }
{ {
// - *this holds a value but rhs does not // - *this holds a value but rhs does not
const ThrowingVariant rhs = ValuelessByException(); const ThrowingVariant rhs = ValuelessByException();
EXPECT_TRUE(MakeExceptionSafetyTester() ThrowingVariant lhs = WithThrower();
.WithInitialValue(WithThrower()) EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
.WithInvariants(nothrow_guarantee)
.Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
} }
// - index() == j // - index() == j
{ {
...@@ -237,10 +237,8 @@ TEST(VariantExceptionSafetyTest, CopyAssign) { ...@@ -237,10 +237,8 @@ TEST(VariantExceptionSafetyTest, CopyAssign) {
// should not throw because emplace() invokes Tj's copy ctor // should not throw because emplace() invokes Tj's copy ctor
// which should not throw. // which should not throw.
const ThrowingVariant rhs(CopyNothrow{}); const ThrowingVariant rhs(CopyNothrow{});
EXPECT_TRUE(MakeExceptionSafetyTester() ThrowingVariant lhs = WithThrower();
.WithInitialValue(WithThrower()) EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
.WithInvariants(nothrow_guarantee)
.Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
} }
{ {
// is_nothrow_copy_constructible<Tj> == false && // is_nothrow_copy_constructible<Tj> == false &&
...@@ -281,23 +279,14 @@ TEST(VariantExceptionSafetyTest, MoveAssign) { ...@@ -281,23 +279,14 @@ TEST(VariantExceptionSafetyTest, MoveAssign) {
{ {
// - neither *this nor rhs holds a value // - neither *this nor rhs holds a value
ThrowingVariant rhs = ValuelessByException(); ThrowingVariant rhs = ValuelessByException();
ThrowingVariant lhs = ValuelessByException();
EXPECT_TRUE(MakeExceptionSafetyTester() EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
.WithInitialValue(ValuelessByException())
.WithInvariants(nothrow_guarantee)
.Test([rhs](ThrowingVariant* lhs) mutable {
*lhs = std::move(rhs);
}));
} }
{ {
// - *this holds a value but rhs does not // - *this holds a value but rhs does not
ThrowingVariant rhs = ValuelessByException(); ThrowingVariant rhs = ValuelessByException();
EXPECT_TRUE(MakeExceptionSafetyTester() ThrowingVariant lhs = WithThrower();
.WithInitialValue(WithThrower()) EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
.WithInvariants(nothrow_guarantee)
.Test([rhs](ThrowingVariant* lhs) mutable {
*lhs = std::move(rhs);
}));
} }
{ {
// - index() == j // - index() == j
...@@ -310,13 +299,14 @@ TEST(VariantExceptionSafetyTest, MoveAssign) { ...@@ -310,13 +299,14 @@ TEST(VariantExceptionSafetyTest, MoveAssign) {
// Since Thrower's move assignment has basic guarantee, so should variant's. // Since Thrower's move assignment has basic guarantee, so should variant's.
auto tester = MakeExceptionSafetyTester() auto tester = MakeExceptionSafetyTester()
.WithInitialValue(WithThrower()) .WithInitialValue(WithThrower())
.WithOperation([rhs](ThrowingVariant* lhs) mutable { .WithOperation([&](ThrowingVariant* lhs) {
*lhs = std::move(rhs); auto copy = rhs;
*lhs = std::move(copy);
}); });
EXPECT_TRUE(tester EXPECT_TRUE(tester
.WithInvariants( .WithInvariants(
CheckInvariants, CheckInvariants,
[j](ThrowingVariant* lhs) { return lhs->index() == j; }) [&](ThrowingVariant* lhs) { return lhs->index() == j; })
.Test()); .Test());
EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test()); EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
} }
...@@ -332,8 +322,9 @@ TEST(VariantExceptionSafetyTest, MoveAssign) { ...@@ -332,8 +322,9 @@ TEST(VariantExceptionSafetyTest, MoveAssign) {
[](ThrowingVariant* lhs) { [](ThrowingVariant* lhs) {
return lhs->valueless_by_exception(); return lhs->valueless_by_exception();
}) })
.Test([rhs](ThrowingVariant* lhs) mutable { .Test([&](ThrowingVariant* lhs) {
*lhs = std::move(rhs); auto copy = rhs;
*lhs = std::move(copy);
})); }));
} }
} }
...@@ -365,8 +356,9 @@ TEST(VariantExceptionSafetyTest, ValueAssign) { ...@@ -365,8 +356,9 @@ TEST(VariantExceptionSafetyTest, ValueAssign) {
// move assign // move assign
auto move_tester = MakeExceptionSafetyTester() auto move_tester = MakeExceptionSafetyTester()
.WithInitialValue(WithThrower()) .WithInitialValue(WithThrower())
.WithOperation([rhs](ThrowingVariant* lhs) mutable { .WithOperation([&](ThrowingVariant* lhs) {
*lhs = std::move(rhs); auto copy = rhs;
*lhs = std::move(copy);
}); });
EXPECT_TRUE(move_tester EXPECT_TRUE(move_tester
.WithInvariants(CheckInvariants, .WithInvariants(CheckInvariants,
...@@ -388,19 +380,13 @@ TEST(VariantExceptionSafetyTest, ValueAssign) { ...@@ -388,19 +380,13 @@ TEST(VariantExceptionSafetyTest, ValueAssign) {
// invokes the copy/move constructor and it should not throw. // invokes the copy/move constructor and it should not throw.
{ {
const CopyNothrow rhs; const CopyNothrow rhs;
EXPECT_TRUE(MakeExceptionSafetyTester() ThrowingVariant lhs = WithThrower();
.WithInitialValue(WithThrower()) EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
.WithInvariants(nothrow_guarantee)
.Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
} }
{ {
MoveNothrow rhs; MoveNothrow rhs;
EXPECT_TRUE(MakeExceptionSafetyTester() ThrowingVariant lhs = WithThrower();
.WithInitialValue(WithThrower()) EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
.WithInvariants(nothrow_guarantee)
.Test([rhs](ThrowingVariant* lhs) mutable {
*lhs = std::move(rhs);
}));
} }
// if is_nothrow_constructible_v<Tj, T> == false && // if is_nothrow_constructible_v<Tj, T> == false &&
// is_nothrow_move_constructible<Tj> == false // is_nothrow_move_constructible<Tj> == false
...@@ -423,8 +409,8 @@ TEST(VariantExceptionSafetyTest, ValueAssign) { ...@@ -423,8 +409,8 @@ TEST(VariantExceptionSafetyTest, ValueAssign) {
// move // move
auto move_tester = MakeExceptionSafetyTester() auto move_tester = MakeExceptionSafetyTester()
.WithInitialValue(WithCopyNoThrow()) .WithInitialValue(WithCopyNoThrow())
.WithOperation([rhs](ThrowingVariant* lhs) mutable { .WithOperation([](ThrowingVariant* lhs) {
*lhs = std::move(rhs); *lhs = ExpectedThrower(testing::nothrow_ctor);
}); });
EXPECT_TRUE(move_tester EXPECT_TRUE(move_tester
.WithInvariants(CheckInvariants, .WithInvariants(CheckInvariants,
...@@ -477,21 +463,20 @@ TEST(VariantExceptionSafetyTest, Swap) { ...@@ -477,21 +463,20 @@ TEST(VariantExceptionSafetyTest, Swap) {
// if both are valueless_by_exception(), no effect // if both are valueless_by_exception(), no effect
{ {
ThrowingVariant rhs = ValuelessByException(); ThrowingVariant rhs = ValuelessByException();
EXPECT_TRUE( ThrowingVariant lhs = ValuelessByException();
MakeExceptionSafetyTester() EXPECT_TRUE(TestNothrowOp([&]() { lhs.swap(rhs); }));
.WithInitialValue(ValuelessByException())
.WithInvariants(nothrow_guarantee)
.Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); }));
} }
// if index() == rhs.index(), calls swap(get<i>(*this), get<i>(rhs)) // if index() == rhs.index(), calls swap(get<i>(*this), get<i>(rhs))
// where i is index(). // where i is index().
{ {
ThrowingVariant rhs = ExpectedThrower(); ThrowingVariant rhs = ExpectedThrower();
EXPECT_TRUE( EXPECT_TRUE(MakeExceptionSafetyTester()
MakeExceptionSafetyTester()
.WithInitialValue(WithThrower()) .WithInitialValue(WithThrower())
.WithInvariants(CheckInvariants) .WithInvariants(CheckInvariants)
.Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); })); .Test([&](ThrowingVariant* lhs) {
auto copy = rhs;
lhs->swap(copy);
}));
} }
// Otherwise, exchanges the value of rhs and *this. The exception safety // Otherwise, exchanges the value of rhs and *this. The exception safety
// involves variant in moved-from state which is not specified in the // involves variant in moved-from state which is not specified in the
...@@ -499,19 +484,23 @@ TEST(VariantExceptionSafetyTest, Swap) { ...@@ -499,19 +484,23 @@ TEST(VariantExceptionSafetyTest, Swap) {
// overall strong guarantee. So, we are only checking basic guarantee here. // overall strong guarantee. So, we are only checking basic guarantee here.
{ {
ThrowingVariant rhs = ExpectedThrower(); ThrowingVariant rhs = ExpectedThrower();
EXPECT_TRUE( EXPECT_TRUE(MakeExceptionSafetyTester()
MakeExceptionSafetyTester()
.WithInitialValue(WithCopyNoThrow()) .WithInitialValue(WithCopyNoThrow())
.WithInvariants(CheckInvariants) .WithInvariants(CheckInvariants)
.Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); })); .Test([&](ThrowingVariant* lhs) {
auto copy = rhs;
lhs->swap(copy);
}));
} }
{ {
ThrowingVariant rhs = ExpectedThrower(); ThrowingVariant rhs = ExpectedThrower();
EXPECT_TRUE( EXPECT_TRUE(MakeExceptionSafetyTester()
MakeExceptionSafetyTester()
.WithInitialValue(WithCopyNoThrow()) .WithInitialValue(WithCopyNoThrow())
.WithInvariants(CheckInvariants) .WithInvariants(CheckInvariants)
.Test([rhs](ThrowingVariant* lhs) mutable { rhs.swap(*lhs); })); .Test([&](ThrowingVariant* lhs) {
auto copy = rhs;
copy.swap(*lhs);
}));
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment