summaryrefslogtreecommitdiff
path: root/absl
diff options
context:
space:
mode:
Diffstat (limited to 'absl')
-rw-r--r--absl/base/config.h24
-rw-r--r--absl/base/exception_safety_testing_test.cc4
-rw-r--r--absl/base/internal/exception_safety_testing.h19
-rw-r--r--absl/base/thread_annotations.h31
-rw-r--r--absl/meta/type_traits.h19
-rw-r--r--absl/strings/str_join.h2
-rw-r--r--absl/time/time.h23
-rw-r--r--absl/types/BUILD.bazel42
-rw-r--r--absl/types/CMakeLists.txt15
-rw-r--r--absl/types/any.h4
-rw-r--r--absl/types/bad_any_cast.h33
-rw-r--r--absl/types/bad_optional_access.h25
-rw-r--r--absl/types/bad_variant_access.cc58
-rw-r--r--absl/types/bad_variant_access.h64
-rw-r--r--absl/types/internal/variant.h1387
-rw-r--r--absl/types/optional.h5
-rw-r--r--absl/types/variant.h838
-rw-r--r--absl/types/variant_test.cc2622
-rw-r--r--absl/utility/utility.h9
19 files changed, 5172 insertions, 52 deletions
diff --git a/absl/base/config.h b/absl/base/config.h
index 93855957..de33120f 100644
--- a/absl/base/config.h
+++ b/absl/base/config.h
@@ -382,6 +382,19 @@
#endif
#endif
+// ABSL_HAVE_STD_VARIANT
+//
+// Checks whether C++17 std::optional is available.
+#ifdef ABSL_HAVE_STD_VARIANT
+#error "ABSL_HAVE_STD_VARIANT cannot be directly set."
+#endif
+
+#ifdef __has_include
+#if __has_include(<variant>) && __cplusplus >= 201703L
+#define ABSL_HAVE_STD_VARIANT 1
+#endif
+#endif
+
// ABSL_HAVE_STD_STRING_VIEW
//
// Checks whether C++17 std::string_view is available.
@@ -396,17 +409,18 @@
#endif
// For MSVC, `__has_include` is supported in VS 2017 15.3, which is later than
-// the support for <optional>, <any>, <string_view>. So we use _MSC_VER to check
-// whether we have VS 2017 RTM (when <optional>, <any>, <string_view> is
-// implemented) or higher.
-// Also, `__cplusplus` is not correctly set by MSVC, so we use `_MSVC_LANG` to
-// check the language version.
+// the support for <optional>, <any>, <string_view>, <variant>. So we use
+// _MSC_VER to check whether we have VS 2017 RTM (when <optional>, <any>,
+// <string_view>, <variant> is implemented) or higher. Also, `__cplusplus` is
+// not correctly set by MSVC, so we use `_MSVC_LANG` to check the language
+// version.
// TODO(zhangxy): fix tests before enabling aliasing for `std::any`,
// `std::string_view`.
#if defined(_MSC_VER) && _MSC_VER >= 1910 && \
((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || __cplusplus > 201402)
// #define ABSL_HAVE_STD_ANY 1
#define ABSL_HAVE_STD_OPTIONAL 1
+#define ABSL_HAVE_STD_VARIANT 1
// #define ABSL_HAVE_STD_STRING_VIEW 1
#endif
diff --git a/absl/base/exception_safety_testing_test.cc b/absl/base/exception_safety_testing_test.cc
index 041d780f..94a7e4f7 100644
--- a/absl/base/exception_safety_testing_test.cc
+++ b/absl/base/exception_safety_testing_test.cc
@@ -27,7 +27,9 @@
namespace absl {
namespace {
+using ::absl::exceptions_internal::SetCountdown;
using ::absl::exceptions_internal::TestException;
+using ::absl::exceptions_internal::UnsetCountdown;
// EXPECT_NO_THROW can't inspect the thrown inspection in general.
template <typename F>
@@ -54,7 +56,7 @@ TEST_F(ThrowingValueTest, Throws) {
// It's not guaranteed that every operator only throws *once*. The default
// ctor only throws once, though, so use it to make sure we only throw when
// the countdown hits 0
- exceptions_internal::countdown = 2;
+ SetCountdown(2);
ExpectNoThrow([]() { ThrowingValue<> bomb; });
ExpectNoThrow([]() { ThrowingValue<> bomb; });
EXPECT_THROW(ThrowingValue<> bomb, TestException);
diff --git a/absl/base/internal/exception_safety_testing.h b/absl/base/internal/exception_safety_testing.h
index 3493b5e2..48a292b3 100644
--- a/absl/base/internal/exception_safety_testing.h
+++ b/absl/base/internal/exception_safety_testing.h
@@ -94,6 +94,12 @@ class TestBadAllocException : public std::bad_alloc, public TestException {
extern int countdown;
+// Allows the countdown variable to be set manually (defaulting to the initial
+// value of 0)
+inline void SetCountdown(int i = 0) { countdown = i; }
+// Sets the countdown to the terminal value -1
+inline void UnsetCountdown() { SetCountdown(-1); }
+
void MaybeThrow(absl::string_view msg, bool throw_bad_alloc = false);
testing::AssertionResult FailureMessage(const TestException& e,
@@ -134,7 +140,7 @@ absl::optional<testing::AssertionResult> TestSingleInvariantAtCountdownImpl(
const Invariant& invariant) {
auto t_ptr = factory();
absl::optional<testing::AssertionResult> current_res;
- exceptions_internal::countdown = count;
+ SetCountdown(count);
try {
operation(t_ptr.get());
} catch (const exceptions_internal::TestException& e) {
@@ -143,7 +149,7 @@ absl::optional<testing::AssertionResult> TestSingleInvariantAtCountdownImpl(
*current_res << e.what() << " failed invariant check";
}
}
- exceptions_internal::countdown = -1;
+ UnsetCountdown();
return current_res;
}
@@ -196,11 +202,6 @@ inline absl::optional<testing::AssertionResult> TestAllInvariantsAtCountdown(
extern exceptions_internal::NoThrowTag no_throw_ctor;
extern exceptions_internal::StrongGuaranteeTagType strong_guarantee;
-// These are useful for tests which just construct objects and make sure there
-// are no leaks.
-inline void SetCountdown() { exceptions_internal::countdown = 0; }
-inline void UnsetCountdown() { exceptions_internal::countdown = -1; }
-
// A test class which is convertible to bool. The conversion can be
// instrumented to throw at a controlled time.
class ThrowingBool {
@@ -731,10 +732,10 @@ struct ConstructorTracker {
template <typename T, typename... Args>
T TestThrowingCtor(Args&&... args) {
struct Cleanup {
- ~Cleanup() { UnsetCountdown(); }
+ ~Cleanup() { exceptions_internal::UnsetCountdown(); }
} c;
for (int count = 0;; ++count) {
- exceptions_internal::countdown = count;
+ exceptions_internal::SetCountdown(count);
try {
return T(std::forward<Args>(args)...);
} catch (const exceptions_internal::TestException&) {
diff --git a/absl/base/thread_annotations.h b/absl/base/thread_annotations.h
index 0da3badc..8d30b932 100644
--- a/absl/base/thread_annotations.h
+++ b/absl/base/thread_annotations.h
@@ -47,10 +47,17 @@
// mutex. GUARDED_BY() allows the user to specify a particular mutex that
// should be held when accessing the annotated variable.
//
+// Although this annotation (and PT_GUARDED_BY, below) cannot be applied to
+// local variables, a local variable and its associated mutex can often be
+// combined into a small class or struct, thereby allowing the annotation.
+//
// Example:
//
-// Mutex mu;
-// int p1 GUARDED_BY(mu);
+// class Foo {
+// Mutex mu_;
+// int p1_ GUARDED_BY(mu_);
+// ...
+// };
#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
// PT_GUARDED_BY()
@@ -59,17 +66,20 @@
// by a mutex when dereferencing the pointer.
//
// Example:
-// Mutex mu;
-// int *p1 PT_GUARDED_BY(mu);
+// class Foo {
+// Mutex mu_;
+// int *p1_ PT_GUARDED_BY(mu_);
+// ...
+// };
//
// Note that a pointer variable to a shared memory location could itself be a
// shared variable.
//
// Example:
//
-// // `q`, guarded by `mu1`, points to a shared memory location that is
-// // guarded by `mu2`:
-// int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
+// // `q_`, guarded by `mu1_`, points to a shared memory location that is
+// // guarded by `mu2_`:
+// int *q_ GUARDED_BY(mu1_) PT_GUARDED_BY(mu2_);
#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
// ACQUIRED_AFTER() / ACQUIRED_BEFORE()
@@ -80,10 +90,13 @@
// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
// and ACQUIRED_BEFORE.)
//
+// As with GUARDED_BY, this is only applicable to mutexes that are shared
+// fields or global variables.
+//
// Example:
//
-// Mutex m1;
-// Mutex m2 ACQUIRED_AFTER(m1);
+// Mutex m1_;
+// Mutex m2_ ACQUIRED_AFTER(m1_);
#define ACQUIRED_AFTER(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h
index 73a5685b..88af17c3 100644
--- a/absl/meta/type_traits.h
+++ b/absl/meta/type_traits.h
@@ -36,6 +36,7 @@
#define ABSL_META_TYPE_TRAITS_H_
#include <stddef.h>
+#include <functional>
#include <type_traits>
#include "absl/base/config.h"
@@ -349,5 +350,23 @@ using underlying_type_t = typename std::underlying_type<T>::type;
template <typename T>
using result_of_t = typename std::result_of<T>::type;
+namespace type_traits_internal {
+template <typename Key, typename = size_t>
+struct IsHashable : std::false_type {};
+
+template <typename Key>
+struct IsHashable<Key,
+ decltype(std::declval<std::hash<Key>>()(std::declval<Key>()))>
+ : std::true_type {};
+
+template <typename Key>
+struct IsHashEnabled
+ : absl::conjunction<std::is_default_constructible<std::hash<Key>>,
+ std::is_copy_constructible<std::hash<Key>>,
+ std::is_destructible<std::hash<Key>>,
+ std::is_copy_assignable<std::hash<Key>>,
+ IsHashable<Key>> {};
+} // namespace type_traits_internal
+
} // namespace absl
#endif // ABSL_META_TYPE_TRAITS_H_
diff --git a/absl/strings/str_join.h b/absl/strings/str_join.h
index 47337490..bd4d0e1d 100644
--- a/absl/strings/str_join.h
+++ b/absl/strings/str_join.h
@@ -165,7 +165,7 @@ DereferenceFormatter() {
//
// Example 1:
// // Joins a collection of strings. This pattern also works with a collection
-// // of `asbl::string_view` or even `const char*`.
+// // of `absl::string_view` or even `const char*`.
// std::vector<std::string> v = {"foo", "bar", "baz"};
// std::string s = absl::StrJoin(v, "-");
// EXPECT_EQ("foo-bar-baz", s);
diff --git a/absl/time/time.h b/absl/time/time.h
index daf0b155..30c49d41 100644
--- a/absl/time/time.h
+++ b/absl/time/time.h
@@ -880,7 +880,8 @@ extern const char RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z
// provided format std::string. Uses strftime()-like formatting options, with
// the following extensions:
//
-// - %Ez - RFC3339-compatible numeric time zone (+hh:mm or -hh:mm)
+// - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
+// - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
// - %E#S - Seconds with # digits of fractional precision
// - %E*S - Seconds with full fractional precision (a literal '*')
// - %E#f - Fractional seconds with # digits of precision
@@ -894,8 +895,8 @@ extern const char RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z
// year. A year outside of [-999:9999] when formatted with %E4Y will produce
// more than four characters, just like %Y.
//
-// We recommend that format strings include %Ez so that the result uniquely
-// identifies a time instant.
+// We recommend that format strings include the UTC offset (%z, %Ez, or %E*z)
+// so that the result uniquely identifies a time instant.
//
// Example:
//
@@ -929,7 +930,8 @@ inline std::ostream& operator<<(std::ostream& os, Time t) {
// Parses an input std::string according to the provided format std::string and
// returns the corresponding `absl::Time`. Uses strftime()-like formatting
// options, with the same extensions as FormatTime(), but with the
-// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f.
+// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez
+// and %E*z also accept the same inputs.
//
// %Y consumes as many numeric characters as it can, so the matching data
// should always be terminated with a non-numeric. %E4Y always consumes
@@ -940,10 +942,11 @@ inline std::ostream& operator<<(std::ostream& os, Time t) {
// "1970-01-01 00:00:00.0 +0000"
//
// For example, parsing a std::string of "15:45" (%H:%M) will return an absl::Time
-// that represents "1970-01-01 15:45:00.0 +0000". Note: Since ParseTime()
-// returns time instants, it makes the most sense to parse fully-specified
-// date/time strings that include a UTC offset (%z/%Ez), such as those
-// matching RFC3339_full above.
+// that represents "1970-01-01 15:45:00.0 +0000".
+//
+// Note that since ParseTime() returns time instants, it makes the most sense
+// to parse fully-specified date/time strings that include a UTC offset (%z,
+// %Ez, or %E*z).
//
// Note also that `absl::ParseTime()` only heeds the fields year, month, day,
// hour, minute, (fractional) second, and UTC offset. Other fields, like
@@ -974,8 +977,8 @@ bool ParseTime(const std::string& format, const std::string& input, Time* time,
std::string* err);
// Like ParseTime() above, but if the format std::string does not contain a UTC
-// offset specification (%z/%Ez) then the input is interpreted in the given
-// TimeZone. This means that the input, by itself, does not identify a
+// offset specification (%z/%Ez/%E*z) then the input is interpreted in the
+// given TimeZone. This means that the input, by itself, does not identify a
// unique instant. Being time-zone dependent, it also admits the possibility
// of ambiguity or non-existence, in which case the "pre" time (as defined
// for ConvertDateTime()) is returned. For these reasons we recommend that
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel
index c2f03387..0bdb2f78 100644
--- a/absl/types/BUILD.bazel
+++ b/absl/types/BUILD.bazel
@@ -165,6 +165,17 @@ cc_library(
],
)
+cc_library(
+ name = "bad_variant_access",
+ srcs = ["bad_variant_access.cc"],
+ hdrs = ["bad_variant_access.h"],
+ copts = ABSL_EXCEPTIONS_FLAG + ABSL_DEFAULT_COPTS,
+ deps = [
+ "//absl/base",
+ "//absl/base:config",
+ ],
+)
+
cc_test(
name = "optional_test",
size = "small",
@@ -181,3 +192,34 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)
+
+cc_library(
+ name = "variant",
+ srcs = ["internal/variant.h"],
+ hdrs = ["variant.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ ":bad_variant_access",
+ "//absl/base:base_internal",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "//absl/meta:type_traits",
+ "//absl/utility",
+ ],
+)
+
+cc_test(
+ name = "variant_test",
+ size = "small",
+ srcs = ["variant_test.cc"],
+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+ deps = [
+ ":variant",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "//absl/memory",
+ "//absl/meta:type_traits",
+ "//absl/strings",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt
index fd71f38b..f51d126f 100644
--- a/absl/types/CMakeLists.txt
+++ b/absl/types/CMakeLists.txt
@@ -20,6 +20,7 @@ list(APPEND TYPES_PUBLIC_HEADERS
"bad_optional_access.h"
"optional.h"
"span.h"
+ "variant.h"
)
@@ -95,7 +96,19 @@ absl_library(
bad_optional_access
)
-
+# variant library
+absl_library(
+ TARGET
+ absl_variant
+ SOURCES
+ "bad_variant_access.h" "bad_variant_access.cc" "variant.h" "internal/variant.h"
+ PUBLIC_LIBRARIES
+ absl::base absl::meta absl::utility
+ PRIVATE_COMPILE_FLAGS
+ ${ABSL_EXCEPTIONS_FLAG}
+ EXPORT_NAME
+ variant
+)
#
## TESTS
diff --git a/absl/types/any.h b/absl/types/any.h
index 346c44aa..a973c6da 100644
--- a/absl/types/any.h
+++ b/absl/types/any.h
@@ -172,7 +172,9 @@ const ValueType* any_cast(const any* operand) noexcept;
template <typename ValueType>
ValueType* any_cast(any* operand) noexcept;
-// any
+// -----------------------------------------------------------------------------
+// absl::any
+// -----------------------------------------------------------------------------
//
// An `absl::any` object provides the facility to either store an instance of a
// type, known as the "contained object", or no value. An `absl::any` is used to
diff --git a/absl/types/bad_any_cast.h b/absl/types/bad_any_cast.h
index 8ffbe4bf..3b963077 100644
--- a/absl/types/bad_any_cast.h
+++ b/absl/types/bad_any_cast.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Abseil Authors.
+// 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.
@@ -11,6 +11,12 @@
// 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.
+//
+// -----------------------------------------------------------------------------
+// bad_any_cast.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `absl::bad_any_cast` type.
#ifndef ABSL_TYPES_BAD_ANY_CAST_H_
#define ABSL_TYPES_BAD_ANY_CAST_H_
@@ -19,21 +25,28 @@
namespace absl {
-////////////////////////
-// [any.bad_any_cast] //
-////////////////////////
-
-// Objects of type bad_any_cast are thrown by a failed any_cast.
+// -----------------------------------------------------------------------------
+// bad_any_cast
+// -----------------------------------------------------------------------------
+//
+// An `absl::bad_any_cast` type is an exception type that is thrown when
+// failing to successfully cast the return value of an `absl::any` object.
+//
+// Example:
+//
+// auto a = absl::any(65);
+// absl::any_cast<int>(a); // 65
+// try {
+// absl::any_cast<char>(a);
+// } catch(const absl::bad_any_cast& e) {
+// std::cout << "Bad any cast: " << e.what() << '\n';
+// }
class bad_any_cast : public std::bad_cast {
public:
~bad_any_cast() override;
const char* what() const noexcept override;
};
-//////////////////////////////////////////////
-// Implementation-details beyond this point //
-//////////////////////////////////////////////
-
namespace any_internal {
[[noreturn]] void ThrowBadAnyCast();
diff --git a/absl/types/bad_optional_access.h b/absl/types/bad_optional_access.h
index c4c74447..e9aa8b83 100644
--- a/absl/types/bad_optional_access.h
+++ b/absl/types/bad_optional_access.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Abseil Authors.
+// 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.
@@ -11,6 +11,12 @@
// 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.
+//
+// -----------------------------------------------------------------------------
+// bad_optional_access.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `absl::bad_optional_access` type.
#ifndef ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
#define ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
@@ -19,6 +25,23 @@
namespace absl {
+// -----------------------------------------------------------------------------
+// bad_optional_access
+// -----------------------------------------------------------------------------
+//
+// An `absl::bad_optional_access` type is an exception type that is thrown when
+// attempting to access an `absl::optional` object that does not contain a
+// value.
+//
+// Example:
+//
+// absl::optional<int> o;
+//
+// try {
+// int n = o.value();
+// } catch(const absl::bad_optional_access& e) {
+// std::cout << "Bad optional access: " << e.what() << '\n';
+// }
class bad_optional_access : public std::exception {
public:
bad_optional_access() = default;
diff --git a/absl/types/bad_variant_access.cc b/absl/types/bad_variant_access.cc
new file mode 100644
index 00000000..817fd789
--- /dev/null
+++ b/absl/types/bad_variant_access.cc
@@ -0,0 +1,58 @@
+// 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/bad_variant_access.h"
+
+#include <cstdlib>
+#include <stdexcept>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+
+//////////////////////////
+// [variant.bad.access] //
+//////////////////////////
+
+bad_variant_access::~bad_variant_access() = default;
+
+const char* bad_variant_access::what() const noexcept {
+ return "Bad variant access";
+}
+
+namespace variant_internal {
+
+void ThrowBadVariantAccess() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+ throw bad_variant_access();
+#else
+ ABSL_RAW_LOG(FATAL, "Bad variant access");
+ abort(); // TODO(calabrese) Remove once RAW_LOG FATAL is noreturn.
+#endif
+}
+
+void Rethrow() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+ throw;
+#else
+ ABSL_RAW_LOG(FATAL,
+ "Internal error in absl::variant implementation. Attempted to "
+ "rethrow an exception when building with exceptions disabled.");
+ abort(); // TODO(calabrese) Remove once RAW_LOG FATAL is noreturn.
+#endif
+}
+
+} // namespace variant_internal
+} // namespace absl
diff --git a/absl/types/bad_variant_access.h b/absl/types/bad_variant_access.h
new file mode 100644
index 00000000..67abe713
--- /dev/null
+++ b/absl/types/bad_variant_access.h
@@ -0,0 +1,64 @@
+// 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.
+//
+// -----------------------------------------------------------------------------
+// bad_variant_access.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `absl::bad_variant_access` type.
+
+#ifndef ABSL_TYPES_BAD_VARIANT_ACCESS_H_
+#define ABSL_TYPES_BAD_VARIANT_ACCESS_H_
+
+#include <stdexcept>
+
+namespace absl {
+
+// -----------------------------------------------------------------------------
+// bad_variant_access
+// -----------------------------------------------------------------------------
+//
+// An `absl::bad_variant_access` type is an exception type that is thrown in
+// the following cases:
+//
+// * Calling `absl::get(absl::variant) with an index or type that does not
+// match the currently selected alternative type
+// * Calling `absl::visit on an `absl::variant` that is in the
+// `variant::valueless_by_exception` state.
+//
+// Example:
+//
+// absl::variant<int, std::string> v;
+// v = 1;
+// try {
+// absl::get<std::string>(v);
+// } catch(const absl::bad_variant_access& e) {
+// std::cout << "Bad variant access: " << e.what() << '\n';
+// }
+class bad_variant_access : public std::exception {
+ public:
+ bad_variant_access() noexcept = default;
+ ~bad_variant_access() override;
+ const char* what() const noexcept override;
+};
+
+namespace variant_internal {
+
+[[noreturn]] void ThrowBadVariantAccess();
+[[noreturn]] void Rethrow();
+
+} // namespace variant_internal
+} // namespace absl
+
+#endif // ABSL_TYPES_BAD_VARIANT_ACCESS_H_
diff --git a/absl/types/internal/variant.h b/absl/types/internal/variant.h
new file mode 100644
index 00000000..61c56ddf
--- /dev/null
+++ b/absl/types/internal/variant.h
@@ -0,0 +1,1387 @@
+// 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.
+//
+// Implementation details of absl/types/variant.h, pulled into a
+// separate file to avoid cluttering the top of the API header with
+// implementation details.
+
+#ifndef ABSL_TYPES_variant_internal_H_
+#define ABSL_TYPES_variant_internal_H_
+
+#include <cstddef>
+#include <memory>
+#include <stdexcept>
+#include <tuple>
+#include <type_traits>
+
+#include "absl/base/internal/identity.h"
+#include "absl/base/internal/inline_variable.h"
+#include "absl/base/internal/invoke.h"
+#include "absl/base/optimization.h"
+#include "absl/meta/type_traits.h"
+#include "absl/types/bad_variant_access.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+
+template <class... Types>
+class variant;
+
+ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1);
+
+template <class T>
+struct variant_size;
+
+template <std::size_t I, class T>
+struct variant_alternative;
+
+namespace variant_internal {
+
+// NOTE: See specializations below for details.
+template <std::size_t I, class T>
+struct VariantAlternativeSfinae {};
+
+// Requires: I < variant_size_v<T>.
+//
+// Value: The Ith type of Types...
+template <std::size_t I, class T0, class... Tn>
+struct VariantAlternativeSfinae<I, variant<T0, Tn...>>
+ : VariantAlternativeSfinae<I - 1, variant<Tn...>> {};
+
+// Value: T0
+template <class T0, class... Ts>
+struct VariantAlternativeSfinae<0, variant<T0, Ts...>> {
+ using type = T0;
+};
+
+template <std::size_t I, class T>
+using VariantAlternativeSfinaeT = typename VariantAlternativeSfinae<I, T>::type;
+
+// NOTE: Requires T to be a reference type.
+template <class T, class U>
+struct GiveQualsTo;
+
+template <class T, class U>
+struct GiveQualsTo<T&, U> {
+ using type = U&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<T&&, U> {
+ using type = U&&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<const T&, U> {
+ using type = const U&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<const T&&, U> {
+ using type = const U&&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<volatile T&, U> {
+ using type = volatile U&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<volatile T&&, U> {
+ using type = volatile U&&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<volatile const T&, U> {
+ using type = volatile const U&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<volatile const T&&, U> {
+ using type = volatile const U&&;
+};
+
+template <class T, class U>
+using GiveQualsToT = typename GiveQualsTo<T, U>::type;
+
+// Convenience alias, since size_t integral_constant is used a lot in this file.
+template <std::size_t I>
+using SizeT = std::integral_constant<std::size_t, I>;
+
+template <class Variant, class T, class = void>
+struct IndexOfConstructedType {};
+
+template <std::size_t I, class Variant>
+struct VariantAccessResultImpl;
+
+template <std::size_t I, template <class...> class Variantemplate, class... T>
+struct VariantAccessResultImpl<I, Variantemplate<T...>&> {
+ using type = typename absl::variant_alternative<I, variant<T...>>::type&;
+};
+
+template <std::size_t I, template <class...> class Variantemplate, class... T>
+struct VariantAccessResultImpl<I, const Variantemplate<T...>&> {
+ using type =
+ const typename absl::variant_alternative<I, variant<T...>>::type&;
+};
+
+template <std::size_t I, template <class...> class Variantemplate, class... T>
+struct VariantAccessResultImpl<I, Variantemplate<T...>&&> {
+ using type = typename absl::variant_alternative<I, variant<T...>>::type&&;
+};
+
+template <std::size_t I, template <class...> class Variantemplate, class... T>
+struct VariantAccessResultImpl<I, const Variantemplate<T...>&&> {
+ using type =
+ const typename absl::variant_alternative<I, variant<T...>>::type&&;
+};
+
+template <std::size_t I, class Variant>
+using VariantAccessResult =
+ typename VariantAccessResultImpl<I, Variant&&>::type;
+
+// NOTE: This is used instead of std::array to reduce instantiation overhead.
+template <class T, std::size_t Size>
+struct SimpleArray {
+ static_assert(Size != 0, "");
+ T value[Size];
+};
+
+template <class T>
+struct AccessedType {
+ using type = T;
+};
+
+template <class T>
+using AccessedTypeT = typename AccessedType<T>::type;
+
+template <class T, std::size_t Size>
+struct AccessedType<SimpleArray<T, Size>> {
+ using type = AccessedTypeT<T>;
+};
+
+template <class T>
+constexpr T AccessSimpleArray(const T& value) {
+ return value;
+}
+
+template <class T, std::size_t Size, class... SizeT>
+constexpr AccessedTypeT<T> AccessSimpleArray(const SimpleArray<T, Size>& table,
+ std::size_t head_index,
+ SizeT... tail_indices) {
+ return AccessSimpleArray(table.value[head_index], tail_indices...);
+}
+
+// Note: Intentionally is an alias.
+template <class T>
+using AlwaysZero = SizeT<0>;
+
+template <class Op, class... Vs>
+struct VisitIndicesResultImpl {
+ using type = absl::result_of_t<Op(AlwaysZero<Vs>...)>;
+};
+
+template <class Op, class... Vs>
+using VisitIndicesResultT = typename VisitIndicesResultImpl<Op, Vs...>::type;
+
+template <class ReturnType, class FunctionObject, class EndIndices,
+ std::size_t... BoundIndices>
+struct MakeVisitationMatrix;
+
+template <class ReturnType, class FunctionObject, std::size_t... Indices>
+constexpr ReturnType call_with_indices(FunctionObject&& function) {
+ static_assert(
+ std::is_same<ReturnType, decltype(std::declval<FunctionObject>()(
+ SizeT<Indices>()...))>::value,
+ "Not all visitation overloads have the same return type.");
+ return absl::forward<FunctionObject>(function)(SizeT<Indices>()...);
+}
+
+template <class ReturnType, class FunctionObject, std::size_t... BoundIndices>
+struct MakeVisitationMatrix<ReturnType, FunctionObject, index_sequence<>,
+ BoundIndices...> {
+ using ResultType = ReturnType (*)(FunctionObject&&);
+ static constexpr ResultType Run() {
+ return &call_with_indices<ReturnType, FunctionObject,
+ (BoundIndices - 1)...>;
+ }
+};
+
+template <class ReturnType, class FunctionObject, class EndIndices,
+ class CurrIndices, std::size_t... BoundIndices>
+struct MakeVisitationMatrixImpl;
+
+template <class ReturnType, class FunctionObject, std::size_t... EndIndices,
+ std::size_t... CurrIndices, std::size_t... BoundIndices>
+struct MakeVisitationMatrixImpl<
+ ReturnType, FunctionObject, index_sequence<EndIndices...>,
+ index_sequence<CurrIndices...>, BoundIndices...> {
+ using ResultType = SimpleArray<
+ typename MakeVisitationMatrix<ReturnType, FunctionObject,
+ index_sequence<EndIndices...>>::ResultType,
+ sizeof...(CurrIndices)>;
+
+ static constexpr ResultType Run() {
+ return {{MakeVisitationMatrix<ReturnType, FunctionObject,
+ index_sequence<EndIndices...>,
+ BoundIndices..., CurrIndices>::Run()...}};
+ }
+};
+
+template <class ReturnType, class FunctionObject, std::size_t HeadEndIndex,
+ std::size_t... TailEndIndices, std::size_t... BoundIndices>
+struct MakeVisitationMatrix<ReturnType, FunctionObject,
+ index_sequence<HeadEndIndex, TailEndIndices...>,
+ BoundIndices...>
+ : MakeVisitationMatrixImpl<
+ ReturnType, FunctionObject, index_sequence<TailEndIndices...>,
+ absl::make_index_sequence<HeadEndIndex>, BoundIndices...> {};
+
+template <std::size_t... EndIndices, class Op, class... SizeT>
+VisitIndicesResultT<Op, SizeT...> visit_indices(Op&& op, SizeT... indices) {
+ return AccessSimpleArray(
+ MakeVisitationMatrix<VisitIndicesResultT<Op, SizeT...>, Op,
+ index_sequence<(EndIndices + 1)...>>::Run(),
+ (indices + 1)...)(absl::forward<Op>(op));
+}
+
+template <class ReturnType>
+[[noreturn]] ReturnType TypedThrowBadVariantAccess() {
+ absl::variant_internal::ThrowBadVariantAccess();
+}
+
+// Suppress bogus warning on MSVC: MSVC complains that the `reinterpret_cast`
+// below is returning the address of a temporary or local object.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4172)
+#endif // _MSC_VER
+
+// TODO(calabrese) std::launder
+// TODO(calabrese) constexpr
+template <class Self, std::size_t I>
+VariantAccessResult<I, Self> AccessUnion(Self&& self, SizeT<I> /*i*/) {
+ return reinterpret_cast<VariantAccessResult<I, Self>>(self);
+}
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif // _MSC_VER
+
+template <class T>
+void DeducedDestroy(T& self) { // NOLINT
+ self.~T();
+}
+
+// NOTE: This type exists as a single entity for variant and its bases to
+// befriend. It contains helper functionality that manipulates the state of the
+// variant, such as the implementation of things like assignment and emplace
+// operations.
+struct VariantCoreAccess {
+ template <class VariantType>
+ static typename VariantType::Variant& Derived(VariantType& self) { // NOLINT
+ return static_cast<typename VariantType::Variant&>(self);
+ }
+
+ template <class VariantType>
+ static const typename VariantType::Variant& Derived(
+ const VariantType& self) { // NOLINT
+ return static_cast<const typename VariantType::Variant&>(self);
+ }
+
+ template <class VariantType>
+ static void Destroy(VariantType& self) { // NOLINT
+ Derived(self).destroy();
+ self.index_ = absl::variant_npos;
+ }
+
+ template <class Variant>
+ static void SetIndex(Variant& self, std::size_t i) { // NOLINT
+ self.index_ = i;
+ }
+
+ template <class Variant>
+ static void InitFrom(Variant& self, Variant&& other) { // NOLINT
+ variant_internal::visit_indices<absl::variant_size<Variant>::value>(
+ InitFromVisitor<Variant, Variant&&>{&self,
+ std::forward<Variant>(other)},
+ other.index());
+ self.index_ = other.index();
+ }
+
+ template <std::size_t I, class Variant>
+ static VariantAccessResult<I, Variant> Access(Variant&& self) {
+ if (ABSL_PREDICT_FALSE(self.index_ != I)) {
+ TypedThrowBadVariantAccess<VariantAccessResult<I, Variant>>();
+ }
+
+ // This cast instead of invocation of AccessUnion with an rvalue is a
+ // workaround for msvc. Without this there is a runtime failure when dealing
+ // with rvalues.
+ // TODO(calabrese) Reduce test case and find a simpler workaround.
+ return static_cast<VariantAccessResult<I, Variant>>(
+ variant_internal::AccessUnion(self.state_, SizeT<I>()));
+ }
+
+ // The implementation of the move-assignment operation for a variant.
+ template <class VType>
+ struct MoveAssignVisitor {
+ using DerivedType = typename VType::Variant;
+ template <std::size_t NewIndex>
+ void operator()(SizeT<NewIndex> /*new_i*/) const {
+ if (left->index_ == NewIndex) {
+ Access<NewIndex>(*left) = std::move(Access<NewIndex>(*right));
+ } else {
+ Derived(*left).template emplace<NewIndex>(
+ std::move(Access<NewIndex>(*right)));
+ }
+ }
+
+ void operator()(SizeT<absl::variant_npos> /*new_i*/) const {
+ Destroy(*left);
+ }
+
+ VType* left;
+ VType* right;
+ };
+
+ template <class VType>
+ static MoveAssignVisitor<VType> MakeMoveAssignVisitor(VType* left,
+ VType* other) {
+ return {left, other};
+ }
+
+ // The implementation of the assignment operation for a variant.
+ template <class VType>
+ struct CopyAssignVisitor {
+ using DerivedType = typename VType::Variant;
+ template <std::size_t NewIndex>
+ void operator()(SizeT<NewIndex> /*new_i*/) const {
+ using New =
+ typename absl::variant_alternative<NewIndex, DerivedType>::type;
+
+ if (left->index_ == NewIndex) {
+ Access<NewIndex>(*left) = Access<NewIndex>(*right);
+ } else if (std::is_nothrow_copy_constructible<New>::value ||
+ !std::is_nothrow_move_constructible<New>::value) {
+ Derived(*left).template emplace<NewIndex>(Access<NewIndex>(*right));
+ } else {
+ Derived(*left) = DerivedType(Derived(*right));
+ }
+ }
+
+ void operator()(SizeT<absl::variant_npos> /*new_i*/) const {
+ Destroy(*left);
+ }
+
+ VType* left;
+ const VType* right;
+ };
+
+ template <class VType>
+ static CopyAssignVisitor<VType> MakeCopyAssignVisitor(VType* left,
+ const VType& other) {
+ return {left, &other};
+ }
+
+ // The implementation of conversion-assignment operations for variant.
+ template <class Left, class QualifiedNew>
+ struct ConversionAssignVisitor {
+ using NewIndex =
+ variant_internal::IndexOfConstructedType<Left, QualifiedNew>;
+
+ void operator()(SizeT<NewIndex::value> /*old_i*/
+ ) const {
+ Access<NewIndex::value>(*left) = absl::forward<QualifiedNew>(other);
+ }
+
+ template <std::size_t OldIndex>
+ void operator()(SizeT<OldIndex> /*old_i*/
+ ) const {
+ using New =
+ typename absl::variant_alternative<NewIndex::value, Left>::type;
+ if (std::is_nothrow_constructible<New, QualifiedNew>::value ||
+ !std::is_nothrow_move_constructible<New>::value) {
+ left->template emplace<NewIndex::value>(
+ absl::forward<QualifiedNew>(other));
+ } else {
+ // the standard says "equivalent to
+ // operator=(variant(std::forward<T>(t)))", but we use `emplace` here
+ // because the variant's move assignment operator could be deleted.
+ left->template emplace<NewIndex::value>(
+ New(absl::forward<QualifiedNew>(other)));
+ }
+ }
+
+ Left* left;
+ QualifiedNew&& other;
+ };
+
+ template <class Left, class QualifiedNew>
+ static ConversionAssignVisitor<Left, QualifiedNew>
+ MakeConversionAssignVisitor(Left* left, QualifiedNew&& qual) {
+ return {left, absl::forward<QualifiedNew>(qual)};
+ }
+
+ // Backend for operations for `emplace()` which destructs `*self` then
+ // construct a new alternative with `Args...`.
+ template <std::size_t NewIndex, class Self, class... Args>
+ static typename absl::variant_alternative<NewIndex, Self>::type& Replace(
+ Self* self, Args&&... args) {
+ Destroy(*self);
+ using New = typename absl::variant_alternative<NewIndex, Self>::type;
+ New* const result = ::new (static_cast<void*>(&self->state_))
+ New(absl::forward<Args>(args)...);
+ self->index_ = NewIndex;
+ return *result;
+ }
+
+ template <class LeftVariant, class QualifiedRightVariant>
+ struct InitFromVisitor {
+ template <std::size_t NewIndex>
+ void operator()(SizeT<NewIndex> /*new_i*/) const {
+ using Alternative =
+ typename variant_alternative<NewIndex, LeftVariant>::type;
+ ::new (static_cast<void*>(&left->state_)) Alternative(
+ Access<NewIndex>(std::forward<QualifiedRightVariant>(right)));
+ }
+
+ void operator()(SizeT<absl::variant_npos> /*new_i*/) const {
+ // This space intentionally left blank.
+ }
+ LeftVariant* left;
+ QualifiedRightVariant&& right;
+ };
+};
+
+template <class Expected, class... T>
+struct IndexOfImpl;
+
+template <class Expected>
+struct IndexOfImpl<Expected> {
+ using IndexFromEnd = SizeT<0>;
+ using MatchedIndexFromEnd = IndexFromEnd;
+ using MultipleMatches = std::false_type;
+};
+
+template <class Expected, class Head, class... Tail>
+struct IndexOfImpl<Expected, Head, Tail...> : IndexOfImpl<Expected, Tail...> {
+ using IndexFromEnd =
+ SizeT<IndexOfImpl<Expected, Tail...>::IndexFromEnd::value + 1>;
+};
+
+template <class Expected, class... Tail>
+struct IndexOfImpl<Expected, Expected, Tail...>
+ : IndexOfImpl<Expected, Tail...> {
+ using IndexFromEnd =
+ SizeT<IndexOfImpl<Expected, Tail...>::IndexFromEnd::value + 1>;
+ using MatchedIndexFromEnd = IndexFromEnd;
+ using MultipleMatches = std::integral_constant<
+ bool, IndexOfImpl<Expected, Tail...>::MatchedIndexFromEnd::value != 0>;
+};
+
+template <class Expected, class... Types>
+struct IndexOfMeta {
+ using Results = IndexOfImpl<Expected, Types...>;
+ static_assert(!Results::MultipleMatches::value,
+ "Attempted to access a variant by specifying a type that "
+ "matches more than one alternative.");
+ static_assert(Results::MatchedIndexFromEnd::value != 0,
+ "Attempted to access a variant by specifying a type that does "
+ "not match any alternative.");
+ using type = SizeT<sizeof...(Types) - Results::MatchedIndexFromEnd::value>;
+};
+
+template <class Expected, class... Types>
+using IndexOf = typename IndexOfMeta<Expected, Types...>::type;
+
+template <class Variant, class T, std::size_t CurrIndex>
+struct UnambiguousIndexOfImpl;
+
+// Terminating case encountered once we've checked all of the alternatives
+template <class T, std::size_t CurrIndex>
+struct UnambiguousIndexOfImpl<variant<>, T, CurrIndex> : SizeT<CurrIndex> {};
+
+// Case where T is not Head
+template <class Head, class... Tail, class T, std::size_t CurrIndex>
+struct UnambiguousIndexOfImpl<variant<Head, Tail...>, T, CurrIndex>
+ : UnambiguousIndexOfImpl<variant<Tail...>, T, CurrIndex + 1>::type {};
+
+// Case where T is Head
+template <class Head, class... Tail, std::size_t CurrIndex>
+struct UnambiguousIndexOfImpl<variant<Head, Tail...>, Head, CurrIndex>
+ : SizeT<UnambiguousIndexOfImpl<variant<Tail...>, Head, 0>::value ==
+ sizeof...(Tail)
+ ? CurrIndex
+ : CurrIndex + sizeof...(Tail) + 1> {};
+
+template <class Variant, class T>
+struct UnambiguousIndexOf;
+
+struct NoMatch {
+ struct type {};
+};
+
+template <class... Alts, class T>
+struct UnambiguousIndexOf<variant<Alts...>, T>
+ : std::conditional<UnambiguousIndexOfImpl<variant<Alts...>, T, 0>::value !=
+ sizeof...(Alts),
+ UnambiguousIndexOfImpl<variant<Alts...>, T, 0>,
+ NoMatch>::type::type {};
+
+template <class T, std::size_t /*Dummy*/>
+using UnambiguousTypeOfImpl = T;
+
+template <class Variant, class T>
+using UnambiguousTypeOfT =
+ UnambiguousTypeOfImpl<T, UnambiguousIndexOf<Variant, T>::value>;
+
+template <class H, class... T>
+class VariantStateBase;
+
+// This is an implementation of the "imaginary function" that is described in
+// [variant.ctor]
+// It is used in order to determine which alternative to construct during
+// initialization from some type T.
+template <class Variant, std::size_t I = 0>
+struct ImaginaryFun;
+
+template <std::size_t I>
+struct ImaginaryFun<variant<>, I> {
+ static void Run() = delete;
+};
+
+template <class H, class... T, std::size_t I>
+struct ImaginaryFun<variant<H, T...>, I> : ImaginaryFun<variant<T...>, I + 1> {
+ using ImaginaryFun<variant<T...>, I + 1>::Run;
+
+ // NOTE: const& and && are used instead of by-value due to lack of guaranteed
+ // move elision of C++17. This may have other minor differences, but tests
+ // pass.
+ static SizeT<I> Run(const H&);
+ static SizeT<I> Run(H&&);
+};
+
+// The following metafunctions are used in constructor and assignment
+// constraints.
+template <class Self, class T>
+struct IsNeitherSelfNorInPlace : std::true_type {};
+
+template <class Self>
+struct IsNeitherSelfNorInPlace<Self, Self> : std::false_type {};
+
+template <class Self, class T>
+struct IsNeitherSelfNorInPlace<Self, in_place_type_t<T>> : std::false_type {};
+
+template <class Self, std::size_t I>
+struct IsNeitherSelfNorInPlace<Self, in_place_index_t<I>> : std::false_type {};
+
+template <class Variant, class T, class = void>
+struct ConversionIsPossibleImpl : std::false_type {};
+
+template <class Variant, class T>
+struct ConversionIsPossibleImpl<
+ Variant, T, void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>()))>>
+ : std::true_type {};
+
+template <class Variant, class T>
+struct ConversionIsPossible : ConversionIsPossibleImpl<Variant, T>::type {};
+
+template <class Variant, class T>
+struct IndexOfConstructedType<
+ Variant, T, void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>()))>>
+ : decltype(ImaginaryFun<Variant>::Run(std::declval<T>())) {};
+
+template <std::size_t... Is>
+struct ContainsVariantNPos
+ : absl::negation<std::is_same< // NOLINT
+ absl::integer_sequence<bool, 0 <= Is...>,
+ absl::integer_sequence<bool, Is != absl::variant_npos...>>> {};
+
+template <class Op, class... QualifiedVariants>
+using RawVisitResult =
+ absl::result_of_t<Op(VariantAccessResult<0, QualifiedVariants>...)>;
+
+// NOTE: The spec requires that all return-paths yield the same type and is not
+// SFINAE-friendly, so we can deduce the return type by examining the first
+// result. If it's not callable, then we get an error, but are compliant and
+// fast to compile.
+// TODO(calabrese) Possibly rewrite in a way that yields better compile errors
+// at the cost of longer compile-times.
+template <class Op, class... QualifiedVariants>
+struct VisitResultImpl {
+ using type =
+ absl::result_of_t<Op(VariantAccessResult<0, QualifiedVariants>...)>;
+};
+
+// Done in two steps intentionally so that we don't cause substitution to fail.
+template <class Op, class... QualifiedVariants>
+using VisitResult = typename VisitResultImpl<Op, QualifiedVariants...>::type;
+
+template <class Op, class... QualifiedVariants>
+struct PerformVisitation {
+ using ReturnType = VisitResult<Op, QualifiedVariants...>;
+
+ template <std::size_t... Is>
+ constexpr ReturnType operator()(SizeT<Is>... indices) const {
+ return Run(typename ContainsVariantNPos<Is...>::type{},
+ absl::index_sequence_for<QualifiedVariants...>(), indices...);
+ }
+
+ template <std::size_t... TupIs, std::size_t... Is>
+ constexpr ReturnType Run(std::false_type /*has_valueless*/,
+ index_sequence<TupIs...>, SizeT<Is>...) const {
+ return absl::base_internal::Invoke(
+ absl::forward<Op>(op),
+ VariantCoreAccess::Access<Is>(
+ absl::forward<QualifiedVariants>(std::get<TupIs>(variant_tup)))...);
+ }
+
+ template <std::size_t... TupIs, std::size_t... Is>
+ [[noreturn]] ReturnType Run(std::true_type /*has_valueless*/,
+ index_sequence<TupIs...>, SizeT<Is>...) const {
+ absl::variant_internal::ThrowBadVariantAccess();
+ }
+
+ // TODO(calabrese) Avoid using a tuple, which causes lots of instantiations
+ // Attempts using lambda variadic captures fail on current GCC.
+ std::tuple<QualifiedVariants&&...> variant_tup;
+ Op&& op;
+};
+
+template <class... T>
+union Union;
+
+// We want to allow for variant<> to be trivial. For that, we need the default
+// constructor to be trivial, which means we can't define it ourselves.
+// Instead, we use a non-default constructor that takes NoopConstructorTag
+// that doesn't affect the triviality of the types.
+struct NoopConstructorTag {};
+
+template <std::size_t I>
+struct EmplaceTag {};
+
+template <>
+union Union<> {
+ constexpr explicit Union(NoopConstructorTag) noexcept {}
+};
+
+// Suppress bogus warning on MSVC: MSVC complains that Union<T...> has a defined
+// deleted destructor from the `std::is_destructible` check below.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4624)
+#endif // _MSC_VER
+
+template <class Head, class... Tail>
+union Union<Head, Tail...> {
+ using TailUnion = Union<Tail...>;
+
+ explicit constexpr Union(NoopConstructorTag /*tag*/) noexcept
+ : tail(NoopConstructorTag()) {}
+
+ template <class... P>
+ explicit constexpr Union(EmplaceTag<0>, P&&... args)
+ : head(absl::forward<P>(args)...) {}
+
+ template <std::size_t I, class... P>
+ explicit constexpr Union(EmplaceTag<I>, P&&... args)
+ : tail(EmplaceTag<I - 1>{}, absl::forward<P>(args)...) {}
+
+ Head head;
+ TailUnion tail;
+};
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif // _MSC_VER
+
+// TODO(calabrese) Just contain a Union in this union (certain configs fail).
+template <class... T>
+union DestructibleUnionImpl;
+
+template <>
+union DestructibleUnionImpl<> {
+ constexpr explicit DestructibleUnionImpl(NoopConstructorTag) noexcept {}
+};
+
+template <class Head, class... Tail>
+union DestructibleUnionImpl<Head, Tail...> {
+ using TailUnion = DestructibleUnionImpl<Tail...>;
+
+ explicit constexpr DestructibleUnionImpl(NoopConstructorTag /*tag*/) noexcept
+ : tail(NoopConstructorTag()) {}
+
+ template <class... P>
+ explicit constexpr DestructibleUnionImpl(EmplaceTag<0>, P&&... args)
+ : head(absl::forward<P>(args)...) {}
+
+ template <std::size_t I, class... P>
+ explicit constexpr DestructibleUnionImpl(EmplaceTag<I>, P&&... args)
+ : tail(EmplaceTag<I - 1>{}, absl::forward<P>(args)...) {}
+
+ ~DestructibleUnionImpl() {}
+
+ Head head;
+ TailUnion tail;
+};
+
+// This union type is destructible even if one or more T are not trivially
+// destructible. In the case that all T are trivially destructible, then so is
+// this resultant type.
+template <class... T>
+using DestructibleUnion =
+ absl::conditional_t<std::is_destructible<Union<T...>>::value, Union<T...>,
+ DestructibleUnionImpl<T...>>;
+
+// Deepest base, containing the actual union and the discriminator
+template <class H, class... T>
+class VariantStateBase {
+ protected:
+ using Variant = variant<H, T...>;
+
+ template <class LazyH = H,
+ class ConstructibleH = absl::enable_if_t<
+ std::is_default_constructible<LazyH>::value, LazyH>>
+ constexpr VariantStateBase() noexcept(
+ std::is_nothrow_default_constructible<ConstructibleH>::value)
+ : state_(EmplaceTag<0>()), index_(0) {}
+
+ template <std::size_t I, class... P>
+ explicit constexpr VariantStateBase(EmplaceTag<I> tag, P&&... args)
+ : state_(tag, absl::forward<P>(args)...), index_(I) {}
+
+ explicit constexpr VariantStateBase(NoopConstructorTag)
+ : state_(NoopConstructorTag()), index_(variant_npos) {}
+
+ void destroy() {} // Does nothing (shadowed in child if non-trivial)
+
+ DestructibleUnion<H, T...> state_;
+ std::size_t index_;
+};
+
+using absl::internal::identity;
+
+// OverloadSet::Overload() is a unary function which is overloaded to
+// take any of the element types of the variant, by reference-to-const.
+// The return type of the overload on T is identity<T>, so that you
+// can statically determine which overload was called.
+//
+// Overload() is not defined, so it can only be called in unevaluated
+// contexts.
+template <typename... Ts>
+struct OverloadSet;
+
+template <typename T, typename... Ts>
+struct OverloadSet<T, Ts...> : OverloadSet<Ts...> {
+ using Base = OverloadSet<Ts...>;
+ static identity<T> Overload(const T&);
+ using Base::Overload;
+};
+
+template <>
+struct OverloadSet<> {
+ // For any case not handled above.
+ static void Overload(...);
+};
+
+////////////////////////////////
+// Library Fundamentals V2 TS //
+////////////////////////////////
+
+// TODO(calabrese): Consider moving this to absl/meta/type_traits.h
+
+// The following is a rough implementation of parts of the detection idiom.
+// It is used for the comparison operator checks.
+
+template <class Enabler, class To, template <class...> class Op, class... Args>
+struct is_detected_convertible_impl {
+ using type = std::false_type;
+};
+
+template <class To, template <class...> class Op, class... Args>
+struct is_detected_convertible_impl<
+ absl::enable_if_t<std::is_convertible<Op<Args...>, To>::value>, To, Op,
+ Args...> {
+ using type = std::true_type;
+};
+
+// NOTE: This differs from library fundamentals by being lazy.
+template <class To, template <class...> class Op, class... Args>
+struct is_detected_convertible
+ : is_detected_convertible_impl<void, To, Op, Args...>::type {};
+
+template <class T>
+using LessThanResult = decltype(std::declval<T>() < std::declval<T>());
+
+template <class T>
+using GreaterThanResult = decltype(std::declval<T>() > std::declval<T>());
+
+template <class T>
+using LessThanOrEqualResult = decltype(std::declval<T>() <= std::declval<T>());
+
+template <class T>
+using GreaterThanOrEqualResult =
+ decltype(std::declval<T>() >= std::declval<T>());
+
+template <class T>
+using EqualResult = decltype(std::declval<T>() == std::declval<T>());
+
+template <class T>
+using NotEqualResult = decltype(std::declval<T>() != std::declval<T>());
+
+template <class T>
+using HasLessThan = is_detected_convertible<bool, LessThanResult, T>;
+
+template <class T>
+using HasGreaterThan = is_detected_convertible<bool, GreaterThanResult, T>;
+
+template <class T>
+using HasLessThanOrEqual =
+ is_detected_convertible<bool, LessThanOrEqualResult, T>;
+
+template <class T>
+using HasGreaterThanOrEqual =
+ is_detected_convertible<bool, GreaterThanOrEqualResult, T>;
+
+template <class T>
+using HasEqual = is_detected_convertible<bool, EqualResult, T>;
+
+template <class T>
+using HasNotEqual = is_detected_convertible<bool, NotEqualResult, T>;
+
+template <class... T>
+using RequireAllHaveEqualT =
+ absl::enable_if_t<absl::conjunction<HasEqual<T>...>::value, bool>;
+
+template <class... T>
+using RequireAllHaveNotEqualT =
+ absl::enable_if_t<absl::conjunction<HasEqual<T>...>::value, bool>;
+
+template <class... T>
+using RequireAllHaveLessThanT =
+ absl::enable_if_t<absl::conjunction<HasLessThan<T>...>::value, bool>;
+
+template <class... T>
+using RequireAllHaveLessThanOrEqualT =
+ absl::enable_if_t<absl::conjunction<HasLessThan<T>...>::value, bool>;
+
+template <class... T>
+using RequireAllHaveGreaterThanOrEqualT =
+ absl::enable_if_t<absl::conjunction<HasLessThan<T>...>::value, bool>;
+
+template <class... T>
+using RequireAllHaveGreaterThanT =
+ absl::enable_if_t<absl::conjunction<HasLessThan<T>...>::value, bool>;
+
+// Helper template containing implementations details of variant that can't go
+// in the private section. For convenience, this takes the variant type as a
+// single template parameter.
+template <typename T>
+struct VariantHelper;
+
+template <typename... Ts>
+struct VariantHelper<variant<Ts...>> {
+ // Type metafunction which returns the element type selected if
+ // OverloadSet::Overload() is well-formed when called with argument type U.
+ template <typename U>
+ using BestMatch = decltype(
+ variant_internal::OverloadSet<Ts...>::Overload(std::declval<U>()));
+
+ // Type metafunction which returns true if OverloadSet::Overload() is
+ // well-formed when called with argument type U.
+ // CanAccept can't be just an alias because there is a MSVC bug on parameter
+ // pack expansion involving decltype.
+ template <typename U>
+ struct CanAccept :
+ std::integral_constant<bool, !std::is_void<BestMatch<U>>::value> {};
+
+ // Type metafunction which returns true if Other is an instantiation of
+ // variant, and variants's converting constructor from Other will be
+ // well-formed. We will use this to remove constructors that would be
+ // ill-formed from the overload set.
+ template <typename Other>
+ struct CanConvertFrom;
+
+ template <typename... Us>
+ struct CanConvertFrom<variant<Us...>>
+ : public absl::conjunction<CanAccept<Us>...> {};
+};
+
+// A type with nontrivial copy ctor and trivial move ctor.
+struct TrivialMoveOnly {
+ TrivialMoveOnly(TrivialMoveOnly&&) = default;
+};
+
+// Trait class to detect whether a type is trivially move constructible.
+// A union's defaulted copy/move constructor is deleted if any variant member's
+// copy/move constructor is nontrivial.
+template <typename T>
+struct IsTriviallyMoveConstructible:
+ std::is_move_constructible<Union<T, TrivialMoveOnly>> {};
+
+// To guarantee triviality of all special-member functions that can be trivial,
+// we use a chain of conditional bases for each one.
+// The order of inheritance of bases from child to base are logically:
+//
+// variant
+// VariantCopyAssignBase
+// VariantMoveAssignBase
+// VariantCopyBase
+// VariantMoveBase
+// VariantStateBaseDestructor
+// VariantStateBase
+//
+// Note that there is a separate branch at each base that is dependent on
+// whether or not that corresponding special-member-function can be trivial in
+// the resultant variant type.
+
+template <class... T>
+class VariantStateBaseDestructorNontrivial;
+
+template <class... T>
+class VariantMoveBaseNontrivial;
+
+template <class... T>
+class VariantCopyBaseNontrivial;
+
+template <class... T>
+class VariantMoveAssignBaseNontrivial;
+
+template <class... T>
+class VariantCopyAssignBaseNontrivial;
+
+// Base that is dependent on whether or not the destructor can be trivial.
+template <class... T>
+using VariantStateBaseDestructor =
+ absl::conditional_t<std::is_destructible<Union<T...>>::value,
+ VariantStateBase<T...>,
+ VariantStateBaseDestructorNontrivial<T...>>;
+
+// Base that is dependent on whether or not the move-constructor can be
+// implicitly generated by the compiler (trivial or deleted).
+// Previously we were using `std::is_move_constructible<Union<T...>>` to check
+// whether all Ts have trivial move constructor, but it ran into a GCC bug:
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84866
+// So we have to use a different approach (i.e. `HasTrivialMoveConstructor`) to
+// work around the bug.
+template <class... T>
+using VariantMoveBase = absl::conditional_t<
+ absl::disjunction<
+ absl::negation<absl::conjunction<std::is_move_constructible<T>...>>,
+ absl::conjunction<IsTriviallyMoveConstructible<T>...>>::value,
+ VariantStateBaseDestructor<T...>, VariantMoveBaseNontrivial<T...>>;
+
+// Base that is dependent on whether or not the copy-constructor can be trivial.
+template <class... T>
+using VariantCopyBase = absl::conditional_t<
+ absl::disjunction<
+ absl::negation<absl::conjunction<std::is_copy_constructible<T>...>>,
+ std::is_copy_constructible<Union<T...>>>::value,
+ VariantMoveBase<T...>, VariantCopyBaseNontrivial<T...>>;
+
+// Base that is dependent on whether or not the move-assign can be trivial.
+template <class... T>
+using VariantMoveAssignBase = absl::conditional_t<
+ absl::disjunction<absl::conjunction<std::is_move_assignable<Union<T...>>,
+ std::is_move_constructible<Union<T...>>,
+ std::is_destructible<Union<T...>>>,
+ absl::negation<absl::conjunction<
+ std::is_move_constructible<T>...,
+ std::is_move_assignable<T>...>>>::value,
+ VariantCopyBase<T...>, VariantMoveAssignBaseNontrivial<T...>>;
+
+// Base that is dependent on whether or not the copy-assign can be trivial.
+template <class... T>
+using VariantCopyAssignBase = absl::conditional_t<
+ absl::disjunction<absl::conjunction<std::is_copy_assignable<Union<T...>>,
+ std::is_copy_constructible<Union<T...>>,
+ std::is_destructible<Union<T...>>>,
+ absl::negation<absl::conjunction<
+ std::is_copy_constructible<T>...,
+ std::is_copy_assignable<T>...>>>::value,
+ VariantMoveAssignBase<T...>, VariantCopyAssignBaseNontrivial<T...>>;
+
+template <class... T>
+using VariantBase = VariantCopyAssignBase<T...>;
+
+template <class... T>
+class VariantStateBaseDestructorNontrivial : protected VariantStateBase<T...> {
+ private:
+ using Base = VariantStateBase<T...>;
+
+ protected:
+ using Base::Base;
+
+ VariantStateBaseDestructorNontrivial() = default;
+ VariantStateBaseDestructorNontrivial(VariantStateBaseDestructorNontrivial&&) =
+ default;
+ VariantStateBaseDestructorNontrivial(
+ const VariantStateBaseDestructorNontrivial&) = default;
+ VariantStateBaseDestructorNontrivial& operator=(
+ VariantStateBaseDestructorNontrivial&&) = default;
+ VariantStateBaseDestructorNontrivial& operator=(
+ const VariantStateBaseDestructorNontrivial&) = default;
+
+ struct Destroyer {
+ template <std::size_t I>
+ void operator()(SizeT<I> i) const {
+ using Alternative =
+ typename absl::variant_alternative<I, variant<T...>>::type;
+ variant_internal::AccessUnion(self->state_, i).~Alternative();
+ }
+
+ void operator()(SizeT<absl::variant_npos> /*i*/) const {
+ // This space intentionally left blank
+ }
+
+ VariantStateBaseDestructorNontrivial* self;
+ };
+
+ void destroy() {
+ variant_internal::visit_indices<sizeof...(T)>(Destroyer{this}, index_);
+ }
+
+ ~VariantStateBaseDestructorNontrivial() { destroy(); }
+
+ protected:
+ using Base::index_;
+ using Base::state_;
+};
+
+template <class... T>
+class VariantMoveBaseNontrivial : protected VariantStateBaseDestructor<T...> {
+ private:
+ using Base = VariantStateBaseDestructor<T...>;
+
+ protected:
+ using Base::Base;
+
+ struct Construct {
+ template <std::size_t I>
+ void operator()(SizeT<I> i) const {
+ using Alternative =
+ typename absl::variant_alternative<I, variant<T...>>::type;
+ ::new (static_cast<void*>(&self->state_)) Alternative(
+ variant_internal::AccessUnion(absl::move(other->state_), i));
+ }
+
+ void operator()(SizeT<absl::variant_npos> /*i*/) const {}
+
+ VariantMoveBaseNontrivial* self;
+ VariantMoveBaseNontrivial* other;
+ };
+
+ VariantMoveBaseNontrivial() = default;
+ VariantMoveBaseNontrivial(VariantMoveBaseNontrivial&& other) noexcept(
+ absl::conjunction<std::is_nothrow_move_constructible<T>...>::value)
+ : Base(NoopConstructorTag()) {
+ variant_internal::visit_indices<sizeof...(T)>(Construct{this, &other},
+ other.index_);
+ index_ = other.index_;
+ }
+
+ VariantMoveBaseNontrivial(VariantMoveBaseNontrivial const&) = default;
+
+ VariantMoveBaseNontrivial& operator=(VariantMoveBaseNontrivial&&) = default;
+ VariantMoveBaseNontrivial& operator=(VariantMoveBaseNontrivial const&) =
+ default;
+
+ protected:
+ using Base::index_;
+ using Base::state_;
+};
+
+template <class... T>
+class VariantCopyBaseNontrivial : protected VariantMoveBase<T...> {
+ private:
+ using Base = VariantMoveBase<T...>;
+
+ protected:
+ using Base::Base;
+
+ VariantCopyBaseNontrivial() = default;
+ VariantCopyBaseNontrivial(VariantCopyBaseNontrivial&&) = default;
+
+ struct Construct {
+ template <std::size_t I>
+ void operator()(SizeT<I> i) const {
+ using Alternative =
+ typename absl::variant_alternative<I, variant<T...>>::type;
+ ::new (static_cast<void*>(&self->state_))
+ Alternative(variant_internal::AccessUnion(other->state_, i));
+ }
+
+ void operator()(SizeT<absl::variant_npos> /*i*/) const {}
+
+ VariantCopyBaseNontrivial* self;
+ const VariantCopyBaseNontrivial* other;
+ };
+
+ VariantCopyBaseNontrivial(VariantCopyBaseNontrivial const& other)
+ : Base(NoopConstructorTag()) {
+ variant_internal::visit_indices<sizeof...(T)>(Construct{this, &other},
+ other.index_);
+ index_ = other.index_;
+ }
+
+ VariantCopyBaseNontrivial& operator=(VariantCopyBaseNontrivial&&) = default;
+ VariantCopyBaseNontrivial& operator=(VariantCopyBaseNontrivial const&) =
+ default;
+
+ protected:
+ using Base::index_;
+ using Base::state_;
+};
+
+template <class... T>
+class VariantMoveAssignBaseNontrivial : protected VariantCopyBase<T...> {
+ friend struct VariantCoreAccess;
+
+ private:
+ using Base = VariantCopyBase<T...>;
+
+ protected:
+ using Base::Base;
+
+ VariantMoveAssignBaseNontrivial() = default;
+ VariantMoveAssignBaseNontrivial(VariantMoveAssignBaseNontrivial&&) = default;
+ VariantMoveAssignBaseNontrivial(const VariantMoveAssignBaseNontrivial&) =
+ default;
+ VariantMoveAssignBaseNontrivial& operator=(
+ VariantMoveAssignBaseNontrivial const&) = default;
+
+ VariantMoveAssignBaseNontrivial&
+ operator=(VariantMoveAssignBaseNontrivial&& other) noexcept(
+ absl::conjunction<std::is_nothrow_move_constructible<T>...,
+ std::is_nothrow_move_assignable<T>...>::value) {
+ variant_internal::visit_indices<sizeof...(T)>(
+ VariantCoreAccess::MakeMoveAssignVisitor(this, &other), other.index_);
+ return *this;
+ }
+
+ protected:
+ using Base::index_;
+ using Base::state_;
+};
+
+template <class... T>
+class VariantCopyAssignBaseNontrivial : protected VariantMoveAssignBase<T...> {
+ friend struct VariantCoreAccess;
+
+ private:
+ using Base = VariantMoveAssignBase<T...>;
+
+ protected:
+ using Base::Base;
+
+ VariantCopyAssignBaseNontrivial() = default;
+ VariantCopyAssignBaseNontrivial(VariantCopyAssignBaseNontrivial&&) = default;
+ VariantCopyAssignBaseNontrivial(const VariantCopyAssignBaseNontrivial&) =
+ default;
+ VariantCopyAssignBaseNontrivial& operator=(
+ VariantCopyAssignBaseNontrivial&&) = default;
+
+ VariantCopyAssignBaseNontrivial& operator=(
+ const VariantCopyAssignBaseNontrivial& other) {
+ variant_internal::visit_indices<sizeof...(T)>(
+ VariantCoreAccess::MakeCopyAssignVisitor(this, other), other.index_);
+ return *this;
+ }
+
+ protected:
+ using Base::index_;
+ using Base::state_;
+};
+
+////////////////////////////////////////
+// Visitors for Comparison Operations //
+////////////////////////////////////////
+
+template <class... Types>
+struct EqualsOp {
+ const variant<Types...>* v;
+ const variant<Types...>* w;
+
+ constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+ return true;
+ }
+
+ template <std::size_t I>
+ constexpr bool operator()(SizeT<I> /*v_i*/) const {
+ return VariantCoreAccess::Access<I>(*v) == VariantCoreAccess::Access<I>(*w);
+ }
+};
+
+template <class... Types>
+struct NotEqualsOp {
+ const variant<Types...>* v;
+ const variant<Types...>* w;
+
+ constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+ return false;
+ }
+
+ template <std::size_t I>
+ constexpr bool operator()(SizeT<I> /*v_i*/) const {
+ return VariantCoreAccess::Access<I>(*v) != VariantCoreAccess::Access<I>(*w);
+ }
+};
+
+template <class... Types>
+struct LessThanOp {
+ const variant<Types...>* v;
+ const variant<Types...>* w;
+
+ constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+ return false;
+ }
+
+ template <std::size_t I>
+ constexpr bool operator()(SizeT<I> /*v_i*/) const {
+ return VariantCoreAccess::Access<I>(*v) < VariantCoreAccess::Access<I>(*w);
+ }
+};
+
+template <class... Types>
+struct GreaterThanOp {
+ const variant<Types...>* v;
+ const variant<Types...>* w;
+
+ constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+ return false;
+ }
+
+ template <std::size_t I>
+ constexpr bool operator()(SizeT<I> /*v_i*/) const {
+ return VariantCoreAccess::Access<I>(*v) > VariantCoreAccess::Access<I>(*w);
+ }
+};
+
+template <class... Types>
+struct LessThanOrEqualsOp {
+ const variant<Types...>* v;
+ const variant<Types...>* w;
+
+ constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+ return true;
+ }
+
+ template <std::size_t I>
+ constexpr bool operator()(SizeT<I> /*v_i*/) const {
+ return VariantCoreAccess::Access<I>(*v) <= VariantCoreAccess::Access<I>(*w);
+ }
+};
+
+template <class... Types>
+struct GreaterThanOrEqualsOp {
+ const variant<Types...>* v;
+ const variant<Types...>* w;
+
+ constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+ return true;
+ }
+
+ template <std::size_t I>
+ constexpr bool operator()(SizeT<I> /*v_i*/) const {
+ return VariantCoreAccess::Access<I>(*v) >= VariantCoreAccess::Access<I>(*w);
+ }
+};
+
+// Precondition: v.index() == w.index();
+template <class... Types>
+struct SwapSameIndex {
+ variant<Types...>* v;
+ variant<Types...>* w;
+ template <std::size_t I>
+ void operator()(SizeT<I>) const {
+ using std::swap;
+ swap(VariantCoreAccess::Access<I>(*v), VariantCoreAccess::Access<I>(*w));
+ }
+
+ void operator()(SizeT<variant_npos>) const {}
+};
+
+// TODO(calabrese) do this from a different namespace for proper adl usage
+template <class... Types>
+struct Swap {
+ variant<Types...>* v;
+ variant<Types...>* w;
+
+ void generic_swap() const {
+ variant<Types...> tmp(std::move(*w));
+ VariantCoreAccess::Destroy(*w);
+ VariantCoreAccess::InitFrom(*w, std::move(*v));
+ VariantCoreAccess::Destroy(*v);
+ VariantCoreAccess::InitFrom(*v, std::move(tmp));
+ }
+
+ void operator()(SizeT<absl::variant_npos> /*w_i*/) const {
+ if (!v->valueless_by_exception()) {
+ generic_swap();
+ }
+ }
+
+ template <std::size_t Wi>
+ void operator()(SizeT<Wi> /*w_i*/) {
+ if (v->index() == Wi) {
+ visit_indices<sizeof...(Types)>(SwapSameIndex<Types...>{v, w}, Wi);
+ } else {
+ generic_swap();
+ }
+ }
+};
+
+template <typename Variant, typename = void, typename... Ts>
+struct VariantHashBase {
+ VariantHashBase() = delete;
+ VariantHashBase(const VariantHashBase&) = delete;
+ VariantHashBase(VariantHashBase&&) = delete;
+ VariantHashBase& operator=(const VariantHashBase&) = delete;
+ VariantHashBase& operator=(VariantHashBase&&) = delete;
+};
+
+struct VariantHashVisitor {
+ template <typename T>
+ size_t operator()(const T& t) {
+ return std::hash<T>{}(t);
+ }
+};
+
+template <typename Variant, typename... Ts>
+struct VariantHashBase<Variant,
+ absl::enable_if_t<absl::conjunction<
+ type_traits_internal::IsHashEnabled<Ts>...>::value>,
+ Ts...> {
+ using argument_type = Variant;
+ using result_type = size_t;
+ size_t operator()(const Variant& var) const {
+ if (var.valueless_by_exception()) {
+ return 239799884;
+ }
+ size_t result =
+ variant_internal::visit_indices<variant_size<Variant>::value>(
+ PerformVisitation<VariantHashVisitor, const Variant&>{
+ std::forward_as_tuple(var), VariantHashVisitor{}},
+ var.index());
+ // Combine the index and the hash result in order to distinguish
+ // std::variant<int, int> holding the same value as different alternative.
+ return result ^ var.index();
+ }
+};
+
+} // namespace variant_internal
+} // namespace absl
+
+#endif // ABSL_TYPES_variant_internal_H_
diff --git a/absl/types/optional.h b/absl/types/optional.h
index 9313fd23..581321dc 100644
--- a/absl/types/optional.h
+++ b/absl/types/optional.h
@@ -1,4 +1,3 @@
-//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -94,7 +93,9 @@ using std::nullopt;
namespace absl {
-// optional
+// -----------------------------------------------------------------------------
+// absl::optional
+// -----------------------------------------------------------------------------
//
// A value of type `absl::optional<T>` holds either a value of `T` or an
// "empty" value. When it holds a value of `T`, it stores it as a direct
diff --git a/absl/types/variant.h b/absl/types/variant.h
new file mode 100644
index 00000000..52a311e3
--- /dev/null
+++ b/absl/types/variant.h
@@ -0,0 +1,838 @@
+// 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.
+//
+// -----------------------------------------------------------------------------
+// variant.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines an `absl::variant` type for holding a type-safe
+// value of some prescribed set of types (noted as alternative types), and
+// associated functions for managing variants.
+//
+// The `absl::variant` type is a form of type-safe union. An `absl::variant`
+// should always hold a value of one of its alternative types (except in the
+// "valueless by exception state" -- see below). A default-constructed
+// `absl::variant` will hold the value of its first alternative type, provided
+// it is default-constructable.
+//
+// In exceptional cases due to error, an `absl::variant` can hold no
+// value (known as a "valueless by exception" state), though this is not the
+// norm.
+//
+// As with `absl::optional`, an `absl::variant` -- when it holds a value --
+// allocates a value of that type directly within the `variant` itself; it
+// cannot hold a reference, array, or the type `void`; it can, however, hold a
+// pointer to externally managed memory.
+//
+// `absl::variant` is a C++11 compatible version of the C++17 `std::variant`
+// abstraction and is designed to be a drop-in replacement for code compliant
+// with C++17.
+
+#ifndef ABSL_TYPES_VARIANT_H_
+#define ABSL_TYPES_VARIANT_H_
+
+#include "absl/base/config.h"
+#include "absl/utility/utility.h"
+
+#ifdef ABSL_HAVE_STD_VARIANT
+
+#include <variant>
+
+namespace absl {
+using std::bad_variant_access;
+using std::get;
+using std::get_if;
+using std::holds_alternative;
+using std::monostate;
+using std::variant;
+using std::variant_alternative;
+using std::variant_alternative_t;
+using std::variant_npos;
+using std::variant_size;
+using std::variant_size_v;
+using std::visit;
+} // namespace absl
+
+#else // ABSL_HAVE_STD_VARIANT
+
+#include <functional>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/meta/type_traits.h"
+#include "absl/types/internal/variant.h"
+
+namespace absl {
+
+// -----------------------------------------------------------------------------
+// absl::variant
+// -----------------------------------------------------------------------------
+//
+// An 'absl::variant` type is a form of type-safe union. An `absl::variant` --
+// except in exceptional cases -- always holds a value of one of its alternative
+// types.
+//
+// Example:
+//
+// // Construct a variant that holds either an integer or a std::string and
+// // assign it to a std::string.
+// absl::variant<int, std::string> v = std::string("abc");
+//
+// // A default-contructed variant will hold a value-initialized value of
+// // the first alternative type.
+// auto a = absl::variant<int, std::string>(); // Holds an int of value '0'.
+//
+// // variants are assignable.
+//
+// // copy assignment
+// auto v1 = absl::variant<int, std::string>("abc");
+// auto v2 = absl::variant<int, std::string>(10);
+// v2 = v1; // copy assign
+//
+// // move assignment
+// auto v1 = absl::variant<int, std::string>("abc");
+// v1 = absl::variant<int, std::string>(10);
+//
+// // assignment through type conversion
+// a = 128; // variant contains int
+// a = "128"; // variant contains std::string
+//
+// An `absl::variant` holding a value of one of its alternative types `T` holds
+// an allocation of `T` directly within the variant itself. An `absl::variant`
+// is not allowed to allocate additional storage, such as dynamic memory, to
+// allocate the contained value. The contained value shall be allocated in a
+// region of the variant storage suitably aligned for all alternative types.
+template <typename... Ts>
+class variant;
+
+// swap()
+//
+// Swaps two `absl::variant` values. This function is equivalent to `v.swap(w)`
+// where `v` and `w` are `absl::variant` types.
+//
+// Note that this function requires all alternative types to be both swappable
+// and move-constructible, because any two variants may refer to either the same
+// type (in which case, they will be swapped) or to two different types (in
+// which case the values will need to be moved).
+//
+template <typename... Ts>
+void swap(variant<Ts...>& v, variant<Ts...>& w) noexcept(noexcept(v.swap(w))) {
+ v.swap(w);
+}
+
+// variant_size
+//
+// Returns the number of alterative types available for a given `absl::variant`
+// type as a compile-time constant expression. As this is a class template, it
+// is not generally useful for accessing the number of alternative types of
+// any given `absl::variant` instance.
+//
+// Example:
+//
+// auto a = absl::variant<int, std::string>;
+// constexpr int num_types =
+// absl::variant_size<absl::variant<int, std::string>>();
+//
+// // You can also use the member constant `value`.
+// constexpr int num_types =
+// absl::variant_size<absl::variant<int, std::string>>::value;
+//
+// // `absl::variant_size` is more valuable for use in generic code:
+// template <typename Variant>
+// constexpr bool IsVariantMultivalue() {
+// return absl::variant_size<Variant>() > 1;
+// }
+//
+// Note that the set of cv-qualified specializations of `variant_size` are
+// provided to ensure that those specializations compile (especially when passed
+// within template logic).
+template <class T>
+struct variant_size;
+
+template <class... Ts>
+struct variant_size<variant<Ts...>>
+ : std::integral_constant<std::size_t, sizeof...(Ts)> {};
+
+// Specialization of `variant_size` for const qualified variants.
+template <class T>
+struct variant_size<const T> : variant_size<T>::type {};
+
+// Specialization of `variant_size` for volatile qualified variants.
+template <class T>
+struct variant_size<volatile T> : variant_size<T>::type {};
+
+// Specialization of `variant_size` for const volatile qualified variants.
+template <class T>
+struct variant_size<const volatile T> : variant_size<T>::type {};
+
+// variant_alternative
+//
+// Returns the alternative type for a given `absl::variant` at the passed
+// index value as a compile-time constant expression. As this is a class
+// template resulting in a type, it is not useful for access of the run-time
+// value of any given `absl::variant` variable.
+//
+// Example:
+//
+// // The type of the 0th alternative is "int".
+// using alternative_type_0
+// = absl::variant_alternative<0, absl::variant<int, std::string>>::type;
+//
+// static_assert(std::is_same<alternative_type_0, int>::value, "");
+//
+// // `absl::variant_alternative` is more valuable for use in generic code:
+// template <typename Variant>
+// constexpr bool IsFirstElementTrivial() {
+// return std::is_trivial_v<variant_alternative<0, Variant>::type>;
+// }
+//
+// Note that the set of cv-qualified specializations of `variant_alternative`
+// are provided to ensure that those specializations compile (especially when
+// passed within template logic).
+template <std::size_t I, class T>
+struct variant_alternative;
+
+template <std::size_t I, class... Types>
+struct variant_alternative<I, variant<Types...>> {
+ using type =
+ variant_internal::VariantAlternativeSfinaeT<I, variant<Types...>>;
+};
+
+// Specialization of `variant_alternative` for const qualified variants.
+template <std::size_t I, class T>
+struct variant_alternative<I, const T> {
+ using type = const typename variant_alternative<I, T>::type;
+};
+
+// Specialization of `variant_alternative` for volatile qualified variants.
+template <std::size_t I, class T>
+struct variant_alternative<I, volatile T> {
+ using type = volatile typename variant_alternative<I, T>::type;
+};
+
+// Specialization of `variant_alternative` for const volatile qualified
+// variants.
+template <std::size_t I, class T>
+struct variant_alternative<I, const volatile T> {
+ using type = const volatile typename variant_alternative<I, T>::type;
+};
+
+// Template type alias for variant_alternative<I, T>::type.
+//
+// Example:
+//
+// using alternative_type_0
+// = absl::variant_alternative_t<0, absl::variant<int, std::string>>;
+// static_assert(std::is_same<alternative_type_0, int>::value, "");
+template <std::size_t I, class T>
+using variant_alternative_t = typename variant_alternative<I, T>::type;
+
+// holds_alternative()
+//
+// Checks whether the given variant currently holds a given alternative type,
+// returning `true` if so.
+//
+// Example:
+//
+// absl::variant<int, std::string> bar = 42;
+// if (absl::holds_alternative<int>(foo)) {
+// std::cout << "The variant holds an integer";
+// }
+template <class T, class... Types>
+constexpr bool holds_alternative(const variant<Types...>& v) noexcept {
+ static_assert(
+ variant_internal::UnambiguousIndexOfImpl<variant<Types...>, T,
+ 0>::value != sizeof...(Types),
+ "The type T must occur exactly once in Types...");
+ return v.index() ==
+ variant_internal::UnambiguousIndexOf<variant<Types...>, T>::value;
+}
+
+// get()
+//
+// Returns a reference to the value currently within a given variant, using
+// either a unique alternative type amongst the variant's set of alternative
+// types, or the variant's index value. Attempting to get a variant's value
+// using a type that is not unique within the variant's set of alternative types
+// is a compile-time error. If the index of the alternative being specified is
+// different from the index of the alternative that is currently stored, throws
+// `absl::bad_variant_access`.
+//
+// Example:
+//
+// auto a = absl::variant<int, std::string>;
+//
+// // Get the value by type (if unique).
+// int i = absl::get<int>(a);
+//
+// auto b = absl::variant<int, int>;
+//
+// // Getting the value by a type that is not unique is ill-formed.
+// int j = absl::get<int>(b); // Compile Error!
+//
+// // Getting value by index not ambiguous and allowed.
+// int k = absl::get<1>(b);
+
+// Overload for getting a variant's lvalue by type.
+template <class T, class... Types>
+constexpr T& get(variant<Types...>& v) { // NOLINT
+ return variant_internal::VariantCoreAccess::Access<
+ variant_internal::IndexOf<T, Types...>::value>(v);
+}
+
+// Overload for getting a variant's rvalue by type.
+// Note: `absl::move()` is required to allow use of constexpr in C++11.
+template <class T, class... Types>
+constexpr T&& get(variant<Types...>&& v) {
+ return variant_internal::VariantCoreAccess::Access<
+ variant_internal::IndexOf<T, Types...>::value>(absl::move(v));
+}
+
+// Overload for getting a variant's const lvalue by type.
+template <class T, class... Types>
+constexpr const T& get(const variant<Types...>& v) {
+ return variant_internal::VariantCoreAccess::Access<
+ variant_internal::IndexOf<T, Types...>::value>(v);
+}
+
+// Overload for getting a variant's const rvalue by type.
+// Note: `absl::move()` is required to allow use of constexpr in C++11.
+template <class T, class... Types>
+constexpr const T&& get(const variant<Types...>&& v) {
+ return variant_internal::VariantCoreAccess::Access<
+ variant_internal::IndexOf<T, Types...>::value>(absl::move(v));
+}
+
+// Overload for getting a variant's lvalue by index.
+template <std::size_t I, class... Types>
+constexpr variant_alternative_t<I, variant<Types...>>& get(
+ variant<Types...>& v) { // NOLINT
+ return variant_internal::VariantCoreAccess::Access<I>(v);
+}
+
+// Overload for getting a variant's rvalue by index.
+// Note: `absl::move()` is required to allow use of constexpr in C++11.
+template <std::size_t I, class... Types>
+constexpr variant_alternative_t<I, variant<Types...>>&& get(
+ variant<Types...>&& v) {
+ return variant_internal::VariantCoreAccess::Access<I>(absl::move(v));
+}
+
+// Overload for getting a variant's const lvalue by index.
+template <std::size_t I, class... Types>
+constexpr const variant_alternative_t<I, variant<Types...>>& get(
+ const variant<Types...>& v) {
+ return variant_internal::VariantCoreAccess::Access<I>(v);
+}
+
+// Overload for getting a variant's const rvalue by index.
+// Note: `absl::move()` is required to allow use of constexpr in C++11.
+template <std::size_t I, class... Types>
+constexpr const variant_alternative_t<I, variant<Types...>>&& get(
+ const variant<Types...>&& v) {
+ return variant_internal::VariantCoreAccess::Access<I>(absl::move(v));
+}
+
+// get_if()
+//
+// Returns a pointer to the value currently stored within a given variant, if
+// present, using either a unique alternative type amonst the variant's set of
+// alternative types, or the variant's index value. If such a value does not
+// exist, returns `nullptr`.
+//
+// As with `get`, attempting to get a variant's value using a type that is not
+// unique within the variant's set of alternative types is a compile-time error.
+
+// Overload for getting a pointer to the value stored in the given variant by
+// index.
+template <std::size_t I, class... Types>
+constexpr absl::add_pointer_t<variant_alternative_t<I, variant<Types...>>>
+get_if(variant<Types...>* v) noexcept {
+ return (v != nullptr && v->index() == I) ? std::addressof(absl::get<I>(*v))
+ : nullptr;
+}
+
+// Overload for getting a pointer to the const value stored in the given
+// variant by index.
+template <std::size_t I, class... Types>
+constexpr absl::add_pointer_t<const variant_alternative_t<I, variant<Types...>>>
+get_if(const variant<Types...>* v) noexcept {
+ return (v != nullptr && v->index() == I) ? std::addressof(absl::get<I>(*v))
+ : nullptr;
+}
+
+// Overload for getting a pointer to the value stored in the given variant by
+// type.
+template <class T, class... Types>
+constexpr absl::add_pointer_t<T> get_if(variant<Types...>* v) noexcept {
+ return absl::get_if<variant_internal::IndexOf<T, Types...>::value>(v);
+}
+
+// Overload for getting a pointer to the const value stored in the given variant
+// by type.
+template <class T, class... Types>
+constexpr absl::add_pointer_t<const T> get_if(
+ const variant<Types...>* v) noexcept {
+ return absl::get_if<variant_internal::IndexOf<T, Types...>::value>(v);
+}
+
+// visit()
+//
+// Calls a provided functor on a given set of variants. `absl::visit()` is
+// commonly used to conditionally inspect the state of a given variant (or set
+// of variants).
+// Requires: The expression in the Effects: element shall be a valid expression
+// of the same type and value category, for all combinations of alternative
+// types of all variants. Otherwise, the program is ill-formed.
+//
+// Example:
+//
+// // Define a visitor functor
+// struct GetVariant {
+// template<typename T>
+// void operator()(const T& i) const {
+// std::cout << "The variant's value is: " << i;
+// }
+// };
+//
+// // Declare our variant, and call `absl::visit()` on it.
+// std::variant<int, std::string> foo = std::string("foo");
+// GetVariant visitor;
+// std::visit(visitor, foo); // Prints `The variant's value is: foo'
+template <typename Visitor, typename... Variants>
+variant_internal::VisitResult<Visitor, Variants...> visit(Visitor&& vis,
+ Variants&&... vars) {
+ return variant_internal::visit_indices<
+ variant_size<absl::decay_t<Variants>>::value...>(
+ variant_internal::PerformVisitation<Visitor, Variants...>{
+ std::forward_as_tuple(absl::forward<Variants>(vars)...),
+ absl::forward<Visitor>(vis)},
+ vars.index()...);
+}
+
+// monostate
+//
+// The monostate class serves as a first alternative type for a variant for
+// which the first variant type is otherwise not default-constructible.
+struct monostate {};
+
+// `absl::monostate` Relational Operators
+
+constexpr bool operator<(monostate, monostate) noexcept { return false; }
+constexpr bool operator>(monostate, monostate) noexcept { return false; }
+constexpr bool operator<=(monostate, monostate) noexcept { return true; }
+constexpr bool operator>=(monostate, monostate) noexcept { return true; }
+constexpr bool operator==(monostate, monostate) noexcept { return true; }
+constexpr bool operator!=(monostate, monostate) noexcept { return false; }
+
+
+//------------------------------------------------------------------------------
+// `absl::variant` Template Definition
+//------------------------------------------------------------------------------
+template <typename T0, typename... Tn>
+class variant<T0, Tn...> : private variant_internal::VariantBase<T0, Tn...> {
+ static_assert(absl::conjunction<std::is_object<T0>, std::is_object<Tn>...,
+ absl::negation<std::is_array<T0>>,
+ absl::negation<std::is_array<Tn>>...,
+ std::is_nothrow_destructible<T0>,
+ std::is_nothrow_destructible<Tn>...>::value,
+ "Attempted to instantiate a variant with an unsupported type.");
+
+ friend struct variant_internal::VariantCoreAccess;
+
+ private:
+ using Base = variant_internal::VariantBase<T0, Tn...>;
+
+ public:
+ // Constructors
+
+ // Constructs a variant holding a default-initialized value of the first
+ // alternative type.
+ constexpr variant() /*noexcept(see 111above)*/ = default;
+
+ // Copy constructor, standard semantics
+ variant(const variant& other) = default;
+
+ // Move constructor, standard semantics
+ variant(variant&& other) /*noexcept(see above)*/ = default;
+
+ // Constructs a variant of an alternative type specified by overload
+ // resolution of the provided forwarding arguments through
+ // direct-initialization.
+ //
+ // Note: If the selected constructor is a constexpr constructor, this
+ // constructor shall be a constexpr constructor.
+ //
+ // NOTE: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0608r1.html
+ // has been voted passed the design phase in the C++ standard meeting in Mar
+ // 2018. It will be implemented and integrated into `absl::variant`.
+ template <
+ class T,
+ std::size_t I = std::enable_if<
+ variant_internal::IsNeitherSelfNorInPlace<variant,
+ absl::decay_t<T>>::value,
+ variant_internal::IndexOfConstructedType<variant, T>>::type::value,
+ class Tj = absl::variant_alternative_t<I, variant>,
+ absl::enable_if_t<std::is_constructible<Tj, T>::value>* =
+ nullptr>
+ constexpr variant(T&& t) noexcept(std::is_nothrow_constructible<Tj, T>::value)
+ : Base(variant_internal::EmplaceTag<I>(), absl::forward<T>(t)) {}
+
+ // Constructs a variant of an alternative type from the arguments through
+ // direct-initialization.
+ //
+ // Note: If the selected constructor is a constexpr constructor, this
+ // constructor shall be a constexpr constructor.
+ template <class T, class... Args,
+ typename std::enable_if<std::is_constructible<
+ variant_internal::UnambiguousTypeOfT<variant, T>,
+ Args...>::value>::type* = nullptr>
+ constexpr explicit variant(in_place_type_t<T>, Args&&... args)
+ : Base(variant_internal::EmplaceTag<
+ variant_internal::UnambiguousIndexOf<variant, T>::value>(),
+ absl::forward<Args>(args)...) {}
+
+ // Constructs a variant of an alternative type from an initializer list
+ // and other arguments through direct-initialization.
+ //
+ // Note: If the selected constructor is a constexpr constructor, this
+ // constructor shall be a constexpr constructor.
+ template <class T, class U, class... Args,
+ typename std::enable_if<std::is_constructible<
+ variant_internal::UnambiguousTypeOfT<variant, T>,
+ std::initializer_list<U>&, Args...>::value>::type* = nullptr>
+ constexpr explicit variant(in_place_type_t<T>, std::initializer_list<U> il,
+ Args&&... args)
+ : Base(variant_internal::EmplaceTag<
+ variant_internal::UnambiguousIndexOf<variant, T>::value>(),
+ il, absl::forward<Args>(args)...) {}
+
+ // Constructs a variant of an alternative type from a provided index,
+ // through value-initialization using the provided forwarded arguments.
+ template <std::size_t I, class... Args,
+ typename std::enable_if<std::is_constructible<
+ variant_internal::VariantAlternativeSfinaeT<I, variant>,
+ Args...>::value>::type* = nullptr>
+ constexpr explicit variant(in_place_index_t<I>, Args&&... args)
+ : Base(variant_internal::EmplaceTag<I>(), absl::forward<Args>(args)...) {}
+
+ // Constructs a variant of an alternative type from a provided index,
+ // through value-initialization of an initializer list and the provided
+ // forwarded arguments.
+ template <std::size_t I, class U, class... Args,
+ typename std::enable_if<std::is_constructible<
+ variant_internal::VariantAlternativeSfinaeT<I, variant>,
+ std::initializer_list<U>&, Args...>::value>::type* = nullptr>
+ constexpr explicit variant(in_place_index_t<I>, std::initializer_list<U> il,
+ Args&&... args)
+ : Base(variant_internal::EmplaceTag<I>(), il,
+ absl::forward<Args>(args)...) {}
+
+ // Destructors
+
+ // Destroys the variant's currently contained value, provided that
+ // `absl::valueless_by_exception()` is false.
+ ~variant() = default;
+
+ // Assignment Operators
+
+ // Copy assignement operator
+ variant& operator=(const variant& other) = default;
+
+ // Move assignment operator
+ variant& operator=(variant&& other) /*noexcept(see above)*/ = default;
+
+ // Converting assignment operator
+ //
+ // NOTE: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0608r1.html
+ // has been voted passed the design phase in the C++ standard meeting in Mar
+ // 2018. It will be implemented and integrated into `absl::variant`.
+ template <
+ class T,
+ std::size_t I = std::enable_if<
+ !std::is_same<absl::decay_t<T>, variant>::value,
+ variant_internal::IndexOfConstructedType<variant, T>>::type::value,
+ class Tj = absl::variant_alternative_t<I, variant>,
+ typename std::enable_if<std::is_assignable<Tj&, T>::value &&
+ std::is_constructible<Tj, T>::value>::type* =
+ nullptr>
+ variant& operator=(T&& t) noexcept(
+ std::is_nothrow_assignable<Tj&, T>::value&&
+ std::is_nothrow_constructible<Tj, T>::value) {
+ variant_internal::visit_indices<sizeof...(Tn) + 1>(
+ variant_internal::VariantCoreAccess::MakeConversionAssignVisitor(
+ this, absl::forward<T>(t)),
+ index());
+
+ return *this;
+ }
+
+
+ // emplace() Functions
+
+ // Constructs a value of the given alternative type T within the variant.
+ //
+ // Example:
+ //
+ // absl::variant<std::vector<int>, int, std::string> v;
+ // v.emplace<int>(99);
+ // v.emplace<std::string>("abc");
+ template <
+ class T, class... Args,
+ typename std::enable_if<std::is_constructible<
+ absl::variant_alternative_t<
+ variant_internal::UnambiguousIndexOf<variant, T>::value, variant>,
+ Args...>::value>::type* = nullptr>
+ T& emplace(Args&&... args) {
+ return variant_internal::VariantCoreAccess::Replace<
+ variant_internal::UnambiguousIndexOf<variant, T>::value>(
+ this, absl::forward<Args>(args)...);
+ }
+
+ // Constructs a value of the given alternative type T within the variant using
+ // an initializer list.
+ //
+ // Example:
+ //
+ // absl::variant<std::vector<int>, int, std::string> v;
+ // v.emplace<std::vector<int>>({0, 1, 2});
+ template <
+ class T, class U, class... Args,
+ typename std::enable_if<std::is_constructible<
+ absl::variant_alternative_t<
+ variant_internal::UnambiguousIndexOf<variant, T>::value, variant>,
+ std::initializer_list<U>&, Args...>::value>::type* = nullptr>
+ T& emplace(std::initializer_list<U> il, Args&&... args) {
+ return variant_internal::VariantCoreAccess::Replace<
+ variant_internal::UnambiguousIndexOf<variant, T>::value>(
+ this, il, absl::forward<Args>(args)...);
+ }
+
+ // Destroys the current value of the variant (provided that
+ // `absl::valueless_by_exception()` is false, and constructs a new value at
+ // the given index.
+ //
+ // Example:
+ //
+ // absl::variant<std::vector<int>, int, int> v;
+ // v.emplace<1>(99);
+ // v.emplace<2>(98);
+ // v.emplace<int>(99); // Won't compile. 'int' isn't a unique type.
+ template <std::size_t I, class... Args,
+ typename std::enable_if<
+ std::is_constructible<absl::variant_alternative_t<I, variant>,
+ Args...>::value>::type* = nullptr>
+ absl::variant_alternative_t<I, variant>& emplace(Args&&... args) {
+ return variant_internal::VariantCoreAccess::Replace<I>(
+ this, absl::forward<Args>(args)...);
+ }
+
+ // Destroys the current value of the variant (provided that
+ // `absl::valueless_by_exception()` is false, and constructs a new value at
+ // the given index using an initializer list and the provided arguments.
+ //
+ // Example:
+ //
+ // absl::variant<std::vector<int>, int, int> v;
+ // v.emplace<0>({0, 1, 2});
+ template <std::size_t I, class U, class... Args,
+ typename std::enable_if<std::is_constructible<
+ absl::variant_alternative_t<I, variant>,
+ std::initializer_list<U>&, Args...>::value>::type* = nullptr>
+ absl::variant_alternative_t<I, variant>& emplace(std::initializer_list<U> il,
+ Args&&... args) {
+ return variant_internal::VariantCoreAccess::Replace<I>(
+ this, il, absl::forward<Args>(args)...);
+ }
+
+ // variant::valueless_by_exception()
+ //
+ // Returns false if and only if the variant currently holds a valid value.
+ constexpr bool valueless_by_exception() const noexcept {
+ return this->index_ == absl::variant_npos;
+ }
+
+ // variant::index()
+ //
+ // Returns the index value of the variant's currently selected alternative
+ // type.
+ constexpr std::size_t index() const noexcept { return this->index_; }
+
+ // variant::swap()
+ //
+ // Swaps the values of two variant objects.
+ //
+ // TODO(calabrese)
+ // `variant::swap()` and `swap()` rely on `std::is_(nothrow)_swappable()`
+ // which is introduced in C++17. So we assume `is_swappable()` is always
+ // true and `is_nothrow_swappable()` is same as `std::is_trivial()`.
+ void swap(variant& rhs) noexcept(
+ absl::conjunction<std::is_trivial<T0>, std::is_trivial<Tn>...>::value) {
+ return variant_internal::visit_indices<sizeof...(Tn) + 1>(
+ variant_internal::Swap<T0, Tn...>{this, &rhs}, rhs.index());
+ }
+};
+
+// We need a valid declaration of variant<> for SFINAE and overload resolution
+// to work properly above, but we don't need a full declaration since this type
+// will never be constructed. This declaration, though incomplete, suffices.
+template <>
+class variant<>;
+
+//------------------------------------------------------------------------------
+// Relational Operators
+//------------------------------------------------------------------------------
+//
+// If neither operand is in the `variant::valueless_by_exception` state:
+//
+// * If the index of both variants is the same, the relational operator
+// returns the result of the corresponding relational operator for the
+// corresponding alternative type.
+// * If the index of both variants is not the same, the relational operator
+// returns the result of that operation applied to the value of the left
+// operand's index and the value of the right operand's index.
+// * If at least one operand is in the valueless_by_exception state:
+// - A variant in the valueless_by_exception state is only considered equal
+// to another variant in the valueless_by_exception state.
+// - If exactly one operand is in the valueless_by_exception state, the
+// variant in the valueless_by_exception state is less than the variant
+// that is not in the valueless_by_exception state.
+//
+// Note: The value 1 is added to each index in the relational comparisons such
+// that the index corresponding to the valueless_by_exception state wraps around
+// to 0 (the lowest value for the index type), and the remaining indices stay in
+// the same relative order.
+
+// Equal-to operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveEqualT<Types...> operator==(
+ const variant<Types...>& a, const variant<Types...>& b) {
+ return (a.index() == b.index()) &&
+ variant_internal::visit_indices<sizeof...(Types)>(
+ variant_internal::EqualsOp<Types...>{&a, &b}, a.index());
+}
+
+// Not equal operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveNotEqualT<Types...> operator!=(
+ const variant<Types...>& a, const variant<Types...>& b) {
+ return (a.index() != b.index()) ||
+ variant_internal::visit_indices<sizeof...(Types)>(
+ variant_internal::NotEqualsOp<Types...>{&a, &b}, a.index());
+}
+
+// Less-than operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveLessThanT<Types...> operator<(
+ const variant<Types...>& a, const variant<Types...>& b) {
+ return (a.index() != b.index())
+ ? (a.index() + 1) < (b.index() + 1)
+ : variant_internal::visit_indices<sizeof...(Types)>(
+ variant_internal::LessThanOp<Types...>{&a, &b}, a.index());
+}
+
+// Greater-than operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveGreaterThanT<Types...> operator>(
+ const variant<Types...>& a, const variant<Types...>& b) {
+ return (a.index() != b.index())
+ ? (a.index() + 1) > (b.index() + 1)
+ : variant_internal::visit_indices<sizeof...(Types)>(
+ variant_internal::GreaterThanOp<Types...>{&a, &b},
+ a.index());
+}
+
+// Less-than or equal-to operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveLessThanOrEqualT<Types...> operator<=(
+ const variant<Types...>& a, const variant<Types...>& b) {
+ return (a.index() != b.index())
+ ? (a.index() + 1) < (b.index() + 1)
+ : variant_internal::visit_indices<sizeof...(Types)>(
+ variant_internal::LessThanOrEqualsOp<Types...>{&a, &b},
+ a.index());
+}
+
+// Greater-than or equal-to operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveGreaterThanOrEqualT<Types...>
+operator>=(const variant<Types...>& a, const variant<Types...>& b) {
+ return (a.index() != b.index())
+ ? (a.index() + 1) > (b.index() + 1)
+ : variant_internal::visit_indices<sizeof...(Types)>(
+ variant_internal::GreaterThanOrEqualsOp<Types...>{&a, &b},
+ a.index());
+}
+
+} // namespace absl
+
+namespace std {
+
+// hash()
+template <> // NOLINT
+struct hash<absl::monostate> {
+ std::size_t operator()(absl::monostate) const { return 0; }
+};
+
+template <class... T> // NOLINT
+struct hash<absl::variant<T...>>
+ : absl::variant_internal::VariantHashBase<absl::variant<T...>, void,
+ absl::remove_const_t<T>...> {};
+
+} // namespace std
+
+#endif // ABSL_HAVE_STD_VARIANT
+
+namespace absl {
+namespace variant_internal {
+
+// Helper visitor for converting a variant<Ts...>` into another type (mostly
+// variant) that can be constructed from any type.
+template <typename To>
+struct ConversionVisitor {
+ template <typename T>
+ To operator()(T&& v) const {
+ return To(std::forward<T>(v));
+ }
+};
+
+} // namespace variant_internal
+
+// ConvertVariantTo()
+//
+// Helper functions to convert an `absl::variant` to a variant of another set of
+// types, provided that the alternative type of the new variant type can be
+// converted from any type in the source variant.
+//
+// Example:
+//
+// absl::variant<name1, name2, float> InternalReq(const Req&);
+//
+// // name1 and name2 are convertible to name
+// absl::variant<name, float> ExternalReq(const Req& req) {
+// return absl::ConvertVariantTo<absl::variant<name, float>>(
+// InternalReq(req));
+// }
+template <typename To, typename Variant>
+To ConvertVariantTo(Variant&& variant) {
+ return absl::visit(variant_internal::ConversionVisitor<To>{},
+ std::forward<Variant>(variant));
+}
+
+} // namespace absl
+
+#endif // ABSL_TYPES_VARIANT_H_
diff --git a/absl/types/variant_test.cc b/absl/types/variant_test.cc
new file mode 100644
index 00000000..c4676c10
--- /dev/null
+++ b/absl/types/variant_test.cc
@@ -0,0 +1,2622 @@
+// 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 <algorithm>
+#include <cstddef>
+#include <functional>
+#include <initializer_list>
+#include <memory>
+#include <ostream>
+#include <queue>
+#include <type_traits>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/base/port.h"
+#include "absl/memory/memory.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+
+#define ABSL_VARIANT_TEST_EXPECT_FAIL(expr, exception_t, text) \
+ EXPECT_THROW(expr, exception_t)
+
+#else
+
+#define ABSL_VARIANT_TEST_EXPECT_FAIL(expr, exception_t, text) \
+ EXPECT_DEATH(expr, text)
+
+#endif // ABSL_HAVE_EXCEPTIONS
+
+#define ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(...) \
+ ABSL_VARIANT_TEST_EXPECT_FAIL((__VA_ARGS__), absl::bad_variant_access, \
+ "Bad variant access")
+
+struct Hashable {};
+
+namespace std {
+template <>
+struct hash<Hashable> {
+ size_t operator()(const Hashable&);
+};
+} // namespace std
+
+struct NonHashable {};
+
+namespace absl {
+namespace {
+
+using ::testing::DoubleEq;
+using ::testing::Pointee;
+using ::testing::VariantWith;
+
+struct MoveCanThrow {
+ MoveCanThrow() : v(0) {}
+ MoveCanThrow(int v) : v(v) {} // NOLINT(runtime/explicit)
+ MoveCanThrow(const MoveCanThrow& other) : v(other.v) {}
+ MoveCanThrow& operator=(const MoveCanThrow& /*other*/) { return *this; }
+ int v;
+};
+
+bool operator==(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v == rhs.v; }
+bool operator!=(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v != rhs.v; }
+bool operator<(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v < rhs.v; }
+bool operator<=(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v <= rhs.v; }
+bool operator>=(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v >= rhs.v; }
+bool operator>(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v > rhs.v; }
+
+// This helper class allows us to determine if it was swapped with std::swap()
+// or with its friend swap() function.
+struct SpecialSwap {
+ explicit SpecialSwap(int i) : i(i) {}
+ friend void swap(SpecialSwap& a, SpecialSwap& b) {
+ a.special_swap = b.special_swap = true;
+ std::swap(a.i, b.i);
+ }
+ bool operator==(SpecialSwap other) const { return i == other.i; }
+ int i;
+ bool special_swap = false;
+};
+
+struct MoveOnlyWithListConstructor {
+ MoveOnlyWithListConstructor() = default;
+ explicit MoveOnlyWithListConstructor(std::initializer_list<int> /*ilist*/,
+ int value)
+ : value(value) {}
+ MoveOnlyWithListConstructor(MoveOnlyWithListConstructor&&) = default;
+ MoveOnlyWithListConstructor& operator=(MoveOnlyWithListConstructor&&) =
+ default;
+
+ int value = 0;
+};
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+
+struct ConversionException {};
+
+template <class T>
+struct ExceptionOnConversion {
+ // Suppress MSVC 2017 warning "noreturn function has a non-void return type".
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4646)
+#endif // _MSC_VER
+
+ [[noreturn]] operator T() const { // NOLINT(runtime/explicit)
+ throw ConversionException();
+ }
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif // _MSC_VER
+};
+
+// Forces a variant into the valueless by exception state.
+template <class H, class... T>
+void ToValuelessByException(absl::variant<H, T...>& v) { // NOLINT
+ try {
+ v.template emplace<0>(ExceptionOnConversion<H>());
+ } catch (ConversionException& /*e*/) {
+ // This space intentionally left blank.
+ }
+}
+
+#endif // ABSL_HAVE_EXCEPTIONS
+
+// An indexed sequence of distinct structures holding a single
+// value of type T
+template<typename T, size_t N>
+struct ValueHolder {
+ explicit ValueHolder(const T& x) : value(x) {}
+ typedef T value_type;
+ value_type value;
+ static const size_t kIndex = N;
+};
+template<typename T, size_t N>
+const size_t ValueHolder<T, N>::kIndex;
+
+// The following three functions make ValueHolder compatible with
+// EXPECT_EQ and EXPECT_NE
+template<typename T, size_t N>
+inline bool operator==(const ValueHolder<T, N>& left,
+ const ValueHolder<T, N>& right) {
+ return left.value == right.value;
+}
+
+template<typename T, size_t N>
+inline bool operator!=(const ValueHolder<T, N>& left,
+ const ValueHolder<T, N>& right) {
+ return left.value != right.value;
+}
+
+template<typename T, size_t N>
+inline std::ostream& operator<<(
+ std::ostream& stream, const ValueHolder<T, N>& object) {
+ return stream << object.value;
+}
+
+// Makes a variant holding twelve uniquely typed T wrappers.
+template<typename T>
+struct VariantFactory {
+ typedef variant<ValueHolder<T, 1>, ValueHolder<T, 2>, ValueHolder<T, 3>,
+ ValueHolder<T, 4>>
+ Type;
+};
+
+// A typelist in 1:1 with VariantFactory, to use type driven unit tests.
+typedef ::testing::Types<ValueHolder<size_t, 1>, ValueHolder<size_t, 2>,
+ ValueHolder<size_t, 3>,
+ ValueHolder<size_t, 4>> VariantTypes;
+
+// Increments the provided counter pointer in the destructor
+struct IncrementInDtor {
+ explicit IncrementInDtor(int* counter) : counter(counter) {}
+ ~IncrementInDtor() { *counter += 1; }
+ int* counter;
+};
+
+struct IncrementInDtorCopyCanThrow {
+ explicit IncrementInDtorCopyCanThrow(int* counter) : counter(counter) {}
+ IncrementInDtorCopyCanThrow(IncrementInDtorCopyCanThrow&& other) noexcept =
+ default;
+ IncrementInDtorCopyCanThrow(const IncrementInDtorCopyCanThrow& other)
+ : counter(other.counter) {}
+ IncrementInDtorCopyCanThrow& operator=(
+ IncrementInDtorCopyCanThrow&&) noexcept = default;
+ IncrementInDtorCopyCanThrow& operator=(
+ IncrementInDtorCopyCanThrow const& other) {
+ counter = other.counter;
+ return *this;
+ }
+ ~IncrementInDtorCopyCanThrow() { *counter += 1; }
+ int* counter;
+};
+
+// This is defined so operator== for ValueHolder<IncrementInDtor> will
+// return true if two IncrementInDtor objects increment the same
+// counter
+inline bool operator==(const IncrementInDtor& left,
+ const IncrementInDtor& right) {
+ return left.counter == right.counter;
+}
+
+// This is defined so EXPECT_EQ can work with IncrementInDtor
+inline std::ostream& operator<<(
+ std::ostream& stream, const IncrementInDtor& object) {
+ return stream << object.counter;
+}
+
+// A class that can be copied, but not assigned.
+class CopyNoAssign {
+ public:
+ explicit CopyNoAssign(int value) : foo(value) {}
+ CopyNoAssign(const CopyNoAssign& other) : foo(other.foo) {}
+ int foo;
+ private:
+ const CopyNoAssign& operator=(const CopyNoAssign&);
+};
+
+// A class that can neither be copied nor assigned. We provide
+// overloads for the constructor with up to four parameters so we can
+// test the overloads of variant::emplace.
+class NonCopyable {
+ public:
+ NonCopyable()
+ : value(0) {}
+ explicit NonCopyable(int value1)
+ : value(value1) {}
+
+ NonCopyable(int value1, int value2)
+ : value(value1 + value2) {}
+
+ NonCopyable(int value1, int value2, int value3)
+ : value(value1 + value2 + value3) {}
+
+ NonCopyable(int value1, int value2, int value3, int value4)
+ : value(value1 + value2 + value3 + value4) {}
+ NonCopyable(const NonCopyable&) = delete;
+ NonCopyable& operator=(const NonCopyable&) = delete;
+ int value;
+};
+
+// A typed test and typed test case over the VariantTypes typelist,
+// from which we derive a number of tests that will execute for one of
+// each type.
+template <typename T>
+class VariantTypesTest : public ::testing::Test {};
+TYPED_TEST_CASE(VariantTypesTest, VariantTypes);
+
+////////////////////
+// [variant.ctor] //
+////////////////////
+
+struct NonNoexceptDefaultConstructible {
+ NonNoexceptDefaultConstructible() {}
+ int value = 5;
+};
+
+struct NonDefaultConstructible {
+ NonDefaultConstructible() = delete;
+};
+
+TEST(VariantTest, TestDefaultConstructor) {
+ {
+ using X = variant<int>;
+ constexpr variant<int> x{};
+ ASSERT_FALSE(x.valueless_by_exception());
+ ASSERT_EQ(0, x.index());
+ EXPECT_EQ(0, absl::get<0>(x));
+ EXPECT_TRUE(std::is_nothrow_default_constructible<X>::value);
+ }
+
+ {
+ using X = variant<NonNoexceptDefaultConstructible>;
+ X x{};
+ ASSERT_FALSE(x.valueless_by_exception());
+ ASSERT_EQ(0, x.index());
+ EXPECT_EQ(5, absl::get<0>(x).value);
+ EXPECT_FALSE(std::is_nothrow_default_constructible<X>::value);
+ }
+
+ {
+ using X = variant<int, NonNoexceptDefaultConstructible>;
+ X x{};
+ ASSERT_FALSE(x.valueless_by_exception());
+ ASSERT_EQ(0, x.index());
+ EXPECT_EQ(0, absl::get<0>(x));
+ EXPECT_TRUE(std::is_nothrow_default_constructible<X>::value);
+ }
+
+ {
+ using X = variant<NonNoexceptDefaultConstructible, int>;
+ X x{};
+ ASSERT_FALSE(x.valueless_by_exception());
+ ASSERT_EQ(0, x.index());
+ EXPECT_EQ(5, absl::get<0>(x).value);
+ EXPECT_FALSE(std::is_nothrow_default_constructible<X>::value);
+ }
+ EXPECT_FALSE(
+ std::is_default_constructible<variant<NonDefaultConstructible>>::value);
+ EXPECT_FALSE((std::is_default_constructible<
+ variant<NonDefaultConstructible, int>>::value));
+ EXPECT_TRUE((std::is_default_constructible<
+ variant<int, NonDefaultConstructible>>::value));
+}
+
+// Test that for each slot, copy constructing a variant with that type
+// produces a sensible object that correctly reports its type, and
+// that copies the provided value.
+TYPED_TEST(VariantTypesTest, TestCopyCtor) {
+ typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant;
+ using value_type1 = absl::variant_alternative_t<0, Variant>;
+ using value_type2 = absl::variant_alternative_t<1, Variant>;
+ using value_type3 = absl::variant_alternative_t<2, Variant>;
+ using value_type4 = absl::variant_alternative_t<3, Variant>;
+ const TypeParam value(TypeParam::kIndex);
+ Variant original(value);
+ Variant copied(original);
+ EXPECT_TRUE(absl::holds_alternative<value_type1>(copied) ||
+ TypeParam::kIndex != 1);
+ EXPECT_TRUE(absl::holds_alternative<value_type2>(copied) ||
+ TypeParam::kIndex != 2);
+ EXPECT_TRUE(absl::holds_alternative<value_type3>(copied) ||
+ TypeParam::kIndex != 3);
+ EXPECT_TRUE(absl::holds_alternative<value_type4>(copied) ||
+ TypeParam::kIndex != 4);
+ EXPECT_TRUE((absl::get_if<value_type1>(&original) ==
+ absl::get_if<value_type1>(&copied)) ||
+ TypeParam::kIndex == 1);
+ EXPECT_TRUE((absl::get_if<value_type2>(&original) ==
+ absl::get_if<value_type2>(&copied)) ||
+ TypeParam::kIndex == 2);
+ EXPECT_TRUE((absl::get_if<value_type3>(&original) ==
+ absl::get_if<value_type3>(&copied)) ||
+ TypeParam::kIndex == 3);
+ EXPECT_TRUE((absl::get_if<value_type4>(&original) ==
+ absl::get_if<value_type4>(&copied)) ||
+ TypeParam::kIndex == 4);
+ EXPECT_TRUE((absl::get_if<value_type1>(&original) ==
+ absl::get_if<value_type1>(&copied)) ||
+ TypeParam::kIndex == 1);
+ EXPECT_TRUE((absl::get_if<value_type2>(&original) ==
+ absl::get_if<value_type2>(&copied)) ||
+ TypeParam::kIndex == 2);
+ EXPECT_TRUE((absl::get_if<value_type3>(&original) ==
+ absl::get_if<value_type3>(&copied)) ||
+ TypeParam::kIndex == 3);
+ EXPECT_TRUE((absl::get_if<value_type4>(&original) ==
+ absl::get_if<value_type4>(&copied)) ||
+ TypeParam::kIndex == 4);
+ const TypeParam* ovalptr = absl::get_if<TypeParam>(&original);
+ const TypeParam* cvalptr = absl::get_if<TypeParam>(&copied);
+ ASSERT_TRUE(ovalptr != nullptr);
+ ASSERT_TRUE(cvalptr != nullptr);
+ EXPECT_EQ(*ovalptr, *cvalptr);
+ TypeParam* mutable_ovalptr = absl::get_if<TypeParam>(&original);
+ TypeParam* mutable_cvalptr = absl::get_if<TypeParam>(&copied);
+ ASSERT_TRUE(mutable_ovalptr != nullptr);
+ ASSERT_TRUE(mutable_cvalptr != nullptr);
+ EXPECT_EQ(*mutable_ovalptr, *mutable_cvalptr);
+}
+
+template <class>
+struct MoveOnly {
+ MoveOnly() = default;
+ explicit MoveOnly(int value) : value(value) {}
+ MoveOnly(MoveOnly&&) = default;
+ MoveOnly& operator=(MoveOnly&&) = default;
+ int value = 5;
+};
+
+TEST(VariantTest, TestMoveConstruct) {
+ using V = variant<MoveOnly<class A>, MoveOnly<class B>, MoveOnly<class C>>;
+
+ V v(in_place_index_t<1>{}, 10);
+ V v2 = absl::move(v);
+ EXPECT_EQ(10, absl::get<1>(v2).value);
+}
+
+// Used internally to emulate missing triviality traits for tests.
+template <class T>
+union SingleUnion {
+ T member;
+};
+
+// NOTE: These don't work with types that can't be union members.
+// They are just for testing.
+template <class T>
+struct is_trivially_move_constructible
+ : std::is_move_constructible<SingleUnion<T>>::type {};
+
+template <class T>
+struct is_trivially_move_assignable
+ : std::is_move_assignable<SingleUnion<T>>::type {};
+
+TEST(VariantTest, NothrowMoveConstructible) {
+ // Verify that variant is nothrow move constructible iff its template
+ // arguments are.
+ using U = std::unique_ptr<int>;
+ struct E {
+ E(E&&) {}
+ };
+ static_assert(std::is_nothrow_move_constructible<variant<U>>::value, "");
+ static_assert(std::is_nothrow_move_constructible<variant<U, int>>::value, "");
+ static_assert(!std::is_nothrow_move_constructible<variant<U, E>>::value, "");
+}
+
+// Test that for each slot, constructing a variant with that type
+// produces a sensible object that correctly reports its type, and
+// that copies the provided value.
+TYPED_TEST(VariantTypesTest, TestValueCtor) {
+ typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant;
+ using value_type1 = absl::variant_alternative_t<0, Variant>;
+ using value_type2 = absl::variant_alternative_t<1, Variant>;
+ using value_type3 = absl::variant_alternative_t<2, Variant>;
+ using value_type4 = absl::variant_alternative_t<3, Variant>;
+ const TypeParam value(TypeParam::kIndex);
+ Variant v(value);
+ EXPECT_TRUE(absl::holds_alternative<value_type1>(v) ||
+ TypeParam::kIndex != 1);
+ EXPECT_TRUE(absl::holds_alternative<value_type2>(v) ||
+ TypeParam::kIndex != 2);
+ EXPECT_TRUE(absl::holds_alternative<value_type3>(v) ||
+ TypeParam::kIndex != 3);
+ EXPECT_TRUE(absl::holds_alternative<value_type4>(v) ||
+ TypeParam::kIndex != 4);
+ EXPECT_TRUE(nullptr != absl::get_if<value_type1>(&v) ||
+ TypeParam::kIndex != 1);
+ EXPECT_TRUE(nullptr != absl::get_if<value_type2>(&v) ||
+ TypeParam::kIndex != 2);
+ EXPECT_TRUE(nullptr != absl::get_if<value_type3>(&v) ||
+ TypeParam::kIndex != 3);
+ EXPECT_TRUE(nullptr != absl::get_if<value_type4>(&v) ||
+ TypeParam::kIndex != 4);
+ EXPECT_TRUE(nullptr != absl::get_if<value_type1>(&v) ||
+ TypeParam::kIndex != 1);
+ EXPECT_TRUE(nullptr != absl::get_if<value_type2>(&v) ||
+ TypeParam::kIndex != 2);
+ EXPECT_TRUE(nullptr != absl::get_if<value_type3>(&v) ||
+ TypeParam::kIndex != 3);
+ EXPECT_TRUE(nullptr != absl::get_if<value_type4>(&v) ||
+ TypeParam::kIndex != 4);
+ const TypeParam* valptr = absl::get_if<TypeParam>(&v);
+ ASSERT_TRUE(nullptr != valptr);
+ EXPECT_EQ(value.value, valptr->value);
+ const TypeParam* mutable_valptr = absl::get_if<TypeParam>(&v);
+ ASSERT_TRUE(nullptr != mutable_valptr);
+ EXPECT_EQ(value.value, mutable_valptr->value);
+}
+
+TEST(VariantTest, InPlaceType) {
+ using Var = variant<int, std::string, NonCopyable, std::vector<int>>;
+
+ Var v1(in_place_type_t<int>(), 7);
+ ASSERT_TRUE(absl::holds_alternative<int>(v1));
+ EXPECT_EQ(7, absl::get<int>(v1));
+
+ Var v2(in_place_type_t<std::string>(), "ABC");
+ ASSERT_TRUE(absl::holds_alternative<std::string>(v2));
+ EXPECT_EQ("ABC", absl::get<std::string>(v2));
+
+ Var v3(in_place_type_t<std::string>(), "ABC", 2);
+ ASSERT_TRUE(absl::holds_alternative<std::string>(v3));
+ EXPECT_EQ("AB", absl::get<std::string>(v3));
+
+ Var v4(in_place_type_t<NonCopyable>{});
+ ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v4));
+
+ Var v5(in_place_type_t<std::vector<int>>(), {1, 2, 3});
+ ASSERT_TRUE(absl::holds_alternative<std::vector<int>>(v5));
+ EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3));
+}
+
+TEST(VariantTest, InPlaceTypeInitializerList) {
+ using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
+
+ Var v1(in_place_type_t<MoveOnlyWithListConstructor>(), {1, 2, 3, 4, 5}, 6);
+ ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1));
+ EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value);
+}
+
+TEST(VariantTest, InPlaceIndex) {
+ using Var = variant<int, std::string, NonCopyable, std::vector<int>>;
+
+ Var v1(in_place_index_t<0>(), 7);
+ ASSERT_TRUE(absl::holds_alternative<int>(v1));
+ EXPECT_EQ(7, absl::get<int>(v1));
+
+ Var v2(in_place_index_t<1>(), "ABC");
+ ASSERT_TRUE(absl::holds_alternative<std::string>(v2));
+ EXPECT_EQ("ABC", absl::get<std::string>(v2));
+
+ Var v3(in_place_index_t<1>(), "ABC", 2);
+ ASSERT_TRUE(absl::holds_alternative<std::string>(v3));
+ EXPECT_EQ("AB", absl::get<std::string>(v3));
+
+ Var v4(in_place_index_t<2>{});
+ EXPECT_TRUE(absl::holds_alternative<NonCopyable>(v4));
+
+ // Verify that a variant with only non-copyables can still be constructed.
+ EXPECT_TRUE(absl::holds_alternative<NonCopyable>(
+ variant<NonCopyable>(in_place_index_t<0>{})));
+
+ Var v5(in_place_index_t<3>(), {1, 2, 3});
+ ASSERT_TRUE(absl::holds_alternative<std::vector<int>>(v5));
+ EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3));
+}
+
+TEST(VariantTest, InPlaceIndexInitializerList) {
+ using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
+
+ Var v1(in_place_index_t<3>(), {1, 2, 3, 4, 5}, 6);
+ ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1));
+ EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value);
+}
+
+////////////////////
+// [variant.dtor] //
+////////////////////
+
+// Make sure that the destructor destroys the contained value
+TEST(VariantTest, TestDtor) {
+ typedef VariantFactory<IncrementInDtor>::Type Variant;
+ using value_type1 = absl::variant_alternative_t<0, Variant>;
+ using value_type2 = absl::variant_alternative_t<1, Variant>;
+ using value_type3 = absl::variant_alternative_t<2, Variant>;
+ using value_type4 = absl::variant_alternative_t<3, Variant>;
+ int counter = 0;
+ IncrementInDtor counter_adjuster(&counter);
+ EXPECT_EQ(0, counter);
+
+ value_type1 value1(counter_adjuster);
+ { Variant object(value1); }
+ EXPECT_EQ(1, counter);
+
+ value_type2 value2(counter_adjuster);
+ { Variant object(value2); }
+ EXPECT_EQ(2, counter);
+
+ value_type3 value3(counter_adjuster);
+ { Variant object(value3); }
+ EXPECT_EQ(3, counter);
+
+ value_type4 value4(counter_adjuster);
+ { Variant object(value4); }
+ EXPECT_EQ(4, counter);
+}
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+
+// Test destruction when in the valueless_by_exception state.
+TEST(VariantTest, TestDtorValuelessByException) {
+ int counter = 0;
+ IncrementInDtor counter_adjuster(&counter);
+
+ {
+ using Variant = VariantFactory<IncrementInDtor>::Type;
+
+ Variant v(in_place_index_t<0>(), counter_adjuster);
+ EXPECT_EQ(0, counter);
+
+ ToValuelessByException(v);
+ ASSERT_TRUE(v.valueless_by_exception());
+ EXPECT_EQ(1, counter);
+ }
+ EXPECT_EQ(1, counter);
+}
+
+#endif // ABSL_HAVE_EXCEPTIONS
+
+//////////////////////
+// [variant.assign] //
+//////////////////////
+
+// Test that self-assignment doesn't destroy the current value
+TEST(VariantTest, TestSelfAssignment) {
+ typedef VariantFactory<IncrementInDtor>::Type Variant;
+ int counter = 0;
+ IncrementInDtor counter_adjuster(&counter);
+ absl::variant_alternative_t<0, Variant> value(counter_adjuster);
+ Variant object(value);
+ object.operator=(object);
+ EXPECT_EQ(0, counter);
+
+ // A std::string long enough that it's likely to defeat any inline representation
+ // optimization.
+ const std::string long_str(128, 'a');
+
+ std::string foo = long_str;
+ foo = *&foo;
+ EXPECT_EQ(long_str, foo);
+
+ variant<int, std::string> so = long_str;
+ ASSERT_EQ(1, so.index());
+ EXPECT_EQ(long_str, absl::get<1>(so));
+ so = *&so;
+
+ ASSERT_EQ(1, so.index());
+ EXPECT_EQ(long_str, absl::get<1>(so));
+}
+
+// Test that assigning a variant<..., T, ...> to a variant<..., T, ...> produces
+// a variant<..., T, ...> with the correct value.
+TYPED_TEST(VariantTypesTest, TestAssignmentCopiesValueSameTypes) {
+ typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant;
+ const TypeParam value(TypeParam::kIndex);
+ const Variant source(value);
+ Variant target(TypeParam(value.value + 1));
+ ASSERT_TRUE(absl::holds_alternative<TypeParam>(source));
+ ASSERT_TRUE(absl::holds_alternative<TypeParam>(target));
+ ASSERT_NE(absl::get<TypeParam>(source), absl::get<TypeParam>(target));
+ target = source;
+ ASSERT_TRUE(absl::holds_alternative<TypeParam>(source));
+ ASSERT_TRUE(absl::holds_alternative<TypeParam>(target));
+ EXPECT_EQ(absl::get<TypeParam>(source), absl::get<TypeParam>(target));
+}
+
+// Test that assisnging a variant<..., T, ...> to a variant<1, ...>
+// produces a variant<..., T, ...> with the correct value.
+TYPED_TEST(VariantTypesTest, TestAssignmentCopiesValuesVaryingSourceType) {
+ typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant;
+ using value_type1 = absl::variant_alternative_t<0, Variant>;
+ const TypeParam value(TypeParam::kIndex);
+ const Variant source(value);
+ ASSERT_TRUE(absl::holds_alternative<TypeParam>(source));
+ Variant target(value_type1(1));
+ ASSERT_TRUE(absl::holds_alternative<value_type1>(target));
+ target = source;
+ EXPECT_TRUE(absl::holds_alternative<TypeParam>(source));
+ EXPECT_TRUE(absl::holds_alternative<TypeParam>(target));
+ EXPECT_EQ(absl::get<TypeParam>(source), absl::get<TypeParam>(target));
+}
+
+// Test that assigning a variant<1, ...> to a variant<..., T, ...>
+// produces a variant<1, ...> with the correct value.
+TYPED_TEST(VariantTypesTest, TestAssignmentCopiesValuesVaryingTargetType) {
+ typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant;
+ using value_type1 = absl::variant_alternative_t<0, Variant>;
+ const Variant source(value_type1(1));
+ ASSERT_TRUE(absl::holds_alternative<value_type1>(source));
+ const TypeParam value(TypeParam::kIndex);
+ Variant target(value);
+ ASSERT_TRUE(absl::holds_alternative<TypeParam>(target));
+ target = source;
+ EXPECT_TRUE(absl::holds_alternative<value_type1>(target));
+ EXPECT_TRUE(absl::holds_alternative<value_type1>(source));
+ EXPECT_EQ(absl::get<value_type1>(source), absl::get<value_type1>(target));
+}
+
+// Test that operator=<T> works, that assigning a new value destroys
+// the old and that assigning the new value again does not redestroy
+// the old
+TEST(VariantTest, TestAssign) {
+ typedef VariantFactory<IncrementInDtor>::Type Variant;
+ using value_type1 = absl::variant_alternative_t<0, Variant>;
+ using value_type2 = absl::variant_alternative_t<1, Variant>;
+ using value_type3 = absl::variant_alternative_t<2, Variant>;
+ using value_type4 = absl::variant_alternative_t<3, Variant>;
+
+ const int kSize = 4;
+ int counter[kSize];
+ std::unique_ptr<IncrementInDtor> counter_adjustor[kSize];
+ for (int i = 0; i != kSize; i++) {
+ counter[i] = 0;
+ counter_adjustor[i] = absl::make_unique<IncrementInDtor>(&counter[i]);
+ }
+
+ value_type1 v1(*counter_adjustor[0]);
+ value_type2 v2(*counter_adjustor[1]);
+ value_type3 v3(*counter_adjustor[2]);
+ value_type4 v4(*counter_adjustor[3]);
+
+ // Test that reassignment causes destruction of old value
+ {
+ Variant object(v1);
+ object = v2;
+ object = v3;
+ object = v4;
+ object = v1;
+ }
+
+ EXPECT_EQ(2, counter[0]);
+ EXPECT_EQ(1, counter[1]);
+ EXPECT_EQ(1, counter[2]);
+ EXPECT_EQ(1, counter[3]);
+
+ std::fill(std::begin(counter), std::end(counter), 0);
+
+ // Test that self-assignment does not cause destruction of old value
+ {
+ Variant object(v1);
+ object.operator=(object);
+ EXPECT_EQ(0, counter[0]);
+ }
+ {
+ Variant object(v2);
+ object.operator=(object);
+ EXPECT_EQ(0, counter[1]);
+ }
+ {
+ Variant object(v3);
+ object.operator=(object);
+ EXPECT_EQ(0, counter[2]);
+ }
+ {
+ Variant object(v4);
+ object.operator=(object);
+ EXPECT_EQ(0, counter[3]);
+ }
+
+ EXPECT_EQ(1, counter[0]);
+ EXPECT_EQ(1, counter[1]);
+ EXPECT_EQ(1, counter[2]);
+ EXPECT_EQ(1, counter[3]);
+}
+
+// This tests that we perform a backup if the copy-assign can throw but the move
+// cannot throw.
+TEST(VariantTest, TestBackupAssign) {
+ typedef VariantFactory<IncrementInDtorCopyCanThrow>::Type Variant;
+ using value_type1 = absl::variant_alternative_t<0, Variant>;
+ using value_type2 = absl::variant_alternative_t<1, Variant>;
+ using value_type3 = absl::variant_alternative_t<2, Variant>;
+ using value_type4 = absl::variant_alternative_t<3, Variant>;
+
+ const int kSize = 4;
+ int counter[kSize];
+ std::unique_ptr<IncrementInDtorCopyCanThrow> counter_adjustor[kSize];
+ for (int i = 0; i != kSize; i++) {
+ counter[i] = 0;
+ counter_adjustor[i].reset(new IncrementInDtorCopyCanThrow(&counter[i]));
+ }
+
+ value_type1 v1(*counter_adjustor[0]);
+ value_type2 v2(*counter_adjustor[1]);
+ value_type3 v3(*counter_adjustor[2]);
+ value_type4 v4(*counter_adjustor[3]);
+
+ // Test that reassignment causes destruction of old value
+ {
+ Variant object(v1);
+ object = v2;
+ object = v3;
+ object = v4;
+ object = v1;
+ }
+
+ // libstdc++ doesn't pass this test
+#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+ EXPECT_EQ(3, counter[0]);
+ EXPECT_EQ(2, counter[1]);
+ EXPECT_EQ(2, counter[2]);
+ EXPECT_EQ(2, counter[3]);
+#endif
+
+ std::fill(std::begin(counter), std::end(counter), 0);
+
+ // Test that self-assignment does not cause destruction of old value
+ {
+ Variant object(v1);
+ object.operator=(object);
+ EXPECT_EQ(0, counter[0]);
+ }
+ {
+ Variant object(v2);
+ object.operator=(object);
+ EXPECT_EQ(0, counter[1]);
+ }
+ {
+ Variant object(v3);
+ object.operator=(object);
+ EXPECT_EQ(0, counter[2]);
+ }
+ {
+ Variant object(v4);
+ object.operator=(object);
+ EXPECT_EQ(0, counter[3]);
+ }
+
+ EXPECT_EQ(1, counter[0]);
+ EXPECT_EQ(1, counter[1]);
+ EXPECT_EQ(1, counter[2]);
+ EXPECT_EQ(1, counter[3]);
+}
+
+///////////////////
+// [variant.mod] //
+///////////////////
+
+TEST(VariantTest, TestEmplaceBasic) {
+ using Variant = variant<int, char>;
+
+ Variant v(absl::in_place_index_t<0>{}, 0);
+
+ {
+ char& emplace_result = v.emplace<char>();
+ ASSERT_TRUE(absl::holds_alternative<char>(v));
+ EXPECT_EQ(absl::get<char>(v), 0);
+ EXPECT_EQ(&emplace_result, &absl::get<char>(v));
+ }
+
+ // Make sure that another emplace does zero-initialization
+ absl::get<char>(v) = 'a';
+ v.emplace<char>('b');
+ ASSERT_TRUE(absl::holds_alternative<char>(v));
+ EXPECT_EQ(absl::get<char>(v), 'b');
+
+ {
+ int& emplace_result = v.emplace<int>();
+ EXPECT_TRUE(absl::holds_alternative<int>(v));
+ EXPECT_EQ(absl::get<int>(v), 0);
+ EXPECT_EQ(&emplace_result, &absl::get<int>(v));
+ }
+}
+
+TEST(VariantTest, TestEmplaceInitializerList) {
+ using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
+
+ Var v1(absl::in_place_index_t<0>{}, 555);
+ MoveOnlyWithListConstructor& emplace_result =
+ v1.emplace<MoveOnlyWithListConstructor>({1, 2, 3, 4, 5}, 6);
+ ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1));
+ EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value);
+ EXPECT_EQ(&emplace_result, &absl::get<MoveOnlyWithListConstructor>(v1));
+}
+
+TEST(VariantTest, TestEmplaceIndex) {
+ using Variant = variant<int, char>;
+
+ Variant v(absl::in_place_index_t<0>{}, 555);
+
+ {
+ char& emplace_result = v.emplace<1>();
+ ASSERT_TRUE(absl::holds_alternative<char>(v));
+ EXPECT_EQ(absl::get<char>(v), 0);
+ EXPECT_EQ(&emplace_result, &absl::get<char>(v));
+ }
+
+ // Make sure that another emplace does zero-initialization
+ absl::get<char>(v) = 'a';
+ v.emplace<1>('b');
+ ASSERT_TRUE(absl::holds_alternative<char>(v));
+ EXPECT_EQ(absl::get<char>(v), 'b');
+
+ {
+ int& emplace_result = v.emplace<0>();
+ EXPECT_TRUE(absl::holds_alternative<int>(v));
+ EXPECT_EQ(absl::get<int>(v), 0);
+ EXPECT_EQ(&emplace_result, &absl::get<int>(v));
+ }
+}
+
+TEST(VariantTest, TestEmplaceIndexInitializerList) {
+ using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
+
+ Var v1(absl::in_place_index_t<0>{}, 555);
+ MoveOnlyWithListConstructor& emplace_result =
+ v1.emplace<3>({1, 2, 3, 4, 5}, 6);
+ ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1));
+ EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value);
+ EXPECT_EQ(&emplace_result, &absl::get<MoveOnlyWithListConstructor>(v1));
+}
+
+//////////////////////
+// [variant.status] //
+//////////////////////
+
+TEST(VariantTest, Index) {
+ using Var = variant<int, std::string, double>;
+
+ Var v = 1;
+ EXPECT_EQ(0, v.index());
+ v = "str";
+ EXPECT_EQ(1, v.index());
+ v = 0.;
+ EXPECT_EQ(2, v.index());
+
+ Var v2 = v;
+ EXPECT_EQ(2, v2.index());
+ v2.emplace<int>(3);
+ EXPECT_EQ(0, v2.index());
+}
+
+TEST(VariantTest, NotValuelessByException) {
+ using Var = variant<int, std::string, double>;
+
+ Var v = 1;
+ EXPECT_FALSE(v.valueless_by_exception());
+ v = "str";
+ EXPECT_FALSE(v.valueless_by_exception());
+ v = 0.;
+ EXPECT_FALSE(v.valueless_by_exception());
+
+ Var v2 = v;
+ EXPECT_FALSE(v.valueless_by_exception());
+ v2.emplace<int>(3);
+ EXPECT_FALSE(v.valueless_by_exception());
+}
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+
+TEST(VariantTest, IndexValuelessByException) {
+ using Var = variant<MoveCanThrow, std::string, double>;
+
+ Var v(absl::in_place_index_t<0>{});
+ EXPECT_EQ(0, v.index());
+ ToValuelessByException(v);
+ EXPECT_EQ(absl::variant_npos, v.index());
+ v = "str";
+ EXPECT_EQ(1, v.index());
+}
+
+TEST(VariantTest, ValuelessByException) {
+ using Var = variant<MoveCanThrow, std::string, double>;
+
+ Var v(absl::in_place_index_t<0>{});
+ EXPECT_FALSE(v.valueless_by_exception());
+ ToValuelessByException(v);
+ EXPECT_TRUE(v.valueless_by_exception());
+ v = "str";
+ EXPECT_FALSE(v.valueless_by_exception());
+}
+
+#endif // ABSL_HAVE_EXCEPTIONS
+
+////////////////////
+// [variant.swap] //
+////////////////////
+
+TEST(VariantTest, MemberSwap) {
+ SpecialSwap v1(3);
+ SpecialSwap v2(7);
+
+ variant<SpecialSwap> a = v1, b = v2;
+
+ EXPECT_THAT(a, VariantWith<SpecialSwap>(v1));
+ EXPECT_THAT(b, VariantWith<SpecialSwap>(v2));
+
+ a.swap(b);
+ EXPECT_THAT(a, VariantWith<SpecialSwap>(v2));
+ EXPECT_THAT(b, VariantWith<SpecialSwap>(v1));
+ EXPECT_TRUE(absl::get<SpecialSwap>(a).special_swap);
+
+ using V = variant<MoveCanThrow, std::string, int>;
+ int i = 33;
+ std::string s = "abc";
+ V valueless(in_place_index_t<0>{});
+ ToValuelessByException(valueless);
+ {
+ // lhs and rhs holds different alternative
+ V lhs(i), rhs(s);
+ lhs.swap(rhs);
+ EXPECT_THAT(lhs, VariantWith<std::string>(s));
+ EXPECT_THAT(rhs, VariantWith<int>(i));
+ }
+ {
+ // lhs is valueless
+ V lhs(valueless), rhs(i);
+ lhs.swap(rhs);
+ EXPECT_THAT(lhs, VariantWith<int>(i));
+ EXPECT_TRUE(rhs.valueless_by_exception());
+ }
+ {
+ // rhs is valueless
+ V lhs(s), rhs(valueless);
+ lhs.swap(rhs);
+ EXPECT_THAT(rhs, VariantWith<std::string>(s));
+ EXPECT_TRUE(lhs.valueless_by_exception());
+ }
+ {
+ // both are valueless
+ V lhs(valueless), rhs(valueless);
+ lhs.swap(rhs);
+ EXPECT_TRUE(lhs.valueless_by_exception());
+ EXPECT_TRUE(rhs.valueless_by_exception());
+ }
+}
+
+//////////////////////
+// [variant.helper] //
+//////////////////////
+
+TEST(VariantTest, VariantSize) {
+ {
+ using Size1Variant = absl::variant<int>;
+ EXPECT_EQ(1, absl::variant_size<Size1Variant>::value);
+ EXPECT_EQ(1, absl::variant_size<const Size1Variant>::value);
+ EXPECT_EQ(1, absl::variant_size<volatile Size1Variant>::value);
+ EXPECT_EQ(1, absl::variant_size<const volatile Size1Variant>::value);
+ }
+
+ {
+ using Size3Variant = absl::variant<int, float, int>;
+ EXPECT_EQ(3, absl::variant_size<Size3Variant>::value);
+ EXPECT_EQ(3, absl::variant_size<const Size3Variant>::value);
+ EXPECT_EQ(3, absl::variant_size<volatile Size3Variant>::value);
+ EXPECT_EQ(3, absl::variant_size<const volatile Size3Variant>::value);
+ }
+}
+
+TEST(VariantTest, VariantAlternative) {
+ {
+ using V = absl::variant<float, int, const char*>;
+ EXPECT_TRUE(
+ (std::is_same<float, absl::variant_alternative_t<0, V>>::value));
+ EXPECT_TRUE((std::is_same<const float,
+ absl::variant_alternative_t<0, const V>>::value));
+ EXPECT_TRUE(
+ (std::is_same<volatile float,
+ absl::variant_alternative_t<0, volatile V>>::value));
+ EXPECT_TRUE((
+ std::is_same<const volatile float,
+ absl::variant_alternative_t<0, const volatile V>>::value));
+
+ EXPECT_TRUE((std::is_same<int, absl::variant_alternative_t<1, V>>::value));
+ EXPECT_TRUE((std::is_same<const int,
+ absl::variant_alternative_t<1, const V>>::value));
+ EXPECT_TRUE(
+ (std::is_same<volatile int,
+ absl::variant_alternative_t<1, volatile V>>::value));
+ EXPECT_TRUE((
+ std::is_same<const volatile int,
+ absl::variant_alternative_t<1, const volatile V>>::value));
+
+ EXPECT_TRUE(
+ (std::is_same<const char*, absl::variant_alternative_t<2, V>>::value));
+ EXPECT_TRUE((std::is_same<const char* const,
+ absl::variant_alternative_t<2, const V>>::value));
+ EXPECT_TRUE(
+ (std::is_same<const char* volatile,
+ absl::variant_alternative_t<2, volatile V>>::value));
+ EXPECT_TRUE((
+ std::is_same<const char* const volatile,
+ absl::variant_alternative_t<2, const volatile V>>::value));
+ }
+
+ {
+ using V = absl::variant<float, volatile int, const char*>;
+ EXPECT_TRUE(
+ (std::is_same<float, absl::variant_alternative_t<0, V>>::value));
+ EXPECT_TRUE((std::is_same<const float,
+ absl::variant_alternative_t<0, const V>>::value));
+ EXPECT_TRUE(
+ (std::is_same<volatile float,
+ absl::variant_alternative_t<0, volatile V>>::value));
+ EXPECT_TRUE((
+ std::is_same<const volatile float,
+ absl::variant_alternative_t<0, const volatile V>>::value));
+
+ EXPECT_TRUE(
+ (std::is_same<volatile int, absl::variant_alternative_t<1, V>>::value));
+ EXPECT_TRUE((std::is_same<const volatile int,
+ absl::variant_alternative_t<1, const V>>::value));
+ EXPECT_TRUE(
+ (std::is_same<volatile int,
+ absl::variant_alternative_t<1, volatile V>>::value));
+ EXPECT_TRUE((
+ std::is_same<const volatile int,
+ absl::variant_alternative_t<1, const volatile V>>::value));
+
+ EXPECT_TRUE(
+ (std::is_same<const char*, absl::variant_alternative_t<2, V>>::value));
+ EXPECT_TRUE((std::is_same<const char* const,
+ absl::variant_alternative_t<2, const V>>::value));
+ EXPECT_TRUE(
+ (std::is_same<const char* volatile,
+ absl::variant_alternative_t<2, volatile V>>::value));
+ EXPECT_TRUE((
+ std::is_same<const char* const volatile,
+ absl::variant_alternative_t<2, const volatile V>>::value));
+ }
+}
+
+///////////////////
+// [variant.get] //
+///////////////////
+
+TEST(VariantTest, HoldsAlternative) {
+ using Var = variant<int, std::string, double>;
+
+ Var v = 1;
+ EXPECT_TRUE(absl::holds_alternative<int>(v));
+ EXPECT_FALSE(absl::holds_alternative<std::string>(v));
+ EXPECT_FALSE(absl::holds_alternative<double>(v));
+ v = "str";
+ EXPECT_FALSE(absl::holds_alternative<int>(v));
+ EXPECT_TRUE(absl::holds_alternative<std::string>(v));
+ EXPECT_FALSE(absl::holds_alternative<double>(v));
+ v = 0.;
+ EXPECT_FALSE(absl::holds_alternative<int>(v));
+ EXPECT_FALSE(absl::holds_alternative<std::string>(v));
+ EXPECT_TRUE(absl::holds_alternative<double>(v));
+
+ Var v2 = v;
+ EXPECT_FALSE(absl::holds_alternative<int>(v2));
+ EXPECT_FALSE(absl::holds_alternative<std::string>(v2));
+ EXPECT_TRUE(absl::holds_alternative<double>(v2));
+ v2.emplace<int>(3);
+ EXPECT_TRUE(absl::holds_alternative<int>(v2));
+ EXPECT_FALSE(absl::holds_alternative<std::string>(v2));
+ EXPECT_FALSE(absl::holds_alternative<double>(v2));
+}
+
+TEST(VariantTest, GetIndex) {
+ using Var = variant<int, std::string, double, int>;
+
+ {
+ Var v(absl::in_place_index_t<0>{}, 0);
+
+ using LValueGetType = decltype(absl::get<0>(v));
+ using RValueGetType = decltype(absl::get<0>(absl::move(v)));
+
+ EXPECT_TRUE((std::is_same<LValueGetType, int&>::value));
+ EXPECT_TRUE((std::is_same<RValueGetType, int&&>::value));
+ EXPECT_EQ(absl::get<0>(v), 0);
+ EXPECT_EQ(absl::get<0>(absl::move(v)), 0);
+
+ const Var& const_v = v;
+ using ConstLValueGetType = decltype(absl::get<0>(const_v));
+ using ConstRValueGetType = decltype(absl::get<0>(absl::move(const_v)));
+ EXPECT_TRUE((std::is_same<ConstLValueGetType, const int&>::value));
+ EXPECT_TRUE((std::is_same<ConstRValueGetType, const int&&>::value));
+ EXPECT_EQ(absl::get<0>(const_v), 0);
+ EXPECT_EQ(absl::get<0>(absl::move(const_v)), 0);
+ }
+
+ {
+ Var v = std::string("Hello");
+
+ using LValueGetType = decltype(absl::get<1>(v));
+ using RValueGetType = decltype(absl::get<1>(absl::move(v)));
+
+ EXPECT_TRUE((std::is_same<LValueGetType, std::string&>::value));
+ EXPECT_TRUE((std::is_same<RValueGetType, std::string&&>::value));
+ EXPECT_EQ(absl::get<1>(v), "Hello");
+ EXPECT_EQ(absl::get<1>(absl::move(v)), "Hello");
+
+ const Var& const_v = v;
+ using ConstLValueGetType = decltype(absl::get<1>(const_v));
+ using ConstRValueGetType = decltype(absl::get<1>(absl::move(const_v)));
+ EXPECT_TRUE((std::is_same<ConstLValueGetType, const std::string&>::value));
+ EXPECT_TRUE((std::is_same<ConstRValueGetType, const std::string&&>::value));
+ EXPECT_EQ(absl::get<1>(const_v), "Hello");
+ EXPECT_EQ(absl::get<1>(absl::move(const_v)), "Hello");
+ }
+
+ {
+ Var v = 2.0;
+
+ using LValueGetType = decltype(absl::get<2>(v));
+ using RValueGetType = decltype(absl::get<2>(absl::move(v)));
+
+ EXPECT_TRUE((std::is_same<LValueGetType, double&>::value));
+ EXPECT_TRUE((std::is_same<RValueGetType, double&&>::value));
+ EXPECT_EQ(absl::get<2>(v), 2.);
+ EXPECT_EQ(absl::get<2>(absl::move(v)), 2.);
+
+ const Var& const_v = v;
+ using ConstLValueGetType = decltype(absl::get<2>(const_v));
+ using ConstRValueGetType = decltype(absl::get<2>(absl::move(const_v)));
+ EXPECT_TRUE((std::is_same<ConstLValueGetType, const double&>::value));
+ EXPECT_TRUE((std::is_same<ConstRValueGetType, const double&&>::value));
+ EXPECT_EQ(absl::get<2>(const_v), 2.);
+ EXPECT_EQ(absl::get<2>(absl::move(const_v)), 2.);
+ }
+
+ {
+ Var v(absl::in_place_index_t<0>{}, 0);
+ v.emplace<3>(1);
+
+ using LValueGetType = decltype(absl::get<3>(v));
+ using RValueGetType = decltype(absl::get<3>(absl::move(v)));
+
+ EXPECT_TRUE((std::is_same<LValueGetType, int&>::value));
+ EXPECT_TRUE((std::is_same<RValueGetType, int&&>::value));
+ EXPECT_EQ(absl::get<3>(v), 1);
+ EXPECT_EQ(absl::get<3>(absl::move(v)), 1);
+
+ const Var& const_v = v;
+ using ConstLValueGetType = decltype(absl::get<3>(const_v));
+ using ConstRValueGetType = decltype(absl::get<3>(absl::move(const_v)));
+ EXPECT_TRUE((std::is_same<ConstLValueGetType, const int&>::value));
+ EXPECT_TRUE((std::is_same<ConstRValueGetType, const int&&>::value));
+ EXPECT_EQ(absl::get<3>(const_v), 1);
+ EXPECT_EQ(absl::get<3>(absl::move(const_v)), 1); // NOLINT
+ }
+}
+
+TEST(VariantTest, BadGetIndex) {
+ using Var = variant<int, std::string, double>;
+
+ {
+ Var v = 1;
+
+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<1>(v));
+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<1>(std::move(v)));
+
+ const Var& const_v = v;
+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<1>(const_v));
+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
+ absl::get<1>(std::move(const_v))); // NOLINT
+ }
+
+ {
+ Var v = std::string("Hello");
+
+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<0>(v));
+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<0>(std::move(v)));
+
+ const Var& const_v = v;
+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<0>(const_v));
+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
+ absl::get<0>(std::move(const_v))); // NOLINT
+ }
+}
+
+TEST(VariantTest, GetType) {
+ using Var = variant<int, std::string, double>;
+
+ {
+ Var v = 1;
+
+ using LValueGetType = decltype(absl::get<int>(v));
+ using RValueGetType = decltype(absl::get<int>(absl::move(v)));
+
+ EXPECT_TRUE((std::is_same<LValueGetType, int&>::value));
+ EXPECT_TRUE((std::is_same<RValueGetType, int&&>::value));
+ EXPECT_EQ(absl::get<int>(v), 1);
+ EXPECT_EQ(absl::get<int>(absl::move(v)), 1);
+
+ const Var& const_v = v;
+ using ConstLValueGetType = decltype(absl::get<int>(const_v));
+ using ConstRValueGetType = decltype(absl::get<int>(absl::move(const_v)));
+ EXPECT_TRUE((std::is_same<ConstLValueGetType, const int&>::value));
+ EXPECT_TRUE((std::is_same<ConstRValueGetType, const int&&>::value));
+ EXPECT_EQ(absl::get<int>(const_v), 1);
+ EXPECT_EQ(absl::get<int>(absl::move(const_v)), 1);
+ }
+
+ {
+ Var v = std::string("Hello");
+
+ using LValueGetType = decltype(absl::get<1>(v));
+ using RValueGetType = decltype(absl::get<1>(absl::move(v)));
+
+ EXPECT_TRUE((std::is_same<LValueGetType, std::string&>::value));
+ EXPECT_TRUE((std::is_same<RValueGetType, std::string&&>::value));
+ EXPECT_EQ(absl::get<std::string>(v), "Hello");
+ EXPECT_EQ(absl::get<std::string>(absl::move(v)), "Hello");
+
+ const Var& const_v = v;
+ using ConstLValueGetType = decltype(absl::get<1>(const_v));
+ using ConstRValueGetType = decltype(absl::get<1>(absl::move(const_v)));
+ EXPECT_TRUE((std::is_same<ConstLValueGetType, const std::string&>::value));
+ EXPECT_TRUE((std::is_same<ConstRValueGetType, const std::string&&>::value));
+ EXPECT_EQ(absl::get<std::string>(const_v), "Hello");
+ EXPECT_EQ(absl::get<std::string>(absl::move(const_v)), "Hello");
+ }
+
+ {
+ Var v = 2.0;
+
+ using LValueGetType = decltype(absl::get<2>(v));
+ using RValueGetType = decltype(absl::get<2>(absl::move(v)));
+
+ EXPECT_TRUE((std::is_same<LValueGetType, double&>::value));
+ EXPECT_TRUE((std::is_same<RValueGetType, double&&>::value));
+ EXPECT_EQ(absl::get<double>(v), 2.);
+ EXPECT_EQ(absl::get<double>(absl::move(v)), 2.);
+
+ const Var& const_v = v;
+ using ConstLValueGetType = decltype(absl::get<2>(const_v));
+ using ConstRValueGetType = decltype(absl::get<2>(absl::move(const_v)));
+ EXPECT_TRUE((std::is_same<ConstLValueGetType, const double&>::value));
+ EXPECT_TRUE((std::is_same<ConstRValueGetType, const double&&>::value));
+ EXPECT_EQ(absl::get<double>(const_v), 2.);
+ EXPECT_EQ(absl::get<double>(absl::move(const_v)), 2.);
+ }
+}
+
+TEST(VariantTest, BadGetType) {
+ using Var = variant<int, std::string, double>;
+
+ {
+ Var v = 1;
+
+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<std::string>(v));
+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
+ absl::get<std::string>(std::move(v)));
+
+ const Var& const_v = v;
+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<std::string>(const_v));
+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
+ absl::get<std::string>(std::move(const_v))); // NOLINT
+ }
+
+ {
+ Var v = std::string("Hello");
+
+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<int>(v));
+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<int>(std::move(v)));
+
+ const Var& const_v = v;
+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<int>(const_v));
+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
+ absl::get<int>(std::move(const_v))); // NOLINT
+ }
+}
+
+TEST(VariantTest, GetIfIndex) {
+ using Var = variant<int, std::string, double, int>;
+
+ {
+ Var v(absl::in_place_index_t<0>{}, 0);
+ EXPECT_TRUE(noexcept(absl::get_if<0>(&v)));
+
+ {
+ auto* elem = absl::get_if<0>(&v);
+ EXPECT_TRUE((std::is_same<decltype(elem), int*>::value));
+ ASSERT_NE(elem, nullptr);
+ EXPECT_EQ(*elem, 0);
+ {
+ auto* bad_elem = absl::get_if<1>(&v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), std::string*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ {
+ auto* bad_elem = absl::get_if<2>(&v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), double*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ {
+ auto* bad_elem = absl::get_if<3>(&v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ }
+
+ const Var& const_v = v;
+ EXPECT_TRUE(noexcept(absl::get_if<0>(&const_v)));
+
+ {
+ auto* elem = absl::get_if<0>(&const_v);
+ EXPECT_TRUE((std::is_same<decltype(elem), const int*>::value));
+ ASSERT_NE(elem, nullptr);
+ EXPECT_EQ(*elem, 0);
+ {
+ auto* bad_elem = absl::get_if<1>(&const_v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const std::string*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ {
+ auto* bad_elem = absl::get_if<2>(&const_v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const double*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ {
+ auto* bad_elem = absl::get_if<3>(&const_v);
+ EXPECT_EQ(bad_elem, nullptr);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
+ }
+ }
+ }
+
+ {
+ Var v = std::string("Hello");
+ EXPECT_TRUE(noexcept(absl::get_if<1>(&v)));
+
+ {
+ auto* elem = absl::get_if<1>(&v);
+ EXPECT_TRUE((std::is_same<decltype(elem), std::string*>::value));
+ ASSERT_NE(elem, nullptr);
+ EXPECT_EQ(*elem, "Hello");
+ {
+ auto* bad_elem = absl::get_if<0>(&v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ {
+ auto* bad_elem = absl::get_if<2>(&v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), double*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ {
+ auto* bad_elem = absl::get_if<3>(&v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ }
+
+ const Var& const_v = v;
+ EXPECT_TRUE(noexcept(absl::get_if<1>(&const_v)));
+
+ {
+ auto* elem = absl::get_if<1>(&const_v);
+ EXPECT_TRUE((std::is_same<decltype(elem), const std::string*>::value));
+ ASSERT_NE(elem, nullptr);
+ EXPECT_EQ(*elem, "Hello");
+ {
+ auto* bad_elem = absl::get_if<0>(&const_v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ {
+ auto* bad_elem = absl::get_if<2>(&const_v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const double*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ {
+ auto* bad_elem = absl::get_if<3>(&const_v);
+ EXPECT_EQ(bad_elem, nullptr);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
+ }
+ }
+ }
+
+ {
+ Var v = 2.0;
+ EXPECT_TRUE(noexcept(absl::get_if<2>(&v)));
+
+ {
+ auto* elem = absl::get_if<2>(&v);
+ EXPECT_TRUE((std::is_same<decltype(elem), double*>::value));
+ ASSERT_NE(elem, nullptr);
+ EXPECT_EQ(*elem, 2.0);
+ {
+ auto* bad_elem = absl::get_if<0>(&v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ {
+ auto* bad_elem = absl::get_if<1>(&v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), std::string*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ {
+ auto* bad_elem = absl::get_if<3>(&v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ }
+
+ const Var& const_v = v;
+ EXPECT_TRUE(noexcept(absl::get_if<2>(&const_v)));
+
+ {
+ auto* elem = absl::get_if<2>(&const_v);
+ EXPECT_TRUE((std::is_same<decltype(elem), const double*>::value));
+ ASSERT_NE(elem, nullptr);
+ EXPECT_EQ(*elem, 2.0);
+ {
+ auto* bad_elem = absl::get_if<0>(&const_v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ {
+ auto* bad_elem = absl::get_if<1>(&const_v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const std::string*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ {
+ auto* bad_elem = absl::get_if<3>(&const_v);
+ EXPECT_EQ(bad_elem, nullptr);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
+ }
+ }
+ }
+
+ {
+ Var v(absl::in_place_index_t<0>{}, 0);
+ v.emplace<3>(1);
+ EXPECT_TRUE(noexcept(absl::get_if<3>(&v)));
+
+ {
+ auto* elem = absl::get_if<3>(&v);
+ EXPECT_TRUE((std::is_same<decltype(elem), int*>::value));
+ ASSERT_NE(elem, nullptr);
+ EXPECT_EQ(*elem, 1);
+ {
+ auto* bad_elem = absl::get_if<0>(&v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ {
+ auto* bad_elem = absl::get_if<1>(&v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), std::string*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ {
+ auto* bad_elem = absl::get_if<2>(&v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), double*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ }
+
+ const Var& const_v = v;
+ EXPECT_TRUE(noexcept(absl::get_if<3>(&const_v)));
+
+ {
+ auto* elem = absl::get_if<3>(&const_v);
+ EXPECT_TRUE((std::is_same<decltype(elem), const int*>::value));
+ ASSERT_NE(elem, nullptr);
+ EXPECT_EQ(*elem, 1);
+ {
+ auto* bad_elem = absl::get_if<0>(&const_v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ {
+ auto* bad_elem = absl::get_if<1>(&const_v);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const std::string*>::value));
+ EXPECT_EQ(bad_elem, nullptr);
+ }
+ {
+ auto* bad_elem = absl::get_if<2>(&const_v);
+ EXPECT_EQ(bad_elem, nullptr);
+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const double*>::value));
+ }
+ }
+ }
+}
+
+//////////////////////
+// [variant.relops] //
+//////////////////////
+
+TEST(VariantTest, OperatorEquals) {
+ variant<int, std::string> a(1), b(1);
+ EXPECT_TRUE(a == b);
+ EXPECT_TRUE(b == a);
+ EXPECT_FALSE(a != b);
+ EXPECT_FALSE(b != a);
+
+ b = "str";
+ EXPECT_FALSE(a == b);
+ EXPECT_FALSE(b == a);
+ EXPECT_TRUE(a != b);
+ EXPECT_TRUE(b != a);
+
+ b = 0;
+ EXPECT_FALSE(a == b);
+ EXPECT_FALSE(b == a);
+ EXPECT_TRUE(a != b);
+ EXPECT_TRUE(b != a);
+
+ a = b = "foo";
+ EXPECT_TRUE(a == b);
+ EXPECT_TRUE(b == a);
+ EXPECT_FALSE(a != b);
+ EXPECT_FALSE(b != a);
+
+ a = "bar";
+ EXPECT_FALSE(a == b);
+ EXPECT_FALSE(b == a);
+ EXPECT_TRUE(a != b);
+ EXPECT_TRUE(b != a);
+}
+
+TEST(VariantTest, OperatorRelational) {
+ variant<int, std::string> a(1), b(1);
+ EXPECT_FALSE(a < b);
+ EXPECT_FALSE(b < a);
+ EXPECT_FALSE(a > b);
+ EXPECT_FALSE(b > a);
+ EXPECT_TRUE(a <= b);
+ EXPECT_TRUE(b <= a);
+ EXPECT_TRUE(a >= b);
+ EXPECT_TRUE(b >= a);
+
+ b = "str";
+ EXPECT_TRUE(a < b);
+ EXPECT_FALSE(b < a);
+ EXPECT_FALSE(a > b);
+ EXPECT_TRUE(b > a);
+ EXPECT_TRUE(a <= b);
+ EXPECT_FALSE(b <= a);
+ EXPECT_FALSE(a >= b);
+ EXPECT_TRUE(b >= a);
+
+ b = 0;
+ EXPECT_FALSE(a < b);
+ EXPECT_TRUE(b < a);
+ EXPECT_TRUE(a > b);
+ EXPECT_FALSE(b > a);
+ EXPECT_FALSE(a <= b);
+ EXPECT_TRUE(b <= a);
+ EXPECT_TRUE(a >= b);
+ EXPECT_FALSE(b >= a);
+
+ a = b = "foo";
+ EXPECT_FALSE(a < b);
+ EXPECT_FALSE(b < a);
+ EXPECT_FALSE(a > b);
+ EXPECT_FALSE(b > a);
+ EXPECT_TRUE(a <= b);
+ EXPECT_TRUE(b <= a);
+ EXPECT_TRUE(a >= b);
+ EXPECT_TRUE(b >= a);
+
+ a = "bar";
+ EXPECT_TRUE(a < b);
+ EXPECT_FALSE(b < a);
+ EXPECT_FALSE(a > b);
+ EXPECT_TRUE(b > a);
+ EXPECT_TRUE(a <= b);
+ EXPECT_FALSE(b <= a);
+ EXPECT_FALSE(a >= b);
+ EXPECT_TRUE(b >= a);
+}
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+
+TEST(VariantTest, ValuelessOperatorEquals) {
+ variant<MoveCanThrow, std::string> int_v(1), string_v("Hello"),
+ valueless(absl::in_place_index_t<0>{}),
+ other_valueless(absl::in_place_index_t<0>{});
+ ToValuelessByException(valueless);
+ ToValuelessByException(other_valueless);
+
+ EXPECT_TRUE(valueless == other_valueless);
+ EXPECT_TRUE(other_valueless == valueless);
+ EXPECT_FALSE(valueless == int_v);
+ EXPECT_FALSE(valueless == string_v);
+ EXPECT_FALSE(int_v == valueless);
+ EXPECT_FALSE(string_v == valueless);
+
+ EXPECT_FALSE(valueless != other_valueless);
+ EXPECT_FALSE(other_valueless != valueless);
+ EXPECT_TRUE(valueless != int_v);
+ EXPECT_TRUE(valueless != string_v);
+ EXPECT_TRUE(int_v != valueless);
+ EXPECT_TRUE(string_v != valueless);
+}
+
+TEST(VariantTest, ValuelessOperatorRelational) {
+ variant<MoveCanThrow, std::string> int_v(1), string_v("Hello"),
+ valueless(absl::in_place_index_t<0>{}),
+ other_valueless(absl::in_place_index_t<0>{});
+ ToValuelessByException(valueless);
+ ToValuelessByException(other_valueless);
+
+ EXPECT_FALSE(valueless < other_valueless);
+ EXPECT_FALSE(other_valueless < valueless);
+ EXPECT_TRUE(valueless < int_v);
+ EXPECT_TRUE(valueless < string_v);
+ EXPECT_FALSE(int_v < valueless);
+ EXPECT_FALSE(string_v < valueless);
+
+ EXPECT_TRUE(valueless <= other_valueless);
+ EXPECT_TRUE(other_valueless <= valueless);
+ EXPECT_TRUE(valueless <= int_v);
+ EXPECT_TRUE(valueless <= string_v);
+ EXPECT_FALSE(int_v <= valueless);
+ EXPECT_FALSE(string_v <= valueless);
+
+ EXPECT_TRUE(valueless >= other_valueless);
+ EXPECT_TRUE(other_valueless >= valueless);
+ EXPECT_FALSE(valueless >= int_v);
+ EXPECT_FALSE(valueless >= string_v);
+ EXPECT_TRUE(int_v >= valueless);
+ EXPECT_TRUE(string_v >= valueless);
+
+ EXPECT_FALSE(valueless > other_valueless);
+ EXPECT_FALSE(other_valueless > valueless);
+ EXPECT_FALSE(valueless > int_v);
+ EXPECT_FALSE(valueless > string_v);
+ EXPECT_TRUE(int_v > valueless);
+ EXPECT_TRUE(string_v > valueless);
+}
+
+#endif
+
+/////////////////////
+// [variant.visit] //
+/////////////////////
+
+template <typename T>
+struct ConvertTo {
+ template <typename U>
+ T operator()(const U& u) const {
+ return u;
+ }
+};
+
+TEST(VariantTest, VisitSimple) {
+ variant<std::string, const char*> v = "A";
+
+ std::string str = absl::visit(ConvertTo<std::string>{}, v);
+ EXPECT_EQ("A", str);
+
+ v = std::string("B");
+
+ absl::string_view piece = absl::visit(ConvertTo<absl::string_view>{}, v);
+ EXPECT_EQ("B", piece);
+
+ struct StrLen {
+ int operator()(const std::string& s) const { return s.size(); }
+ int operator()(const char* s) const { return strlen(s); }
+ };
+
+ v = "SomeStr";
+ EXPECT_EQ(7, absl::visit(StrLen{}, v));
+ v = std::string("VeryLargeThisTime");
+ EXPECT_EQ(17, absl::visit(StrLen{}, v));
+}
+
+TEST(VariantTest, VisitRValue) {
+ variant<std::string> v = std::string("X");
+ struct Visitor {
+ bool operator()(const std::string&) const { return false; }
+ bool operator()(std::string&&) const { return true; } // NOLINT
+
+ int operator()(const std::string&, const std::string&) const { return 0; }
+ int operator()(const std::string&, std::string&&) const { return 1; } // NOLINT
+ int operator()(std::string&&, const std::string&) const { return 2; } // NOLINT
+ int operator()(std::string&&, std::string&&) const { return 3; } // NOLINT
+ };
+ EXPECT_FALSE(absl::visit(Visitor{}, v));
+ EXPECT_TRUE(absl::visit(Visitor{}, absl::move(v)));
+
+ // Also test the variadic overload.
+ EXPECT_EQ(0, absl::visit(Visitor{}, v, v));
+ EXPECT_EQ(1, absl::visit(Visitor{}, v, absl::move(v)));
+ EXPECT_EQ(2, absl::visit(Visitor{}, absl::move(v), v));
+ EXPECT_EQ(3, absl::visit(Visitor{}, absl::move(v), absl::move(v)));
+}
+
+TEST(VariantTest, VisitRValueVisitor) {
+ variant<std::string> v = std::string("X");
+ struct Visitor {
+ bool operator()(const std::string&) const& { return false; }
+ bool operator()(const std::string&) && { return true; }
+ };
+ Visitor visitor;
+ EXPECT_FALSE(absl::visit(visitor, v));
+ EXPECT_TRUE(absl::visit(Visitor{}, v));
+}
+
+TEST(VariantTest, VisitResultTypeDifferent) {
+ variant<std::string> v = std::string("X");
+ struct LValue_LValue {};
+ struct RValue_LValue {};
+ struct LValue_RValue {};
+ struct RValue_RValue {};
+ struct Visitor {
+ LValue_LValue operator()(const std::string&) const& { return {}; }
+ RValue_LValue operator()(std::string&&) const& { return {}; } // NOLINT
+ LValue_RValue operator()(const std::string&) && { return {}; }
+ RValue_RValue operator()(std::string&&) && { return {}; } // NOLINT
+ } visitor;
+
+ EXPECT_TRUE(
+ (std::is_same<LValue_LValue, decltype(absl::visit(visitor, v))>::value));
+ EXPECT_TRUE(
+ (std::is_same<RValue_LValue,
+ decltype(absl::visit(visitor, absl::move(v)))>::value));
+ EXPECT_TRUE((
+ std::is_same<LValue_RValue, decltype(absl::visit(Visitor{}, v))>::value));
+ EXPECT_TRUE(
+ (std::is_same<RValue_RValue,
+ decltype(absl::visit(Visitor{}, absl::move(v)))>::value));
+}
+
+TEST(VariantTest, VisitVariadic) {
+ using A = variant<int, std::string>;
+ using B = variant<std::unique_ptr<int>, absl::string_view>;
+
+ struct Visitor {
+ std::pair<int, int> operator()(int a, std::unique_ptr<int> b) const {
+ return {a, *b};
+ }
+ std::pair<int, int> operator()(absl::string_view a,
+ std::unique_ptr<int> b) const {
+ return {static_cast<int>(a.size()), static_cast<int>(*b)};
+ }
+ std::pair<int, int> operator()(int a, absl::string_view b) const {
+ return {a, static_cast<int>(b.size())};
+ }
+ std::pair<int, int> operator()(absl::string_view a,
+ absl::string_view b) const {
+ return {static_cast<int>(a.size()), static_cast<int>(b.size())};
+ }
+ };
+
+ EXPECT_THAT(absl::visit(Visitor(), A(1), B(std::unique_ptr<int>(new int(7)))),
+ ::testing::Pair(1, 7));
+ EXPECT_THAT(absl::visit(Visitor(), A(1), B(absl::string_view("ABC"))),
+ ::testing::Pair(1, 3));
+ EXPECT_THAT(absl::visit(Visitor(), A(std::string("BBBBB")),
+ B(std::unique_ptr<int>(new int(7)))),
+ ::testing::Pair(5, 7));
+ EXPECT_THAT(
+ absl::visit(Visitor(), A(std::string("BBBBB")), B(absl::string_view("ABC"))),
+ ::testing::Pair(5, 3));
+}
+
+TEST(VariantTest, VisitNoArgs) {
+ EXPECT_EQ(5, absl::visit([] { return 5; }));
+}
+
+struct ConstFunctor {
+ int operator()(int a, int b) const { return a - b; }
+};
+
+struct MutableFunctor {
+ int operator()(int a, int b) { return a - b; }
+};
+
+struct Class {
+ int Method(int a, int b) { return a - b; }
+ int ConstMethod(int a, int b) const { return a - b; }
+
+ int member;
+};
+
+TEST(VariantTest, VisitReferenceWrapper) {
+ ConstFunctor cf;
+ MutableFunctor mf;
+ absl::variant<int> three = 3;
+ absl::variant<int> two = 2;
+
+ EXPECT_EQ(1, absl::visit(std::cref(cf), three, two));
+ EXPECT_EQ(1, absl::visit(std::ref(cf), three, two));
+ EXPECT_EQ(1, absl::visit(std::ref(mf), three, two));
+}
+
+// libstdc++ std::variant doesn't support the INVOKE semantics.
+#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+TEST(VariantTest, VisitMemberFunction) {
+ absl::variant<std::unique_ptr<Class>> p(absl::make_unique<Class>());
+ absl::variant<std::unique_ptr<const Class>> cp(
+ absl::make_unique<const Class>());
+ absl::variant<int> three = 3;
+ absl::variant<int> two = 2;
+
+ EXPECT_EQ(1, absl::visit(&Class::Method, p, three, two));
+ EXPECT_EQ(1, absl::visit(&Class::ConstMethod, p, three, two));
+ EXPECT_EQ(1, absl::visit(&Class::ConstMethod, cp, three, two));
+}
+
+TEST(VariantTest, VisitDataMember) {
+ absl::variant<std::unique_ptr<Class>> p(absl::make_unique<Class>(Class{42}));
+ absl::variant<std::unique_ptr<const Class>> cp(
+ absl::make_unique<const Class>(Class{42}));
+ EXPECT_EQ(42, absl::visit(&Class::member, p));
+
+ absl::visit(&Class::member, p) = 5;
+ EXPECT_EQ(5, absl::visit(&Class::member, p));
+
+ EXPECT_EQ(42, absl::visit(&Class::member, cp));
+}
+#endif // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+
+/////////////////////////
+// [variant.monostate] //
+/////////////////////////
+
+TEST(VariantTest, MonostateBasic) {
+ absl::monostate mono;
+ (void)mono;
+
+ // TODO(mattcalabrese) Expose move triviality metafunctions in absl.
+ EXPECT_TRUE(absl::is_trivially_default_constructible<absl::monostate>::value);
+ EXPECT_TRUE(is_trivially_move_constructible<absl::monostate>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<absl::monostate>::value);
+ EXPECT_TRUE(is_trivially_move_assignable<absl::monostate>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<absl::monostate>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<absl::monostate>::value);
+}
+
+TEST(VariantTest, VariantMonostateDefaultConstruction) {
+ absl::variant<absl::monostate, NonDefaultConstructible> var;
+ EXPECT_EQ(var.index(), 0);
+}
+
+////////////////////////////////
+// [variant.monostate.relops] //
+////////////////////////////////
+
+TEST(VariantTest, MonostateComparisons) {
+ absl::monostate lhs, rhs;
+
+ EXPECT_EQ(lhs, lhs);
+ EXPECT_EQ(lhs, rhs);
+
+ EXPECT_FALSE(lhs != lhs);
+ EXPECT_FALSE(lhs != rhs);
+ EXPECT_FALSE(lhs < lhs);
+ EXPECT_FALSE(lhs < rhs);
+ EXPECT_FALSE(lhs > lhs);
+ EXPECT_FALSE(lhs > rhs);
+
+ EXPECT_LE(lhs, lhs);
+ EXPECT_LE(lhs, rhs);
+ EXPECT_GE(lhs, lhs);
+ EXPECT_GE(lhs, rhs);
+
+ EXPECT_TRUE(noexcept(std::declval<absl::monostate>() ==
+ std::declval<absl::monostate>()));
+ EXPECT_TRUE(noexcept(std::declval<absl::monostate>() !=
+ std::declval<absl::monostate>()));
+ EXPECT_TRUE(noexcept(std::declval<absl::monostate>() <
+ std::declval<absl::monostate>()));
+ EXPECT_TRUE(noexcept(std::declval<absl::monostate>() >
+ std::declval<absl::monostate>()));
+ EXPECT_TRUE(noexcept(std::declval<absl::monostate>() <=
+ std::declval<absl::monostate>()));
+ EXPECT_TRUE(noexcept(std::declval<absl::monostate>() >=
+ std::declval<absl::monostate>()));
+}
+
+///////////////////////
+// [variant.specalg] //
+///////////////////////
+
+TEST(VariantTest, NonmemberSwap) {
+ using std::swap;
+
+ SpecialSwap v1(3);
+ SpecialSwap v2(7);
+
+ variant<SpecialSwap> a = v1, b = v2;
+
+ EXPECT_THAT(a, VariantWith<SpecialSwap>(v1));
+ EXPECT_THAT(b, VariantWith<SpecialSwap>(v2));
+
+ std::swap(a, b);
+ EXPECT_THAT(a, VariantWith<SpecialSwap>(v2));
+ EXPECT_THAT(b, VariantWith<SpecialSwap>(v1));
+#ifndef ABSL_HAVE_STD_VARIANT
+ EXPECT_FALSE(absl::get<SpecialSwap>(a).special_swap);
+#endif
+
+ swap(a, b);
+ EXPECT_THAT(a, VariantWith<SpecialSwap>(v1));
+ EXPECT_THAT(b, VariantWith<SpecialSwap>(v2));
+ EXPECT_TRUE(absl::get<SpecialSwap>(b).special_swap);
+}
+
+//////////////////////////
+// [variant.bad.access] //
+//////////////////////////
+
+TEST(VariantTest, BadAccess) {
+ EXPECT_TRUE(noexcept(absl::bad_variant_access()));
+ absl::bad_variant_access exception_obj;
+ std::exception* base = &exception_obj;
+ (void)base;
+}
+
+////////////////////
+// [variant.hash] //
+////////////////////
+
+TEST(VariantTest, MonostateHash) {
+ absl::monostate mono, other_mono;
+ std::hash<absl::monostate> const hasher{};
+ static_assert(std::is_same<decltype(hasher(mono)), std::size_t>::value, "");
+ EXPECT_EQ(hasher(mono), hasher(other_mono));
+}
+
+TEST(VariantTest, Hash) {
+ static_assert(type_traits_internal::IsHashEnabled<variant<int>>::value, "");
+ static_assert(type_traits_internal::IsHashEnabled<variant<Hashable>>::value,
+ "");
+ static_assert(
+ type_traits_internal::IsHashEnabled<variant<int, Hashable>>::value, "");
+
+#if defined(_MSC_VER) || \
+ (defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 4000 && \
+ _LIBCPP_STD_VER > 11) || \
+ defined(__APPLE__)
+ // For MSVC and libc++ (< 4.0 and c++14), std::hash primary template has a
+ // static_assert to catch any user-defined type T that doesn't provide a hash
+ // specialization. So instantiating std::hash<variant<T>> will result
+ // in a hard error which is not SFINAE friendly.
+#define ABSL_STD_HASH_NOT_SFINAE_FRIENDLY 1
+#endif
+
+#ifndef ABSL_STD_HASH_NOT_SFINAE_FRIENDLY
+ static_assert(
+ !type_traits_internal::IsHashEnabled<variant<NonHashable>>::value, "");
+ static_assert(!type_traits_internal::IsHashEnabled<
+ variant<Hashable, NonHashable>>::value,
+ "");
+#endif
+
+// MSVC std::hash<std::variant> does not use the index, thus produce the same
+// result on the same value as different alternative.
+#if !(defined(_MSC_VER) && defined(ABSL_HAVE_STD_VARIANT))
+ {
+ // same value as different alternative
+ variant<int, int> v0(in_place_index_t<0>{}, 42);
+ variant<int, int> v1(in_place_index_t<1>{}, 42);
+ std::hash<variant<int, int>> hash;
+ EXPECT_NE(hash(v0), hash(v1));
+ }
+#endif // !(defined(_MSC_VER) && defined(ABSL_HAVE_STD_VARIANT))
+
+ {
+ std::hash<variant<int>> hash;
+ std::set<size_t> hashcodes;
+ for (int i = 0; i < 100; ++i) {
+ hashcodes.insert(hash(i));
+ }
+ EXPECT_GT(hashcodes.size(), 90);
+
+ // test const-qualified
+ static_assert(
+ type_traits_internal::IsHashEnabled<variant<const int>>::value, "");
+ static_assert(
+ type_traits_internal::IsHashEnabled<variant<const Hashable>>::value,
+ "");
+ std::hash<absl::variant<const int>> c_hash;
+ for (int i = 0; i < 100; ++i) {
+ EXPECT_EQ(hash(i), c_hash(i));
+ }
+ }
+}
+
+////////////////////////////////////////
+// Miscellaneous and deprecated tests //
+////////////////////////////////////////
+
+// Test that a set requiring a basic type conversion works correctly.
+TEST(VariantTest, TestConvertingSet) {
+ typedef variant<double> Variant;
+ Variant v(1.0);
+ const int two = 2;
+ v = two;
+ EXPECT_TRUE(absl::holds_alternative<double>(v));
+ ASSERT_TRUE(nullptr != absl::get_if<double>(&v));
+ EXPECT_DOUBLE_EQ(2, absl::get<double>(v));
+}
+
+// Test that a vector of variants behaves reasonably.
+TEST(VariantTest, Container) {
+ typedef variant<int, float> Variant;
+
+ // Creation of vector should work
+ std::vector<Variant> vec;
+ vec.push_back(Variant(10));
+ vec.push_back(Variant(20.0f));
+
+ // Vector resizing should work if we supply a value for new slots
+ vec.resize(10, Variant(0));
+}
+
+// Test that a variant with a non-copyable type can be constructed and
+// manipulated to some degree.
+TEST(VariantTest, TestVariantWithNonCopyableType) {
+ typedef variant<int, NonCopyable> Variant;
+ const int kValue = 1;
+ Variant v(kValue);
+ ASSERT_TRUE(absl::holds_alternative<int>(v));
+ EXPECT_EQ(kValue, absl::get<int>(v));
+}
+
+// Test that a variant with a non-copyable type can be transformed to
+// the non-copyable type with a call to `emplace` for different numbers
+// of arguments. We do not need to test this for each of T1 ... T8
+// because `emplace` does not overload on T1 ... to T8, so if this
+// works for any one of T1 ... T8, then it works for all of them. We
+// do need to test that it works with varying numbers of parameters
+// though.
+TEST(VariantTest, TestEmplace) {
+ typedef variant<int, NonCopyable> Variant;
+ const int kValue = 1;
+ Variant v(kValue);
+ ASSERT_TRUE(absl::holds_alternative<int>(v));
+ EXPECT_EQ(kValue, absl::get<int>(v));
+
+ // emplace with zero arguments, then back to 'int'
+ v.emplace<NonCopyable>();
+ ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
+ EXPECT_EQ(0, absl::get<NonCopyable>(v).value);
+ v = kValue;
+ ASSERT_TRUE(absl::holds_alternative<int>(v));
+
+ // emplace with one argument:
+ v.emplace<NonCopyable>(1);
+ ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
+ EXPECT_EQ(1, absl::get<NonCopyable>(v).value);
+ v = kValue;
+ ASSERT_TRUE(absl::holds_alternative<int>(v));
+
+ // emplace with two arguments:
+ v.emplace<NonCopyable>(1, 2);
+ ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
+ EXPECT_EQ(3, absl::get<NonCopyable>(v).value);
+ v = kValue;
+ ASSERT_TRUE(absl::holds_alternative<int>(v));
+
+ // emplace with three arguments
+ v.emplace<NonCopyable>(1, 2, 3);
+ ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
+ EXPECT_EQ(6, absl::get<NonCopyable>(v).value);
+ v = kValue;
+ ASSERT_TRUE(absl::holds_alternative<int>(v));
+
+ // emplace with four arguments
+ v.emplace<NonCopyable>(1, 2, 3, 4);
+ ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
+ EXPECT_EQ(10, absl::get<NonCopyable>(v).value);
+ v = kValue;
+ ASSERT_TRUE(absl::holds_alternative<int>(v));
+}
+
+TEST(VariantTest, TestEmplaceDestroysCurrentValue) {
+ typedef variant<int, IncrementInDtor, NonCopyable> Variant;
+ int counter = 0;
+ Variant v(0);
+ ASSERT_TRUE(absl::holds_alternative<int>(v));
+ v.emplace<IncrementInDtor>(&counter);
+ ASSERT_TRUE(absl::holds_alternative<IncrementInDtor>(v));
+ ASSERT_EQ(0, counter);
+ v.emplace<NonCopyable>();
+ ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
+ EXPECT_EQ(1, counter);
+}
+
+TEST(VariantTest, TestMoveSemantics) {
+ typedef variant<std::unique_ptr<int>, std::unique_ptr<std::string>> Variant;
+
+ // Construct a variant by moving from an element value.
+ Variant v(absl::WrapUnique(new int(10)));
+ EXPECT_TRUE(absl::holds_alternative<std::unique_ptr<int>>(v));
+
+ // Construct a variant by moving from another variant.
+ Variant v2(absl::move(v));
+ ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<int>>(v2));
+ ASSERT_NE(nullptr, absl::get<std::unique_ptr<int>>(v2));
+ EXPECT_EQ(10, *absl::get<std::unique_ptr<int>>(v2));
+
+ // Moving from a variant object leaves it holding moved-from value of the
+ // same element type.
+ EXPECT_TRUE(absl::holds_alternative<std::unique_ptr<int>>(v));
+ ASSERT_NE(nullptr, absl::get_if<std::unique_ptr<int>>(&v));
+ EXPECT_EQ(nullptr, absl::get<std::unique_ptr<int>>(v));
+
+ // Assign a variant from an element value by move.
+ v = absl::make_unique<std::string>("foo");
+ ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<std::string>>(v));
+ EXPECT_EQ("foo", *absl::get<std::unique_ptr<std::string>>(v));
+
+ // Move-assign a variant.
+ v2 = absl::move(v);
+ ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<std::string>>(v2));
+ EXPECT_EQ("foo", *absl::get<std::unique_ptr<std::string>>(v2));
+ EXPECT_TRUE(absl::holds_alternative<std::unique_ptr<std::string>>(v));
+}
+
+variant<int, std::string> PassThrough(const variant<int, std::string>& arg) {
+ return arg;
+}
+
+TEST(VariantTest, TestImplicitConversion) {
+ EXPECT_TRUE(absl::holds_alternative<int>(PassThrough(0)));
+
+ // We still need the explicit cast for std::string, because C++ won't apply
+ // two user-defined implicit conversions in a row.
+ EXPECT_TRUE(absl::holds_alternative<std::string>(PassThrough(std::string("foo"))));
+}
+
+struct Convertible2;
+struct Convertible1 {
+ Convertible1() {}
+ Convertible1(const Convertible1&) {}
+ Convertible1& operator=(const Convertible1&) { return *this; }
+
+ // implicit conversion from Convertible2
+ Convertible1(const Convertible2&) {} // NOLINT(runtime/explicit)
+};
+
+struct Convertible2 {
+ Convertible2() {}
+ Convertible2(const Convertible2&) {}
+ Convertible2& operator=(const Convertible2&) { return *this; }
+
+ // implicit conversion from Convertible1
+ Convertible2(const Convertible1&) {} // NOLINT(runtime/explicit)
+};
+
+TEST(VariantTest, TestRvalueConversion) {
+ variant<double, std::string> var(
+ ConvertVariantTo<variant<double, std::string>>(variant<std::string, int>(0)));
+ ASSERT_TRUE(absl::holds_alternative<double>(var));
+ EXPECT_EQ(0.0, absl::get<double>(var));
+
+ var = ConvertVariantTo<variant<double, std::string>>(
+ variant<const char*, float>("foo"));
+ ASSERT_TRUE(absl::holds_alternative<std::string>(var));
+ EXPECT_EQ("foo", absl::get<std::string>(var));
+
+ variant<double> singleton(
+ ConvertVariantTo<variant<double>>(variant<int, float>(42)));
+ ASSERT_TRUE(absl::holds_alternative<double>(singleton));
+ EXPECT_EQ(42.0, absl::get<double>(singleton));
+
+ singleton = ConvertVariantTo<variant<double>>(variant<int, float>(3.14f));
+ ASSERT_TRUE(absl::holds_alternative<double>(singleton));
+ EXPECT_FLOAT_EQ(3.14f, static_cast<float>(absl::get<double>(singleton)));
+
+ singleton = ConvertVariantTo<variant<double>>(variant<int>(0));
+ ASSERT_TRUE(absl::holds_alternative<double>(singleton));
+ EXPECT_EQ(0.0, absl::get<double>(singleton));
+
+ variant<int32_t, uint32_t> variant2(
+ ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42)));
+ ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2));
+ EXPECT_EQ(42, absl::get<int32_t>(variant2));
+
+ variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
+ ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2));
+ EXPECT_EQ(42, absl::get<uint32_t>(variant2));
+
+ variant<Convertible1, Convertible2> variant3(
+ ConvertVariantTo<variant<Convertible1, Convertible2>>(
+ (variant<Convertible2, Convertible1>(Convertible1()))));
+ ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3));
+
+ variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>(
+ variant<Convertible2, Convertible1>(Convertible2()));
+ ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3));
+}
+
+TEST(VariantTest, TestLvalueConversion) {
+ variant<std::string, int> source1 = 0;
+ variant<double, std::string> destination(
+ ConvertVariantTo<variant<double, std::string>>(source1));
+ ASSERT_TRUE(absl::holds_alternative<double>(destination));
+ EXPECT_EQ(0.0, absl::get<double>(destination));
+
+ variant<const char*, float> source2 = "foo";
+ destination = ConvertVariantTo<variant<double, std::string>>(source2);
+ ASSERT_TRUE(absl::holds_alternative<std::string>(destination));
+ EXPECT_EQ("foo", absl::get<std::string>(destination));
+
+ variant<int, float> source3(42);
+ variant<double> singleton(ConvertVariantTo<variant<double>>(source3));
+ ASSERT_TRUE(absl::holds_alternative<double>(singleton));
+ EXPECT_EQ(42.0, absl::get<double>(singleton));
+
+ source3 = 3.14f;
+ singleton = ConvertVariantTo<variant<double>>(source3);
+ ASSERT_TRUE(absl::holds_alternative<double>(singleton));
+ EXPECT_FLOAT_EQ(3.14f, static_cast<float>(absl::get<double>(singleton)));
+
+ variant<int> source4(0);
+ singleton = ConvertVariantTo<variant<double>>(source4);
+ ASSERT_TRUE(absl::holds_alternative<double>(singleton));
+ EXPECT_EQ(0.0, absl::get<double>(singleton));
+
+ variant<int32_t> source5(42);
+ variant<int32_t, uint32_t> variant2(
+ ConvertVariantTo<variant<int32_t, uint32_t>>(source5));
+ ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2));
+ EXPECT_EQ(42, absl::get<int32_t>(variant2));
+
+ variant<uint32_t> source6(42);
+ variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(source6);
+ ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2));
+ EXPECT_EQ(42, absl::get<uint32_t>(variant2));
+
+ variant<Convertible2, Convertible1> source7((Convertible1()));
+ variant<Convertible1, Convertible2> variant3(
+ ConvertVariantTo<variant<Convertible1, Convertible2>>(source7));
+ ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3));
+
+ source7 = Convertible2();
+ variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>(source7);
+ ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3));
+}
+
+TEST(VariantTest, TestMoveConversion) {
+ using Variant =
+ variant<std::unique_ptr<const int>, std::unique_ptr<const std::string>>;
+ using OtherVariant = variant<std::unique_ptr<int>, std::unique_ptr<std::string>>;
+
+ Variant var(
+ ConvertVariantTo<Variant>(OtherVariant{absl::make_unique<int>(0)}));
+ ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<const int>>(var));
+ ASSERT_NE(absl::get<std::unique_ptr<const int>>(var), nullptr);
+ EXPECT_EQ(0, *absl::get<std::unique_ptr<const int>>(var));
+
+ var =
+ ConvertVariantTo<Variant>(OtherVariant(absl::make_unique<std::string>("foo")));
+ ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<const std::string>>(var));
+ EXPECT_EQ("foo", *absl::get<std::unique_ptr<const std::string>>(var));
+}
+
+TEST(VariantTest, DoesNotMoveFromLvalues) {
+ // We use shared_ptr here because it's both copyable and movable, and
+ // a moved-from shared_ptr is guaranteed to be null, so we can detect
+ // whether moving or copying has occurred.
+ using Variant =
+ variant<std::shared_ptr<const int>, std::shared_ptr<const std::string>>;
+ using OtherVariant = variant<std::shared_ptr<int>, std::shared_ptr<std::string>>;
+
+ Variant v1(std::make_shared<const int>(0));
+
+ // Test copy constructor
+ Variant v2(v1);
+ EXPECT_EQ(absl::get<std::shared_ptr<const int>>(v1),
+ absl::get<std::shared_ptr<const int>>(v2));
+
+ // Test copy-assignment operator
+ v1 = std::make_shared<const std::string>("foo");
+ v2 = v1;
+ EXPECT_EQ(absl::get<std::shared_ptr<const std::string>>(v1),
+ absl::get<std::shared_ptr<const std::string>>(v2));
+
+ // Test converting copy constructor
+ OtherVariant other(std::make_shared<int>(0));
+ Variant v3(ConvertVariantTo<Variant>(other));
+ EXPECT_EQ(absl::get<std::shared_ptr<int>>(other),
+ absl::get<std::shared_ptr<const int>>(v3));
+
+ other = std::make_shared<std::string>("foo");
+ v3 = ConvertVariantTo<Variant>(other);
+ EXPECT_EQ(absl::get<std::shared_ptr<std::string>>(other),
+ absl::get<std::shared_ptr<const std::string>>(v3));
+}
+
+TEST(VariantTest, TestRvalueConversionViaConvertVariantTo) {
+ variant<double, std::string> var(
+ ConvertVariantTo<variant<double, std::string>>(variant<std::string, int>(3)));
+ EXPECT_THAT(absl::get_if<double>(&var), Pointee(3.0));
+
+ var = ConvertVariantTo<variant<double, std::string>>(
+ variant<const char*, float>("foo"));
+ EXPECT_THAT(absl::get_if<std::string>(&var), Pointee(std::string("foo")));
+
+ variant<double> singleton(
+ ConvertVariantTo<variant<double>>(variant<int, float>(42)));
+ EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(42.0));
+
+ singleton = ConvertVariantTo<variant<double>>(variant<int, float>(3.14f));
+ EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(DoubleEq(3.14f)));
+
+ singleton = ConvertVariantTo<variant<double>>(variant<int>(3));
+ EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(3.0));
+
+ variant<int32_t, uint32_t> variant2(
+ ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42)));
+ EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42));
+
+ variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
+ EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42));
+
+ variant<Convertible1, Convertible2> variant3(
+ ConvertVariantTo<variant<Convertible1, Convertible2>>(
+ (variant<Convertible2, Convertible1>(Convertible1()))));
+ ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3));
+
+ variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>(
+ variant<Convertible2, Convertible1>(Convertible2()));
+ ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3));
+}
+
+TEST(VariantTest, TestLvalueConversionViaConvertVariantTo) {
+ variant<std::string, int> source1 = 3;
+ variant<double, std::string> destination(
+ ConvertVariantTo<variant<double, std::string>>(source1));
+ EXPECT_THAT(absl::get_if<double>(&destination), Pointee(3.0));
+
+ variant<const char*, float> source2 = "foo";
+ destination = ConvertVariantTo<variant<double, std::string>>(source2);
+ EXPECT_THAT(absl::get_if<std::string>(&destination), Pointee(std::string("foo")));
+
+ variant<int, float> source3(42);
+ variant<double> singleton(ConvertVariantTo<variant<double>>(source3));
+ EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(42.0));
+
+ source3 = 3.14f;
+ singleton = ConvertVariantTo<variant<double>>(source3);
+ EXPECT_FLOAT_EQ(3.14f, static_cast<float>(absl::get<double>(singleton)));
+ EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(DoubleEq(3.14f)));
+
+ variant<int> source4(3);
+ singleton = ConvertVariantTo<variant<double>>(source4);
+ EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(3.0));
+
+ variant<int32_t> source5(42);
+ variant<int32_t, uint32_t> variant2(
+ ConvertVariantTo<variant<int32_t, uint32_t>>(source5));
+ EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42));
+
+ variant<uint32_t> source6(42);
+ variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(source6);
+ EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42));
+
+ variant<Convertible2, Convertible1> source7((Convertible1()));
+ variant<Convertible1, Convertible2> variant3(
+ ConvertVariantTo<variant<Convertible1, Convertible2>>(source7));
+ ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3));
+
+ source7 = Convertible2();
+ variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>(source7);
+ ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3));
+}
+
+TEST(VariantTest, TestMoveConversionViaConvertVariantTo) {
+ using Variant =
+ variant<std::unique_ptr<const int>, std::unique_ptr<const std::string>>;
+ using OtherVariant = variant<std::unique_ptr<int>, std::unique_ptr<std::string>>;
+
+ Variant var(
+ ConvertVariantTo<Variant>(OtherVariant{absl::make_unique<int>(3)}));
+ EXPECT_THAT(absl::get_if<std::unique_ptr<const int>>(&var),
+ Pointee(Pointee(3)));
+
+ var =
+ ConvertVariantTo<Variant>(OtherVariant(absl::make_unique<std::string>("foo")));
+ EXPECT_THAT(absl::get_if<std::unique_ptr<const std::string>>(&var),
+ Pointee(Pointee(std::string("foo"))));
+}
+
+// If all alternatives are trivially copy/move constructible, variant should
+// also be trivially copy/move constructible. This is not required by the
+// standard and we know that libstdc++ variant doesn't have this feature.
+// For more details see the paper:
+// http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0602r0.html
+#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+#define ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY 1
+#endif
+
+TEST(VariantTest, TestCopyAndMoveTypeTraits) {
+ EXPECT_TRUE(std::is_copy_constructible<variant<std::string>>::value);
+ EXPECT_TRUE(std::is_copy_assignable<variant<std::string>>::value);
+ EXPECT_TRUE(std::is_move_constructible<variant<std::string>>::value);
+ EXPECT_TRUE(std::is_move_assignable<variant<std::string>>::value);
+ EXPECT_TRUE(std::is_move_constructible<variant<std::unique_ptr<int>>>::value);
+ EXPECT_TRUE(std::is_move_assignable<variant<std::unique_ptr<int>>>::value);
+ EXPECT_FALSE(
+ std::is_copy_constructible<variant<std::unique_ptr<int>>>::value);
+ EXPECT_FALSE(std::is_copy_assignable<variant<std::unique_ptr<int>>>::value);
+
+ EXPECT_FALSE(
+ absl::is_trivially_copy_constructible<variant<std::string>>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_assignable<variant<std::string>>::value);
+#if ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<variant<int>>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<variant<int>>::value);
+ EXPECT_TRUE(is_trivially_move_constructible<variant<int>>::value);
+ EXPECT_TRUE(is_trivially_move_assignable<variant<int>>::value);
+#endif // ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
+}
+
+TEST(VariantTest, TestVectorOfMoveonlyVariant) {
+ // Verify that variant<MoveonlyType> works correctly as a std::vector element.
+ std::vector<variant<std::unique_ptr<int>, std::string>> vec;
+ vec.push_back(absl::make_unique<int>(42));
+ vec.emplace_back("Hello");
+ vec.reserve(3);
+ auto another_vec = absl::move(vec);
+ // As a sanity check, verify vector contents.
+ ASSERT_EQ(2, another_vec.size());
+ EXPECT_EQ(42, *absl::get<std::unique_ptr<int>>(another_vec[0]));
+ EXPECT_EQ("Hello", absl::get<std::string>(another_vec[1]));
+}
+
+TEST(VariantTest, NestedVariant) {
+#if ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
+ static_assert(absl::is_trivially_copy_constructible<variant<int>>(), "");
+ static_assert(absl::is_trivially_copy_assignable<variant<int>>(), "");
+ static_assert(is_trivially_move_constructible<variant<int>>(), "");
+ static_assert(is_trivially_move_assignable<variant<int>>(), "");
+
+ static_assert(absl::is_trivially_copy_constructible<variant<variant<int>>>(),
+ "");
+ static_assert(absl::is_trivially_copy_assignable<variant<variant<int>>>(),
+ "");
+ static_assert(is_trivially_move_constructible<variant<variant<int>>>(), "");
+ static_assert(is_trivially_move_assignable<variant<variant<int>>>(), "");
+#endif // ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
+
+ variant<int> x(42);
+ variant<variant<int>> y(x);
+ variant<variant<int>> z(y);
+ EXPECT_TRUE(absl::holds_alternative<variant<int>>(z));
+ EXPECT_EQ(x, absl::get<variant<int>>(z));
+}
+
+struct TriviallyDestructible {
+ TriviallyDestructible(TriviallyDestructible&&) {}
+ TriviallyDestructible(const TriviallyDestructible&) {}
+ TriviallyDestructible& operator=(TriviallyDestructible&&) { return *this; }
+ TriviallyDestructible& operator=(const TriviallyDestructible&) {
+ return *this;
+ }
+};
+
+struct TriviallyMovable {
+ TriviallyMovable(TriviallyMovable&&) = default;
+ TriviallyMovable(TriviallyMovable const&) {}
+ TriviallyMovable& operator=(const TriviallyMovable&) { return *this; }
+};
+
+struct TriviallyCopyable {
+ TriviallyCopyable(const TriviallyCopyable&) = default;
+ TriviallyCopyable& operator=(const TriviallyCopyable&) { return *this; }
+};
+
+struct TriviallyMoveAssignable {
+ TriviallyMoveAssignable(TriviallyMoveAssignable&&) = default;
+ TriviallyMoveAssignable(const TriviallyMoveAssignable&) {}
+ TriviallyMoveAssignable& operator=(TriviallyMoveAssignable&&) = default;
+ TriviallyMoveAssignable& operator=(const TriviallyMoveAssignable&) {
+ return *this;
+ }
+};
+
+struct TriviallyCopyAssignable {};
+
+#if ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
+TEST(VariantTest, TestTriviality) {
+ {
+ using TrivDestVar = absl::variant<TriviallyDestructible>;
+
+ EXPECT_FALSE(is_trivially_move_constructible<TrivDestVar>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_constructible<TrivDestVar>::value);
+ EXPECT_FALSE(is_trivially_move_assignable<TrivDestVar>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivDestVar>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<TrivDestVar>::value);
+ }
+
+ {
+ using TrivMoveVar = absl::variant<TriviallyMovable>;
+
+ EXPECT_TRUE(is_trivially_move_constructible<TrivMoveVar>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_constructible<TrivMoveVar>::value);
+ EXPECT_FALSE(is_trivially_move_assignable<TrivMoveVar>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivMoveVar>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<TrivMoveVar>::value);
+ }
+
+ {
+ using TrivCopyVar = absl::variant<TriviallyCopyable>;
+
+ EXPECT_TRUE(is_trivially_move_constructible<TrivCopyVar>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<TrivCopyVar>::value);
+ EXPECT_FALSE(is_trivially_move_assignable<TrivCopyVar>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivCopyVar>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<TrivCopyVar>::value);
+ }
+
+ {
+ using TrivMoveAssignVar = absl::variant<TriviallyMoveAssignable>;
+
+ EXPECT_TRUE(is_trivially_move_constructible<TrivMoveAssignVar>::value);
+ EXPECT_FALSE(
+ absl::is_trivially_copy_constructible<TrivMoveAssignVar>::value);
+ EXPECT_TRUE(is_trivially_move_assignable<TrivMoveAssignVar>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivMoveAssignVar>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<TrivMoveAssignVar>::value);
+ }
+
+ {
+ using TrivCopyAssignVar = absl::variant<TriviallyCopyAssignable>;
+
+ EXPECT_TRUE(is_trivially_move_constructible<TrivCopyAssignVar>::value);
+ EXPECT_TRUE(
+ absl::is_trivially_copy_constructible<TrivCopyAssignVar>::value);
+ EXPECT_TRUE(is_trivially_move_assignable<TrivCopyAssignVar>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<TrivCopyAssignVar>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<TrivCopyAssignVar>::value);
+ }
+}
+#endif // ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
+
+// To verify that absl::variant correctly use the nontrivial move ctor of its
+// member rather than use the trivial copy constructor.
+TEST(VariantTest, MoveCtorBug) {
+ // To simulate std::tuple in libstdc++.
+ struct TrivialCopyNontrivialMove {
+ TrivialCopyNontrivialMove() = default;
+ TrivialCopyNontrivialMove(const TrivialCopyNontrivialMove&) = default;
+ TrivialCopyNontrivialMove(TrivialCopyNontrivialMove&&) { called = true; }
+ bool called = false;
+ };
+ {
+ using V = absl::variant<TrivialCopyNontrivialMove, int>;
+ V v1(absl::in_place_index_t<0>{});
+ // this should invoke the move ctor, rather than the trivial copy ctor.
+ V v2(std::move(v1));
+ EXPECT_TRUE(absl::get<0>(v2).called);
+ }
+ {
+ // this case failed to compile before our fix due to a GCC bug.
+ using V = absl::variant<int, TrivialCopyNontrivialMove>;
+ V v1(absl::in_place_index_t<1>{});
+ // this should invoke the move ctor, rather than the trivial copy ctor.
+ V v2(std::move(v1));
+ EXPECT_TRUE(absl::get<1>(v2).called);
+ }
+}
+
+} // namespace
+} // namespace absl
diff --git a/absl/utility/utility.h b/absl/utility/utility.h
index 1943c4ac..5b9b84e0 100644
--- a/absl/utility/utility.h
+++ b/absl/utility/utility.h
@@ -161,7 +161,7 @@ ABSL_INTERNAL_INLINE_CONSTEXPR(in_place_t, in_place, {});
#endif // ABSL_HAVE_STD_OPTIONAL
-#ifdef ABSL_HAVE_STD_ANY
+#if defined(ABSL_HAVE_STD_ANY) || defined(ABSL_HAVE_STD_VARIANT)
using std::in_place_type_t;
#else
@@ -172,7 +172,11 @@ using std::in_place_type_t;
// for C++17's `std::in_place_type_t`.
template <typename T>
struct in_place_type_t {};
-#endif // ABSL_HAVE_STD_ANY
+#endif // ABSL_HAVE_STD_ANY || ABSL_HAVE_STD_VARIANT
+
+#ifdef ABSL_HAVE_STD_VARIANT
+using std::in_place_index_t;
+#else
// in_place_index_t
//
@@ -181,6 +185,7 @@ struct in_place_type_t {};
// for C++17's `std::in_place_index_t`.
template <size_t I>
struct in_place_index_t {};
+#endif // ABSL_HAVE_STD_VARIANT
// Constexpr move and forward