-- 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: Ibad3da416d08a96ec1f8313f8b519b4270b7e01apull/294/head
parent
93dfcf74cb
commit
666fc1266b
17 changed files with 634 additions and 573 deletions
@ -0,0 +1,364 @@ |
||||
// 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/base/internal/inline_variable.h" |
||||
#include "absl/memory/memory.h" |
||||
#include "absl/meta/type_traits.h" |
||||
#include "absl/utility/utility.h" |
||||
|
||||
namespace absl { |
||||
|
||||
// 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 { |
||||
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
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TYPES_INTERNAL_OPTIONAL_H_
|
Loading…
Reference in new issue