Commit eb686c06 by Abseil Team Committed by Gennadiy Rozental

- b9a479321581cd0293f124041bf5c06f456afec1 Adds exception safety tests for…

  - b9a479321581cd0293f124041bf5c06f456afec1 Adds exception safety tests for absl::make_unique<T>(...) by Abseil Team <absl-team@google.com>
  - 78c61364007f6ab66155c151d0061bbec89c3dbd Update variadic visitation to use a switch statement when... by Matt Calabrese <calabrese@google.com>
  - b62eb9546087e0001307a741fcdf023b2d156966 Merge GitHub PR #130 - Add MIPS support to GetProgramCoun... by Derek Mauro <dmauro@google.com>
  - 09ab5739de33c8f1bebab2bb70bf7d4331348f05 Update ABSL_ASSERT to silence clang-tidy warnings about c... by Matt Calabrese <calabrese@google.com>
  - e73ee389ce8fe1a90738973c219ebbb19bb389f3 Update unary visitation to use a switch statement when th... by Matt Calabrese <calabrese@google.com>
  - c8734ccf475b856c95220f21a5ec4f44302cb5ce Work around a MSVC bug for absl::variant, by making `Acce... by Xiaoyi Zhang <zhangxy@google.com>

GitOrigin-RevId: b9a479321581cd0293f124041bf5c06f456afec1
Change-Id: Idb6fc906087c0a4e6fc5c75a391c7f73101c613e
parent e5be8053
...@@ -195,7 +195,8 @@ enum LinkerInitialized { ...@@ -195,7 +195,8 @@ enum LinkerInitialized {
#define ABSL_ASSERT(expr) (false ? (void)(expr) : (void)0) #define ABSL_ASSERT(expr) (false ? (void)(expr) : (void)0)
#else #else
#define ABSL_ASSERT(expr) \ #define ABSL_ASSERT(expr) \
(ABSL_PREDICT_TRUE((expr)) ? (void)0 : [] { assert(false && #expr); }()) (ABSL_PREDICT_TRUE((expr)) ? (void)0 \
: [] { assert(false && #expr); }()) // NOLINT
#endif #endif
#endif // ABSL_BASE_MACROS_H_ #endif // ABSL_BASE_MACROS_H_
...@@ -18,6 +18,7 @@ load( ...@@ -18,6 +18,7 @@ load(
"//absl:copts.bzl", "//absl:copts.bzl",
"ABSL_DEFAULT_COPTS", "ABSL_DEFAULT_COPTS",
"ABSL_TEST_COPTS", "ABSL_TEST_COPTS",
"ABSL_EXCEPTIONS_FLAG",
) )
package(default_visibility = ["//visibility:public"]) package(default_visibility = ["//visibility:public"])
...@@ -45,3 +46,16 @@ cc_test( ...@@ -45,3 +46,16 @@ cc_test(
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
) )
cc_test(
name = "memory_exception_safety_test",
srcs = [
"memory_exception_safety_test.cc",
],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
deps = [
":memory",
"//absl/base:exception_safety_testing",
"@com_google_googletest//:gtest_main",
],
)
...@@ -49,4 +49,23 @@ absl_test( ...@@ -49,4 +49,23 @@ absl_test(
) )
# test memory_exception_safety_test
set(MEMORY_EXCEPTION_SAFETY_TEST_SRC "memory_exception_safety_test.cc")
set(MEMORY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES
absl::memory
absl_base_internal_exception_safety_testing
)
absl_test(
TARGET
memory_exception_safety_test
SOURCES
${MEMORY_EXCEPTION_SAFETY_TEST_SRC}
PUBLIC_LIBRARIES
${MEMORY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES}
PRIVATE_COMPILE_FLAGS
${ABSL_EXCEPTIONS_FLAG}
)
// 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/memory/memory.h"
#include "gtest/gtest.h"
#include "absl/base/internal/exception_safety_testing.h"
namespace absl {
namespace {
using Thrower = ::testing::ThrowingValue<>;
TEST(MakeUnique, CheckForLeaks) {
constexpr int kValue = 321;
constexpr size_t kLength = 10;
auto tester = testing::MakeExceptionSafetyTester()
.WithInitialValue(Thrower(kValue))
// Ensures make_unique does not modify the input. The real
// test, though, is ConstructorTracker checking for leaks.
.WithInvariants(testing::strong_guarantee);
EXPECT_TRUE(tester.Test([](Thrower* thrower) {
static_cast<void>(absl::make_unique<Thrower>(*thrower));
}));
EXPECT_TRUE(tester.Test([](Thrower* thrower) {
static_cast<void>(absl::make_unique<Thrower>(std::move(*thrower)));
}));
// Test T[n] overload
EXPECT_TRUE(tester.Test([&](Thrower*) {
static_cast<void>(absl::make_unique<Thrower[]>(kLength));
}));
}
} // namespace
} // namespace absl
...@@ -248,6 +248,19 @@ cc_test( ...@@ -248,6 +248,19 @@ cc_test(
) )
cc_test( cc_test(
name = "variant_benchmark",
srcs = [
"variant_benchmark.cc",
],
copts = ABSL_TEST_COPTS,
deps = [
":variant",
"//absl/utility",
"@com_github_google_benchmark//:benchmark_main",
],
)
cc_test(
name = "variant_exception_safety_test", name = "variant_exception_safety_test",
size = "small", size = "small",
srcs = [ srcs = [
......
...@@ -416,8 +416,8 @@ constexpr absl::add_pointer_t<const T> get_if( ...@@ -416,8 +416,8 @@ constexpr absl::add_pointer_t<const T> get_if(
template <typename Visitor, typename... Variants> template <typename Visitor, typename... Variants>
variant_internal::VisitResult<Visitor, Variants...> visit(Visitor&& vis, variant_internal::VisitResult<Visitor, Variants...> visit(Visitor&& vis,
Variants&&... vars) { Variants&&... vars) {
return variant_internal::visit_indices< return variant_internal::
variant_size<absl::decay_t<Variants>>::value...>( VisitIndices<variant_size<absl::decay_t<Variants> >::value...>::Run(
variant_internal::PerformVisitation<Visitor, Variants...>{ variant_internal::PerformVisitation<Visitor, Variants...>{
std::forward_as_tuple(absl::forward<Variants>(vars)...), std::forward_as_tuple(absl::forward<Variants>(vars)...),
absl::forward<Visitor>(vis)}, absl::forward<Visitor>(vis)},
...@@ -573,7 +573,7 @@ class variant<T0, Tn...> : private variant_internal::VariantBase<T0, Tn...> { ...@@ -573,7 +573,7 @@ class variant<T0, Tn...> : private variant_internal::VariantBase<T0, Tn...> {
variant& operator=(T&& t) noexcept( variant& operator=(T&& t) noexcept(
std::is_nothrow_assignable<Tj&, T>::value&& std::is_nothrow_assignable<Tj&, T>::value&&
std::is_nothrow_constructible<Tj, T>::value) { std::is_nothrow_constructible<Tj, T>::value) {
variant_internal::visit_indices<sizeof...(Tn) + 1>( variant_internal::VisitIndices<sizeof...(Tn) + 1>::Run(
variant_internal::VariantCoreAccess::MakeConversionAssignVisitor( variant_internal::VariantCoreAccess::MakeConversionAssignVisitor(
this, absl::forward<T>(t)), this, absl::forward<T>(t)),
index()); index());
...@@ -682,7 +682,7 @@ class variant<T0, Tn...> : private variant_internal::VariantBase<T0, Tn...> { ...@@ -682,7 +682,7 @@ class variant<T0, Tn...> : private variant_internal::VariantBase<T0, Tn...> {
// true and `is_nothrow_swappable()` is same as `std::is_trivial()`. // true and `is_nothrow_swappable()` is same as `std::is_trivial()`.
void swap(variant& rhs) noexcept( void swap(variant& rhs) noexcept(
absl::conjunction<std::is_trivial<T0>, std::is_trivial<Tn>...>::value) { absl::conjunction<std::is_trivial<T0>, std::is_trivial<Tn>...>::value) {
return variant_internal::visit_indices<sizeof...(Tn) + 1>( return variant_internal::VisitIndices<sizeof...(Tn) + 1>::Run(
variant_internal::Swap<T0, Tn...>{this, &rhs}, rhs.index()); variant_internal::Swap<T0, Tn...>{this, &rhs}, rhs.index());
} }
}; };
...@@ -722,7 +722,7 @@ template <typename... Types> ...@@ -722,7 +722,7 @@ template <typename... Types>
constexpr variant_internal::RequireAllHaveEqualT<Types...> operator==( constexpr variant_internal::RequireAllHaveEqualT<Types...> operator==(
const variant<Types...>& a, const variant<Types...>& b) { const variant<Types...>& a, const variant<Types...>& b) {
return (a.index() == b.index()) && return (a.index() == b.index()) &&
variant_internal::visit_indices<sizeof...(Types)>( variant_internal::VisitIndices<sizeof...(Types)>::Run(
variant_internal::EqualsOp<Types...>{&a, &b}, a.index()); variant_internal::EqualsOp<Types...>{&a, &b}, a.index());
} }
...@@ -731,7 +731,7 @@ template <typename... Types> ...@@ -731,7 +731,7 @@ template <typename... Types>
constexpr variant_internal::RequireAllHaveNotEqualT<Types...> operator!=( constexpr variant_internal::RequireAllHaveNotEqualT<Types...> operator!=(
const variant<Types...>& a, const variant<Types...>& b) { const variant<Types...>& a, const variant<Types...>& b) {
return (a.index() != b.index()) || return (a.index() != b.index()) ||
variant_internal::visit_indices<sizeof...(Types)>( variant_internal::VisitIndices<sizeof...(Types)>::Run(
variant_internal::NotEqualsOp<Types...>{&a, &b}, a.index()); variant_internal::NotEqualsOp<Types...>{&a, &b}, a.index());
} }
...@@ -741,7 +741,7 @@ constexpr variant_internal::RequireAllHaveLessThanT<Types...> operator<( ...@@ -741,7 +741,7 @@ constexpr variant_internal::RequireAllHaveLessThanT<Types...> operator<(
const variant<Types...>& a, const variant<Types...>& b) { const variant<Types...>& a, const variant<Types...>& b) {
return (a.index() != b.index()) return (a.index() != b.index())
? (a.index() + 1) < (b.index() + 1) ? (a.index() + 1) < (b.index() + 1)
: variant_internal::visit_indices<sizeof...(Types)>( : variant_internal::VisitIndices<sizeof...(Types)>::Run(
variant_internal::LessThanOp<Types...>{&a, &b}, a.index()); variant_internal::LessThanOp<Types...>{&a, &b}, a.index());
} }
...@@ -751,7 +751,7 @@ constexpr variant_internal::RequireAllHaveGreaterThanT<Types...> operator>( ...@@ -751,7 +751,7 @@ constexpr variant_internal::RequireAllHaveGreaterThanT<Types...> operator>(
const variant<Types...>& a, const variant<Types...>& b) { const variant<Types...>& a, const variant<Types...>& b) {
return (a.index() != b.index()) return (a.index() != b.index())
? (a.index() + 1) > (b.index() + 1) ? (a.index() + 1) > (b.index() + 1)
: variant_internal::visit_indices<sizeof...(Types)>( : variant_internal::VisitIndices<sizeof...(Types)>::Run(
variant_internal::GreaterThanOp<Types...>{&a, &b}, variant_internal::GreaterThanOp<Types...>{&a, &b},
a.index()); a.index());
} }
...@@ -762,7 +762,7 @@ constexpr variant_internal::RequireAllHaveLessThanOrEqualT<Types...> operator<=( ...@@ -762,7 +762,7 @@ constexpr variant_internal::RequireAllHaveLessThanOrEqualT<Types...> operator<=(
const variant<Types...>& a, const variant<Types...>& b) { const variant<Types...>& a, const variant<Types...>& b) {
return (a.index() != b.index()) return (a.index() != b.index())
? (a.index() + 1) < (b.index() + 1) ? (a.index() + 1) < (b.index() + 1)
: variant_internal::visit_indices<sizeof...(Types)>( : variant_internal::VisitIndices<sizeof...(Types)>::Run(
variant_internal::LessThanOrEqualsOp<Types...>{&a, &b}, variant_internal::LessThanOrEqualsOp<Types...>{&a, &b},
a.index()); a.index());
} }
...@@ -773,7 +773,7 @@ constexpr variant_internal::RequireAllHaveGreaterThanOrEqualT<Types...> ...@@ -773,7 +773,7 @@ constexpr variant_internal::RequireAllHaveGreaterThanOrEqualT<Types...>
operator>=(const variant<Types...>& a, const variant<Types...>& b) { operator>=(const variant<Types...>& a, const variant<Types...>& b) {
return (a.index() != b.index()) return (a.index() != b.index())
? (a.index() + 1) > (b.index() + 1) ? (a.index() + 1) > (b.index() + 1)
: variant_internal::visit_indices<sizeof...(Types)>( : variant_internal::VisitIndices<sizeof...(Types)>::Run(
variant_internal::GreaterThanOrEqualsOp<Types...>{&a, &b}, variant_internal::GreaterThanOrEqualsOp<Types...>{&a, &b},
a.index()); a.index());
} }
......
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Unit tests for the variant template. The 'is' and 'IsEmpty' methods
// of variant are not explicitly tested because they are used repeatedly
// in building other tests. All other public variant methods should have
// explicit tests.
#include "absl/types/variant.h"
#include <cstddef>
#include <cstdlib>
#include <string>
#include <tuple>
#include "benchmark/benchmark.h"
#include "absl/utility/utility.h"
namespace absl {
namespace {
template <std::size_t I>
struct VariantAlternative {
char member;
};
template <class Indices>
struct VariantOfAlternativesImpl;
template <std::size_t... Indices>
struct VariantOfAlternativesImpl<absl::index_sequence<Indices...>> {
using type = absl::variant<VariantAlternative<Indices>...>;
};
template <std::size_t NumAlternatives>
using VariantOfAlternatives = typename VariantOfAlternativesImpl<
absl::make_index_sequence<NumAlternatives>>::type;
struct Empty {};
template <class... T>
void Ignore(T...) noexcept {}
template <class T>
Empty DoNotOptimizeAndReturnEmpty(T&& arg) noexcept {
benchmark::DoNotOptimize(arg);
return {};
}
struct VisitorApplier {
struct Visitor {
template <class... T>
void operator()(T&&... args) const noexcept {
Ignore(DoNotOptimizeAndReturnEmpty(args)...);
}
};
template <class... Vars>
void operator()(const Vars&... vars) const noexcept {
absl::visit(Visitor(), vars...);
}
};
template <std::size_t NumIndices, std::size_t CurrIndex = NumIndices - 1>
struct MakeWithIndex {
using Variant = VariantOfAlternatives<NumIndices>;
static Variant Run(std::size_t index) {
return index == CurrIndex
? Variant(absl::in_place_index_t<CurrIndex>())
: MakeWithIndex<NumIndices, CurrIndex - 1>::Run(index);
}
};
template <std::size_t NumIndices>
struct MakeWithIndex<NumIndices, 0> {
using Variant = VariantOfAlternatives<NumIndices>;
static Variant Run(std::size_t /*index*/) { return Variant(); }
};
template <std::size_t NumIndices, class Dimensions>
struct MakeVariantTuple;
template <class T, std::size_t /*I*/>
using always_t = T;
template <std::size_t NumIndices>
VariantOfAlternatives<NumIndices> MakeVariant(std::size_t dimension,
std::size_t index) {
return dimension == 0
? MakeWithIndex<NumIndices>::Run(index % NumIndices)
: MakeVariant<NumIndices>(dimension - 1, index / NumIndices);
}
template <std::size_t NumIndices, std::size_t... Dimensions>
struct MakeVariantTuple<NumIndices, absl::index_sequence<Dimensions...>> {
using VariantTuple =
std::tuple<always_t<VariantOfAlternatives<NumIndices>, Dimensions>...>;
static VariantTuple Run(int index) {
return std::make_tuple(MakeVariant<NumIndices>(Dimensions, index)...);
}
};
constexpr std::size_t integral_pow(std::size_t base, std::size_t power) {
return power == 0 ? 1 : base * integral_pow(base, power - 1);
}
template <std::size_t End, std::size_t I = 0>
struct VisitTestBody {
template <class Vars, class State>
static bool Run(Vars& vars, State& state) {
if (state.KeepRunning()) {
absl::apply(VisitorApplier(), vars[I]);
return VisitTestBody<End, I + 1>::Run(vars, state);
}
return false;
}
};
template <std::size_t End>
struct VisitTestBody<End, End> {
template <class Vars, class State>
static bool Run(Vars& /*vars*/, State& /*state*/) {
return true;
}
};
// Visit operations where branch prediction is likely to give a boost.
template <std::size_t NumIndices, std::size_t NumDimensions = 1>
void BM_RedundantVisit(benchmark::State& state) {
auto vars =
MakeVariantTuple<NumIndices, absl::make_index_sequence<NumDimensions>>::
Run(static_cast<std::size_t>(state.range(0)));
for (auto _ : state) { // NOLINT
benchmark::DoNotOptimize(vars);
absl::apply(VisitorApplier(), vars);
}
}
// Visit operations where branch prediction is unlikely to give a boost.
template <std::size_t NumIndices, std::size_t NumDimensions = 1>
void BM_Visit(benchmark::State& state) {
constexpr std::size_t num_possibilities =
integral_pow(NumIndices, NumDimensions);
using VariantTupleMaker =
MakeVariantTuple<NumIndices, absl::make_index_sequence<NumDimensions>>;
using Tuple = typename VariantTupleMaker::VariantTuple;
Tuple vars[num_possibilities];
for (std::size_t i = 0; i < num_possibilities; ++i)
vars[i] = VariantTupleMaker::Run(i);
while (VisitTestBody<num_possibilities>::Run(vars, state)) {
}
}
// Visitation
// Each visit is on a different variant with a different active alternative)
// Unary visit
BENCHMARK_TEMPLATE(BM_Visit, 1);
BENCHMARK_TEMPLATE(BM_Visit, 2);
BENCHMARK_TEMPLATE(BM_Visit, 3);
BENCHMARK_TEMPLATE(BM_Visit, 4);
BENCHMARK_TEMPLATE(BM_Visit, 5);
BENCHMARK_TEMPLATE(BM_Visit, 6);
BENCHMARK_TEMPLATE(BM_Visit, 7);
BENCHMARK_TEMPLATE(BM_Visit, 8);
BENCHMARK_TEMPLATE(BM_Visit, 16);
BENCHMARK_TEMPLATE(BM_Visit, 32);
BENCHMARK_TEMPLATE(BM_Visit, 64);
// Binary visit
BENCHMARK_TEMPLATE(BM_Visit, 1, 2);
BENCHMARK_TEMPLATE(BM_Visit, 2, 2);
BENCHMARK_TEMPLATE(BM_Visit, 3, 2);
BENCHMARK_TEMPLATE(BM_Visit, 4, 2);
BENCHMARK_TEMPLATE(BM_Visit, 5, 2);
// Ternary visit
BENCHMARK_TEMPLATE(BM_Visit, 1, 3);
BENCHMARK_TEMPLATE(BM_Visit, 2, 3);
BENCHMARK_TEMPLATE(BM_Visit, 3, 3);
// Quaternary visit
BENCHMARK_TEMPLATE(BM_Visit, 1, 4);
BENCHMARK_TEMPLATE(BM_Visit, 2, 4);
// Redundant Visitation
// Each visit consistently has the same alternative active
// Unary visit
BENCHMARK_TEMPLATE(BM_RedundantVisit, 1)->Arg(0);
BENCHMARK_TEMPLATE(BM_RedundantVisit, 2)->DenseRange(0, 1);
BENCHMARK_TEMPLATE(BM_RedundantVisit, 8)->DenseRange(0, 7);
// Binary visit
BENCHMARK_TEMPLATE(BM_RedundantVisit, 1, 2)->Arg(0);
BENCHMARK_TEMPLATE(BM_RedundantVisit, 2, 2)
->DenseRange(0, integral_pow(2, 2) - 1);
BENCHMARK_TEMPLATE(BM_RedundantVisit, 4, 2)
->DenseRange(0, integral_pow(4, 2) - 1);
} // namespace
} // namespace absl
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