diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 78337aec547..a2d835d422e 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -246,7 +246,6 @@ cc_library( "lib/gtl/flatmap.h", "lib/gtl/flatset.h", "lib/gtl/inlined_vector.h", - "lib/gtl/optional.h", "lib/gtl/priority_queue_util.h", "lib/hash/crc32c.h", "lib/histogram/histogram.h", @@ -1698,7 +1697,6 @@ tf_cc_tests( "lib/gtl/iterator_range_test.cc", "lib/gtl/manual_constructor_test.cc", "lib/gtl/map_util_test.cc", - "lib/gtl/optional_test.cc", "lib/gtl/top_n_test.cc", "lib/hash/crc32c_test.cc", "lib/hash/hash_test.cc", diff --git a/tensorflow/core/lib/gtl/optional.h b/tensorflow/core/lib/gtl/optional.h deleted file mode 100644 index 443e4a0f8b3..00000000000 --- a/tensorflow/core/lib/gtl/optional.h +++ /dev/null @@ -1,565 +0,0 @@ -/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -==============================================================================*/ - -#ifndef TENSORFLOW_LIB_GTL_OPTIONAL_H_ -#define TENSORFLOW_LIB_GTL_OPTIONAL_H_ - -#include -#include -#include -#include - -#include "tensorflow/core/platform/logging.h" - -namespace tensorflow { -namespace gtl { - -// A value of type gtl::optional holds either a value of T or an -// "empty" value. When it holds a value of T, it stores it as a direct -// subobject, so sizeof(optional) is approximately sizeof(T)+1. The interface -// is based on the upcoming std::optional, and gtl::optional is -// designed to be cheaply drop-in replaceable by std::optional, once it is -// rolled out. -// -// This implementation is based on the specification in N4606 Section 20.6: -// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf -// -// Differences between gtl::optional and std::optional include: -// - gtl::optional is basically a proper subset of -// std::optional. -// - constexpr not used. (dependency on some differences between C++11 and -// C++14.) -// - noexcept not used. -// - exceptions not used - in lieu of exceptions we use CHECK-failure. -// - (b/30115483) gtl::make_optional has a different API than -// std::make_optional. -// -// (b/30115368) std::optional might not quite be a drop-in replacement for -// std::experimental::optional because the semantics of relational operators -// are slightly different. The best way of making sure you aren't affected by -// those changes is to make sure that your type T defines all of the operators -// consistently. (x <= y is exactly equivalent to !(x > y), etc.) -// -// Synopsis: -// -// #include "tensorflow/core/lib/gtl/optional.h" -// -// tensorflow::gtl::optional f() { -// string result; -// if (...) { -// ... -// result = ...; -// return result; -// } else { -// ... -// return tensorflow::gtl::nullopt; -// } -// } -// -// int main() { -// tensorflow::gtl::optional optstr = f(); -// if (optstr) { -// // non-empty -// print(optstr.value()); -// } else { -// // empty -// error(); -// } -// } -template -class optional; - -// The tag constant `in_place` is used as the first parameter of an optional -// constructor to indicate that the remaining arguments should be forwarded -// to the underlying T constructor. -struct in_place_t {}; -extern const in_place_t in_place; - -// The tag constant `nullopt` is used to indicate an empty optional in -// certain functions, such as construction or assignment. -struct nullopt_t { - // It must not be default-constructible to avoid ambiguity for opt = {}. - explicit constexpr nullopt_t(int /*unused*/) {} -}; -extern const nullopt_t nullopt; - -// See comment above first declaration. -template -class optional { - public: - typedef T value_type; - - // A default constructed optional holds the empty value, NOT a default - // constructed T. - optional() {} - - // An optional initialized with `nullopt` holds the empty value. - optional(nullopt_t /*unused*/) {} // NOLINT(runtime/explicit) - - // Copy constructor, standard semantics. - optional(const optional& src) { - if (src) { - construct(src.reference()); - } - } - - // Move constructor, standard semantics. - optional(optional&& src) noexcept( - std::is_nothrow_move_constructible::value) { - if (src) { - construct(std::move(src.reference())); - } - } - - // Creates a non-empty optional with a copy of the given value of T. - optional(const T& src) { // NOLINT(runtime/explicit) - construct(src); - } - - // Creates a non-empty optional with a moved-in value of T. - optional(T&& src) { // NOLINT - construct(std::move(src)); - } - - // optional(in_place, arg1, arg2, arg3) constructs a non-empty optional - // with an in-place constructed value of T(arg1,arg2,arg3). - template - explicit optional(in_place_t /*unused*/, - Args&&... args) { // NOLINT(build/c++11) - construct(std::forward(args)...); - } - - // optional(in_place, {arg1, arg2, arg3}) constructs a non-empty optional - // with an in-place list-initialized value of T({arg1, arg2, arg3}). - template - explicit optional(in_place_t /*unused*/, std::initializer_list il, - Args&&... args) { // NOLINT(build/c++11) - construct(il, std::forward(args)...); - } - - // Destructor, standard semantics. - ~optional() { reset(); } - - // Assignment from nullopt: opt = nullopt - optional& operator=(nullopt_t /*unused*/) { - reset(); - return *this; - } - - // Copy assigment, standard semantics. - optional& operator=(const optional& src) { - if (src) { - operator=(src.reference()); - } else { - reset(); - } - return *this; - } - - // Move assignment, standard semantics. - optional& operator=(optional&& src) { // NOLINT(build/c++11) - if (src) { - operator=(std::move(src.reference())); - } else { - reset(); - } - return *this; - } - - // Copy assigment from T. If empty becomes copy construction. - optional& operator=(const T& src) { // NOLINT(build/c++11) - if (*this) { - reference() = src; - } else { - construct(src); - } - return *this; - } - - // Move assignment from T. If empty becomes move construction. - optional& operator=(T&& src) { // NOLINT(build/c++11) - if (*this) { - reference() = std::move(src); - } else { - construct(std::move(src)); - } - return *this; - } - - // Destroys the inner T value if one is present. - void reset() { - if (engaged_) { - destruct(); - } - DCHECK(!engaged_); - } - - // Emplace reconstruction. (Re)constructs the underlying T in-place with the - // given arguments forwarded: - // - // optional 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. This is because the current - // object will be destructed before the new object is constructed with `args`. - // - template - void emplace(Args&&... args) { - reset(); - construct(std::forward(args)...); - } - - // Emplace reconstruction with initializer-list. See immediately above. - template - void emplace(std::initializer_list il, Args&&... args) { - reset(); - construct(il, std::forward(args)...); - } - - // Swap, standard semantics. - void swap(optional& src) { - if (*this) { - if (src) { - using std::swap; - swap(reference(), src.reference()); - } else { - src.construct(std::move(reference())); - destruct(); - } - } else { - if (src) { - construct(std::move(src.reference())); - src.destruct(); - } else { - // no effect (swap(disengaged, disengaged)) - } - } - } - - // You may use `*opt`, and `opt->m`, to access the underlying T value and T's - // member `m`, respectively. If the optional is empty, behaviour is - // undefined. - const T* operator->() const { - DCHECK(engaged_); - return pointer(); - } - T* operator->() { - DCHECK(engaged_); - return pointer(); - } - const T& operator*() const & { - DCHECK(engaged_); - return reference(); - } - T& operator*() & { - DCHECK(engaged_); - return reference(); - } - const T&& operator*() const && { - DCHECK(engaged_); - return std::move(reference()); - } - T&& operator*() && { - DCHECK(engaged_); - return std::move(reference()); - } - - // In a bool context an optional will return false if and only if it is - // empty. - // - // if (opt) { - // // do something with opt.value(); - // } else { - // // opt is empty - // } - // - explicit operator bool() const { return engaged_; } - - // Returns false if and only if *this is empty. - bool has_value() const { return engaged_; } - - // Use `opt.value()` to get a reference to underlying value. The constness - // and lvalue/rvalue-ness of `opt` is preserved to the view of the T - // subobject. - const T& value() const & { - CHECK(*this) << "Bad optional access"; - return reference(); - } - T& value() & { - CHECK(*this) << "Bad optional access"; - return reference(); - } - T&& value() && { // NOLINT(build/c++11) - CHECK(*this) << "Bad optional access"; - return std::move(reference()); - } - const T&& value() const && { // NOLINT(build/c++11) - CHECK(*this) << "Bad optional access"; - return std::move(reference()); - } - - // Use `opt.value_or(val)` to get either the value of T or the given default - // `val` in the empty case. - template - T value_or(U&& val) const & { - if (*this) { - return reference(); - } else { - return static_cast(std::forward(val)); - } - } - template - T value_or(U&& val) && { // NOLINT(build/c++11) - if (*this) { - return std::move(reference()); - } else { - return static_cast(std::forward(val)); - } - } - - private: - // Private accessors for internal storage viewed as pointer or reference to T. - const T* pointer() const { - return static_cast(static_cast(&storage_)); - } - T* pointer() { return static_cast(static_cast(&storage_)); } - const T& reference() const { return *pointer(); } - T& reference() { return *pointer(); } - - // Construct inner T in place with given `args`. - // Precondition: engaged_ is false - // Postcondition: engaged_ is true - template - void construct(Args&&... args) { - DCHECK(!engaged_); - engaged_ = true; - new (pointer()) T(std::forward(args)...); - DCHECK(engaged_); - } - - // Destruct inner T. - // Precondition: engaged_ is true - // Postcondition: engaged_ is false - void destruct() { - DCHECK(engaged_); - pointer()->T::~T(); - engaged_ = false; - DCHECK(!engaged_); - } - - // The internal storage for a would-be T value, constructed and destroyed - // with placement new and placement delete. - typename std::aligned_storage::type storage_; - - // Whether or not this optional is non-empty. - bool engaged_ = false; - - // T constaint checks. You can't have an optional of nullopt_t, in_place_t or - // a reference. - static_assert( - !std::is_same::type>::value, - "optional is not allowed."); - static_assert( - !std::is_same::type>::value, - "optional is not allowed."); - static_assert(!std::is_reference::value, - "optional is not allowed."); -}; - -// make_optional(v) creates a non-empty optional where the type T is deduced -// from v. Can also be explicitly instantiated as make_optional(v). -template -optional::type> make_optional(T&& v) { - return optional::type>(std::forward(v)); -} - -// Relational operators. Empty optionals are considered equal to each -// other and less than non-empty optionals. Supports relations between -// optional and optional, between optional and T, and between -// optional and nullopt. -// Note: We're careful to support T having non-bool relationals. - -// Relational operators [optional.relops] -// 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 -constexpr bool operator==(const optional& x, const optional& y) { - return static_cast(x) != static_cast(y) - ? false - : static_cast(x) == false ? true : *x == *y; -} -// Returns: If bool(x) != bool(y), true; otherwise, if bool(x) == false, false; -// otherwise *x != *y. -template -constexpr bool operator!=(const optional& x, const optional& y) { - return static_cast(x) != static_cast(y) - ? true - : static_cast(x) == false ? false : *x != *y; -} -// Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y. -template -constexpr bool operator<(const optional& x, const optional& y) { - return !y ? false : !x ? true : *x < *y; -} -// Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y. -template -constexpr bool operator>(const optional& x, const optional& y) { - return !x ? false : !y ? true : *x > *y; -} -// Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y. -template -constexpr bool operator<=(const optional& x, const optional& y) { - return !x ? true : !y ? false : *x <= *y; -} -// Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y. -template -constexpr bool operator>=(const optional& x, const optional& y) { - return !y ? true : !x ? false : *x >= *y; -} - -// Comparison with nullopt [optional.nullops] -// The C++17 (N4606) "Returns:" statements are used directly here. -template -constexpr bool operator==(const optional& x, nullopt_t) noexcept { - return !x; -} -template -constexpr bool operator==(nullopt_t, const optional& x) noexcept { - return !x; -} -template -constexpr bool operator!=(const optional& x, nullopt_t) noexcept { - return static_cast(x); -} -template -constexpr bool operator!=(nullopt_t, const optional& x) noexcept { - return static_cast(x); -} -template -constexpr bool operator<(const optional& x, nullopt_t) noexcept { - return false; -} -template -constexpr bool operator<(nullopt_t, const optional& x) noexcept { - return static_cast(x); -} -template -constexpr bool operator<=(const optional& x, nullopt_t) noexcept { - return !x; -} -template -constexpr bool operator<=(nullopt_t, const optional& x) noexcept { - return true; -} -template -constexpr bool operator>(const optional& x, nullopt_t) noexcept { - return static_cast(x); -} -template -constexpr bool operator>(nullopt_t, const optional& x) noexcept { - return false; -} -template -constexpr bool operator>=(const optional& x, nullopt_t) noexcept { - return true; -} -template -constexpr bool operator>=(nullopt_t, const optional& x) noexcept { - return !x; -} - -// Comparison with T [optional.comp_with_t] -// The C++17 (N4606) "Equivalent to:" statements are used directly here. -template -constexpr bool operator==(const optional& x, const T& v) { - return static_cast(x) ? *x == v : false; -} -template -constexpr bool operator==(const T& v, const optional& x) { - return static_cast(x) ? v == *x : false; -} -template -constexpr bool operator!=(const optional& x, const T& v) { - return static_cast(x) ? *x != v : true; -} -template -constexpr bool operator!=(const T& v, const optional& x) { - return static_cast(x) ? v != *x : true; -} -template -constexpr bool operator<(const optional& x, const T& v) { - return static_cast(x) ? *x < v : true; -} -template -constexpr bool operator<(const T& v, const optional& x) { - return static_cast(x) ? v < *x : false; -} -template -constexpr bool operator<=(const optional& x, const T& v) { - return static_cast(x) ? *x <= v : true; -} -template -constexpr bool operator<=(const T& v, const optional& x) { - return static_cast(x) ? v <= *x : false; -} -template -constexpr bool operator>(const optional& x, const T& v) { - return static_cast(x) ? *x > v : false; -} -template -constexpr bool operator>(const T& v, const optional& x) { - return static_cast(x) ? v > *x : true; -} -template -constexpr bool operator>=(const optional& x, const T& v) { - return static_cast(x) ? *x >= v : false; -} -template -constexpr bool operator>=(const T& v, const optional& x) { - return static_cast(x) ? v >= *x : true; -} - -// Swap, standard semantics. -template -void swap(optional& a, optional& b) { - a.swap(b); -} - -} // namespace gtl -} // namespace tensorflow - -namespace std { - -// std::hash specialization for gtl::optional. Normally std::hash -// specializations are banned in Google code, but the arbiters granted a -// styleguide exception for this one in cl/95369397, as optional is following -// a standard library component. -template -struct hash<::tensorflow::gtl::optional> { - size_t operator()(const ::tensorflow::gtl::optional& opt) const { - if (opt) { - return hash()(*opt); - } else { - return static_cast(0x297814aaad196e6dULL); - } - } -}; - -} // namespace std - -#endif // TENSORFLOW_LIB_GTL_OPTIONAL_H_ diff --git a/tensorflow/core/lib/gtl/optional_test.cc b/tensorflow/core/lib/gtl/optional_test.cc deleted file mode 100644 index 201ccf78892..00000000000 --- a/tensorflow/core/lib/gtl/optional_test.cc +++ /dev/null @@ -1,602 +0,0 @@ -/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -==============================================================================*/ - -#include "tensorflow/core/lib/gtl/optional.h" -#include "tensorflow/core/platform/test.h" - -namespace { - -using tensorflow::gtl::optional; -using tensorflow::gtl::nullopt; -using tensorflow::gtl::nullopt_t; -using tensorflow::gtl::in_place; -using tensorflow::gtl::make_optional; - -template string TypeQuals(T&) { return "&"; } -template string TypeQuals(T&&) { return "&&"; } -template string TypeQuals(const T&) { return "c&"; } -template string TypeQuals(const T&&) { 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; -}; - -struct Listenable { - static StructorListener* listener; - - Listenable() { ++listener->construct0; } - Listenable(int /*unused*/) { ++listener->construct1; } // NOLINT - Listenable(int /*unused*/, int /*unused*/) { ++listener->construct2; } - Listenable(std::initializer_list /*unused*/) { ++listener->listinit; } - Listenable(const Listenable& /*unused*/) { ++listener->copy; } - Listenable(Listenable&& /*unused*/) { ++listener->move; } // NOLINT - Listenable& operator=(const Listenable& /*unused*/) { - ++listener->copy_assign; - return *this; - } - Listenable& operator=(Listenable&& /*unused*/) { // NOLINT - ++listener->move_assign; - return *this; - } - ~Listenable() { ++listener->destruct; } -}; - -StructorListener* Listenable::listener = nullptr; - -TEST(optionalTest, DefaultConstructor) { - optional empty; - EXPECT_FALSE(empty); -} - -TEST(optionalTest, NullOptConstructor) { - optional empty(nullopt); - EXPECT_FALSE(empty); -} - -TEST(optionalTest, CopyConstructor) { - optional empty, opt42 = 42; - optional empty_copy(empty); - EXPECT_FALSE(empty_copy); - optional opt42_copy(opt42); - EXPECT_TRUE(opt42_copy); - EXPECT_EQ(42, opt42_copy); -} - -TEST(optionalTest, StructorBasic) { - StructorListener listener; - Listenable::listener = &listener; - { - optional empty; - EXPECT_FALSE(empty); - optional opt0(in_place); - EXPECT_TRUE(opt0); - optional opt1(in_place, 1); - EXPECT_TRUE(opt1); - optional opt2(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; - optional original(in_place); - EXPECT_EQ(1, listener.construct0); - EXPECT_EQ(0, listener.copy); - EXPECT_EQ(0, listener.move); - optional copy(original); - EXPECT_EQ(1, listener.construct0); - EXPECT_EQ(1, listener.copy); - EXPECT_EQ(0, listener.move); - optional 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; - optional listinit1(in_place, {1}); - optional listinit2(in_place, {1, 2}); - EXPECT_EQ(2, listener.listinit); -} - -TEST(optionalTest, CopyAssignment) { - const optional empty, opt1 = 1, opt2 = 2; - optional 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); -} - -TEST(optionalTest, MoveAssignment) { - StructorListener listener; - Listenable::listener = &listener; - - optional empty1, empty2, set1(in_place), set2(in_place); - EXPECT_EQ(2, listener.construct0); - optional empty_to_empty, empty_to_set, set_to_empty(in_place), - set_to_set(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); -} - -TEST(optionalTest, AssignmentVarious) { - optional opt; - EXPECT_FALSE(opt); - opt = 42; - EXPECT_TRUE(opt); - EXPECT_EQ(42, opt.value()); - opt = nullopt; - EXPECT_FALSE(opt); - opt = 42; - EXPECT_TRUE(opt); - EXPECT_EQ(42, opt.value()); - opt = 43; - EXPECT_TRUE(opt); - EXPECT_EQ(43, opt.value()); -} - -TEST(optionalTest, ResetAndHasValue) { - StructorListener listener; - Listenable::listener = &listener; - optional 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()); -} - -TEST(optionalTest, Emplace) { - StructorListener listener; - Listenable::listener = &listener; - optional 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); -} - -TEST(optionalTest, Swap) { - optional 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()); -} - -TEST(optionalTest, PointerStuff) { - optional opt(in_place, "foo"); - EXPECT_EQ("foo", *opt); - const auto& opt_const = opt; - EXPECT_EQ("foo", *opt_const); - EXPECT_EQ(opt->size(), 3); - EXPECT_EQ(opt_const->size(), 3); -} - -// gcc has a bug pre 4.9 where it doesn't do correct overload resolution -// between rvalue reference qualified member methods. Skip that test to make -// the build green again when using the old compiler. -#if defined(__GNUC__) && !defined(__clang__) -#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 9) -#define SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG -#endif -#endif - -TEST(optionalTest, Value) { - using O = optional; - using CO = const optional; - O lvalue(in_place, "lvalue"); - CO clvalue(in_place, "clvalue"); - EXPECT_EQ("lvalue", lvalue.value()); - EXPECT_EQ("clvalue", clvalue.value()); - EXPECT_EQ("xvalue", O(in_place, "xvalue").value()); -#ifndef SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG - EXPECT_EQ("cxvalue", CO(in_place, "cxvalue").value()); -#endif - EXPECT_EQ("&", TypeQuals(lvalue.value())); - EXPECT_EQ("c&", TypeQuals(clvalue.value())); - EXPECT_EQ("&&", TypeQuals(O(in_place, "xvalue").value())); - EXPECT_EQ("c&&", TypeQuals(CO(in_place, "cxvalue").value())); -} - -TEST(optionalTest, DerefOperator) { - using O = optional; - using CO = const optional; - O lvalue(in_place, "lvalue"); - CO clvalue(in_place, "clvalue"); - EXPECT_EQ("lvalue", *lvalue); - EXPECT_EQ("clvalue", *clvalue); - EXPECT_EQ("xvalue", *O(in_place, "xvalue")); -#ifndef SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG - EXPECT_EQ("cxvalue", *CO(in_place, "cxvalue")); -#endif - EXPECT_EQ("&", TypeQuals(*lvalue)); - EXPECT_EQ("c&", TypeQuals(*clvalue)); - EXPECT_EQ("&&", TypeQuals(*O(in_place, "xvalue"))); - EXPECT_EQ("c&&", TypeQuals(*CO(in_place, "cxvalue"))); -} - -TEST(optionalTest, ValueOr) { - optional 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, optional().value_or(42)); - EXPECT_EQ(1.2, optional(1.2).value_or(42)); -} - -TEST(optionalTest, make_optional) { EXPECT_EQ(42, make_optional(42).value()); } - -TEST(optionalTest, Comparisons) { - optional ae, be, a2 = 2, b2 = 2, a4 = 4, b4 = 4; - -#define optionalTest_Comparisons_EXPECT_LESS(x, 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)); - -#define optionalTest_Comparisons_EXPECT_SAME(x, 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)); - -#define optionalTest_Comparisons_EXPECT_GREATER(x, 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)); - - // LHS: nullopt, ae, a2, 3, a4 - // RHS: nullopt, be, b2, 3, b4 - - // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(nullopt,nullopt); - optionalTest_Comparisons_EXPECT_SAME(nullopt, be); - optionalTest_Comparisons_EXPECT_LESS(nullopt, b2); - // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(nullopt,3); - optionalTest_Comparisons_EXPECT_LESS(nullopt, b4); - - optionalTest_Comparisons_EXPECT_SAME(ae, nullopt); - optionalTest_Comparisons_EXPECT_SAME(ae, be); - optionalTest_Comparisons_EXPECT_LESS(ae, b2); - optionalTest_Comparisons_EXPECT_LESS(ae, 3); - optionalTest_Comparisons_EXPECT_LESS(ae, b4); - - optionalTest_Comparisons_EXPECT_GREATER(a2, nullopt); - optionalTest_Comparisons_EXPECT_GREATER(a2, be); - optionalTest_Comparisons_EXPECT_SAME(a2, b2); - optionalTest_Comparisons_EXPECT_LESS(a2, 3); - optionalTest_Comparisons_EXPECT_LESS(a2, b4); - - // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(3,nullopt); - optionalTest_Comparisons_EXPECT_GREATER(3, be); - optionalTest_Comparisons_EXPECT_GREATER(3, b2); - optionalTest_Comparisons_EXPECT_SAME(3, 3); - optionalTest_Comparisons_EXPECT_LESS(3, b4); - - optionalTest_Comparisons_EXPECT_GREATER(a4, nullopt); - optionalTest_Comparisons_EXPECT_GREATER(a4, be); - optionalTest_Comparisons_EXPECT_GREATER(a4, b2); - optionalTest_Comparisons_EXPECT_GREATER(a4, 3); - optionalTest_Comparisons_EXPECT_SAME(a4, b4); -} - -TEST(optionalTest, SwapRegression) { - StructorListener listener; - Listenable::listener = &listener; - - { - optional a; - optional b(in_place); - a.swap(b); - } - - EXPECT_EQ(1, listener.construct0); - EXPECT_EQ(1, listener.move); - EXPECT_EQ(2, listener.destruct); - - { - optional a(in_place); - optional 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 = optional; - - OS a; - OS b = nullopt; - OS c = string(n, 'c'); - string sd(n, 'd'); - OS d = sd; - OS e(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 = nullopt; - OS oc = string(n, 'c'); - string sod(n, 'd'); - OS od = sod; - OS oe(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 = nullopt; - OS ac1 = string(n, 'c'); - string sad1(n, 'd'); - OS ad1 = sad1; - OS ae1(in_place, n, 'e'); - OS af1; - af1.emplace(n, 'f'); - - OS aa2; - OS ab2 = nullopt; - OS ac2 = string(n, 'c'); - string sad2(n, 'd'); - OS ad2 = sad2; - OS ae2(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 = nullopt; - OS ac3 = string(n, 'c'); - string sad3(n, 'd'); - OS ad3 = sad3; - OS ae3(in_place, n, 'e'); - OS af3; - af3.emplace(n, 'f'); - - aa3 = nullopt; - ab3 = nullopt; - ac3 = nullopt; - ad3 = nullopt; - ae3 = nullopt; - af3 = nullopt; - - OS aa4; - OS ab4 = nullopt; - OS ac4 = string(n, 'c'); - string sad4(n, 'd'); - OS ad4 = sad4; - OS ae4(in_place, n, 'e'); - OS af4; - af4.emplace(n, 'f'); - - aa4 = OS(in_place, n, 'a'); - ab4 = OS(in_place, n, 'b'); - ac4 = OS(in_place, n, 'c'); - ad4 = OS(in_place, n, 'd'); - ae4 = OS(in_place, n, 'e'); - af4 = OS(in_place, n, 'f'); - - OS aa5; - OS ab5 = nullopt; - OS ac5 = string(n, 'c'); - string sad5(n, 'd'); - OS ad5 = sad5; - OS ae5(in_place, n, 'e'); - OS af5; - af5.emplace(n, 'f'); - - string saa5(n, 'a'); - string sab5(n, 'a'); - string sac5(n, 'a'); - string sad52(n, 'a'); - string sae5(n, 'a'); - string saf5(n, 'a'); - - aa5 = saa5; - ab5 = sab5; - ac5 = sac5; - ad5 = sad52; - ae5 = sae5; - af5 = saf5; - - OS aa6; - OS ab6 = nullopt; - OS ac6 = string(n, 'c'); - string sad6(n, 'd'); - OS ad6 = sad6; - OS ae6(in_place, n, 'e'); - OS af6; - af6.emplace(n, 'f'); - - aa6 = string(n, 'a'); - ab6 = string(n, 'b'); - ac6 = string(n, 'c'); - ad6 = string(n, 'd'); - ae6 = string(n, 'e'); - af6 = string(n, 'f'); - - OS aa7; - OS ab7 = nullopt; - OS ac7 = string(n, 'c'); - string sad7(n, 'd'); - OS ad7 = sad7; - OS ae7(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; - - { - optional 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::value_type, int>::value)); - EXPECT_TRUE((std::is_same::value_type, string>::value)); - EXPECT_FALSE((std::is_same::value_type, nullopt_t>::value)); -} - -TEST(optionalTest, Hash) { - std::hash> hash; - std::set hashcodes; - hashcodes.insert(hash(nullopt)); - for (int i = 0; i < 100; ++i) { - hashcodes.insert(hash(i)); - } - EXPECT_GT(hashcodes.size(), 90); -} - -struct MoveMeNoThrow { - MoveMeNoThrow() : x(0) {} - 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>::value, ""); - static_assert( - !std::is_nothrow_move_constructible>::value, ""); - std::vector> v; - for (int i = 0; i < 10; ++i) v.emplace_back(); -} - -} // namespace