Automated rollback of change 148702459
Change: 148740836
This commit is contained in:
parent
cb126319de
commit
5a31e9c8bd
@ -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",
|
||||
|
@ -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 <functional>
|
||||
#include <initializer_list>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "tensorflow/core/platform/logging.h"
|
||||
|
||||
namespace tensorflow {
|
||||
namespace gtl {
|
||||
|
||||
// A value of type gtl::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
|
||||
// subobject, so sizeof(optional<T>) is approximately sizeof(T)+1. The interface
|
||||
// is based on the upcoming std::optional<T>, and gtl::optional<T> is
|
||||
// designed to be cheaply drop-in replaceable by std::optional<T>, 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<T> and std::optional<T> include:
|
||||
// - gtl::optional<T> is basically a proper subset of
|
||||
// std::optional<T>.
|
||||
// - 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<T> might not quite be a drop-in replacement for
|
||||
// std::experimental::optional<T> 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<string> f() {
|
||||
// string result;
|
||||
// if (...) {
|
||||
// ...
|
||||
// result = ...;
|
||||
// return result;
|
||||
// } else {
|
||||
// ...
|
||||
// return tensorflow::gtl::nullopt;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// int main() {
|
||||
// tensorflow::gtl::optional<string> optstr = f();
|
||||
// if (optstr) {
|
||||
// // non-empty
|
||||
// print(optstr.value());
|
||||
// } else {
|
||||
// // empty
|
||||
// error();
|
||||
// }
|
||||
// }
|
||||
template <typename T>
|
||||
class optional;
|
||||
|
||||
// The tag constant `in_place` is used as the first parameter of an optional<T>
|
||||
// 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<T> 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 <typename T>
|
||||
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<T>::value) {
|
||||
if (src) {
|
||||
construct(std::move(src.reference()));
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a non-empty optional<T> with a copy of the given value of T.
|
||||
optional(const T& src) { // NOLINT(runtime/explicit)
|
||||
construct(src);
|
||||
}
|
||||
|
||||
// Creates a non-empty optional<T> with a moved-in value of T.
|
||||
optional(T&& src) { // NOLINT
|
||||
construct(std::move(src));
|
||||
}
|
||||
|
||||
// optional<T>(in_place, arg1, arg2, arg3) constructs a non-empty optional
|
||||
// with an in-place constructed value of T(arg1,arg2,arg3).
|
||||
template <typename... Args>
|
||||
explicit optional(in_place_t /*unused*/,
|
||||
Args&&... args) { // NOLINT(build/c++11)
|
||||
construct(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// optional<T>(in_place, {arg1, arg2, arg3}) constructs a non-empty optional
|
||||
// with an in-place list-initialized value of T({arg1, arg2, arg3}).
|
||||
template <class U, typename... Args>
|
||||
explicit optional(in_place_t /*unused*/, std::initializer_list<U> il,
|
||||
Args&&... args) { // NOLINT(build/c++11)
|
||||
construct(il, std::forward<Args>(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<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. This is because the current
|
||||
// object will be destructed before the new object is constructed with `args`.
|
||||
//
|
||||
template <typename... Args>
|
||||
void emplace(Args&&... args) {
|
||||
reset();
|
||||
construct(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Emplace reconstruction with initializer-list. See immediately above.
|
||||
template <class U, class... Args>
|
||||
void emplace(std::initializer_list<U> il, Args&&... args) {
|
||||
reset();
|
||||
construct(il, std::forward<Args>(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<T> 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 <class U>
|
||||
T value_or(U&& val) const & {
|
||||
if (*this) {
|
||||
return reference();
|
||||
} else {
|
||||
return static_cast<T>(std::forward<U>(val));
|
||||
}
|
||||
}
|
||||
template <class U>
|
||||
T value_or(U&& val) && { // NOLINT(build/c++11)
|
||||
if (*this) {
|
||||
return std::move(reference());
|
||||
} else {
|
||||
return static_cast<T>(std::forward<U>(val));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Private accessors for internal storage viewed as pointer or reference to T.
|
||||
const T* pointer() const {
|
||||
return static_cast<const T*>(static_cast<const void*>(&storage_));
|
||||
}
|
||||
T* pointer() { return static_cast<T*>(static_cast<void*>(&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 <class... Args>
|
||||
void construct(Args&&... args) {
|
||||
DCHECK(!engaged_);
|
||||
engaged_ = true;
|
||||
new (pointer()) T(std::forward<Args>(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<sizeof(T), alignof(T)>::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<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.");
|
||||
};
|
||||
|
||||
// make_optional(v) creates a non-empty optional<T> where the type T is deduced
|
||||
// from v. Can also be explicitly instantiated as make_optional<T>(v).
|
||||
template <typename T>
|
||||
optional<typename std::decay<T>::type> make_optional(T&& v) {
|
||||
return optional<typename std::decay<T>::type>(std::forward<T>(v));
|
||||
}
|
||||
|
||||
// Relational operators. Empty optionals are considered equal to each
|
||||
// other and less than non-empty optionals. Supports relations between
|
||||
// optional<T> and optional<T>, between optional<T> and T, and between
|
||||
// optional<T> 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 <class T>
|
||||
constexpr bool operator==(const optional<T>& x, const optional<T>& y) {
|
||||
return static_cast<bool>(x) != static_cast<bool>(y)
|
||||
? false
|
||||
: static_cast<bool>(x) == false ? true : *x == *y;
|
||||
}
|
||||
// Returns: If bool(x) != bool(y), true; otherwise, if bool(x) == false, false;
|
||||
// otherwise *x != *y.
|
||||
template <class T>
|
||||
constexpr bool operator!=(const optional<T>& x, const optional<T>& y) {
|
||||
return static_cast<bool>(x) != static_cast<bool>(y)
|
||||
? true
|
||||
: static_cast<bool>(x) == false ? false : *x != *y;
|
||||
}
|
||||
// Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y.
|
||||
template <class T>
|
||||
constexpr bool operator<(const optional<T>& x, const optional<T>& y) {
|
||||
return !y ? false : !x ? true : *x < *y;
|
||||
}
|
||||
// Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y.
|
||||
template <class T>
|
||||
constexpr bool operator>(const optional<T>& x, const optional<T>& y) {
|
||||
return !x ? false : !y ? true : *x > *y;
|
||||
}
|
||||
// Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y.
|
||||
template <class T>
|
||||
constexpr bool operator<=(const optional<T>& x, const optional<T>& y) {
|
||||
return !x ? true : !y ? false : *x <= *y;
|
||||
}
|
||||
// Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y.
|
||||
template <class T>
|
||||
constexpr bool operator>=(const optional<T>& x, const optional<T>& y) {
|
||||
return !y ? true : !x ? false : *x >= *y;
|
||||
}
|
||||
|
||||
// Comparison with nullopt [optional.nullops]
|
||||
// The C++17 (N4606) "Returns:" statements are used directly here.
|
||||
template <class T>
|
||||
constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept {
|
||||
return !x;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept {
|
||||
return !x;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept {
|
||||
return static_cast<bool>(x);
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept {
|
||||
return static_cast<bool>(x);
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator<(const optional<T>& x, nullopt_t) noexcept {
|
||||
return false;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept {
|
||||
return static_cast<bool>(x);
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept {
|
||||
return !x;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator<=(nullopt_t, const optional<T>& x) noexcept {
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept {
|
||||
return static_cast<bool>(x);
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator>(nullopt_t, const optional<T>& x) noexcept {
|
||||
return false;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator>=(const optional<T>& x, nullopt_t) noexcept {
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept {
|
||||
return !x;
|
||||
}
|
||||
|
||||
// Comparison with T [optional.comp_with_t]
|
||||
// The C++17 (N4606) "Equivalent to:" statements are used directly here.
|
||||
template <class T>
|
||||
constexpr bool operator==(const optional<T>& x, const T& v) {
|
||||
return static_cast<bool>(x) ? *x == v : false;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator==(const T& v, const optional<T>& x) {
|
||||
return static_cast<bool>(x) ? v == *x : false;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator!=(const optional<T>& x, const T& v) {
|
||||
return static_cast<bool>(x) ? *x != v : true;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator!=(const T& v, const optional<T>& x) {
|
||||
return static_cast<bool>(x) ? v != *x : true;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator<(const optional<T>& x, const T& v) {
|
||||
return static_cast<bool>(x) ? *x < v : true;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator<(const T& v, const optional<T>& x) {
|
||||
return static_cast<bool>(x) ? v < *x : false;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator<=(const optional<T>& x, const T& v) {
|
||||
return static_cast<bool>(x) ? *x <= v : true;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator<=(const T& v, const optional<T>& x) {
|
||||
return static_cast<bool>(x) ? v <= *x : false;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator>(const optional<T>& x, const T& v) {
|
||||
return static_cast<bool>(x) ? *x > v : false;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator>(const T& v, const optional<T>& x) {
|
||||
return static_cast<bool>(x) ? v > *x : true;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator>=(const optional<T>& x, const T& v) {
|
||||
return static_cast<bool>(x) ? *x >= v : false;
|
||||
}
|
||||
template <class T>
|
||||
constexpr bool operator>=(const T& v, const optional<T>& x) {
|
||||
return static_cast<bool>(x) ? v >= *x : true;
|
||||
}
|
||||
|
||||
// Swap, standard semantics.
|
||||
template <typename T>
|
||||
void swap(optional<T>& a, optional<T>& 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 <class T>
|
||||
struct hash<::tensorflow::gtl::optional<T>> {
|
||||
size_t operator()(const ::tensorflow::gtl::optional<T>& opt) const {
|
||||
if (opt) {
|
||||
return hash<T>()(*opt);
|
||||
} else {
|
||||
return static_cast<size_t>(0x297814aaad196e6dULL);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // TENSORFLOW_LIB_GTL_OPTIONAL_H_
|
@ -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 <typename T> string TypeQuals(T&) { return "&"; }
|
||||
template <typename T> string TypeQuals(T&&) { return "&&"; }
|
||||
template <typename T> string TypeQuals(const T&) { return "c&"; }
|
||||
template <typename T> 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<int> /*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<int> empty;
|
||||
EXPECT_FALSE(empty);
|
||||
}
|
||||
|
||||
TEST(optionalTest, NullOptConstructor) {
|
||||
optional<int> empty(nullopt);
|
||||
EXPECT_FALSE(empty);
|
||||
}
|
||||
|
||||
TEST(optionalTest, CopyConstructor) {
|
||||
optional<int> empty, opt42 = 42;
|
||||
optional<int> empty_copy(empty);
|
||||
EXPECT_FALSE(empty_copy);
|
||||
optional<int> opt42_copy(opt42);
|
||||
EXPECT_TRUE(opt42_copy);
|
||||
EXPECT_EQ(42, opt42_copy);
|
||||
}
|
||||
|
||||
TEST(optionalTest, StructorBasic) {
|
||||
StructorListener listener;
|
||||
Listenable::listener = &listener;
|
||||
{
|
||||
optional<Listenable> empty;
|
||||
EXPECT_FALSE(empty);
|
||||
optional<Listenable> opt0(in_place);
|
||||
EXPECT_TRUE(opt0);
|
||||
optional<Listenable> opt1(in_place, 1);
|
||||
EXPECT_TRUE(opt1);
|
||||
optional<Listenable> 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<Listenable> original(in_place);
|
||||
EXPECT_EQ(1, listener.construct0);
|
||||
EXPECT_EQ(0, listener.copy);
|
||||
EXPECT_EQ(0, listener.move);
|
||||
optional<Listenable> copy(original);
|
||||
EXPECT_EQ(1, listener.construct0);
|
||||
EXPECT_EQ(1, listener.copy);
|
||||
EXPECT_EQ(0, listener.move);
|
||||
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;
|
||||
optional<Listenable> listinit1(in_place, {1});
|
||||
optional<Listenable> listinit2(in_place, {1, 2});
|
||||
EXPECT_EQ(2, listener.listinit);
|
||||
}
|
||||
|
||||
TEST(optionalTest, CopyAssignment) {
|
||||
const optional<int> empty, opt1 = 1, opt2 = 2;
|
||||
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);
|
||||
}
|
||||
|
||||
TEST(optionalTest, MoveAssignment) {
|
||||
StructorListener listener;
|
||||
Listenable::listener = &listener;
|
||||
|
||||
optional<Listenable> empty1, empty2, set1(in_place), set2(in_place);
|
||||
EXPECT_EQ(2, listener.construct0);
|
||||
optional<Listenable> 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<int> 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<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());
|
||||
}
|
||||
|
||||
TEST(optionalTest, Emplace) {
|
||||
StructorListener listener;
|
||||
Listenable::listener = &listener;
|
||||
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);
|
||||
}
|
||||
|
||||
TEST(optionalTest, Swap) {
|
||||
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());
|
||||
}
|
||||
|
||||
TEST(optionalTest, PointerStuff) {
|
||||
optional<string> 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<string>;
|
||||
using CO = const optional<string>;
|
||||
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<string>;
|
||||
using CO = const optional<string>;
|
||||
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<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, optional<double>().value_or(42));
|
||||
EXPECT_EQ(1.2, optional<double>(1.2).value_or(42));
|
||||
}
|
||||
|
||||
TEST(optionalTest, make_optional) { EXPECT_EQ(42, make_optional(42).value()); }
|
||||
|
||||
TEST(optionalTest, Comparisons) {
|
||||
optional<int> 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<Listenable> a;
|
||||
optional<Listenable> b(in_place);
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
EXPECT_EQ(1, listener.construct0);
|
||||
EXPECT_EQ(1, listener.move);
|
||||
EXPECT_EQ(2, listener.destruct);
|
||||
|
||||
{
|
||||
optional<Listenable> a(in_place);
|
||||
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 = optional<string>;
|
||||
|
||||
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<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<optional<int>::value_type, int>::value));
|
||||
EXPECT_TRUE((std::is_same<optional<string>::value_type, string>::value));
|
||||
EXPECT_FALSE((std::is_same<optional<int>::value_type, nullopt_t>::value));
|
||||
}
|
||||
|
||||
TEST(optionalTest, Hash) {
|
||||
std::hash<optional<int>> hash;
|
||||
std::set<size_t> 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<optional<MoveMeNoThrow>>::value, "");
|
||||
static_assert(
|
||||
!std::is_nothrow_move_constructible<optional<MoveMeThrow>>::value, "");
|
||||
std::vector<optional<MoveMeNoThrow>> v;
|
||||
for (int i = 0; i < 10; ++i) v.emplace_back();
|
||||
}
|
||||
|
||||
} // namespace
|
Loading…
Reference in New Issue
Block a user