Remove the implementation of `absl::optional`, which was only needed prior to C++17. `absl::optional` is now an alias for `std::optional`. It is recommended that clients simply use `std::optional`. PiperOrigin-RevId: 729860560 Change-Id: I8f3a23ed46c451cb441771cc544df79e6c326b67
diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index de8bc27..789acf0 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake
@@ -430,14 +430,11 @@ "time/internal/cctz/src/tzfile.h" "time/internal/cctz/src/zone_info_source.cc" "types/any.h" - "types/bad_optional_access.cc" - "types/bad_optional_access.h" "types/bad_variant_access.cc" "types/bad_variant_access.h" "types/compare.h" "types/internal/variant.h" "types/optional.h" - "types/internal/optional.h" "types/span.h" "types/internal/span.h" "types/variant.h" @@ -491,7 +488,6 @@ "any" "any_invocable" "atomic_hook" - "bad_optional_access" "bad_variant_access" "base" "base_internal"
diff --git a/absl/base/config.h b/absl/base/config.h index f5cd03a..510c485 100644 --- a/absl/base/config.h +++ b/absl/base/config.h
@@ -519,22 +519,11 @@ #define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0 #endif -// ABSL_HAVE_STD_ANY/ABSL_USES_STD_ANY +// Deprecated macros for polyfill detection. #define ABSL_HAVE_STD_ANY 1 #define ABSL_USES_STD_ANY 1 - -// ABSL_HAVE_STD_OPTIONAL -// -// Checks whether C++17 std::optional is available. -#ifdef ABSL_HAVE_STD_OPTIONAL -#error "ABSL_HAVE_STD_OPTIONAL cannot be directly set." -#elif defined(__cpp_lib_optional) && __cpp_lib_optional >= 201606L #define ABSL_HAVE_STD_OPTIONAL 1 -#elif defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ - ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L && \ - !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE -#define ABSL_HAVE_STD_OPTIONAL 1 -#endif +#define ABSL_USES_STD_OPTIONAL 1 // ABSL_HAVE_STD_VARIANT // @@ -577,21 +566,6 @@ #define ABSL_HAVE_STD_ORDERING 1 #endif -// ABSL_USES_STD_OPTIONAL -// -// Indicates whether absl::optional is an alias for std::optional. -#if !defined(ABSL_OPTION_USE_STD_OPTIONAL) -#error options.h is misconfigured. -#elif ABSL_OPTION_USE_STD_OPTIONAL == 0 || \ - (ABSL_OPTION_USE_STD_OPTIONAL == 2 && !defined(ABSL_HAVE_STD_OPTIONAL)) -#undef ABSL_USES_STD_OPTIONAL -#elif ABSL_OPTION_USE_STD_OPTIONAL == 1 || \ - (ABSL_OPTION_USE_STD_OPTIONAL == 2 && defined(ABSL_HAVE_STD_OPTIONAL)) -#define ABSL_USES_STD_OPTIONAL 1 -#else -#error options.h is misconfigured. -#endif - // ABSL_USES_STD_VARIANT // // Indicates whether absl::variant is an alias for std::variant.
diff --git a/absl/base/options.h b/absl/base/options.h index 582c4fd..593b952 100644 --- a/absl/base/options.h +++ b/absl/base/options.h
@@ -73,33 +73,6 @@ // Type Compatibility Options // ----------------------------------------------------------------------------- -// ABSL_OPTION_USE_STD_OPTIONAL -// -// This option controls whether absl::optional is implemented as an alias to -// std::optional, or as an independent implementation. -// -// A value of 0 means to use Abseil's implementation. This requires only C++11 -// support, and is expected to work on every toolchain we support. -// -// A value of 1 means to use an alias to std::optional. This requires that all -// code using Abseil is built in C++17 mode or later. -// -// A value of 2 means to detect the C++ version being used to compile Abseil, -// and use an alias only if a working std::optional is available. This option -// is useful when you are building your program from source. It should not be -// used otherwise -- for example, if you are distributing Abseil in a binary -// package manager -- since in mode 2, absl::optional will name a different -// type, with a different mangled name and binary layout, depending on the -// compiler flags passed by the end user. For more info, see -// https://abseil.io/about/design/dropin-types. - -// User code should not inspect this macro. To check in the preprocessor if -// absl::optional is a typedef of std::optional, use the feature macro -// ABSL_USES_STD_OPTIONAL. - -#define ABSL_OPTION_USE_STD_OPTIONAL 2 - - // ABSL_OPTION_USE_STD_STRING_VIEW // // This option controls whether absl::string_view is implemented as an alias to
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel index 564d69a..6160daa 100644 --- a/absl/types/BUILD.bazel +++ b/absl/types/BUILD.bazel
@@ -91,32 +91,18 @@ cc_library( name = "optional", - srcs = ["internal/optional.h"], hdrs = ["optional.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ - ":bad_optional_access", - "//absl/base:base_internal", "//absl/base:config", - "//absl/base:core_headers", - "//absl/base:nullability", - "//absl/memory", - "//absl/meta:type_traits", "//absl/utility", ], ) cc_library( name = "bad_optional_access", - srcs = ["bad_optional_access.cc"], - hdrs = ["bad_optional_access.h"], - copts = ABSL_DEFAULT_COPTS, - linkopts = ABSL_DEFAULT_LINKOPTS, - deps = [ - "//absl/base:config", - "//absl/base:raw_logging_internal", - ], + deprecation = "bad_optional_access dependency is empty can be removed", ) cc_library( @@ -131,41 +117,6 @@ ], ) -cc_test( - name = "optional_test", - size = "small", - srcs = [ - "optional_test.cc", - ], - copts = ABSL_TEST_COPTS, - linkopts = ABSL_DEFAULT_LINKOPTS, - deps = [ - ":optional", - "//absl/base:config", - "//absl/log", - "//absl/meta:type_traits", - "//absl/strings", - "@googletest//:gtest", - "@googletest//:gtest_main", - ], -) - -cc_test( - name = "optional_exception_safety_test", - srcs = [ - "optional_exception_safety_test.cc", - ], - copts = ABSL_TEST_COPTS, - linkopts = ABSL_DEFAULT_LINKOPTS, - deps = [ - ":optional", - "//absl/base:config", - "//absl/base:exception_safety_testing", - "@googletest//:gtest", - "@googletest//:gtest_main", - ], -) - cc_library( name = "variant", srcs = ["internal/variant.h"],
diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt index 3c1f19e..a18bf3d 100644 --- a/absl/types/CMakeLists.txt +++ b/absl/types/CMakeLists.txt
@@ -92,39 +92,16 @@ optional HDRS "optional.h" - SRCS - "internal/optional.h" COPTS ${ABSL_DEFAULT_COPTS} DEPS - absl::bad_optional_access - absl::base_internal absl::config - absl::core_headers - absl::memory - absl::nullability - absl::type_traits absl::utility PUBLIC ) absl_cc_library( NAME - bad_optional_access - HDRS - "bad_optional_access.h" - SRCS - "bad_optional_access.cc" - COPTS - ${ABSL_DEFAULT_COPTS} - DEPS - absl::config - absl::raw_logging_internal - PUBLIC -) - -absl_cc_library( - NAME bad_variant_access HDRS "bad_variant_access.h" @@ -138,36 +115,6 @@ PUBLIC ) -absl_cc_test( - NAME - optional_test - SRCS - "optional_test.cc" - COPTS - ${ABSL_TEST_COPTS} - DEPS - absl::optional - absl::config - absl::log - absl::strings - absl::type_traits - GTest::gmock_main -) - -absl_cc_test( - NAME - optional_exception_safety_test - SRCS - "optional_exception_safety_test.cc" - COPTS - ${ABSL_TEST_COPTS} - DEPS - absl::optional - absl::config - absl::exception_safety_testing - GTest::gmock_main -) - absl_cc_library( NAME variant
diff --git a/absl/types/bad_optional_access.cc b/absl/types/bad_optional_access.cc deleted file mode 100644 index 2552cc8..0000000 --- a/absl/types/bad_optional_access.cc +++ /dev/null
@@ -1,66 +0,0 @@ -// 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 -// -// https://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_optional_access.h" - -#ifndef ABSL_USES_STD_OPTIONAL - -#include <cstdlib> - -#include "absl/base/config.h" -#include "absl/base/internal/raw_logging.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN - -bad_optional_access::~bad_optional_access() = default; - -const char* bad_optional_access::what() const noexcept { - return "optional has no value"; -} - -namespace optional_internal { - -void throw_bad_optional_access() { -#ifdef ABSL_HAVE_EXCEPTIONS - throw bad_optional_access(); -#else - ABSL_RAW_LOG(FATAL, "Bad optional access"); - abort(); -#endif -} - -} // namespace optional_internal -ABSL_NAMESPACE_END -} // namespace absl - -#else - -// https://github.com/abseil/abseil-cpp/issues/1465 -// CMake builds on Apple platforms error when libraries are empty. -// Our CMake configuration can avoid this error on header-only libraries, -// but since this library is conditionally empty, including a single -// variable is an easy workaround. -#ifdef __APPLE__ -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace types_internal { -extern const char kAvoidEmptyBadOptionalAccessLibraryWarning; -const char kAvoidEmptyBadOptionalAccessLibraryWarning = 0; -} // namespace types_internal -ABSL_NAMESPACE_END -} // namespace absl -#endif // __APPLE__ - -#endif // ABSL_USES_STD_OPTIONAL
diff --git a/absl/types/bad_optional_access.h b/absl/types/bad_optional_access.h deleted file mode 100644 index 049e72a..0000000 --- a/absl/types/bad_optional_access.h +++ /dev/null
@@ -1,78 +0,0 @@ -// 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 -// -// https://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_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_ - -#include <stdexcept> - -#include "absl/base/config.h" - -#ifdef ABSL_USES_STD_OPTIONAL - -#include <optional> - -namespace absl { -ABSL_NAMESPACE_BEGIN -using std::bad_optional_access; -ABSL_NAMESPACE_END -} // namespace absl - -#else // ABSL_USES_STD_OPTIONAL - -namespace absl { -ABSL_NAMESPACE_BEGIN - -// ----------------------------------------------------------------------------- -// 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; - ~bad_optional_access() override; - const char* what() const noexcept override; -}; - -namespace optional_internal { - -// throw delegator -[[noreturn]] ABSL_DLL void throw_bad_optional_access(); - -} // namespace optional_internal -ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_USES_STD_OPTIONAL - -#endif // ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
diff --git a/absl/types/internal/optional.h b/absl/types/internal/optional.h deleted file mode 100644 index 660bdfc..0000000 --- a/absl/types/internal/optional.h +++ /dev/null
@@ -1,351 +0,0 @@ -// 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 -// -// https://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. -// -#ifndef ABSL_TYPES_INTERNAL_OPTIONAL_H_ -#define ABSL_TYPES_INTERNAL_OPTIONAL_H_ - -#include <functional> -#include <new> -#include <type_traits> -#include <utility> - -#include "absl/memory/memory.h" -#include "absl/meta/type_traits.h" -#include "absl/utility/utility.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN - -// Forward declaration -template <typename T> -class optional; - -namespace optional_internal { - -// This tag type is used as a constructor parameter type for `nullopt_t`. -struct init_t { - explicit init_t() = default; -}; - -struct empty_struct {}; - -// This class stores the data in optional<T>. -// It is specialized based on whether T is trivially destructible. -// This is the specialization for non trivially destructible type. -template <typename T, bool unused = std::is_trivially_destructible<T>::value> -class optional_data_dtor_base { - struct dummy_type { - static_assert(sizeof(T) % sizeof(empty_struct) == 0, ""); - // Use an array to avoid GCC 6 placement-new warning. - empty_struct data[sizeof(T) / sizeof(empty_struct)]; - }; - - protected: - // Whether there is data or not. - bool engaged_; - // Data storage - union { - T data_; - dummy_type dummy_; - }; - - void destruct() noexcept { - if (engaged_) { - // `data_` must be initialized if `engaged_` is true. -#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#endif - data_.~T(); -#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0) -#pragma GCC diagnostic pop -#endif - engaged_ = false; - } - } - - // dummy_ must be initialized for constexpr constructor. - constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {} - - template <typename... Args> - constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args) - : engaged_(true), data_(std::forward<Args>(args)...) {} - - ~optional_data_dtor_base() { destruct(); } -}; - -// Specialization for trivially destructible type. -template <typename T> -class optional_data_dtor_base<T, true> { - struct dummy_type { - static_assert(sizeof(T) % sizeof(empty_struct) == 0, ""); - // Use array to avoid GCC 6 placement-new warning. - empty_struct data[sizeof(T) / sizeof(empty_struct)]; - }; - - protected: - // Whether there is data or not. - bool engaged_; - // Data storage - union { - T data_; - dummy_type dummy_; - }; - void destruct() noexcept { engaged_ = false; } - - // dummy_ must be initialized for constexpr constructor. - constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {} - - template <typename... Args> - constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args) - : engaged_(true), data_(std::forward<Args>(args)...) {} -}; - -template <typename T> -class optional_data_base : public optional_data_dtor_base<T> { - protected: - using base = optional_data_dtor_base<T>; - using base::base; - - template <typename... Args> - void construct(Args&&... args) { - // Use dummy_'s address to work around casting cv-qualified T* to void*. - ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...); - this->engaged_ = true; - } - - template <typename U> - void assign(U&& u) { - if (this->engaged_) { - this->data_ = std::forward<U>(u); - } else { - construct(std::forward<U>(u)); - } - } -}; - -// TODO(absl-team): Add another class using -// std::is_trivially_move_constructible trait when available to match -// http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that -// have trivial move but nontrivial copy. -// Also, we should be checking is_trivially_copyable here, which is not -// supported now, so we use is_trivially_* traits instead. -template <typename T, - bool unused = absl::is_trivially_copy_constructible<T>::value&& - absl::is_trivially_copy_assignable<typename std::remove_cv< - T>::type>::value&& std::is_trivially_destructible<T>::value> -class optional_data; - -// Trivially copyable types -template <typename T> -class optional_data<T, true> : public optional_data_base<T> { - protected: - using optional_data_base<T>::optional_data_base; -}; - -template <typename T> -class optional_data<T, false> : public optional_data_base<T> { - protected: - using optional_data_base<T>::optional_data_base; - - optional_data() = default; - - optional_data(const optional_data& rhs) : optional_data_base<T>() { - if (rhs.engaged_) { - this->construct(rhs.data_); - } - } - - optional_data(optional_data&& rhs) noexcept( - absl::default_allocator_is_nothrow::value || - std::is_nothrow_move_constructible<T>::value) - : optional_data_base<T>() { - if (rhs.engaged_) { - this->construct(std::move(rhs.data_)); - } - } - - optional_data& operator=(const optional_data& rhs) { - if (rhs.engaged_) { - this->assign(rhs.data_); - } else { - this->destruct(); - } - return *this; - } - - optional_data& operator=(optional_data&& rhs) noexcept( - std::is_nothrow_move_assignable<T>::value&& - std::is_nothrow_move_constructible<T>::value) { - if (rhs.engaged_) { - this->assign(std::move(rhs.data_)); - } else { - this->destruct(); - } - return *this; - } -}; - -// Ordered by level of restriction, from low to high. -// Copyable implies movable. -enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 }; - -// Base class for enabling/disabling copy/move constructor. -template <copy_traits> -class optional_ctor_base; - -template <> -class optional_ctor_base<copy_traits::copyable> { - public: - constexpr optional_ctor_base() = default; - optional_ctor_base(const optional_ctor_base&) = default; - optional_ctor_base(optional_ctor_base&&) = default; - optional_ctor_base& operator=(const optional_ctor_base&) = default; - optional_ctor_base& operator=(optional_ctor_base&&) = default; -}; - -template <> -class optional_ctor_base<copy_traits::movable> { - public: - constexpr optional_ctor_base() = default; - optional_ctor_base(const optional_ctor_base&) = delete; - optional_ctor_base(optional_ctor_base&&) = default; - optional_ctor_base& operator=(const optional_ctor_base&) = default; - optional_ctor_base& operator=(optional_ctor_base&&) = default; -}; - -template <> -class optional_ctor_base<copy_traits::non_movable> { - public: - constexpr optional_ctor_base() = default; - optional_ctor_base(const optional_ctor_base&) = delete; - optional_ctor_base(optional_ctor_base&&) = delete; - optional_ctor_base& operator=(const optional_ctor_base&) = default; - optional_ctor_base& operator=(optional_ctor_base&&) = default; -}; - -// Base class for enabling/disabling copy/move assignment. -template <copy_traits> -class optional_assign_base; - -template <> -class optional_assign_base<copy_traits::copyable> { - public: - constexpr optional_assign_base() = default; - optional_assign_base(const optional_assign_base&) = default; - optional_assign_base(optional_assign_base&&) = default; - optional_assign_base& operator=(const optional_assign_base&) = default; - optional_assign_base& operator=(optional_assign_base&&) = default; -}; - -template <> -class optional_assign_base<copy_traits::movable> { - public: - constexpr optional_assign_base() = default; - optional_assign_base(const optional_assign_base&) = default; - optional_assign_base(optional_assign_base&&) = default; - optional_assign_base& operator=(const optional_assign_base&) = delete; - optional_assign_base& operator=(optional_assign_base&&) = default; -}; - -template <> -class optional_assign_base<copy_traits::non_movable> { - public: - constexpr optional_assign_base() = default; - optional_assign_base(const optional_assign_base&) = default; - optional_assign_base(optional_assign_base&&) = default; - optional_assign_base& operator=(const optional_assign_base&) = delete; - optional_assign_base& operator=(optional_assign_base&&) = delete; -}; - -template <typename T> -struct ctor_copy_traits { - static constexpr copy_traits traits = - std::is_copy_constructible<T>::value - ? copy_traits::copyable - : std::is_move_constructible<T>::value ? copy_traits::movable - : copy_traits::non_movable; -}; - -template <typename T> -struct assign_copy_traits { - static constexpr copy_traits traits = - absl::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value - ? copy_traits::copyable - : absl::is_move_assignable<T>::value && - std::is_move_constructible<T>::value - ? copy_traits::movable - : copy_traits::non_movable; -}; - -// Whether T is constructible or convertible from optional<U>. -template <typename T, typename U> -struct is_constructible_convertible_from_optional - : std::integral_constant< - bool, std::is_constructible<T, optional<U>&>::value || - std::is_constructible<T, optional<U>&&>::value || - std::is_constructible<T, const optional<U>&>::value || - std::is_constructible<T, const optional<U>&&>::value || - std::is_convertible<optional<U>&, T>::value || - std::is_convertible<optional<U>&&, T>::value || - std::is_convertible<const optional<U>&, T>::value || - std::is_convertible<const optional<U>&&, T>::value> {}; - -// Whether T is constructible or convertible or assignable from optional<U>. -template <typename T, typename U> -struct is_constructible_convertible_assignable_from_optional - : std::integral_constant< - bool, is_constructible_convertible_from_optional<T, U>::value || - std::is_assignable<T&, optional<U>&>::value || - std::is_assignable<T&, optional<U>&&>::value || - std::is_assignable<T&, const optional<U>&>::value || - std::is_assignable<T&, const optional<U>&&>::value> {}; - -// Helper function used by [optional.relops], [optional.comp_with_t], -// for checking whether an expression is convertible to bool. -bool convertible_to_bool(bool); - -// Base class for std::hash<absl::optional<T>>: -// If std::hash<std::remove_const_t<T>> is enabled, it provides operator() to -// compute the hash; Otherwise, it is disabled. -// Reference N4659 23.14.15 [unord.hash]. -template <typename T, typename = size_t> -struct optional_hash_base { - optional_hash_base() = delete; - optional_hash_base(const optional_hash_base&) = delete; - optional_hash_base(optional_hash_base&&) = delete; - optional_hash_base& operator=(const optional_hash_base&) = delete; - optional_hash_base& operator=(optional_hash_base&&) = delete; -}; - -template <typename T> -struct optional_hash_base<T, decltype(std::hash<absl::remove_const_t<T> >()( - std::declval<absl::remove_const_t<T> >()))> { - using argument_type = absl::optional<T>; - using result_type = size_t; - size_t operator()(const absl::optional<T>& opt) const { - absl::type_traits_internal::AssertHashEnabled<absl::remove_const_t<T>>(); - if (opt) { - return std::hash<absl::remove_const_t<T> >()(*opt); - } else { - return static_cast<size_t>(0x297814aaad196e6dULL); - } - } -}; - -} // namespace optional_internal -ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_TYPES_INTERNAL_OPTIONAL_H_
diff --git a/absl/types/optional.h b/absl/types/optional.h index 97ac02e..65bba64 100644 --- a/absl/types/optional.h +++ b/absl/types/optional.h
@@ -16,32 +16,18 @@ // optional.h // ----------------------------------------------------------------------------- // -// This header file defines the `absl::optional` type for holding a value which -// may or may not be present. This type is useful for providing value semantics -// for operations that may either wish to return or hold "something-or-nothing". -// -// Example: -// -// // A common way to signal operation failure is to provide an output -// // parameter and a bool return type: -// bool AcquireResource(const Input&, Resource * out); -// -// // Providing an absl::optional return type provides a cleaner API: -// absl::optional<Resource> AcquireResource(const Input&); -// -// `absl::optional` is a C++11 compatible version of the C++17 `std::optional` -// abstraction and is designed to be a drop-in replacement for code compliant -// with C++17. +// Historical note: Abseil once provided an implementation of `absl::optional` +// as a polyfill for `std::optional` prior to C++17. Now that C++17 is required, +// `absl::optional` is an alias for `std::optional`. + #ifndef ABSL_TYPES_OPTIONAL_H_ #define ABSL_TYPES_OPTIONAL_H_ -#include "absl/base/config.h" // TODO(calabrese) IWYU removal? +#include <optional> + +#include "absl/base/config.h" #include "absl/utility/utility.h" -#ifdef ABSL_USES_STD_OPTIONAL - -#include <optional> // IWYU pragma: export - namespace absl { ABSL_NAMESPACE_BEGIN using std::bad_optional_access; @@ -52,728 +38,4 @@ ABSL_NAMESPACE_END } // namespace absl -#else // ABSL_USES_STD_OPTIONAL - -#include <cassert> -#include <functional> -#include <initializer_list> -#include <type_traits> -#include <utility> - -#include "absl/base/attributes.h" -#include "absl/base/nullability.h" -#include "absl/meta/type_traits.h" -#include "absl/types/bad_optional_access.h" -#include "absl/types/internal/optional.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN - -// nullopt_t -// -// Class type for `absl::nullopt` used to indicate an `absl::optional<T>` type -// that does not contain a value. -struct nullopt_t { - // It must not be default-constructible to avoid ambiguity for opt = {}. - explicit constexpr nullopt_t(optional_internal::init_t) noexcept {} -}; - -// nullopt -// -// A tag constant of type `absl::nullopt_t` used to indicate an empty -// `absl::optional` in certain functions, such as construction or assignment. -inline constexpr nullopt_t nullopt = nullopt_t(optional_internal::init_t()); - -// ----------------------------------------------------------------------------- -// 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 -// sub-object, so `sizeof(optional<T>)` is approximately -// `sizeof(T) + sizeof(bool)`. -// -// This implementation is based on the specification in the latest draft of the -// C++17 `std::optional` specification as of May 2017, section 20.6. -// -// Differences between `absl::optional<T>` and `std::optional<T>` include: -// -// * `constexpr` is not used for non-const member functions. -// (dependency on some differences between C++11 and C++14.) -// * `absl::nullopt` and `absl::in_place` are not declared `constexpr`. We -// need the inline variable support in C++17 for external linkage. -// * Throws `absl::bad_optional_access` instead of -// `std::bad_optional_access`. -// * `make_optional()` cannot be declared `constexpr` due to the absence of -// guaranteed copy elision. -// * The move constructor's `noexcept` specification is stronger, i.e. if the -// default allocator is non-throwing (via setting -// `ABSL_ALLOCATOR_NOTHROW`), it evaluates to `noexcept(true)`, because -// we assume -// a) move constructors should only throw due to allocation failure and -// b) if T's move constructor allocates, it uses the same allocation -// function as the default allocator. -// -template <typename T> -class optional : private optional_internal::optional_data<T>, - private optional_internal::optional_ctor_base< - optional_internal::ctor_copy_traits<T>::traits>, - private optional_internal::optional_assign_base< - optional_internal::assign_copy_traits<T>::traits> { - using data_base = optional_internal::optional_data<T>; - - public: - typedef T value_type; - - // Constructors - - // Constructs an `optional` holding an empty value, NOT a default constructed - // `T`. - constexpr optional() noexcept = default; - - // Constructs an `optional` initialized with `nullopt` to hold an empty value. - constexpr optional(nullopt_t) noexcept {} // NOLINT(runtime/explicit) - - // Copy constructor, standard semantics - optional(const optional&) = default; - - // Move constructor, standard semantics - optional(optional&&) = default; - - // Constructs a non-empty `optional` direct-initialized value of type `T` from - // the arguments `std::forward<Args>(args)...` within the `optional`. - // (The `in_place_t` is a tag used to indicate that the contained object - // should be constructed in-place.) - template <typename InPlaceT, typename... Args, - absl::enable_if_t<absl::conjunction< - std::is_same<InPlaceT, in_place_t>, - std::is_constructible<T, Args&&...> >::value>* = nullptr> - constexpr explicit optional(InPlaceT, Args&&... args) - : data_base(in_place_t(), std::forward<Args>(args)...) {} - - // Constructs a non-empty `optional` direct-initialized value of type `T` from - // the arguments of an initializer_list and `std::forward<Args>(args)...`. - // (The `in_place_t` is a tag used to indicate that the contained object - // should be constructed in-place.) - template <typename U, typename... Args, - typename = typename std::enable_if<std::is_constructible< - T, std::initializer_list<U>&, Args&&...>::value>::type> - constexpr explicit optional(in_place_t, std::initializer_list<U> il, - Args&&... args) - : data_base(in_place_t(), il, std::forward<Args>(args)...) {} - - // Value constructor (implicit) - template < - typename U = T, - typename std::enable_if< - absl::conjunction<absl::negation<std::is_same< - in_place_t, typename std::decay<U>::type> >, - absl::negation<std::is_same< - optional<T>, typename std::decay<U>::type> >, - std::is_convertible<U&&, T>, - std::is_constructible<T, U&&> >::value, - bool>::type = false> - constexpr optional(U&& v) : data_base(in_place_t(), std::forward<U>(v)) {} - - // Value constructor (explicit) - template < - typename U = T, - typename std::enable_if< - absl::conjunction<absl::negation<std::is_same< - in_place_t, typename std::decay<U>::type> >, - absl::negation<std::is_same< - optional<T>, typename std::decay<U>::type> >, - absl::negation<std::is_convertible<U&&, T> >, - std::is_constructible<T, U&&> >::value, - bool>::type = false> - explicit constexpr optional(U&& v) - : data_base(in_place_t(), std::forward<U>(v)) {} - - // Converting copy constructor (implicit) - template <typename U, - typename std::enable_if< - absl::conjunction< - absl::negation<std::is_same<T, U> >, - std::is_constructible<T, const U&>, - absl::negation< - optional_internal:: - is_constructible_convertible_from_optional<T, U> >, - std::is_convertible<const U&, T> >::value, - bool>::type = false> - optional(const optional<U>& rhs) { - if (rhs) { - this->construct(*rhs); - } - } - - // Converting copy constructor (explicit) - template <typename U, - typename std::enable_if< - absl::conjunction< - absl::negation<std::is_same<T, U>>, - std::is_constructible<T, const U&>, - absl::negation< - optional_internal:: - is_constructible_convertible_from_optional<T, U>>, - absl::negation<std::is_convertible<const U&, T>>>::value, - bool>::type = false> - explicit optional(const optional<U>& rhs) { - if (rhs) { - this->construct(*rhs); - } - } - - // Converting move constructor (implicit) - template <typename U, - typename std::enable_if< - absl::conjunction< - absl::negation<std::is_same<T, U> >, - std::is_constructible<T, U&&>, - absl::negation< - optional_internal:: - is_constructible_convertible_from_optional<T, U> >, - std::is_convertible<U&&, T> >::value, - bool>::type = false> - optional(optional<U>&& rhs) { - if (rhs) { - this->construct(std::move(*rhs)); - } - } - - // Converting move constructor (explicit) - template < - typename U, - typename std::enable_if< - absl::conjunction< - absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>, - absl::negation< - optional_internal::is_constructible_convertible_from_optional< - T, U>>, - absl::negation<std::is_convertible<U&&, T>>>::value, - bool>::type = false> - explicit optional(optional<U>&& rhs) { - if (rhs) { - this->construct(std::move(*rhs)); - } - } - - // Destructor. Trivial if `T` is trivially destructible. - ~optional() = default; - - // Assignment Operators - - // Assignment from `nullopt` - // - // Example: - // - // struct S { int value; }; - // optional<S> opt = absl::nullopt; // Could also use opt = { }; - optional& operator=(nullopt_t) noexcept { - this->destruct(); - return *this; - } - - // Copy assignment operator, standard semantics - optional& operator=(const optional& src) = default; - - // Move assignment operator, standard semantics - optional& operator=(optional&& src) = default; - - // Value assignment operators - template <typename U = T, - int&..., // Workaround an internal compiler error in GCC 5 to 10. - typename = typename std::enable_if<absl::conjunction< - absl::negation< - std::is_same<optional<T>, typename std::decay<U>::type> >, - absl::negation<absl::conjunction< - std::is_scalar<T>, - std::is_same<T, typename std::decay<U>::type> > >, - std::is_constructible<T, U>, - std::is_assignable<T&, U> >::value>::type> - optional& operator=(U&& v) { - this->assign(std::forward<U>(v)); - return *this; - } - - template < - typename U, - int&..., // Workaround an internal compiler error in GCC 5 to 10. - typename = typename std::enable_if<absl::conjunction< - absl::negation<std::is_same<T, U> >, - std::is_constructible<T, const U&>, std::is_assignable<T&, const U&>, - absl::negation< - optional_internal:: - is_constructible_convertible_assignable_from_optional< - T, U> > >::value>::type> - optional& operator=(const optional<U>& rhs) { - if (rhs) { - this->assign(*rhs); - } else { - this->destruct(); - } - return *this; - } - - template <typename U, - int&..., // Workaround an internal compiler error in GCC 5 to 10. - typename = typename std::enable_if<absl::conjunction< - absl::negation<std::is_same<T, U> >, - std::is_constructible<T, U>, std::is_assignable<T&, U>, - absl::negation< - optional_internal:: - is_constructible_convertible_assignable_from_optional< - T, U> > >::value>::type> - optional& operator=(optional<U>&& rhs) { - if (rhs) { - this->assign(std::move(*rhs)); - } else { - this->destruct(); - } - return *this; - } - - // Modifiers - - // optional::reset() - // - // Destroys the inner `T` value of an `absl::optional` if one is present. - ABSL_ATTRIBUTE_REINITIALIZES void reset() noexcept { this->destruct(); } - - // optional::emplace() - // - // (Re)constructs the underlying `T` in-place with the given forwarded - // arguments. - // - // Example: - // - // optional<Foo> opt; - // opt.emplace(arg1,arg2,arg3); // Constructs Foo(arg1,arg2,arg3) - // - // If the optional is non-empty, and the `args` refer to subobjects of the - // current object, then behaviour is undefined, because the current object - // will be destructed before the new object is constructed with `args`. - template <typename... Args, - typename = typename std::enable_if< - std::is_constructible<T, Args&&...>::value>::type> - T& emplace(Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND { - this->destruct(); - this->construct(std::forward<Args>(args)...); - return reference(); - } - - // Emplace reconstruction overload for an initializer list and the given - // forwarded arguments. - // - // Example: - // - // struct Foo { - // Foo(std::initializer_list<int>); - // }; - // - // optional<Foo> opt; - // opt.emplace({1,2,3}); // Constructs Foo({1,2,3}) - template <typename U, typename... Args, - typename = typename std::enable_if<std::is_constructible< - T, std::initializer_list<U>&, Args&&...>::value>::type> - T& emplace(std::initializer_list<U> il, - Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND { - this->destruct(); - this->construct(il, std::forward<Args>(args)...); - return reference(); - } - - // Swaps - - // Swap, standard semantics - void swap(optional& rhs) noexcept( - std::is_nothrow_move_constructible<T>::value&& - type_traits_internal::IsNothrowSwappable<T>::value) { - if (*this) { - if (rhs) { - type_traits_internal::Swap(**this, *rhs); - } else { - rhs.construct(std::move(**this)); - this->destruct(); - } - } else { - if (rhs) { - this->construct(std::move(*rhs)); - rhs.destruct(); - } else { - // No effect (swap(disengaged, disengaged)). - } - } - } - - // Observers - - // optional::operator->() - // - // Accesses the underlying `T` value's member `m` of an `optional`. If the - // `optional` is empty, behavior is undefined. - // - // If you need myOpt->foo in constexpr, use (*myOpt).foo instead. - absl::Nonnull<const T*> operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND { - ABSL_HARDENING_ASSERT(this->engaged_); - return std::addressof(this->data_); - } - absl::Nonnull<T*> operator->() ABSL_ATTRIBUTE_LIFETIME_BOUND { - ABSL_HARDENING_ASSERT(this->engaged_); - return std::addressof(this->data_); - } - - // optional::operator*() - // - // Accesses the underlying `T` value of an `optional`. If the `optional` is - // empty, behavior is undefined. - constexpr const T& operator*() const& ABSL_ATTRIBUTE_LIFETIME_BOUND { - ABSL_HARDENING_ASSERT(this->engaged_); - return reference(); - } - T& operator*() & ABSL_ATTRIBUTE_LIFETIME_BOUND { - ABSL_HARDENING_ASSERT(this->engaged_); - return reference(); - } - constexpr const T&& operator*() const&& ABSL_ATTRIBUTE_LIFETIME_BOUND { - ABSL_HARDENING_ASSERT(this->engaged_); - return std::move(reference()); - } - T&& operator*() && ABSL_ATTRIBUTE_LIFETIME_BOUND { - ABSL_HARDENING_ASSERT(this->engaged_); - return std::move(reference()); - } - - // optional::operator bool() - // - // Returns false if and only if the `optional` is empty. - // - // if (opt) { - // // do something with *opt or opt->; - // } else { - // // opt is empty. - // } - // - constexpr explicit operator bool() const noexcept { return this->engaged_; } - - // optional::has_value() - // - // Determines whether the `optional` contains a value. Returns `false` if and - // only if `*this` is empty. - constexpr bool has_value() const noexcept { return this->engaged_; } - -// Suppress bogus warning on MSVC: MSVC complains call to reference() after -// throw_bad_optional_access() is unreachable. -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4702) -#endif // _MSC_VER - // optional::value() - // - // Returns a reference to an `optional`s underlying value. The constness - // and lvalue/rvalue-ness of the `optional` is preserved to the view of - // the `T` sub-object. Throws `absl::bad_optional_access` when the `optional` - // is empty. - constexpr const T& value() const& ABSL_ATTRIBUTE_LIFETIME_BOUND { - return static_cast<bool>(*this) - ? reference() - : (optional_internal::throw_bad_optional_access(), reference()); - } - T& value() & ABSL_ATTRIBUTE_LIFETIME_BOUND { - return static_cast<bool>(*this) - ? reference() - : (optional_internal::throw_bad_optional_access(), reference()); - } - T&& value() && ABSL_ATTRIBUTE_LIFETIME_BOUND { // NOLINT(build/c++11) - return std::move( - static_cast<bool>(*this) - ? reference() - : (optional_internal::throw_bad_optional_access(), reference())); - } - constexpr const T&& value() - const&& ABSL_ATTRIBUTE_LIFETIME_BOUND { // NOLINT(build/c++11) - return std::move( - static_cast<bool>(*this) - ? reference() - : (optional_internal::throw_bad_optional_access(), reference())); - } -#ifdef _MSC_VER -#pragma warning(pop) -#endif // _MSC_VER - - // optional::value_or() - // - // Returns either the value of `T` or a passed default `v` if the `optional` - // is empty. - template <typename U> - constexpr T value_or(U&& v) const& { - static_assert(std::is_copy_constructible<value_type>::value, - "optional<T>::value_or: T must be copy constructible"); - static_assert(std::is_convertible<U&&, value_type>::value, - "optional<T>::value_or: U must be convertible to T"); - return static_cast<bool>(*this) ? **this - : static_cast<T>(std::forward<U>(v)); - } - template <typename U> - T value_or(U&& v) && { // NOLINT(build/c++11) - static_assert(std::is_move_constructible<value_type>::value, - "optional<T>::value_or: T must be move constructible"); - static_assert(std::is_convertible<U&&, value_type>::value, - "optional<T>::value_or: U must be convertible to T"); - return static_cast<bool>(*this) ? std::move(**this) - : static_cast<T>(std::forward<U>(v)); - } - - private: - // Private accessors for internal storage viewed as reference to T. - constexpr const T& reference() const { return this->data_; } - T& reference() { return this->data_; } - - // T constraint checks. You can't have an optional of nullopt_t, in_place_t - // or a reference. - static_assert( - !std::is_same<nullopt_t, typename std::remove_cv<T>::type>::value, - "optional<nullopt_t> is not allowed."); - static_assert( - !std::is_same<in_place_t, typename std::remove_cv<T>::type>::value, - "optional<in_place_t> is not allowed."); - static_assert(!std::is_reference<T>::value, - "optional<reference> is not allowed."); -}; - -// Non-member functions - -// swap() -// -// Performs a swap between two `absl::optional` objects, using standard -// semantics. -template <typename T, typename std::enable_if< - std::is_move_constructible<T>::value && - type_traits_internal::IsSwappable<T>::value, - bool>::type = false> -void swap(optional<T>& a, optional<T>& b) noexcept(noexcept(a.swap(b))) { - a.swap(b); -} - -// make_optional() -// -// Creates a non-empty `optional<T>` where the type of `T` is deduced. An -// `absl::optional` can also be explicitly instantiated with -// `make_optional<T>(v)`. -// -// Note: `make_optional()` constructions may be declared `constexpr` for -// trivially copyable types `T`. Non-trivial types require copy elision -// support in C++17 for `make_optional` to support `constexpr` on such -// non-trivial types. -// -// Example: -// -// constexpr absl::optional<int> opt = absl::make_optional(1); -// static_assert(opt.value() == 1, ""); -template <typename T> -constexpr optional<typename std::decay<T>::type> make_optional(T&& v) { - return optional<typename std::decay<T>::type>(std::forward<T>(v)); -} - -template <typename T, typename... Args> -constexpr optional<T> make_optional(Args&&... args) { - return optional<T>(in_place_t(), std::forward<Args>(args)...); -} - -template <typename T, typename U, typename... Args> -constexpr optional<T> make_optional(std::initializer_list<U> il, - Args&&... args) { - return optional<T>(in_place_t(), il, std::forward<Args>(args)...); -} - -// Relational operators [optional.relops] - -// Empty optionals are considered equal to each other and less than non-empty -// optionals. Supports relations between optional<T> and optional<U>, between -// optional<T> and U, and between optional<T> and nullopt. -// -// Note: We're careful to support T having non-bool relationals. - -// Requires: The expression, e.g. "*x == *y" shall be well-formed and its result -// shall be convertible to bool. -// The C++17 (N4606) "Returns:" statements are translated into -// code in an obvious way here, and the original text retained as function docs. -// Returns: If bool(x) != bool(y), false; otherwise if bool(x) == false, true; -// otherwise *x == *y. -template <typename T, typename U> -constexpr auto operator==(const optional<T>& x, const optional<U>& y) - -> decltype(optional_internal::convertible_to_bool(*x == *y)) { - return static_cast<bool>(x) != static_cast<bool>(y) - ? false - : static_cast<bool>(x) == false ? true - : static_cast<bool>(*x == *y); -} - -// Returns: If bool(x) != bool(y), true; otherwise, if bool(x) == false, false; -// otherwise *x != *y. -template <typename T, typename U> -constexpr auto operator!=(const optional<T>& x, const optional<U>& y) - -> decltype(optional_internal::convertible_to_bool(*x != *y)) { - return static_cast<bool>(x) != static_cast<bool>(y) - ? true - : static_cast<bool>(x) == false ? false - : static_cast<bool>(*x != *y); -} -// Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y. -template <typename T, typename U> -constexpr auto operator<(const optional<T>& x, const optional<U>& y) - -> decltype(optional_internal::convertible_to_bool(*x < *y)) { - return !y ? false : !x ? true : static_cast<bool>(*x < *y); -} -// Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y. -template <typename T, typename U> -constexpr auto operator>(const optional<T>& x, const optional<U>& y) - -> decltype(optional_internal::convertible_to_bool(*x > *y)) { - return !x ? false : !y ? true : static_cast<bool>(*x > *y); -} -// Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y. -template <typename T, typename U> -constexpr auto operator<=(const optional<T>& x, const optional<U>& y) - -> decltype(optional_internal::convertible_to_bool(*x <= *y)) { - return !x ? true : !y ? false : static_cast<bool>(*x <= *y); -} -// Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y. -template <typename T, typename U> -constexpr auto operator>=(const optional<T>& x, const optional<U>& y) - -> decltype(optional_internal::convertible_to_bool(*x >= *y)) { - return !y ? true : !x ? false : static_cast<bool>(*x >= *y); -} - -// Comparison with nullopt [optional.nullops] -// The C++17 (N4606) "Returns:" statements are used directly here. -template <typename T> -constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept { - return !x; -} -template <typename T> -constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept { - return !x; -} -template <typename T> -constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept { - return static_cast<bool>(x); -} -template <typename T> -constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept { - return static_cast<bool>(x); -} -template <typename T> -constexpr bool operator<(const optional<T>&, nullopt_t) noexcept { - return false; -} -template <typename T> -constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept { - return static_cast<bool>(x); -} -template <typename T> -constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept { - return !x; -} -template <typename T> -constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept { - return true; -} -template <typename T> -constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept { - return static_cast<bool>(x); -} -template <typename T> -constexpr bool operator>(nullopt_t, const optional<T>&) noexcept { - return false; -} -template <typename T> -constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept { - return true; -} -template <typename T> -constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept { - return !x; -} - -// Comparison with T [optional.comp_with_t] - -// Requires: The expression, e.g. "*x == v" shall be well-formed and its result -// shall be convertible to bool. -// The C++17 (N4606) "Equivalent to:" statements are used directly here. -template <typename T, typename U> -constexpr auto operator==(const optional<T>& x, const U& v) - -> decltype(optional_internal::convertible_to_bool(*x == v)) { - return static_cast<bool>(x) ? static_cast<bool>(*x == v) : false; -} -template <typename T, typename U> -constexpr auto operator==(const U& v, const optional<T>& x) - -> decltype(optional_internal::convertible_to_bool(v == *x)) { - return static_cast<bool>(x) ? static_cast<bool>(v == *x) : false; -} -template <typename T, typename U> -constexpr auto operator!=(const optional<T>& x, const U& v) - -> decltype(optional_internal::convertible_to_bool(*x != v)) { - return static_cast<bool>(x) ? static_cast<bool>(*x != v) : true; -} -template <typename T, typename U> -constexpr auto operator!=(const U& v, const optional<T>& x) - -> decltype(optional_internal::convertible_to_bool(v != *x)) { - return static_cast<bool>(x) ? static_cast<bool>(v != *x) : true; -} -template <typename T, typename U> -constexpr auto operator<(const optional<T>& x, const U& v) - -> decltype(optional_internal::convertible_to_bool(*x < v)) { - return static_cast<bool>(x) ? static_cast<bool>(*x < v) : true; -} -template <typename T, typename U> -constexpr auto operator<(const U& v, const optional<T>& x) - -> decltype(optional_internal::convertible_to_bool(v < *x)) { - return static_cast<bool>(x) ? static_cast<bool>(v < *x) : false; -} -template <typename T, typename U> -constexpr auto operator<=(const optional<T>& x, const U& v) - -> decltype(optional_internal::convertible_to_bool(*x <= v)) { - return static_cast<bool>(x) ? static_cast<bool>(*x <= v) : true; -} -template <typename T, typename U> -constexpr auto operator<=(const U& v, const optional<T>& x) - -> decltype(optional_internal::convertible_to_bool(v <= *x)) { - return static_cast<bool>(x) ? static_cast<bool>(v <= *x) : false; -} -template <typename T, typename U> -constexpr auto operator>(const optional<T>& x, const U& v) - -> decltype(optional_internal::convertible_to_bool(*x > v)) { - return static_cast<bool>(x) ? static_cast<bool>(*x > v) : false; -} -template <typename T, typename U> -constexpr auto operator>(const U& v, const optional<T>& x) - -> decltype(optional_internal::convertible_to_bool(v > *x)) { - return static_cast<bool>(x) ? static_cast<bool>(v > *x) : true; -} -template <typename T, typename U> -constexpr auto operator>=(const optional<T>& x, const U& v) - -> decltype(optional_internal::convertible_to_bool(*x >= v)) { - return static_cast<bool>(x) ? static_cast<bool>(*x >= v) : false; -} -template <typename T, typename U> -constexpr auto operator>=(const U& v, const optional<T>& x) - -> decltype(optional_internal::convertible_to_bool(v >= *x)) { - return static_cast<bool>(x) ? static_cast<bool>(v >= *x) : true; -} - -ABSL_NAMESPACE_END -} // namespace absl - -namespace std { - -// std::hash specialization for absl::optional. -template <typename T> -struct hash<absl::optional<T> > - : absl::optional_internal::optional_hash_base<T> {}; - -} // namespace std - -#undef ABSL_MSVC_CONSTEXPR_BUG_IN_UNION_LIKE_CLASS - -#endif // ABSL_USES_STD_OPTIONAL - #endif // ABSL_TYPES_OPTIONAL_H_
diff --git a/absl/types/optional_exception_safety_test.cc b/absl/types/optional_exception_safety_test.cc deleted file mode 100644 index 8e5fe85..0000000 --- a/absl/types/optional_exception_safety_test.cc +++ /dev/null
@@ -1,292 +0,0 @@ -// 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 -// -// https://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/optional.h" - -#include "absl/base/config.h" - -// This test is a no-op when absl::optional is an alias for std::optional and -// when exceptions are not enabled. -#if !defined(ABSL_USES_STD_OPTIONAL) && defined(ABSL_HAVE_EXCEPTIONS) - -#include "gtest/gtest.h" -#include "absl/base/internal/exception_safety_testing.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN - -namespace { - -using ::testing::AssertionFailure; -using ::testing::AssertionResult; -using ::testing::AssertionSuccess; -using ::testing::MakeExceptionSafetyTester; - -using Thrower = testing::ThrowingValue<testing::TypeSpec::kEverythingThrows>; -using Optional = absl::optional<Thrower>; - -using MoveThrower = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>; -using MoveOptional = absl::optional<MoveThrower>; - -constexpr int kInitialInteger = 5; -constexpr int kUpdatedInteger = 10; - -template <typename OptionalT> -bool ValueThrowsBadOptionalAccess(const OptionalT& optional) try { - return (static_cast<void>(optional.value()), false); -} catch (const absl::bad_optional_access&) { - return true; -} - -template <typename OptionalT> -AssertionResult OptionalInvariants(OptionalT* optional_ptr) { - // Check the current state post-throw for validity - auto& optional = *optional_ptr; - - if (optional.has_value() && ValueThrowsBadOptionalAccess(optional)) { - return AssertionFailure() - << "Optional with value should not throw bad_optional_access when " - "accessing the value."; - } - if (!optional.has_value() && !ValueThrowsBadOptionalAccess(optional)) { - return AssertionFailure() - << "Optional without a value should throw bad_optional_access when " - "accessing the value."; - } - - // Reset to a known state - optional.reset(); - - // Confirm that the known post-reset state is valid - if (optional.has_value()) { - return AssertionFailure() - << "Optional should not contain a value after being reset."; - } - if (!ValueThrowsBadOptionalAccess(optional)) { - return AssertionFailure() << "Optional should throw bad_optional_access " - "when accessing the value after being reset."; - } - - return AssertionSuccess(); -} - -template <typename OptionalT> -AssertionResult CheckDisengaged(OptionalT* optional_ptr) { - auto& optional = *optional_ptr; - - if (optional.has_value()) { - return AssertionFailure() - << "Expected optional to not contain a value but a value was found."; - } - - return AssertionSuccess(); -} - -template <typename OptionalT> -AssertionResult CheckEngaged(OptionalT* optional_ptr) { - auto& optional = *optional_ptr; - - if (!optional.has_value()) { - return AssertionFailure() - << "Expected optional to contain a value but no value was found."; - } - - return AssertionSuccess(); -} - -TEST(OptionalExceptionSafety, ThrowingConstructors) { - auto thrower_nonempty = Optional(Thrower(kInitialInteger)); - testing::TestThrowingCtor<Optional>(thrower_nonempty); - - auto integer_nonempty = absl::optional<int>(kInitialInteger); - testing::TestThrowingCtor<Optional>(integer_nonempty); - testing::TestThrowingCtor<Optional>(std::move(integer_nonempty)); // NOLINT - - testing::TestThrowingCtor<Optional>(kInitialInteger); - using ThrowerVec = std::vector<Thrower, testing::ThrowingAllocator<Thrower>>; - testing::TestThrowingCtor<absl::optional<ThrowerVec>>( - absl::in_place, - std::initializer_list<Thrower>{Thrower(), Thrower(), Thrower()}, - testing::ThrowingAllocator<Thrower>()); -} - -TEST(OptionalExceptionSafety, NothrowConstructors) { - // This constructor is marked noexcept. If it throws, the program will - // terminate. - testing::TestThrowingCtor<MoveOptional>(MoveOptional(kUpdatedInteger)); -} - -TEST(OptionalExceptionSafety, Emplace) { - // Test the basic guarantee plus test the result of optional::has_value() - // is false in all cases - auto disengaged_test = MakeExceptionSafetyTester().WithContracts( - OptionalInvariants<Optional>, CheckDisengaged<Optional>); - auto disengaged_test_empty = disengaged_test.WithInitialValue(Optional()); - auto disengaged_test_nonempty = - disengaged_test.WithInitialValue(Optional(kInitialInteger)); - - auto emplace_thrower_directly = [](Optional* optional_ptr) { - optional_ptr->emplace(kUpdatedInteger); - }; - EXPECT_TRUE(disengaged_test_empty.Test(emplace_thrower_directly)); - EXPECT_TRUE(disengaged_test_nonempty.Test(emplace_thrower_directly)); - - auto emplace_thrower_copy = [](Optional* optional_ptr) { - auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor); - optional_ptr->emplace(thrower); - }; - EXPECT_TRUE(disengaged_test_empty.Test(emplace_thrower_copy)); - EXPECT_TRUE(disengaged_test_nonempty.Test(emplace_thrower_copy)); -} - -TEST(OptionalExceptionSafety, EverythingThrowsSwap) { - // Test the basic guarantee plus test the result of optional::has_value() - // remains the same - auto test = - MakeExceptionSafetyTester().WithContracts(OptionalInvariants<Optional>); - auto disengaged_test_empty = test.WithInitialValue(Optional()) - .WithContracts(CheckDisengaged<Optional>); - auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger)) - .WithContracts(CheckEngaged<Optional>); - - auto swap_empty = [](Optional* optional_ptr) { - auto empty = Optional(); - optional_ptr->swap(empty); - }; - EXPECT_TRUE(engaged_test_nonempty.Test(swap_empty)); - - auto swap_nonempty = [](Optional* optional_ptr) { - auto nonempty = - Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor); - optional_ptr->swap(nonempty); - }; - EXPECT_TRUE(disengaged_test_empty.Test(swap_nonempty)); - EXPECT_TRUE(engaged_test_nonempty.Test(swap_nonempty)); -} - -TEST(OptionalExceptionSafety, NoThrowMoveSwap) { - // Tests the nothrow guarantee for optional of T with non-throwing move - { - auto empty = MoveOptional(); - auto nonempty = MoveOptional(kInitialInteger); - EXPECT_TRUE(testing::TestNothrowOp([&]() { nonempty.swap(empty); })); - } - { - auto nonempty = MoveOptional(kUpdatedInteger); - auto empty = MoveOptional(); - EXPECT_TRUE(testing::TestNothrowOp([&]() { empty.swap(nonempty); })); - } - { - auto nonempty_from = MoveOptional(kUpdatedInteger); - auto nonempty_to = MoveOptional(kInitialInteger); - EXPECT_TRUE( - testing::TestNothrowOp([&]() { nonempty_to.swap(nonempty_from); })); - } -} - -TEST(OptionalExceptionSafety, CopyAssign) { - // Test the basic guarantee plus test the result of optional::has_value() - // remains the same - auto test = - MakeExceptionSafetyTester().WithContracts(OptionalInvariants<Optional>); - auto disengaged_test_empty = test.WithInitialValue(Optional()) - .WithContracts(CheckDisengaged<Optional>); - auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger)) - .WithContracts(CheckEngaged<Optional>); - - auto copyassign_nonempty = [](Optional* optional_ptr) { - auto nonempty = - Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor); - *optional_ptr = nonempty; - }; - EXPECT_TRUE(disengaged_test_empty.Test(copyassign_nonempty)); - EXPECT_TRUE(engaged_test_nonempty.Test(copyassign_nonempty)); - - auto copyassign_thrower = [](Optional* optional_ptr) { - auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor); - *optional_ptr = thrower; - }; - EXPECT_TRUE(disengaged_test_empty.Test(copyassign_thrower)); - EXPECT_TRUE(engaged_test_nonempty.Test(copyassign_thrower)); -} - -TEST(OptionalExceptionSafety, MoveAssign) { - // Test the basic guarantee plus test the result of optional::has_value() - // remains the same - auto test = - MakeExceptionSafetyTester().WithContracts(OptionalInvariants<Optional>); - auto disengaged_test_empty = test.WithInitialValue(Optional()) - .WithContracts(CheckDisengaged<Optional>); - auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger)) - .WithContracts(CheckEngaged<Optional>); - - auto moveassign_empty = [](Optional* optional_ptr) { - auto empty = Optional(); - *optional_ptr = std::move(empty); - }; - EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_empty)); - - auto moveassign_nonempty = [](Optional* optional_ptr) { - auto nonempty = - Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor); - *optional_ptr = std::move(nonempty); - }; - EXPECT_TRUE(disengaged_test_empty.Test(moveassign_nonempty)); - EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_nonempty)); - - auto moveassign_thrower = [](Optional* optional_ptr) { - auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor); - *optional_ptr = std::move(thrower); - }; - EXPECT_TRUE(disengaged_test_empty.Test(moveassign_thrower)); - EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_thrower)); -} - -TEST(OptionalExceptionSafety, NothrowMoveAssign) { - // Tests the nothrow guarantee for optional of T with non-throwing move - { - auto empty = MoveOptional(); - auto nonempty = MoveOptional(kInitialInteger); - EXPECT_TRUE(testing::TestNothrowOp([&]() { nonempty = std::move(empty); })); - } - { - auto nonempty = MoveOptional(kInitialInteger); - auto empty = MoveOptional(); - EXPECT_TRUE(testing::TestNothrowOp([&]() { empty = std::move(nonempty); })); - } - { - auto nonempty_from = MoveOptional(kUpdatedInteger); - auto nonempty_to = MoveOptional(kInitialInteger); - EXPECT_TRUE(testing::TestNothrowOp( - [&]() { nonempty_to = std::move(nonempty_from); })); - } - { - auto thrower = MoveThrower(kUpdatedInteger); - auto empty = MoveOptional(); - EXPECT_TRUE(testing::TestNothrowOp([&]() { empty = std::move(thrower); })); - } - { - auto thrower = MoveThrower(kUpdatedInteger); - auto nonempty = MoveOptional(kInitialInteger); - EXPECT_TRUE( - testing::TestNothrowOp([&]() { nonempty = std::move(thrower); })); - } -} - -} // namespace - -ABSL_NAMESPACE_END -} // namespace absl - -#endif // #if !defined(ABSL_USES_STD_OPTIONAL) && defined(ABSL_HAVE_EXCEPTIONS)
diff --git a/absl/types/optional_test.cc b/absl/types/optional_test.cc deleted file mode 100644 index 115e20c..0000000 --- a/absl/types/optional_test.cc +++ /dev/null
@@ -1,1615 +0,0 @@ -// 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 -// -// https://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/optional.h" - -// This test is a no-op when absl::optional is an alias for std::optional. -#if !defined(ABSL_USES_STD_OPTIONAL) - -#include <string> -#include <type_traits> -#include <utility> - -#include "gtest/gtest.h" -#include "absl/base/config.h" -#include "absl/log/log.h" -#include "absl/meta/type_traits.h" -#include "absl/strings/string_view.h" - -#if defined(__cplusplus) && __cplusplus >= 202002L -// In C++20, volatile-qualified return types are deprecated. -#define ABSL_VOLATILE_RETURN_TYPES_DEPRECATED 1 -#endif - -// The following types help test an internal compiler error in GCC5 though -// GCC10. The case OptionalTest.InternalCompilerErrorInGcc5ToGcc10 crashes the -// compiler without a workaround. This test case should remain at the beginning -// of the file as the internal compiler error is sensitive to other constructs -// in this file. -template <class T, class...> -using GccIceHelper1 = T; -template <typename T> -struct GccIceHelper2 {}; -template <typename T> -class GccIce { - template <typename U, - typename SecondTemplateArgHasToExistForSomeReason = void, - typename DependentType = void, - typename = std::is_assignable<GccIceHelper1<T, DependentType>&, U>> - GccIce& operator=(GccIceHelper2<U> const&) {} -}; - -TEST(OptionalTest, InternalCompilerErrorInGcc5ToGcc10) { - GccIce<int> instantiate_ice_with_same_type_as_optional; - static_cast<void>(instantiate_ice_with_same_type_as_optional); - absl::optional<int> val1; - absl::optional<int> val2; - val1 = val2; -} - -struct Hashable {}; - -namespace std { -template <> -struct hash<Hashable> { - size_t operator()(const Hashable&) { return 0; } -}; -} // namespace std - -struct NonHashable {}; - -namespace { - -std::string TypeQuals(std::string&) { return "&"; } -std::string TypeQuals(std::string&&) { return "&&"; } -std::string TypeQuals(const std::string&) { return "c&"; } -std::string TypeQuals(const std::string&&) { return "c&&"; } - -struct StructorListener { - int construct0 = 0; - int construct1 = 0; - int construct2 = 0; - int listinit = 0; - int copy = 0; - int move = 0; - int copy_assign = 0; - int move_assign = 0; - int destruct = 0; - int volatile_copy = 0; - int volatile_move = 0; - int volatile_copy_assign = 0; - int volatile_move_assign = 0; -}; - -// Suppress MSVC warnings. -// 4521: multiple copy constructors specified -// 4522: multiple assignment operators specified -// We wrote multiple of them to test that the correct overloads are selected. -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4521) -#pragma warning(disable : 4522) -#endif -struct Listenable { - static StructorListener* listener; - - Listenable() { ++listener->construct0; } - explicit Listenable(int /*unused*/) { ++listener->construct1; } - Listenable(int /*unused*/, int /*unused*/) { ++listener->construct2; } - Listenable(std::initializer_list<int> /*unused*/) { ++listener->listinit; } - Listenable(const Listenable& /*unused*/) { ++listener->copy; } - Listenable(const volatile Listenable& /*unused*/) { - ++listener->volatile_copy; - } - Listenable(volatile Listenable&& /*unused*/) { ++listener->volatile_move; } - Listenable(Listenable&& /*unused*/) { ++listener->move; } - Listenable& operator=(const Listenable& /*unused*/) { - ++listener->copy_assign; - return *this; - } - Listenable& operator=(Listenable&& /*unused*/) { - ++listener->move_assign; - return *this; - } - // use void return type instead of volatile T& to work around GCC warning - // when the assignment's returned reference is ignored. - void operator=(const volatile Listenable& /*unused*/) volatile { - ++listener->volatile_copy_assign; - } - void operator=(volatile Listenable&& /*unused*/) volatile { - ++listener->volatile_move_assign; - } - ~Listenable() { ++listener->destruct; } -}; -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -StructorListener* Listenable::listener = nullptr; - -struct ConstexprType { - enum CtorTypes { - kCtorDefault, - kCtorInt, - kCtorInitializerList, - kCtorConstChar - }; - constexpr ConstexprType() : x(kCtorDefault) {} - constexpr explicit ConstexprType(int i) : x(kCtorInt) {} - constexpr ConstexprType(std::initializer_list<int> il) - : x(kCtorInitializerList) {} - constexpr ConstexprType(const char*) // NOLINT(runtime/explicit) - : x(kCtorConstChar) {} - int x; -}; - -struct Copyable { - Copyable() {} - Copyable(const Copyable&) {} - Copyable& operator=(const Copyable&) { return *this; } -}; - -struct MoveableThrow { - MoveableThrow() {} - MoveableThrow(MoveableThrow&&) {} - MoveableThrow& operator=(MoveableThrow&&) { return *this; } -}; - -struct MoveableNoThrow { - MoveableNoThrow() {} - MoveableNoThrow(MoveableNoThrow&&) noexcept {} - MoveableNoThrow& operator=(MoveableNoThrow&&) noexcept { return *this; } -}; - -struct NonMovable { - NonMovable() {} - NonMovable(const NonMovable&) = delete; - NonMovable& operator=(const NonMovable&) = delete; - NonMovable(NonMovable&&) = delete; - NonMovable& operator=(NonMovable&&) = delete; -}; - -struct NoDefault { - NoDefault() = delete; - NoDefault(const NoDefault&) {} - NoDefault& operator=(const NoDefault&) { return *this; } -}; - -struct ConvertsFromInPlaceT { - ConvertsFromInPlaceT(absl::in_place_t) {} // NOLINT -}; - -TEST(optionalTest, DefaultConstructor) { - absl::optional<int> empty; - EXPECT_FALSE(empty); - constexpr absl::optional<int> cempty; - static_assert(!cempty.has_value(), ""); - EXPECT_TRUE( - std::is_nothrow_default_constructible<absl::optional<int>>::value); -} - -TEST(optionalTest, nulloptConstructor) { - absl::optional<int> empty(absl::nullopt); - EXPECT_FALSE(empty); - constexpr absl::optional<int> cempty{absl::nullopt}; - static_assert(!cempty.has_value(), ""); - EXPECT_TRUE((std::is_nothrow_constructible<absl::optional<int>, - absl::nullopt_t>::value)); -} - -TEST(optionalTest, CopyConstructor) { - { - absl::optional<int> empty, opt42 = 42; - absl::optional<int> empty_copy(empty); - EXPECT_FALSE(empty_copy); - absl::optional<int> opt42_copy(opt42); - EXPECT_TRUE(opt42_copy); - EXPECT_EQ(42, *opt42_copy); - } - { - absl::optional<const int> empty, opt42 = 42; - absl::optional<const int> empty_copy(empty); - EXPECT_FALSE(empty_copy); - absl::optional<const int> opt42_copy(opt42); - EXPECT_TRUE(opt42_copy); - EXPECT_EQ(42, *opt42_copy); - } -#if !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED) - { - absl::optional<volatile int> empty, opt42 = 42; - absl::optional<volatile int> empty_copy(empty); - EXPECT_FALSE(empty_copy); - absl::optional<volatile int> opt42_copy(opt42); - EXPECT_TRUE(opt42_copy); - EXPECT_EQ(42, *opt42_copy); - } -#endif - // test copyablility - EXPECT_TRUE(std::is_copy_constructible<absl::optional<int>>::value); - EXPECT_TRUE(std::is_copy_constructible<absl::optional<Copyable>>::value); - EXPECT_FALSE( - std::is_copy_constructible<absl::optional<MoveableThrow>>::value); - EXPECT_FALSE( - std::is_copy_constructible<absl::optional<MoveableNoThrow>>::value); - EXPECT_FALSE(std::is_copy_constructible<absl::optional<NonMovable>>::value); - - EXPECT_FALSE( - absl::is_trivially_copy_constructible<absl::optional<Copyable>>::value); - EXPECT_TRUE( - absl::is_trivially_copy_constructible<absl::optional<int>>::value); - EXPECT_TRUE( - absl::is_trivially_copy_constructible<absl::optional<const int>>::value); -#if !defined(_MSC_VER) && !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED) - // See defect report "Trivial copy/move constructor for class with volatile - // member" at - // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2094 - // A class with non-static data member of volatile-qualified type should still - // have a trivial copy constructor if the data member is trivial. - // Also a cv-qualified scalar type should be trivially copyable. - EXPECT_TRUE(absl::is_trivially_copy_constructible< - absl::optional<volatile int>>::value); -#endif // !defined(_MSC_VER) && !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED) - - // constexpr copy constructor for trivially copyable types - { - constexpr absl::optional<int> o1; - constexpr absl::optional<int> o2 = o1; - static_assert(!o2, ""); - } - { - constexpr absl::optional<int> o1 = 42; - constexpr absl::optional<int> o2 = o1; - static_assert(o2, ""); - static_assert(*o2 == 42, ""); - } - { - struct TrivialCopyable { - constexpr TrivialCopyable() : x(0) {} - constexpr explicit TrivialCopyable(int i) : x(i) {} - int x; - }; - constexpr absl::optional<TrivialCopyable> o1(42); - constexpr absl::optional<TrivialCopyable> o2 = o1; - static_assert(o2, ""); - static_assert((*o2).x == 42, ""); -#ifndef ABSL_GLIBCXX_OPTIONAL_TRIVIALITY_BUG - EXPECT_TRUE(absl::is_trivially_copy_constructible< - absl::optional<TrivialCopyable>>::value); - EXPECT_TRUE(absl::is_trivially_copy_constructible< - absl::optional<const TrivialCopyable>>::value); -#endif -#if !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED) - EXPECT_FALSE(std::is_copy_constructible< - absl::optional<volatile TrivialCopyable>>::value); -#endif // !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED) - } -} - -TEST(optionalTest, MoveConstructor) { - absl::optional<int> empty, opt42 = 42; - absl::optional<int> empty_move(std::move(empty)); - EXPECT_FALSE(empty_move); - absl::optional<int> opt42_move(std::move(opt42)); - EXPECT_TRUE(opt42_move); - EXPECT_EQ(42, opt42_move); - // test movability - EXPECT_TRUE(std::is_move_constructible<absl::optional<int>>::value); - EXPECT_TRUE(std::is_move_constructible<absl::optional<Copyable>>::value); - EXPECT_TRUE(std::is_move_constructible<absl::optional<MoveableThrow>>::value); - EXPECT_TRUE( - std::is_move_constructible<absl::optional<MoveableNoThrow>>::value); - EXPECT_FALSE(std::is_move_constructible<absl::optional<NonMovable>>::value); - // test noexcept - EXPECT_TRUE(std::is_nothrow_move_constructible<absl::optional<int>>::value); - EXPECT_EQ( - absl::default_allocator_is_nothrow::value, - std::is_nothrow_move_constructible<absl::optional<MoveableThrow>>::value); - EXPECT_TRUE(std::is_nothrow_move_constructible< - absl::optional<MoveableNoThrow>>::value); -} - -TEST(optionalTest, Destructor) { - struct Trivial {}; - - struct NonTrivial { - NonTrivial(const NonTrivial&) {} - NonTrivial& operator=(const NonTrivial&) { return *this; } - ~NonTrivial() {} - }; - - EXPECT_TRUE(std::is_trivially_destructible<absl::optional<int>>::value); - EXPECT_TRUE(std::is_trivially_destructible<absl::optional<Trivial>>::value); - EXPECT_FALSE( - std::is_trivially_destructible<absl::optional<NonTrivial>>::value); -} - -TEST(optionalTest, InPlaceConstructor) { - constexpr absl::optional<ConstexprType> opt0{absl::in_place_t()}; - static_assert(opt0, ""); - static_assert((*opt0).x == ConstexprType::kCtorDefault, ""); - constexpr absl::optional<ConstexprType> opt1{absl::in_place_t(), 1}; - static_assert(opt1, ""); - static_assert((*opt1).x == ConstexprType::kCtorInt, ""); - constexpr absl::optional<ConstexprType> opt2{absl::in_place_t(), {1, 2}}; - static_assert(opt2, ""); - static_assert((*opt2).x == ConstexprType::kCtorInitializerList, ""); - - EXPECT_FALSE((std::is_constructible<absl::optional<ConvertsFromInPlaceT>, - absl::in_place_t>::value)); - EXPECT_FALSE((std::is_constructible<absl::optional<ConvertsFromInPlaceT>, - const absl::in_place_t&>::value)); - EXPECT_TRUE( - (std::is_constructible<absl::optional<ConvertsFromInPlaceT>, - absl::in_place_t, absl::in_place_t>::value)); - - EXPECT_FALSE((std::is_constructible<absl::optional<NoDefault>, - absl::in_place_t>::value)); - EXPECT_FALSE((std::is_constructible<absl::optional<NoDefault>, - absl::in_place_t&&>::value)); -} - -// template<U=T> optional(U&&); -TEST(optionalTest, ValueConstructor) { - constexpr absl::optional<int> opt0(0); - static_assert(opt0, ""); - static_assert(*opt0 == 0, ""); - EXPECT_TRUE((std::is_convertible<int, absl::optional<int>>::value)); - // Copy initialization ( = "abc") won't work due to optional(optional&&) - // is not constexpr. Use list initialization instead. This invokes - // absl::optional<ConstexprType>::absl::optional<U>(U&&), with U = const char - // (&) [4], which direct-initializes the ConstexprType value held by the - // optional via ConstexprType::ConstexprType(const char*). - constexpr absl::optional<ConstexprType> opt1 = {"abc"}; - static_assert(opt1, ""); - static_assert(ConstexprType::kCtorConstChar == (*opt1).x, ""); - EXPECT_TRUE( - (std::is_convertible<const char*, absl::optional<ConstexprType>>::value)); - // direct initialization - constexpr absl::optional<ConstexprType> opt2{2}; - static_assert(opt2, ""); - static_assert(ConstexprType::kCtorInt == (*opt2).x, ""); - EXPECT_FALSE( - (std::is_convertible<int, absl::optional<ConstexprType>>::value)); - - // this invokes absl::optional<int>::optional(int&&) - // NOTE: this has different behavior than assignment, e.g. - // "opt3 = {};" clears the optional rather than setting the value to 0 - // According to C++17 standard N4659 [over.ics.list] 16.3.3.1.5, (9.2)- "if - // the initializer list has no elements, the implicit conversion is the - // identity conversion", so `optional(int&&)` should be a better match than - // `optional(optional&&)` which is a user-defined conversion. - // Note: GCC 7 has a bug with this overload selection when compiled with - // `-std=c++17`. -#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 7 && \ - __cplusplus == 201703L -#define ABSL_GCC7_OVER_ICS_LIST_BUG 1 -#endif -#ifndef ABSL_GCC7_OVER_ICS_LIST_BUG - constexpr absl::optional<int> opt3({}); - static_assert(opt3, ""); - static_assert(*opt3 == 0, ""); -#endif - - // this invokes the move constructor with a default constructed optional - // because non-template function is a better match than template function. - absl::optional<ConstexprType> opt4({}); - EXPECT_FALSE(opt4); -} - -struct Implicit {}; - -struct Explicit {}; - -struct Convert { - Convert(const Implicit&) // NOLINT(runtime/explicit) - : implicit(true), move(false) {} - Convert(Implicit&&) // NOLINT(runtime/explicit) - : implicit(true), move(true) {} - explicit Convert(const Explicit&) : implicit(false), move(false) {} - explicit Convert(Explicit&&) : implicit(false), move(true) {} - - bool implicit; - bool move; -}; - -struct ConvertFromOptional { - ConvertFromOptional(const Implicit&) // NOLINT(runtime/explicit) - : implicit(true), move(false), from_optional(false) {} - ConvertFromOptional(Implicit&&) // NOLINT(runtime/explicit) - : implicit(true), move(true), from_optional(false) {} - ConvertFromOptional( - const absl::optional<Implicit>&) // NOLINT(runtime/explicit) - : implicit(true), move(false), from_optional(true) {} - ConvertFromOptional(absl::optional<Implicit>&&) // NOLINT(runtime/explicit) - : implicit(true), move(true), from_optional(true) {} - explicit ConvertFromOptional(const Explicit&) - : implicit(false), move(false), from_optional(false) {} - explicit ConvertFromOptional(Explicit&&) - : implicit(false), move(true), from_optional(false) {} - explicit ConvertFromOptional(const absl::optional<Explicit>&) - : implicit(false), move(false), from_optional(true) {} - explicit ConvertFromOptional(absl::optional<Explicit>&&) - : implicit(false), move(true), from_optional(true) {} - - bool implicit; - bool move; - bool from_optional; -}; - -TEST(optionalTest, ConvertingConstructor) { - absl::optional<Implicit> i_empty; - absl::optional<Implicit> i(absl::in_place); - absl::optional<Explicit> e_empty; - absl::optional<Explicit> e(absl::in_place); - { - // implicitly constructing absl::optional<Convert> from - // absl::optional<Implicit> - absl::optional<Convert> empty = i_empty; - EXPECT_FALSE(empty); - absl::optional<Convert> opt_copy = i; - EXPECT_TRUE(opt_copy); - EXPECT_TRUE(opt_copy->implicit); - EXPECT_FALSE(opt_copy->move); - absl::optional<Convert> opt_move = absl::optional<Implicit>(absl::in_place); - EXPECT_TRUE(opt_move); - EXPECT_TRUE(opt_move->implicit); - EXPECT_TRUE(opt_move->move); - } - { - // explicitly constructing absl::optional<Convert> from - // absl::optional<Explicit> - absl::optional<Convert> empty(e_empty); - EXPECT_FALSE(empty); - absl::optional<Convert> opt_copy(e); - EXPECT_TRUE(opt_copy); - EXPECT_FALSE(opt_copy->implicit); - EXPECT_FALSE(opt_copy->move); - EXPECT_FALSE((std::is_convertible<const absl::optional<Explicit>&, - absl::optional<Convert>>::value)); - absl::optional<Convert> opt_move{absl::optional<Explicit>(absl::in_place)}; - EXPECT_TRUE(opt_move); - EXPECT_FALSE(opt_move->implicit); - EXPECT_TRUE(opt_move->move); - EXPECT_FALSE((std::is_convertible<absl::optional<Explicit>&&, - absl::optional<Convert>>::value)); - } - { - // implicitly constructing absl::optional<ConvertFromOptional> from - // absl::optional<Implicit> via - // ConvertFromOptional(absl::optional<Implicit>&&) check that - // ConvertFromOptional(Implicit&&) is NOT called - static_assert( - std::is_convertible<absl::optional<Implicit>, - absl::optional<ConvertFromOptional>>::value, - ""); - absl::optional<ConvertFromOptional> opt0 = i_empty; - EXPECT_TRUE(opt0); - EXPECT_TRUE(opt0->implicit); - EXPECT_FALSE(opt0->move); - EXPECT_TRUE(opt0->from_optional); - absl::optional<ConvertFromOptional> opt1 = absl::optional<Implicit>(); - EXPECT_TRUE(opt1); - EXPECT_TRUE(opt1->implicit); - EXPECT_TRUE(opt1->move); - EXPECT_TRUE(opt1->from_optional); - } - { - // implicitly constructing absl::optional<ConvertFromOptional> from - // absl::optional<Explicit> via - // ConvertFromOptional(absl::optional<Explicit>&&) check that - // ConvertFromOptional(Explicit&&) is NOT called - absl::optional<ConvertFromOptional> opt0(e_empty); - EXPECT_TRUE(opt0); - EXPECT_FALSE(opt0->implicit); - EXPECT_FALSE(opt0->move); - EXPECT_TRUE(opt0->from_optional); - EXPECT_FALSE( - (std::is_convertible<const absl::optional<Explicit>&, - absl::optional<ConvertFromOptional>>::value)); - absl::optional<ConvertFromOptional> opt1{absl::optional<Explicit>()}; - EXPECT_TRUE(opt1); - EXPECT_FALSE(opt1->implicit); - EXPECT_TRUE(opt1->move); - EXPECT_TRUE(opt1->from_optional); - EXPECT_FALSE( - (std::is_convertible<absl::optional<Explicit>&&, - absl::optional<ConvertFromOptional>>::value)); - } -} - -TEST(optionalTest, StructorBasic) { - StructorListener listener; - Listenable::listener = &listener; - { - absl::optional<Listenable> empty; - EXPECT_FALSE(empty); - absl::optional<Listenable> opt0(absl::in_place); - EXPECT_TRUE(opt0); - absl::optional<Listenable> opt1(absl::in_place, 1); - EXPECT_TRUE(opt1); - absl::optional<Listenable> opt2(absl::in_place, 1, 2); - EXPECT_TRUE(opt2); - } - EXPECT_EQ(1, listener.construct0); - EXPECT_EQ(1, listener.construct1); - EXPECT_EQ(1, listener.construct2); - EXPECT_EQ(3, listener.destruct); -} - -TEST(optionalTest, CopyMoveStructor) { - StructorListener listener; - Listenable::listener = &listener; - absl::optional<Listenable> original(absl::in_place); - EXPECT_EQ(1, listener.construct0); - EXPECT_EQ(0, listener.copy); - EXPECT_EQ(0, listener.move); - absl::optional<Listenable> copy(original); - EXPECT_EQ(1, listener.construct0); - EXPECT_EQ(1, listener.copy); - EXPECT_EQ(0, listener.move); - absl::optional<Listenable> move(std::move(original)); - EXPECT_EQ(1, listener.construct0); - EXPECT_EQ(1, listener.copy); - EXPECT_EQ(1, listener.move); -} - -TEST(optionalTest, ListInit) { - StructorListener listener; - Listenable::listener = &listener; - absl::optional<Listenable> listinit1(absl::in_place, {1}); - absl::optional<Listenable> listinit2(absl::in_place, {1, 2}); - EXPECT_EQ(2, listener.listinit); -} - -TEST(optionalTest, AssignFromNullopt) { - absl::optional<int> opt(1); - opt = absl::nullopt; - EXPECT_FALSE(opt); - - StructorListener listener; - Listenable::listener = &listener; - absl::optional<Listenable> opt1(absl::in_place); - opt1 = absl::nullopt; - EXPECT_FALSE(opt1); - EXPECT_EQ(1, listener.construct0); - EXPECT_EQ(1, listener.destruct); - - EXPECT_TRUE(( - std::is_nothrow_assignable<absl::optional<int>, absl::nullopt_t>::value)); - EXPECT_TRUE((std::is_nothrow_assignable<absl::optional<Listenable>, - absl::nullopt_t>::value)); -} - -TEST(optionalTest, CopyAssignment) { - const absl::optional<int> empty, opt1 = 1, opt2 = 2; - absl::optional<int> empty_to_opt1, opt1_to_opt2, opt2_to_empty; - - EXPECT_FALSE(empty_to_opt1); - empty_to_opt1 = empty; - EXPECT_FALSE(empty_to_opt1); - empty_to_opt1 = opt1; - EXPECT_TRUE(empty_to_opt1); - EXPECT_EQ(1, empty_to_opt1.value()); - - EXPECT_FALSE(opt1_to_opt2); - opt1_to_opt2 = opt1; - EXPECT_TRUE(opt1_to_opt2); - EXPECT_EQ(1, opt1_to_opt2.value()); - opt1_to_opt2 = opt2; - EXPECT_TRUE(opt1_to_opt2); - EXPECT_EQ(2, opt1_to_opt2.value()); - - EXPECT_FALSE(opt2_to_empty); - opt2_to_empty = opt2; - EXPECT_TRUE(opt2_to_empty); - EXPECT_EQ(2, opt2_to_empty.value()); - opt2_to_empty = empty; - EXPECT_FALSE(opt2_to_empty); - - EXPECT_FALSE(absl::is_copy_assignable<absl::optional<const int>>::value); - EXPECT_TRUE(absl::is_copy_assignable<absl::optional<Copyable>>::value); - EXPECT_FALSE(absl::is_copy_assignable<absl::optional<MoveableThrow>>::value); - EXPECT_FALSE( - absl::is_copy_assignable<absl::optional<MoveableNoThrow>>::value); - EXPECT_FALSE(absl::is_copy_assignable<absl::optional<NonMovable>>::value); - - EXPECT_TRUE(absl::is_trivially_copy_assignable<int>::value); - EXPECT_TRUE(absl::is_trivially_copy_assignable<volatile int>::value); - - struct Trivial { - int i; - }; - struct NonTrivial { - NonTrivial& operator=(const NonTrivial&) { return *this; } - int i; - }; - - EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial>::value); - EXPECT_FALSE(absl::is_copy_assignable<const Trivial>::value); - EXPECT_FALSE(absl::is_copy_assignable<volatile Trivial>::value); - EXPECT_TRUE(absl::is_copy_assignable<NonTrivial>::value); - EXPECT_FALSE(absl::is_trivially_copy_assignable<NonTrivial>::value); - -#if !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED) - { - StructorListener listener; - Listenable::listener = &listener; - - absl::optional<volatile Listenable> empty, set(absl::in_place); - EXPECT_EQ(1, listener.construct0); - absl::optional<volatile Listenable> empty_to_empty, empty_to_set, - set_to_empty(absl::in_place), set_to_set(absl::in_place); - EXPECT_EQ(3, listener.construct0); - empty_to_empty = empty; // no effect - empty_to_set = set; // copy construct - set_to_empty = empty; // destruct - set_to_set = set; // copy assign - EXPECT_EQ(1, listener.volatile_copy); - EXPECT_EQ(0, listener.volatile_move); - EXPECT_EQ(1, listener.destruct); - EXPECT_EQ(1, listener.volatile_copy_assign); - } -#endif // !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED) -} - -TEST(optionalTest, MoveAssignment) { - { - StructorListener listener; - Listenable::listener = &listener; - - absl::optional<Listenable> empty1, empty2, set1(absl::in_place), - set2(absl::in_place); - EXPECT_EQ(2, listener.construct0); - absl::optional<Listenable> empty_to_empty, empty_to_set, - set_to_empty(absl::in_place), set_to_set(absl::in_place); - EXPECT_EQ(4, listener.construct0); - empty_to_empty = std::move(empty1); - empty_to_set = std::move(set1); - set_to_empty = std::move(empty2); - set_to_set = std::move(set2); - EXPECT_EQ(0, listener.copy); - EXPECT_EQ(1, listener.move); - EXPECT_EQ(1, listener.destruct); - EXPECT_EQ(1, listener.move_assign); - } -#if !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED) - { - StructorListener listener; - Listenable::listener = &listener; - - absl::optional<volatile Listenable> empty1, empty2, set1(absl::in_place), - set2(absl::in_place); - EXPECT_EQ(2, listener.construct0); - absl::optional<volatile Listenable> empty_to_empty, empty_to_set, - set_to_empty(absl::in_place), set_to_set(absl::in_place); - EXPECT_EQ(4, listener.construct0); - empty_to_empty = std::move(empty1); // no effect - empty_to_set = std::move(set1); // move construct - set_to_empty = std::move(empty2); // destruct - set_to_set = std::move(set2); // move assign - EXPECT_EQ(0, listener.volatile_copy); - EXPECT_EQ(1, listener.volatile_move); - EXPECT_EQ(1, listener.destruct); - EXPECT_EQ(1, listener.volatile_move_assign); - } -#endif // !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED) - EXPECT_FALSE(absl::is_move_assignable<absl::optional<const int>>::value); - EXPECT_TRUE(absl::is_move_assignable<absl::optional<Copyable>>::value); - EXPECT_TRUE(absl::is_move_assignable<absl::optional<MoveableThrow>>::value); - EXPECT_TRUE(absl::is_move_assignable<absl::optional<MoveableNoThrow>>::value); - EXPECT_FALSE(absl::is_move_assignable<absl::optional<NonMovable>>::value); - - EXPECT_FALSE( - std::is_nothrow_move_assignable<absl::optional<MoveableThrow>>::value); - EXPECT_TRUE( - std::is_nothrow_move_assignable<absl::optional<MoveableNoThrow>>::value); -} - -struct NoConvertToOptional { - // disable implicit conversion from const NoConvertToOptional& - // to absl::optional<NoConvertToOptional>. - NoConvertToOptional(const NoConvertToOptional&) = delete; -}; - -struct CopyConvert { - CopyConvert(const NoConvertToOptional&); - CopyConvert& operator=(const CopyConvert&) = delete; - CopyConvert& operator=(const NoConvertToOptional&); -}; - -struct CopyConvertFromOptional { - CopyConvertFromOptional(const NoConvertToOptional&); - CopyConvertFromOptional(const absl::optional<NoConvertToOptional>&); - CopyConvertFromOptional& operator=(const CopyConvertFromOptional&) = delete; - CopyConvertFromOptional& operator=(const NoConvertToOptional&); - CopyConvertFromOptional& operator=( - const absl::optional<NoConvertToOptional>&); -}; - -struct MoveConvert { - MoveConvert(NoConvertToOptional&&); - MoveConvert& operator=(const MoveConvert&) = delete; - MoveConvert& operator=(NoConvertToOptional&&); -}; - -struct MoveConvertFromOptional { - MoveConvertFromOptional(NoConvertToOptional&&); - MoveConvertFromOptional(absl::optional<NoConvertToOptional>&&); - MoveConvertFromOptional& operator=(const MoveConvertFromOptional&) = delete; - MoveConvertFromOptional& operator=(NoConvertToOptional&&); - MoveConvertFromOptional& operator=(absl::optional<NoConvertToOptional>&&); -}; - -// template <typename U = T> absl::optional<T>& operator=(U&& v); -TEST(optionalTest, ValueAssignment) { - absl::optional<int> opt; - EXPECT_FALSE(opt); - opt = 42; - EXPECT_TRUE(opt); - EXPECT_EQ(42, opt.value()); - opt = absl::nullopt; - EXPECT_FALSE(opt); - opt = 42; - EXPECT_TRUE(opt); - EXPECT_EQ(42, opt.value()); - opt = 43; - EXPECT_TRUE(opt); - EXPECT_EQ(43, opt.value()); - opt = {}; // this should clear optional - EXPECT_FALSE(opt); - - opt = {44}; - EXPECT_TRUE(opt); - EXPECT_EQ(44, opt.value()); - - // U = const NoConvertToOptional& - EXPECT_TRUE((std::is_assignable<absl::optional<CopyConvert>&, - const NoConvertToOptional&>::value)); - // U = const absl::optional<NoConvertToOptional>& - EXPECT_TRUE((std::is_assignable<absl::optional<CopyConvertFromOptional>&, - const NoConvertToOptional&>::value)); - // U = const NoConvertToOptional& triggers SFINAE because - // std::is_constructible_v<MoveConvert, const NoConvertToOptional&> is false - EXPECT_FALSE((std::is_assignable<absl::optional<MoveConvert>&, - const NoConvertToOptional&>::value)); - // U = NoConvertToOptional - EXPECT_TRUE((std::is_assignable<absl::optional<MoveConvert>&, - NoConvertToOptional&&>::value)); - // U = const NoConvertToOptional& triggers SFINAE because - // std::is_constructible_v<MoveConvertFromOptional, const - // NoConvertToOptional&> is false - EXPECT_FALSE((std::is_assignable<absl::optional<MoveConvertFromOptional>&, - const NoConvertToOptional&>::value)); - // U = NoConvertToOptional - EXPECT_TRUE((std::is_assignable<absl::optional<MoveConvertFromOptional>&, - NoConvertToOptional&&>::value)); - // U = const absl::optional<NoConvertToOptional>& - EXPECT_TRUE( - (std::is_assignable<absl::optional<CopyConvertFromOptional>&, - const absl::optional<NoConvertToOptional>&>::value)); - // U = absl::optional<NoConvertToOptional> - EXPECT_TRUE( - (std::is_assignable<absl::optional<MoveConvertFromOptional>&, - absl::optional<NoConvertToOptional>&&>::value)); -} - -// template <typename U> absl::optional<T>& operator=(const absl::optional<U>& -// rhs); template <typename U> absl::optional<T>& operator=(absl::optional<U>&& -// rhs); -TEST(optionalTest, ConvertingAssignment) { - absl::optional<int> opt_i; - absl::optional<char> opt_c('c'); - opt_i = opt_c; - EXPECT_TRUE(opt_i); - EXPECT_EQ(*opt_c, *opt_i); - opt_i = absl::optional<char>(); - EXPECT_FALSE(opt_i); - opt_i = absl::optional<char>('d'); - EXPECT_TRUE(opt_i); - EXPECT_EQ('d', *opt_i); - - absl::optional<std::string> opt_str; - absl::optional<const char*> opt_cstr("abc"); - opt_str = opt_cstr; - EXPECT_TRUE(opt_str); - EXPECT_EQ(std::string("abc"), *opt_str); - opt_str = absl::optional<const char*>(); - EXPECT_FALSE(opt_str); - opt_str = absl::optional<const char*>("def"); - EXPECT_TRUE(opt_str); - EXPECT_EQ(std::string("def"), *opt_str); - - // operator=(const absl::optional<U>&) with U = NoConvertToOptional - EXPECT_TRUE( - (std::is_assignable<absl::optional<CopyConvert>, - const absl::optional<NoConvertToOptional>&>::value)); - // operator=(const absl::optional<U>&) with U = NoConvertToOptional - // triggers SFINAE because - // std::is_constructible_v<MoveConvert, const NoConvertToOptional&> is false - EXPECT_FALSE( - (std::is_assignable<absl::optional<MoveConvert>&, - const absl::optional<NoConvertToOptional>&>::value)); - // operator=(absl::optional<U>&&) with U = NoConvertToOptional - EXPECT_TRUE( - (std::is_assignable<absl::optional<MoveConvert>&, - absl::optional<NoConvertToOptional>&&>::value)); - // operator=(const absl::optional<U>&) with U = NoConvertToOptional triggers - // SFINAE because std::is_constructible_v<MoveConvertFromOptional, const - // NoConvertToOptional&> is false. operator=(U&&) with U = const - // absl::optional<NoConverToOptional>& triggers SFINAE because - // std::is_constructible<MoveConvertFromOptional, - // absl::optional<NoConvertToOptional>&&> is true. - EXPECT_FALSE( - (std::is_assignable<absl::optional<MoveConvertFromOptional>&, - const absl::optional<NoConvertToOptional>&>::value)); -} - -TEST(optionalTest, ResetAndHasValue) { - StructorListener listener; - Listenable::listener = &listener; - absl::optional<Listenable> opt; - EXPECT_FALSE(opt); - EXPECT_FALSE(opt.has_value()); - opt.emplace(); - EXPECT_TRUE(opt); - EXPECT_TRUE(opt.has_value()); - opt.reset(); - EXPECT_FALSE(opt); - EXPECT_FALSE(opt.has_value()); - EXPECT_EQ(1, listener.destruct); - opt.reset(); - EXPECT_FALSE(opt); - EXPECT_FALSE(opt.has_value()); - - constexpr absl::optional<int> empty; - static_assert(!empty.has_value(), ""); - constexpr absl::optional<int> nonempty(1); - static_assert(nonempty.has_value(), ""); -} - -TEST(optionalTest, Emplace) { - StructorListener listener; - Listenable::listener = &listener; - absl::optional<Listenable> opt; - EXPECT_FALSE(opt); - opt.emplace(1); - EXPECT_TRUE(opt); - opt.emplace(1, 2); - EXPECT_EQ(1, listener.construct1); - EXPECT_EQ(1, listener.construct2); - EXPECT_EQ(1, listener.destruct); - - absl::optional<std::string> o; - EXPECT_TRUE((std::is_same<std::string&, decltype(o.emplace("abc"))>::value)); - std::string& ref = o.emplace("abc"); - EXPECT_EQ(&ref, &o.value()); -} - -TEST(optionalTest, ListEmplace) { - StructorListener listener; - Listenable::listener = &listener; - absl::optional<Listenable> opt; - EXPECT_FALSE(opt); - opt.emplace({1}); - EXPECT_TRUE(opt); - opt.emplace({1, 2}); - EXPECT_EQ(2, listener.listinit); - EXPECT_EQ(1, listener.destruct); - - absl::optional<Listenable> o; - EXPECT_TRUE((std::is_same<Listenable&, decltype(o.emplace({1}))>::value)); - Listenable& ref = o.emplace({1}); - EXPECT_EQ(&ref, &o.value()); -} - -TEST(optionalTest, Swap) { - absl::optional<int> opt_empty, opt1 = 1, opt2 = 2; - EXPECT_FALSE(opt_empty); - EXPECT_TRUE(opt1); - EXPECT_EQ(1, opt1.value()); - EXPECT_TRUE(opt2); - EXPECT_EQ(2, opt2.value()); - swap(opt_empty, opt1); - EXPECT_FALSE(opt1); - EXPECT_TRUE(opt_empty); - EXPECT_EQ(1, opt_empty.value()); - EXPECT_TRUE(opt2); - EXPECT_EQ(2, opt2.value()); - swap(opt_empty, opt1); - EXPECT_FALSE(opt_empty); - EXPECT_TRUE(opt1); - EXPECT_EQ(1, opt1.value()); - EXPECT_TRUE(opt2); - EXPECT_EQ(2, opt2.value()); - swap(opt1, opt2); - EXPECT_FALSE(opt_empty); - EXPECT_TRUE(opt1); - EXPECT_EQ(2, opt1.value()); - EXPECT_TRUE(opt2); - EXPECT_EQ(1, opt2.value()); - - EXPECT_TRUE(noexcept(opt1.swap(opt2))); - EXPECT_TRUE(noexcept(swap(opt1, opt2))); -} - -template <int v> -struct DeletedOpAddr { - int value = v; - constexpr DeletedOpAddr() = default; - constexpr const DeletedOpAddr<v>* operator&() const = delete; // NOLINT - DeletedOpAddr<v>* operator&() = delete; // NOLINT -}; - -// The static_assert featuring a constexpr call to operator->() is commented out -// to document the fact that the current implementation of absl::optional<T> -// expects such usecases to be malformed and not compile. -TEST(optionalTest, OperatorAddr) { - constexpr int v = -1; - { // constexpr - constexpr absl::optional<DeletedOpAddr<v>> opt(absl::in_place_t{}); - static_assert(opt.has_value(), ""); - // static_assert(opt->value == v, ""); - static_assert((*opt).value == v, ""); - } - { // non-constexpr - const absl::optional<DeletedOpAddr<v>> opt(absl::in_place_t{}); - EXPECT_TRUE(opt.has_value()); - EXPECT_TRUE(opt->value == v); - EXPECT_TRUE((*opt).value == v); - } -} - -TEST(optionalTest, PointerStuff) { - absl::optional<std::string> opt(absl::in_place, "foo"); - EXPECT_EQ("foo", *opt); - const auto& opt_const = opt; - EXPECT_EQ("foo", *opt_const); - EXPECT_EQ(opt->size(), 3u); - EXPECT_EQ(opt_const->size(), 3u); - - constexpr absl::optional<ConstexprType> opt1(1); - static_assert((*opt1).x == ConstexprType::kCtorInt, ""); -} - -TEST(optionalTest, Value) { - using O = absl::optional<std::string>; - using CO = const absl::optional<std::string>; - using OC = absl::optional<const std::string>; - O lvalue(absl::in_place, "lvalue"); - CO clvalue(absl::in_place, "clvalue"); - OC lvalue_c(absl::in_place, "lvalue_c"); - EXPECT_EQ("lvalue", lvalue.value()); - EXPECT_EQ("clvalue", clvalue.value()); - EXPECT_EQ("lvalue_c", lvalue_c.value()); - EXPECT_EQ("xvalue", O(absl::in_place, "xvalue").value()); - EXPECT_EQ("xvalue_c", OC(absl::in_place, "xvalue_c").value()); - EXPECT_EQ("cxvalue", CO(absl::in_place, "cxvalue").value()); - EXPECT_EQ("&", TypeQuals(lvalue.value())); - EXPECT_EQ("c&", TypeQuals(clvalue.value())); - EXPECT_EQ("c&", TypeQuals(lvalue_c.value())); - EXPECT_EQ("&&", TypeQuals(O(absl::in_place, "xvalue").value())); - EXPECT_EQ("c&&", TypeQuals(CO(absl::in_place, "cxvalue").value())); - EXPECT_EQ("c&&", TypeQuals(OC(absl::in_place, "xvalue_c").value())); - -#if !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED) - // test on volatile type - using OV = absl::optional<volatile int>; - OV lvalue_v(absl::in_place, 42); - EXPECT_EQ(42, lvalue_v.value()); - EXPECT_EQ(42, OV(42).value()); - EXPECT_TRUE((std::is_same<volatile int&, decltype(lvalue_v.value())>::value)); - EXPECT_TRUE((std::is_same<volatile int&&, decltype(OV(42).value())>::value)); -#endif // !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED) - - // test exception throw on value() - absl::optional<int> empty; -#ifdef ABSL_HAVE_EXCEPTIONS - EXPECT_THROW((void)empty.value(), absl::bad_optional_access); -#else - EXPECT_DEATH_IF_SUPPORTED((void)empty.value(), "Bad optional access"); -#endif - - // test constexpr value() - constexpr absl::optional<int> o1(1); - static_assert(1 == o1.value(), ""); // const & -#ifndef _MSC_VER - using COI = const absl::optional<int>; - static_assert(2 == COI(2).value(), ""); // const && -#endif -} - -TEST(optionalTest, DerefOperator) { - using O = absl::optional<std::string>; - using CO = const absl::optional<std::string>; - using OC = absl::optional<const std::string>; - O lvalue(absl::in_place, "lvalue"); - CO clvalue(absl::in_place, "clvalue"); - OC lvalue_c(absl::in_place, "lvalue_c"); - EXPECT_EQ("lvalue", *lvalue); - EXPECT_EQ("clvalue", *clvalue); - EXPECT_EQ("lvalue_c", *lvalue_c); - EXPECT_EQ("xvalue", *O(absl::in_place, "xvalue")); - EXPECT_EQ("xvalue_c", *OC(absl::in_place, "xvalue_c")); - EXPECT_EQ("cxvalue", *CO(absl::in_place, "cxvalue")); - EXPECT_EQ("&", TypeQuals(*lvalue)); - EXPECT_EQ("c&", TypeQuals(*clvalue)); - EXPECT_EQ("&&", TypeQuals(*O(absl::in_place, "xvalue"))); - EXPECT_EQ("c&&", TypeQuals(*CO(absl::in_place, "cxvalue"))); - EXPECT_EQ("c&&", TypeQuals(*OC(absl::in_place, "xvalue_c"))); - -#if !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED) - // test on volatile type - using OV = absl::optional<volatile int>; - OV lvalue_v(absl::in_place, 42); - EXPECT_EQ(42, *lvalue_v); - EXPECT_EQ(42, *OV(42)); - EXPECT_TRUE((std::is_same<volatile int&, decltype(*lvalue_v)>::value)); - EXPECT_TRUE((std::is_same<volatile int&&, decltype(*OV(42))>::value)); -#endif // !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED) - - constexpr absl::optional<int> opt1(1); - static_assert(*opt1 == 1, ""); -#if !defined(_MSC_VER) && !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG) - using COI = const absl::optional<int>; - static_assert(*COI(2) == 2, ""); -#endif -} - -TEST(optionalTest, ValueOr) { - absl::optional<double> opt_empty, opt_set = 1.2; - EXPECT_EQ(42.0, opt_empty.value_or(42)); - EXPECT_EQ(1.2, opt_set.value_or(42)); - EXPECT_EQ(42.0, absl::optional<double>().value_or(42)); - EXPECT_EQ(1.2, absl::optional<double>(1.2).value_or(42)); - - constexpr absl::optional<double> copt_empty, copt_set = {1.2}; - static_assert(42.0 == copt_empty.value_or(42), ""); - static_assert(1.2 == copt_set.value_or(42), ""); - using COD = const absl::optional<double>; - static_assert(42.0 == COD().value_or(42), ""); - static_assert(1.2 == COD(1.2).value_or(42), ""); -} - -// make_optional cannot be constexpr until C++17 -TEST(optionalTest, make_optional) { - auto opt_int = absl::make_optional(42); - EXPECT_TRUE((std::is_same<decltype(opt_int), absl::optional<int>>::value)); - EXPECT_EQ(42, opt_int); - - StructorListener listener; - Listenable::listener = &listener; - - absl::optional<Listenable> opt0 = absl::make_optional<Listenable>(); - EXPECT_EQ(1, listener.construct0); - absl::optional<Listenable> opt1 = absl::make_optional<Listenable>(1); - EXPECT_EQ(1, listener.construct1); - absl::optional<Listenable> opt2 = absl::make_optional<Listenable>(1, 2); - EXPECT_EQ(1, listener.construct2); - absl::optional<Listenable> opt3 = absl::make_optional<Listenable>({1}); - absl::optional<Listenable> opt4 = absl::make_optional<Listenable>({1, 2}); - EXPECT_EQ(2, listener.listinit); - - // Constexpr tests on trivially copyable types - // optional<T> has trivial copy/move ctors when T is trivially copyable. - // For nontrivial types with constexpr constructors, we need copy elision in - // C++17 for make_optional to be constexpr. - { - constexpr absl::optional<int> c_opt = absl::make_optional(42); - static_assert(c_opt.value() == 42, ""); - } - { - struct TrivialCopyable { - constexpr TrivialCopyable() : x(0) {} - constexpr explicit TrivialCopyable(int i) : x(i) {} - int x; - }; - - constexpr TrivialCopyable v; - constexpr absl::optional<TrivialCopyable> c_opt0 = absl::make_optional(v); - static_assert((*c_opt0).x == 0, ""); - constexpr absl::optional<TrivialCopyable> c_opt1 = - absl::make_optional<TrivialCopyable>(); - static_assert((*c_opt1).x == 0, ""); - constexpr absl::optional<TrivialCopyable> c_opt2 = - absl::make_optional<TrivialCopyable>(42); - static_assert((*c_opt2).x == 42, ""); - } -} - -template <typename T, typename U> -void optionalTest_Comparisons_EXPECT_LESS(T x, U y) { - EXPECT_FALSE(x == y); - EXPECT_TRUE(x != y); - EXPECT_TRUE(x < y); - EXPECT_FALSE(x > y); - EXPECT_TRUE(x <= y); - EXPECT_FALSE(x >= y); -} - -template <typename T, typename U> -void optionalTest_Comparisons_EXPECT_SAME(T x, U y) { - EXPECT_TRUE(x == y); - EXPECT_FALSE(x != y); - EXPECT_FALSE(x < y); - EXPECT_FALSE(x > y); - EXPECT_TRUE(x <= y); - EXPECT_TRUE(x >= y); -} - -template <typename T, typename U> -void optionalTest_Comparisons_EXPECT_GREATER(T x, U y) { - EXPECT_FALSE(x == y); - EXPECT_TRUE(x != y); - EXPECT_FALSE(x < y); - EXPECT_TRUE(x > y); - EXPECT_FALSE(x <= y); - EXPECT_TRUE(x >= y); -} - -template <typename T, typename U, typename V> -void TestComparisons() { - absl::optional<T> ae, a2{2}, a4{4}; - absl::optional<U> be, b2{2}, b4{4}; - V v3 = 3; - - // LHS: absl::nullopt, ae, a2, v3, a4 - // RHS: absl::nullopt, be, b2, v3, b4 - - // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(absl::nullopt,absl::nullopt); - optionalTest_Comparisons_EXPECT_SAME(absl::nullopt, be); - optionalTest_Comparisons_EXPECT_LESS(absl::nullopt, b2); - // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(absl::nullopt,v3); - optionalTest_Comparisons_EXPECT_LESS(absl::nullopt, b4); - - optionalTest_Comparisons_EXPECT_SAME(ae, absl::nullopt); - optionalTest_Comparisons_EXPECT_SAME(ae, be); - optionalTest_Comparisons_EXPECT_LESS(ae, b2); - optionalTest_Comparisons_EXPECT_LESS(ae, v3); - optionalTest_Comparisons_EXPECT_LESS(ae, b4); - - optionalTest_Comparisons_EXPECT_GREATER(a2, absl::nullopt); - optionalTest_Comparisons_EXPECT_GREATER(a2, be); - optionalTest_Comparisons_EXPECT_SAME(a2, b2); - optionalTest_Comparisons_EXPECT_LESS(a2, v3); - optionalTest_Comparisons_EXPECT_LESS(a2, b4); - - // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(v3,absl::nullopt); - optionalTest_Comparisons_EXPECT_GREATER(v3, be); - optionalTest_Comparisons_EXPECT_GREATER(v3, b2); - optionalTest_Comparisons_EXPECT_SAME(v3, v3); - optionalTest_Comparisons_EXPECT_LESS(v3, b4); - - optionalTest_Comparisons_EXPECT_GREATER(a4, absl::nullopt); - optionalTest_Comparisons_EXPECT_GREATER(a4, be); - optionalTest_Comparisons_EXPECT_GREATER(a4, b2); - optionalTest_Comparisons_EXPECT_GREATER(a4, v3); - optionalTest_Comparisons_EXPECT_SAME(a4, b4); -} - -struct Int1 { - Int1() = default; - Int1(int i) : i(i) {} // NOLINT(runtime/explicit) - int i; -}; - -struct Int2 { - Int2() = default; - Int2(int i) : i(i) {} // NOLINT(runtime/explicit) - int i; -}; - -// comparison between Int1 and Int2 -constexpr bool operator==(const Int1& lhs, const Int2& rhs) { - return lhs.i == rhs.i; -} -constexpr bool operator!=(const Int1& lhs, const Int2& rhs) { - return !(lhs == rhs); -} -constexpr bool operator<(const Int1& lhs, const Int2& rhs) { - return lhs.i < rhs.i; -} -constexpr bool operator<=(const Int1& lhs, const Int2& rhs) { - return lhs < rhs || lhs == rhs; -} -constexpr bool operator>(const Int1& lhs, const Int2& rhs) { - return !(lhs <= rhs); -} -constexpr bool operator>=(const Int1& lhs, const Int2& rhs) { - return !(lhs < rhs); -} - -TEST(optionalTest, Comparisons) { - TestComparisons<int, int, int>(); - TestComparisons<const int, int, int>(); - TestComparisons<Int1, int, int>(); - TestComparisons<int, Int2, int>(); - TestComparisons<Int1, Int2, int>(); - - // compare absl::optional<std::string> with const char* - absl::optional<std::string> opt_str = "abc"; - const char* cstr = "abc"; - EXPECT_TRUE(opt_str == cstr); - // compare absl::optional<std::string> with absl::optional<const char*> - absl::optional<const char*> opt_cstr = cstr; - EXPECT_TRUE(opt_str == opt_cstr); - // compare absl::optional<std::string> with absl::optional<absl::string_view> - absl::optional<absl::string_view> e1; - absl::optional<std::string> e2; - EXPECT_TRUE(e1 == e2); -} - -TEST(optionalTest, SwapRegression) { - StructorListener listener; - Listenable::listener = &listener; - - { - absl::optional<Listenable> a; - absl::optional<Listenable> b(absl::in_place); - a.swap(b); - } - - EXPECT_EQ(1, listener.construct0); - EXPECT_EQ(1, listener.move); - EXPECT_EQ(2, listener.destruct); - - { - absl::optional<Listenable> a(absl::in_place); - absl::optional<Listenable> b; - a.swap(b); - } - - EXPECT_EQ(2, listener.construct0); - EXPECT_EQ(2, listener.move); - EXPECT_EQ(4, listener.destruct); -} - -TEST(optionalTest, BigStringLeakCheck) { - constexpr size_t n = 1 << 16; - - using OS = absl::optional<std::string>; - - OS a; - OS b = absl::nullopt; - OS c = std::string(n, 'c'); - std::string sd(n, 'd'); - OS d = sd; - OS e(absl::in_place, n, 'e'); - OS f; - f.emplace(n, 'f'); - - OS ca(a); - OS cb(b); - OS cc(c); - OS cd(d); - OS ce(e); - - OS oa; - OS ob = absl::nullopt; - OS oc = std::string(n, 'c'); - std::string sod(n, 'd'); - OS od = sod; - OS oe(absl::in_place, n, 'e'); - OS of; - of.emplace(n, 'f'); - - OS ma(std::move(oa)); - OS mb(std::move(ob)); - OS mc(std::move(oc)); - OS md(std::move(od)); - OS me(std::move(oe)); - OS mf(std::move(of)); - - OS aa1; - OS ab1 = absl::nullopt; - OS ac1 = std::string(n, 'c'); - std::string sad1(n, 'd'); - OS ad1 = sad1; - OS ae1(absl::in_place, n, 'e'); - OS af1; - af1.emplace(n, 'f'); - - OS aa2; - OS ab2 = absl::nullopt; - OS ac2 = std::string(n, 'c'); - std::string sad2(n, 'd'); - OS ad2 = sad2; - OS ae2(absl::in_place, n, 'e'); - OS af2; - af2.emplace(n, 'f'); - - aa1 = af2; - ab1 = ae2; - ac1 = ad2; - ad1 = ac2; - ae1 = ab2; - af1 = aa2; - - OS aa3; - OS ab3 = absl::nullopt; - OS ac3 = std::string(n, 'c'); - std::string sad3(n, 'd'); - OS ad3 = sad3; - OS ae3(absl::in_place, n, 'e'); - OS af3; - af3.emplace(n, 'f'); - - aa3 = absl::nullopt; - ab3 = absl::nullopt; - ac3 = absl::nullopt; - ad3 = absl::nullopt; - ae3 = absl::nullopt; - af3 = absl::nullopt; - - OS aa4; - OS ab4 = absl::nullopt; - OS ac4 = std::string(n, 'c'); - std::string sad4(n, 'd'); - OS ad4 = sad4; - OS ae4(absl::in_place, n, 'e'); - OS af4; - af4.emplace(n, 'f'); - - aa4 = OS(absl::in_place, n, 'a'); - ab4 = OS(absl::in_place, n, 'b'); - ac4 = OS(absl::in_place, n, 'c'); - ad4 = OS(absl::in_place, n, 'd'); - ae4 = OS(absl::in_place, n, 'e'); - af4 = OS(absl::in_place, n, 'f'); - - OS aa5; - OS ab5 = absl::nullopt; - OS ac5 = std::string(n, 'c'); - std::string sad5(n, 'd'); - OS ad5 = sad5; - OS ae5(absl::in_place, n, 'e'); - OS af5; - af5.emplace(n, 'f'); - - std::string saa5(n, 'a'); - std::string sab5(n, 'a'); - std::string sac5(n, 'a'); - std::string sad52(n, 'a'); - std::string sae5(n, 'a'); - std::string saf5(n, 'a'); - - aa5 = saa5; - ab5 = sab5; - ac5 = sac5; - ad5 = sad52; - ae5 = sae5; - af5 = saf5; - - OS aa6; - OS ab6 = absl::nullopt; - OS ac6 = std::string(n, 'c'); - std::string sad6(n, 'd'); - OS ad6 = sad6; - OS ae6(absl::in_place, n, 'e'); - OS af6; - af6.emplace(n, 'f'); - - aa6 = std::string(n, 'a'); - ab6 = std::string(n, 'b'); - ac6 = std::string(n, 'c'); - ad6 = std::string(n, 'd'); - ae6 = std::string(n, 'e'); - af6 = std::string(n, 'f'); - - OS aa7; - OS ab7 = absl::nullopt; - OS ac7 = std::string(n, 'c'); - std::string sad7(n, 'd'); - OS ad7 = sad7; - OS ae7(absl::in_place, n, 'e'); - OS af7; - af7.emplace(n, 'f'); - - aa7.emplace(n, 'A'); - ab7.emplace(n, 'B'); - ac7.emplace(n, 'C'); - ad7.emplace(n, 'D'); - ae7.emplace(n, 'E'); - af7.emplace(n, 'F'); -} - -TEST(optionalTest, MoveAssignRegression) { - StructorListener listener; - Listenable::listener = &listener; - - { - absl::optional<Listenable> a; - Listenable b; - a = std::move(b); - } - - EXPECT_EQ(1, listener.construct0); - EXPECT_EQ(1, listener.move); - EXPECT_EQ(2, listener.destruct); -} - -TEST(optionalTest, ValueType) { - EXPECT_TRUE((std::is_same<absl::optional<int>::value_type, int>::value)); - EXPECT_TRUE((std::is_same<absl::optional<std::string>::value_type, - std::string>::value)); - EXPECT_FALSE( - (std::is_same<absl::optional<int>::value_type, absl::nullopt_t>::value)); -} - -template <typename T> -struct is_hash_enabled_for { - template <typename U, typename = decltype(std::hash<U>()(std::declval<U>()))> - static std::true_type test(int); - - template <typename U> - static std::false_type test(...); - - static constexpr bool value = decltype(test<T>(0))::value; -}; - -TEST(optionalTest, Hash) { - std::hash<absl::optional<int>> hash; - std::set<size_t> hashcodes; - hashcodes.insert(hash(absl::nullopt)); - for (int i = 0; i < 100; ++i) { - hashcodes.insert(hash(i)); - } - EXPECT_GT(hashcodes.size(), 90u); - - static_assert(is_hash_enabled_for<absl::optional<int>>::value, ""); - static_assert(is_hash_enabled_for<absl::optional<Hashable>>::value, ""); - static_assert( - absl::type_traits_internal::IsHashable<absl::optional<int>>::value, ""); - static_assert( - absl::type_traits_internal::IsHashable<absl::optional<Hashable>>::value, - ""); - absl::type_traits_internal::AssertHashEnabled<absl::optional<int>>(); - absl::type_traits_internal::AssertHashEnabled<absl::optional<Hashable>>(); - -#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ - static_assert(!is_hash_enabled_for<absl::optional<NonHashable>>::value, ""); - static_assert(!absl::type_traits_internal::IsHashable< - absl::optional<NonHashable>>::value, - ""); -#endif - - // libstdc++ std::optional is missing remove_const_t, i.e. it's using - // std::hash<T> rather than std::hash<std::remove_const_t<T>>. - // Reference: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82262 -#ifndef __GLIBCXX__ - static_assert(is_hash_enabled_for<absl::optional<const int>>::value, ""); - static_assert(is_hash_enabled_for<absl::optional<const Hashable>>::value, ""); - std::hash<absl::optional<const int>> c_hash; - for (int i = 0; i < 100; ++i) { - EXPECT_EQ(hash(i), c_hash(i)); - } -#endif -} - -struct MoveMeNoThrow { - MoveMeNoThrow() : x(0) {} - [[noreturn]] MoveMeNoThrow(const MoveMeNoThrow& other) : x(other.x) { - LOG(FATAL) << "Should not be called."; - } - MoveMeNoThrow(MoveMeNoThrow&& other) noexcept : x(other.x) {} - int x; -}; - -struct MoveMeThrow { - MoveMeThrow() : x(0) {} - MoveMeThrow(const MoveMeThrow& other) : x(other.x) {} - MoveMeThrow(MoveMeThrow&& other) : x(other.x) {} - int x; -}; - -TEST(optionalTest, NoExcept) { - static_assert( - std::is_nothrow_move_constructible<absl::optional<MoveMeNoThrow>>::value, - ""); - static_assert(absl::default_allocator_is_nothrow::value == - std::is_nothrow_move_constructible< - absl::optional<MoveMeThrow>>::value, - ""); - std::vector<absl::optional<MoveMeNoThrow>> v; - for (int i = 0; i < 10; ++i) v.emplace_back(); -} - -struct AnyLike { - AnyLike(AnyLike&&) = default; - AnyLike(const AnyLike&) = default; - - template <typename ValueType, - typename T = typename std::decay<ValueType>::type, - typename std::enable_if< - !absl::disjunction< - std::is_same<AnyLike, T>, - absl::negation<std::is_copy_constructible<T>>>::value, - int>::type = 0> - AnyLike(ValueType&&) {} // NOLINT(runtime/explicit) - - AnyLike& operator=(AnyLike&&) = default; - AnyLike& operator=(const AnyLike&) = default; - - template <typename ValueType, - typename T = typename std::decay<ValueType>::type> - typename std::enable_if< - absl::conjunction<absl::negation<std::is_same<AnyLike, T>>, - std::is_copy_constructible<T>>::value, - AnyLike&>::type - operator=(ValueType&& /* rhs */) { - return *this; - } -}; - -TEST(optionalTest, ConstructionConstraints) { - EXPECT_TRUE((std::is_constructible<AnyLike, absl::optional<AnyLike>>::value)); - - EXPECT_TRUE( - (std::is_constructible<AnyLike, const absl::optional<AnyLike>&>::value)); - - EXPECT_TRUE((std::is_constructible<absl::optional<AnyLike>, AnyLike>::value)); - EXPECT_TRUE( - (std::is_constructible<absl::optional<AnyLike>, const AnyLike&>::value)); - - EXPECT_TRUE((std::is_convertible<absl::optional<AnyLike>, AnyLike>::value)); - - EXPECT_TRUE( - (std::is_convertible<const absl::optional<AnyLike>&, AnyLike>::value)); - - EXPECT_TRUE((std::is_convertible<AnyLike, absl::optional<AnyLike>>::value)); - EXPECT_TRUE( - (std::is_convertible<const AnyLike&, absl::optional<AnyLike>>::value)); - - EXPECT_TRUE(std::is_move_constructible<absl::optional<AnyLike>>::value); - EXPECT_TRUE(std::is_copy_constructible<absl::optional<AnyLike>>::value); -} - -TEST(optionalTest, AssignmentConstraints) { - EXPECT_TRUE((std::is_assignable<AnyLike&, absl::optional<AnyLike>>::value)); - EXPECT_TRUE( - (std::is_assignable<AnyLike&, const absl::optional<AnyLike>&>::value)); - EXPECT_TRUE((std::is_assignable<absl::optional<AnyLike>&, AnyLike>::value)); - EXPECT_TRUE( - (std::is_assignable<absl::optional<AnyLike>&, const AnyLike&>::value)); - EXPECT_TRUE(std::is_move_assignable<absl::optional<AnyLike>>::value); - EXPECT_TRUE(absl::is_copy_assignable<absl::optional<AnyLike>>::value); -} - -#if !defined(__EMSCRIPTEN__) -struct NestedClassBug { - struct Inner { - bool dummy = false; - }; - absl::optional<Inner> value; -}; - -TEST(optionalTest, InPlaceTSFINAEBug) { - NestedClassBug b; - ((void)b); - using Inner = NestedClassBug::Inner; - - EXPECT_TRUE((std::is_default_constructible<Inner>::value)); - EXPECT_TRUE((std::is_constructible<Inner>::value)); - EXPECT_TRUE( - (std::is_constructible<absl::optional<Inner>, absl::in_place_t>::value)); - - absl::optional<Inner> o(absl::in_place); - EXPECT_TRUE(o.has_value()); - o.emplace(); - EXPECT_TRUE(o.has_value()); -} -#endif // !defined(__EMSCRIPTEN__) - -} // namespace - -#endif // #if !defined(ABSL_USES_STD_OPTIONAL)
diff --git a/absl/utility/utility.h b/absl/utility/utility.h index 47074bd..c357e79 100644 --- a/absl/utility/utility.h +++ b/absl/utility/utility.h
@@ -53,6 +53,8 @@ using std::forward; using std::index_sequence; using std::index_sequence_for; +using std::in_place; +using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::integer_sequence; @@ -80,24 +82,6 @@ // Tag types -#ifdef ABSL_USES_STD_OPTIONAL - -using std::in_place_t; -using std::in_place; - -#else // ABSL_USES_STD_OPTIONAL - -// in_place_t -// -// Tag type used to specify in-place construction, such as with -// `absl::optional`, designed to be a drop-in replacement for C++17's -// `std::in_place_t`. -struct in_place_t {}; - -inline constexpr in_place_t in_place = {}; - -#endif // ABSL_USES_STD_OPTIONAL - #ifdef ABSL_USES_STD_VARIANT using std::in_place_index; using std::in_place_index_t;