Export of internal Abseil changes.
-- bc89d3221e3927d08881d75eeee0e8db862300fa by Benjamin Barenblat <bbaren@google.com>: Clean up C-style casts in `ABSL_ASSERT` PiperOrigin-RevId: 241932756 -- 17482daae4b3e2fc725b759586590ac466b72a1e by Jon Cohen <cohenjon@google.com>: Move Gtest-specific CMake code to its own directory PiperOrigin-RevId: 241920192 -- 9ae52b4f665625352c0a789cff884bde492c28f5 by CJ Johnson <johnsoncj@google.com>: Moves private data methods from InlinedVector to InlinedVector Storage in anticipation of migrating the Rep union type PiperOrigin-RevId: 241794144 -- 95315bc50a61a0aae4f171b44c2312158a43e72e by Jon Cohen <cohenjon@google.com>: Use /DNOMINMAX in Abseil tests. This offsets inlcudes of <windows.h> from gtest. PiperOrigin-RevId: 241790584 -- ee505c7f2ab99d29c165ea21a07190474f64053d by CJ Johnson <johnsoncj@google.com>: Adds inlined_vector_internal to the deps of inlined_vector in CMakeLists.txt PiperOrigin-RevId: 241775332 -- 94eb5165b49bab59ce7de143be38a4581d5658da by CJ Johnson <johnsoncj@google.com>: Migrates InlinedVector Storage to class Metadata for compatibility with the eventual member-wise migration to the new exception safe implementation PiperOrigin-RevId: 241633420 -- f99e172caad1ec8b35bf7bbabaf2833d55a6f055 by Abseil Team <absl-team@google.com>: Add MSVC specific linker flags only to MSVC builds. PiperOrigin-RevId: 241615711 -- 3ad19d2779281e945bdf56643dc5cee3f730eb4f by Abseil Team <absl-team@google.com>: Add a comment about per-process randomization of absl::Hash. PiperOrigin-RevId: 241583697 -- 8dfb02d725fee3528351b2da4ed32a7455f9858a by Tom Manshreck <shreck@google.com>: Internal change PiperOrigin-RevId: 241564734 GitOrigin-RevId: bc89d3221e3927d08881d75eeee0e8db862300fa Change-Id: Ibad3da416d08a96ec1f8313f8b519b4270b7e01a
This commit is contained in:
parent
93dfcf74cb
commit
666fc1266b
17 changed files with 634 additions and 573 deletions
|
|
@ -35,8 +35,7 @@
|
|||
#ifndef ABSL_TYPES_OPTIONAL_H_
|
||||
#define ABSL_TYPES_OPTIONAL_H_
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/base/config.h" // TODO(calabrese) IWYU removal?
|
||||
#include "absl/utility/utility.h"
|
||||
|
||||
#ifdef ABSL_HAVE_STD_OPTIONAL
|
||||
|
|
@ -56,7 +55,6 @@ using std::nullopt;
|
|||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
|
|
@ -64,6 +62,7 @@ using std::nullopt;
|
|||
#include "absl/base/internal/inline_variable.h"
|
||||
#include "absl/meta/type_traits.h"
|
||||
#include "absl/types/bad_optional_access.h"
|
||||
#include "absl/types/internal/optional.h"
|
||||
|
||||
// ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
|
||||
//
|
||||
|
|
@ -95,6 +94,22 @@ using std::nullopt;
|
|||
|
||||
namespace absl {
|
||||
|
||||
// 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.
|
||||
ABSL_INTERNAL_INLINE_CONSTEXPR(nullopt_t, nullopt,
|
||||
nullopt_t(optional_internal::init_t()));
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// absl::optional
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
@ -124,361 +139,7 @@ namespace absl {
|
|||
// 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;
|
||||
|
||||
namespace optional_internal {
|
||||
|
||||
// This tag type is used as a constructor parameter type for `nullopt_t`.
|
||||
struct init_t {
|
||||
explicit init_t() = default;
|
||||
};
|
||||
|
||||
} // namespace optional_internal
|
||||
|
||||
// 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.
|
||||
ABSL_INTERNAL_INLINE_CONSTEXPR(nullopt_t, nullopt,
|
||||
nullopt_t(optional_internal::init_t()));
|
||||
|
||||
namespace optional_internal {
|
||||
|
||||
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 {
|
||||
dummy_type dummy_;
|
||||
T data_;
|
||||
};
|
||||
|
||||
void destruct() noexcept {
|
||||
if (engaged_) {
|
||||
data_.~T();
|
||||
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_(absl::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 {
|
||||
dummy_type dummy_;
|
||||
T data_;
|
||||
};
|
||||
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_(absl::forward<Args>(args)...) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class optional_data_base : public optional_data_dtor_base<T> {
|
||||
protected:
|
||||
using base = optional_data_dtor_base<T>;
|
||||
#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
|
||||
using base::base;
|
||||
#else
|
||||
optional_data_base() = default;
|
||||
|
||||
template <typename... Args>
|
||||
constexpr explicit optional_data_base(in_place_t t, Args&&... args)
|
||||
: base(t, absl::forward<Args>(args)...) {}
|
||||
#endif
|
||||
|
||||
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:
|
||||
#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
|
||||
using optional_data_base<T>::optional_data_base;
|
||||
#else
|
||||
optional_data() = default;
|
||||
|
||||
template <typename... Args>
|
||||
constexpr explicit optional_data(in_place_t t, Args&&... args)
|
||||
: optional_data_base<T>(t, absl::forward<Args>(args)...) {}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class optional_data<T, false> : public optional_data_base<T> {
|
||||
protected:
|
||||
#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
|
||||
using optional_data_base<T>::optional_data_base;
|
||||
#else
|
||||
template <typename... Args>
|
||||
constexpr explicit optional_data(in_place_t t, Args&&... args)
|
||||
: optional_data_base<T>(t, absl::forward<Args>(args)...) {}
|
||||
#endif
|
||||
|
||||
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::optional class definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
class optional : private optional_internal::optional_data<T>,
|
||||
private optional_internal::optional_ctor_base<
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue