about summary refs log tree commit diff
path: root/absl/types
diff options
context:
space:
mode:
authorAbseil Team <absl-team@google.com>2018-01-05T15·54-0800
committerDerek Mauro <dmauro@google.com>2018-01-08T15·38-0500
commit4132ce25956a91e1224e0f205b7f8c326304a995 (patch)
tree724485e8778f91d865db86af663af9e7be3293db /absl/types
parent0271cd35577599fa99b59202da17d3136956e4c0 (diff)
Changes imported from Abseil "staging" branch:
  - 0a519d9a4507158267cc515e0c7c83959d94fc78 Fix missing header include when compiling with _GLIBCXX_D... by Alex Strelnikov <strel@google.com>
  - d089af70781d92af9a5de2d84c417ddf2c87689a Internal change by Gennadiy Rozental <rogeeff@google.com>
  - 0d3afc89d3907923ede964d58c6bcca579e8ad65 Test absl::any for exception safety.  This test is tempor... by Jon Cohen <cohenjon@google.com>
  - 29af424b8a3174a7b3e657e478aa30a8a425aee2 Tweak the ABSL type trait library and expand its tests. by Abseil Team <absl-team@google.com>
  - 99ab42b2ebbe466cc3730fb6b16b5fad848f95af Rollback GLIBCXX_DEBUG fix due to internal breakage. by Alex Strelnikov <strel@google.com>
  - 1a5bcb93ee16d4dd2170254e54c4b62b38fbf17b Internal change. by Abseil Team <absl-team@google.com>
  - 46de7d09c7d4aef5b7b5389ce9b4f96b654aac02 absl::string_view::rfind: doc fix. by Abseil Team <absl-team@google.com>
  - edda4c7ddd2d76fbb5b3fd5226b95082083c57d9 Fix string_view_test with c++17/clang/libc++ to address by Xiaoyi Zhang <zhangxy@google.com>

