diff options
author | Abseil Team <absl-team@google.com> | 2018-04-20 09:16:52 -0700 |
---|---|---|
committer | Jon Cohen <cohenjon@google.com> | 2018-04-20 12:30:23 -0400 |
commit | faf0a1b90374eab44e8956973b0e13febdcf3377 (patch) | |
tree | 63a7fd12a50b15c4a321e8373c1bbd975df0b7ba | |
parent | 5b535401665cc6aa96d54a5c9b0901153d97210f (diff) |
- 551e205ef49682a1cb7e6e0cda46957fbcf88edd Release absl::variant. by Xiaoyi Zhang <zhangxy@google.com>
- 01c52f640594d073c6e54c47e7853b25522cf085 Update comments in absl::variant (and minor changes to ab... by Tom Manshreck <shreck@google.com>
- 064465e1e6b158abd8c38fd1942b4fc464b57d6a Documentation change. by Abseil Team <absl-team@google.com>
- 58df2c8a27e80c9ea21d87c1acee8019246377c9 Relocates SetCountdown and UnsetCountdown to the exceptio... by Abseil Team <absl-team@google.com>
- fd9d248d0948d472f2543f7fd9c0ae4a1cd60d01 Clarify thread_annotation.h documentation around local va... by Abseil Team <absl-team@google.com>
- 0d0abaf7f0945ac5f2c5f49e78afe1b326d5aca0 Typo fix in comments. by Abseil Team <absl-team@google.com>
- 67286d587cbd07508a81e5b8147c245a5b5538b4 Internal change. by Xiaoyi Zhang <zhangxy@google.com>
GitOrigin-RevId: 551e205ef49682a1cb7e6e0cda46957fbcf88edd
Change-Id: I1a343b080187293cb5f892a309618b5712e7aa14
-rw-r--r-- | absl/base/config.h | 24 | ||||
-rw-r--r-- | absl/base/exception_safety_testing_test.cc | 4 | ||||
-rw-r--r-- | absl/base/internal/exception_safety_testing.h | 19 | ||||
-rw-r--r-- | absl/base/thread_annotations.h | 31 | ||||
-rw-r--r-- | absl/meta/type_traits.h | 19 | ||||
-rw-r--r-- | absl/strings/str_join.h | 2 | ||||
-rw-r--r-- | absl/time/time.h | 23 | ||||
-rw-r--r-- | absl/types/BUILD.bazel | 42 | ||||
-rw-r--r-- | absl/types/CMakeLists.txt | 15 | ||||
-rw-r--r-- | absl/types/any.h | 4 | ||||
-rw-r--r-- | absl/types/bad_any_cast.h | 33 | ||||
-rw-r--r-- | absl/types/bad_optional_access.h | 25 | ||||
-rw-r--r-- | absl/types/bad_variant_access.cc | 58 | ||||
-rw-r--r-- | absl/types/bad_variant_access.h | 64 | ||||
-rw-r--r-- | absl/types/internal/variant.h | 1387 | ||||
-rw-r--r-- | absl/types/optional.h | 5 | ||||
-rw-r--r-- | absl/types/variant.h | 838 | ||||
-rw-r--r-- | absl/types/variant_test.cc | 2622 | ||||
-rw-r--r-- | absl/utility/utility.h | 9 |
19 files changed, 5172 insertions, 52 deletions
diff --git a/absl/base/config.h b/absl/base/config.h index 500bc8c8..3eb24abf 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 ac5d8e1c..bb1b0baf 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 760a160e..68bc288b 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 |