GitOrigin-RevId: 0a519d9a4507158267cc515e0c7c83959d94fc78
Change-Id: Ie27de1be3e79bba011f05e924d34e8fcc62d8de5
Diffstat (limited to 'absl/types')
-rw-r--r--absl/types/BUILD.bazel13
-rw-r--r--absl/types/CMakeLists.txt17
-rw-r--r--absl/types/any_exception_safety_test.cc201
3 files changed, 230 insertions, 1 deletions
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel
index f98d9af429ce..60d6a60fa881 100644
--- a/absl/types/BUILD.bazel
+++ b/absl/types/BUILD.bazel
@@ -28,7 +28,7 @@ licenses(["notice"])  # Apache 2.0
 cc_library(
     name = "any",
     hdrs = ["any.h"],
-    copts = ABSL_DEFAULT_COPTS,
+    copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG,
     deps = [
         ":bad_any_cast",
         "//absl/base:config",
@@ -83,6 +83,17 @@ cc_test(
     ],
 )
 
+cc_test(
+    name = "any_exception_safety_test",
+    srcs = ["any_exception_safety_test.cc"],
+    copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+    deps = [
+        ":any",
+        "//absl/base:exception_safety_testing",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
 cc_library(
     name = "span",
     hdrs = ["span.h"],
diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt
index 3e4644974921..b2d95b48fbe7 100644
--- a/absl/types/CMakeLists.txt
+++ b/absl/types/CMakeLists.txt
@@ -29,6 +29,8 @@ absl_header_library(
     absl_any
   PUBLIC_LIBRARIES
     absl::utility
+  PRIVATE_COMPILE_FLAGS
+    ${ABSL_EXCEPTIONS_FLAG}
   EXPORT_NAME
     any
 )
@@ -126,6 +128,21 @@ absl_test(
     ${ANY_TEST_PUBLIC_LIBRARIES}
 )
 
+# test any_exception_safety_test
+set(ANY_EXCEPTION_SAFETY_TEST_SRC "any_exception_safety_test.cc")
+set(ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES absl::any absl::base)
+
+absl_test(
+  TARGET
+    any_exception_safety_test
+  SOURCES
+    ${ANY_EXCEPTION_SAFETY_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES}
+  PRIVATE_COMPILE_FLAGS
+    ${ABSL_EXCEPTIONS_FLAG}
+)
+
 
 # test span_test
 set(SPAN_TEST_SRC "span_test.cc")
diff --git a/absl/types/any_exception_safety_test.cc b/absl/types/any_exception_safety_test.cc
new file mode 100644
index 000000000000..eadba3080437
--- /dev/null
+++ b/absl/types/any_exception_safety_test.cc
@@ -0,0 +1,201 @@
+// 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/any.h"
+
+#include <typeinfo>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/exception_safety_testing.h"
+
+using Thrower = absl::ThrowingValue<>;
+using ThrowerList = std::initializer_list<Thrower>;
+using ThrowerVec = std::vector<Thrower>;
+using ThrowingAlloc = absl::ThrowingAllocator<Thrower>;
+using ThrowingThrowerVec = std::vector<Thrower, ThrowingAlloc>;
+
+namespace absl {
+
+testing::AssertionResult AbslCheckInvariants(absl::any* a,
+                                             InternalAbslNamespaceFinder) {
+  using testing::AssertionFailure;
+  using testing::AssertionSuccess;
+
+  if (a->has_value()) {
+    if (a->type() == typeid(void)) {
+      return AssertionFailure()
+             << "A non-empty any should not have type `void`";
+    }
+  } else {
+    if (a->type() != typeid(void)) {
+      return AssertionFailure()
+             << "An empty any should have type void, but has type "
+             << a->type().name();
+    }
+  }
+
+  //  Make sure that reset() changes any to a valid state.
+  a->reset();
+  if (a->has_value()) {
+    return AssertionFailure() << "A reset `any` should be valueless";
+  }
+  if (a->type() != typeid(void)) {
+    return AssertionFailure() << "A reset `any` should have type() of `void`, "
+                                 "but instead has type "
+                              << a->type().name();
+  }
+  try {
+    auto unused = absl::any_cast<Thrower>(*a);
+    static_cast<void>(unused);
+    return AssertionFailure()
+           << "A reset `any` should not be able to be any_cast";
+  } catch (absl::bad_any_cast) {
+  } catch (...) {
+    return AssertionFailure()
+           << "Unexpected exception thrown from absl::any_cast";
+  }
+  return AssertionSuccess();
+}
+
+}  // namespace absl
+
+namespace {
+
+class AnyExceptionSafety : public ::testing::Test {
+ private:
+  absl::AllocInspector inspector_;
+};
+
+testing::AssertionResult AnyIsEmpty(absl::any* a) {
+  if (!a->has_value()) return testing::AssertionSuccess();
+  return testing::AssertionFailure()
+         << "a should be empty, but instead has value "
+         << absl::any_cast<Thrower>(*a).Get();
+}
+
+TEST_F(AnyExceptionSafety, Ctors) {
+  Thrower val(1);
+  auto with_val = absl::TestThrowingCtor<absl::any>(val);
+  auto copy = absl::TestThrowingCtor<absl::any>(with_val);
+  auto in_place =
+      absl::TestThrowingCtor<absl::any>(absl::in_place_type_t<Thrower>(), 1);
+  auto in_place_list = absl::TestThrowingCtor<absl::any>(
+      absl::in_place_type_t<ThrowerVec>(), ThrowerList{val});
+  auto in_place_list_again =
+      absl::TestThrowingCtor<absl::any,
+                             absl::in_place_type_t<ThrowingThrowerVec>,
+                             ThrowerList, ThrowingAlloc>(
+          absl::in_place_type_t<ThrowingThrowerVec>(), {val}, ThrowingAlloc());
+}
+
+struct OneFactory {
+  std::unique_ptr<absl::any> operator()() const {
+    return absl::make_unique<absl::any>(absl::in_place_type_t<Thrower>(), 1,
+                                        absl::no_throw_ctor);
+  }
+};
+
+struct EmptyFactory {
+  std::unique_ptr<absl::any> operator()() const {
+    return absl::make_unique<absl::any>();
+  }
+};
+
+TEST_F(AnyExceptionSafety, Assignment) {
+  auto thrower_comp = [](const absl::any& l, const absl::any& r) {
+    return absl::any_cast<Thrower>(l) == absl::any_cast<Thrower>(r);
+  };
+
+  OneFactory one_factory;
+
+  absl::ThrowingValue<absl::NoThrow::kMoveCtor | absl::NoThrow::kMoveAssign>
+      moveable_val(2);
+  Thrower val(2);
+  absl::any any_val(val);
+
+  EXPECT_TRUE(absl::TestExceptionSafety(
+      one_factory, [&any_val](absl::any* ap) { *ap = any_val; },
+      absl::StrongGuarantee(one_factory, thrower_comp)));
+
+  EXPECT_TRUE(absl::TestExceptionSafety(
+      one_factory, [&val](absl::any* ap) { *ap = val; },
+      absl::StrongGuarantee(one_factory, thrower_comp)));
+
+  EXPECT_TRUE(absl::TestExceptionSafety(
+      one_factory, [&val](absl::any* ap) { *ap = std::move(val); },
+      absl::StrongGuarantee(one_factory, thrower_comp)));
+
+  EXPECT_TRUE(absl::TestExceptionSafety(
+      one_factory,
+      [&moveable_val](absl::any* ap) { *ap = std::move(moveable_val); },
+      absl::StrongGuarantee(one_factory, thrower_comp)));
+
+  EmptyFactory empty_factory;
+  auto empty_comp = [](const absl::any& l, const absl::any& r) {
+    return !(l.has_value() || r.has_value());
+  };
+
+  EXPECT_TRUE(absl::TestExceptionSafety(
+      empty_factory, [&any_val](absl::any* ap) { *ap = any_val; },
+      absl::StrongGuarantee(empty_factory, empty_comp)));
+
+  EXPECT_TRUE(absl::TestExceptionSafety(
+      empty_factory, [&val](absl::any* ap) { *ap = val; },
+      absl::StrongGuarantee(empty_factory, empty_comp)));
+
+  EXPECT_TRUE(absl::TestExceptionSafety(
+      empty_factory, [&val](absl::any* ap) { *ap = std::move(val); },
+      absl::StrongGuarantee(empty_factory, empty_comp)));
+}
+// libstdc++ std::any fails this test
+#if !defined(ABSL_HAVE_STD_ANY)
+TEST_F(AnyExceptionSafety, Emplace) {
+  OneFactory one_factory;
+
+  EXPECT_TRUE(absl::TestExceptionSafety(
+      one_factory, [](absl::any* ap) { ap->emplace<Thrower>(2); }, AnyIsEmpty));
+
+  EXPECT_TRUE(absl::TestExceptionSafety(
+      one_factory,
+      [](absl::any* ap) {
+        ap->emplace<absl::ThrowingValue<absl::NoThrow::kMoveCtor |
+                                        absl::NoThrow::kMoveAssign>>(2);
+      },
+      AnyIsEmpty));
+
+  EXPECT_TRUE(absl::TestExceptionSafety(one_factory,
+                                        [](absl::any* ap) {
+                                          std::initializer_list<Thrower> il{
+                                              Thrower(2, absl::no_throw_ctor)};
+                                          ap->emplace<ThrowerVec>(il);
+                                        },
+                                        AnyIsEmpty));
+
+  EmptyFactory empty_factory;
+  EXPECT_TRUE(absl::TestExceptionSafety(
+      empty_factory, [](absl::any* ap) { ap->emplace<Thrower>(2); },
+      AnyIsEmpty));
+
+  EXPECT_TRUE(absl::TestExceptionSafety(empty_factory,
+                                        [](absl::any* ap) {
+                                          std::initializer_list<Thrower> il{
+                                              Thrower(2, absl::no_throw_ctor)};
+                                          ap->emplace<ThrowerVec>(il);
+                                        },
+                                        AnyIsEmpty));
+}
+#endif  // ABSL_HAVE_STD_ANY
+
+}  // namespace