| // Copyright 2019 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. |
| // |
| // ----------------------------------------------------------------------------- |
| // conformance_archetype.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This file contains a facility for generating "archetypes" of out of |
| // "Conformance Profiles" (see "conformance_profiles.h" for more information |
| // about Conformance Profiles). An archetype is a type that aims to support the |
| // bare minimum requirements of a given Conformance Profile. For instance, an |
| // archetype that corresponds to an ImmutableProfile has exactly a nothrow |
| // move-constructor, a potentially-throwing copy constructor, a nothrow |
| // destructor, with all other special-member-functions deleted. These archetypes |
| // are useful for testing to make sure that templates are able to work with the |
| // kinds of types that they claim to support (i.e. that they do not accidentally |
| // under-constrain), |
| // |
| // The main type template in this file is the Archetype template, which takes |
| // a Conformance Profile as a template argument and its instantiations are a |
| // minimum-conforming model of that profile. |
| |
| #ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_ARCHETYPE_H_ |
| #define ABSL_TYPES_INTERNAL_CONFORMANCE_ARCHETYPE_H_ |
| |
| #include <cstddef> |
| #include <functional> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/meta/type_traits.h" |
| #include "absl/types/internal/conformance_profile.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace types_internal { |
| |
| // A minimum-conforming implementation of a type with properties specified in |
| // `Prof`, where `Prof` is a valid Conformance Profile. |
| template <class Prof, class /*Enabler*/ = void> |
| class Archetype; |
| |
| // Given an Archetype, obtain the properties of the profile associated with that |
| // archetype. |
| template <class Archetype> |
| struct PropertiesOfArchetype; |
| |
| template <class Prof> |
| struct PropertiesOfArchetype<Archetype<Prof>> { |
| using type = PropertiesOfT<Prof>; |
| }; |
| |
| template <class Archetype> |
| using PropertiesOfArchetypeT = typename PropertiesOfArchetype<Archetype>::type; |
| |
| // A metafunction to determine if a type is an `Archetype`. |
| template <class T> |
| struct IsArchetype : std::false_type {}; |
| |
| template <class Prof> |
| struct IsArchetype<Archetype<Prof>> : std::true_type {}; |
| |
| // A constructor tag type used when creating an Archetype with internal state. |
| struct MakeArchetypeState {}; |
| |
| // Data stored within an archetype that is copied/compared/hashed when the |
| // corresponding operations are used. |
| using ArchetypeState = std::size_t; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // This section of the file defines a chain of base classes for Archetype, // |
| // where each base defines a specific special member function with the // |
| // appropriate properties (deleted, noexcept(false), noexcept, or trivial). // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| // The bottom-most base, which contains the state and the default constructor. |
| template <default_constructible DefaultConstructibleValue> |
| struct ArchetypeStateBase { |
| static_assert(DefaultConstructibleValue == default_constructible::yes || |
| DefaultConstructibleValue == default_constructible::nothrow, |
| ""); |
| |
| ArchetypeStateBase() noexcept( |
| DefaultConstructibleValue == |
| default_constructible:: |
| nothrow) /*Vacuous archetype_state initialization*/ {} |
| explicit ArchetypeStateBase(MakeArchetypeState, ArchetypeState state) noexcept |
| : archetype_state(state) {} |
| |
| ArchetypeState archetype_state; |
| }; |
| |
| template <> |
| struct ArchetypeStateBase<default_constructible::maybe> { |
| explicit ArchetypeStateBase() = delete; |
| explicit ArchetypeStateBase(MakeArchetypeState, ArchetypeState state) noexcept |
| : archetype_state(state) {} |
| |
| ArchetypeState archetype_state; |
| }; |
| |
| template <> |
| struct ArchetypeStateBase<default_constructible::trivial> { |
| ArchetypeStateBase() = default; |
| explicit ArchetypeStateBase(MakeArchetypeState, ArchetypeState state) noexcept |
| : archetype_state(state) {} |
| |
| ArchetypeState archetype_state; |
| }; |
| |
| // The move-constructor base |
| template <default_constructible DefaultConstructibleValue, |
| move_constructible MoveConstructibleValue> |
| struct ArchetypeMoveConstructor |
| : ArchetypeStateBase<DefaultConstructibleValue> { |
| static_assert(MoveConstructibleValue == move_constructible::yes || |
| MoveConstructibleValue == move_constructible::nothrow, |
| ""); |
| |
| explicit ArchetypeMoveConstructor(MakeArchetypeState, |
| ArchetypeState state) noexcept |
| : ArchetypeStateBase<DefaultConstructibleValue>(MakeArchetypeState(), |
| state) {} |
| |
| ArchetypeMoveConstructor() = default; |
| ArchetypeMoveConstructor(ArchetypeMoveConstructor&& other) noexcept( |
| MoveConstructibleValue == move_constructible::nothrow) |
| : ArchetypeStateBase<DefaultConstructibleValue>(MakeArchetypeState(), |
| other.archetype_state) {} |
| ArchetypeMoveConstructor(const ArchetypeMoveConstructor&) = default; |
| ArchetypeMoveConstructor& operator=(ArchetypeMoveConstructor&&) = default; |
| ArchetypeMoveConstructor& operator=(const ArchetypeMoveConstructor&) = |
| default; |
| }; |
| |
| template <default_constructible DefaultConstructibleValue> |
| struct ArchetypeMoveConstructor<DefaultConstructibleValue, |
| move_constructible::trivial> |
| : ArchetypeStateBase<DefaultConstructibleValue> { |
| explicit ArchetypeMoveConstructor(MakeArchetypeState, |
| ArchetypeState state) noexcept |
| : ArchetypeStateBase<DefaultConstructibleValue>(MakeArchetypeState(), |
| state) {} |
| |
| ArchetypeMoveConstructor() = default; |
| }; |
| |
| // The copy-constructor base |
| template <default_constructible DefaultConstructibleValue, |
| move_constructible MoveConstructibleValue, |
| copy_constructible CopyConstructibleValue> |
| struct ArchetypeCopyConstructor |
| : ArchetypeMoveConstructor<DefaultConstructibleValue, |
| MoveConstructibleValue> { |
| static_assert(CopyConstructibleValue == copy_constructible::yes || |
| CopyConstructibleValue == copy_constructible::nothrow, |
| ""); |
| explicit ArchetypeCopyConstructor(MakeArchetypeState, |
| ArchetypeState state) noexcept |
| : ArchetypeMoveConstructor<DefaultConstructibleValue, |
| MoveConstructibleValue>(MakeArchetypeState(), |
| state) {} |
| |
| ArchetypeCopyConstructor() = default; |
| ArchetypeCopyConstructor(ArchetypeCopyConstructor&&) = default; |
| ArchetypeCopyConstructor(const ArchetypeCopyConstructor& other) noexcept( |
| CopyConstructibleValue == copy_constructible::nothrow) |
| : ArchetypeMoveConstructor<DefaultConstructibleValue, |
| MoveConstructibleValue>( |
| MakeArchetypeState(), other.archetype_state) {} |
| ArchetypeCopyConstructor& operator=(ArchetypeCopyConstructor&&) = default; |
| ArchetypeCopyConstructor& operator=(const ArchetypeCopyConstructor&) = |
| default; |
| }; |
| |
| template <default_constructible DefaultConstructibleValue, |
| move_constructible MoveConstructibleValue> |
| struct ArchetypeCopyConstructor<DefaultConstructibleValue, |
| MoveConstructibleValue, |
| copy_constructible::maybe> |
| : ArchetypeMoveConstructor<DefaultConstructibleValue, |
| MoveConstructibleValue> { |
| explicit ArchetypeCopyConstructor(MakeArchetypeState, |
| ArchetypeState state) noexcept |
| : ArchetypeMoveConstructor<DefaultConstructibleValue, |
| MoveConstructibleValue>(MakeArchetypeState(), |
| state) {} |
| |
| ArchetypeCopyConstructor() = default; |
| ArchetypeCopyConstructor(ArchetypeCopyConstructor&&) = default; |
| ArchetypeCopyConstructor(const ArchetypeCopyConstructor&) = delete; |
| ArchetypeCopyConstructor& operator=(ArchetypeCopyConstructor&&) = default; |
| ArchetypeCopyConstructor& operator=(const ArchetypeCopyConstructor&) = |
| default; |
| }; |
| |
| template <default_constructible DefaultConstructibleValue, |
| move_constructible MoveConstructibleValue> |
| struct ArchetypeCopyConstructor<DefaultConstructibleValue, |
| MoveConstructibleValue, |
| copy_constructible::trivial> |
| : ArchetypeMoveConstructor<DefaultConstructibleValue, |
| MoveConstructibleValue> { |
| explicit ArchetypeCopyConstructor(MakeArchetypeState, |
| ArchetypeState state) noexcept |
| : ArchetypeMoveConstructor<DefaultConstructibleValue, |
| MoveConstructibleValue>(MakeArchetypeState(), |
| state) {} |
| |
| ArchetypeCopyConstructor() = default; |
| }; |
| |
| // The move-assign base |
| template <default_constructible DefaultConstructibleValue, |
| move_constructible MoveConstructibleValue, |
| copy_constructible CopyConstructibleValue, |
| move_assignable MoveAssignableValue> |
| struct ArchetypeMoveAssign |
| : ArchetypeCopyConstructor<DefaultConstructibleValue, |
| MoveConstructibleValue, CopyConstructibleValue> { |
| static_assert(MoveAssignableValue == move_assignable::yes || |
| MoveAssignableValue == move_assignable::nothrow, |
| ""); |
| explicit ArchetypeMoveAssign(MakeArchetypeState, |
| ArchetypeState state) noexcept |
| : ArchetypeCopyConstructor<DefaultConstructibleValue, |
| MoveConstructibleValue, |
| CopyConstructibleValue>(MakeArchetypeState(), |
| state) {} |
| |
| ArchetypeMoveAssign() = default; |
| ArchetypeMoveAssign(ArchetypeMoveAssign&&) = default; |
| ArchetypeMoveAssign(const ArchetypeMoveAssign&) = default; |
| ArchetypeMoveAssign& operator=(ArchetypeMoveAssign&& other) noexcept( |
| MoveAssignableValue == move_assignable::nothrow) { |
| this->archetype_state = other.archetype_state; |
| return *this; |
| } |
| |
| ArchetypeMoveAssign& operator=(const ArchetypeMoveAssign&) = default; |
| }; |
| |
| template <default_constructible DefaultConstructibleValue, |
| move_constructible MoveConstructibleValue, |
| copy_constructible CopyConstructibleValue> |
| struct ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue, |
| CopyConstructibleValue, move_assignable::trivial> |
| : ArchetypeCopyConstructor<DefaultConstructibleValue, |
| MoveConstructibleValue, CopyConstructibleValue> { |
| explicit ArchetypeMoveAssign(MakeArchetypeState, |
| ArchetypeState state) noexcept |
| : ArchetypeCopyConstructor<DefaultConstructibleValue, |
| MoveConstructibleValue, |
| CopyConstructibleValue>(MakeArchetypeState(), |
| state) {} |
| |
| ArchetypeMoveAssign() = default; |
| }; |
| |
| // The copy-assign base |
| template <default_constructible DefaultConstructibleValue, |
| move_constructible MoveConstructibleValue, |
| copy_constructible CopyConstructibleValue, |
| move_assignable MoveAssignableValue, |
| copy_assignable CopyAssignableValue> |
| struct ArchetypeCopyAssign |
| : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue, |
| CopyConstructibleValue, MoveAssignableValue> { |
| static_assert(CopyAssignableValue == copy_assignable::yes || |
| CopyAssignableValue == copy_assignable::nothrow, |
| ""); |
| explicit ArchetypeCopyAssign(MakeArchetypeState, |
| ArchetypeState state) noexcept |
| : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue, |
| CopyConstructibleValue, MoveAssignableValue>( |
| MakeArchetypeState(), state) {} |
| |
| ArchetypeCopyAssign() = default; |
| ArchetypeCopyAssign(ArchetypeCopyAssign&&) = default; |
| ArchetypeCopyAssign(const ArchetypeCopyAssign&) = default; |
| ArchetypeCopyAssign& operator=(ArchetypeCopyAssign&&) = default; |
| |
| ArchetypeCopyAssign& operator=(const ArchetypeCopyAssign& other) noexcept( |
| CopyAssignableValue == copy_assignable::nothrow) { |
| this->archetype_state = other.archetype_state; |
| return *this; |
| } |
| }; |
| |
| template <default_constructible DefaultConstructibleValue, |
| move_constructible MoveConstructibleValue, |
| copy_constructible CopyConstructibleValue, |
| move_assignable MoveAssignableValue> |
| struct ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue, |
| CopyConstructibleValue, MoveAssignableValue, |
| copy_assignable::maybe> |
| : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue, |
| CopyConstructibleValue, MoveAssignableValue> { |
| explicit ArchetypeCopyAssign(MakeArchetypeState, |
| ArchetypeState state) noexcept |
| : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue, |
| CopyConstructibleValue, MoveAssignableValue>( |
| MakeArchetypeState(), state) {} |
| |
| ArchetypeCopyAssign() = default; |
| ArchetypeCopyAssign(ArchetypeCopyAssign&&) = default; |
| ArchetypeCopyAssign(const ArchetypeCopyAssign&) = default; |
| ArchetypeCopyAssign& operator=(ArchetypeCopyAssign&&) = default; |
| ArchetypeCopyAssign& operator=(const ArchetypeCopyAssign&) = delete; |
| }; |
| |
| template <default_constructible DefaultConstructibleValue, |
| move_constructible MoveConstructibleValue, |
| copy_constructible CopyConstructibleValue, |
| move_assignable MoveAssignableValue> |
| struct ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue, |
| CopyConstructibleValue, MoveAssignableValue, |
| copy_assignable::trivial> |
| : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue, |
| CopyConstructibleValue, MoveAssignableValue> { |
| explicit ArchetypeCopyAssign(MakeArchetypeState, |
| ArchetypeState state) noexcept |
| : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue, |
| CopyConstructibleValue, MoveAssignableValue>( |
| MakeArchetypeState(), state) {} |
| |
| ArchetypeCopyAssign() = default; |
| }; |
| |
| // The destructor base |
| template <default_constructible DefaultConstructibleValue, |
| move_constructible MoveConstructibleValue, |
| copy_constructible CopyConstructibleValue, |
| move_assignable MoveAssignableValue, |
| copy_assignable CopyAssignableValue, destructible DestructibleValue> |
| struct ArchetypeDestructor |
| : ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue, |
| CopyConstructibleValue, MoveAssignableValue, |
| CopyAssignableValue> { |
| static_assert(DestructibleValue == destructible::yes || |
| DestructibleValue == destructible::nothrow, |
| ""); |
| |
| explicit ArchetypeDestructor(MakeArchetypeState, |
| ArchetypeState state) noexcept |
| : ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue, |
| CopyConstructibleValue, MoveAssignableValue, |
| CopyAssignableValue>(MakeArchetypeState(), state) {} |
| |
| ArchetypeDestructor() = default; |
| ArchetypeDestructor(ArchetypeDestructor&&) = default; |
| ArchetypeDestructor(const ArchetypeDestructor&) = default; |
| ArchetypeDestructor& operator=(ArchetypeDestructor&&) = default; |
| ArchetypeDestructor& operator=(const ArchetypeDestructor&) = default; |
| ~ArchetypeDestructor() noexcept(DestructibleValue == destructible::nothrow) {} |
| }; |
| |
| template <default_constructible DefaultConstructibleValue, |
| move_constructible MoveConstructibleValue, |
| copy_constructible CopyConstructibleValue, |
| move_assignable MoveAssignableValue, |
| copy_assignable CopyAssignableValue> |
| struct ArchetypeDestructor<DefaultConstructibleValue, MoveConstructibleValue, |
| CopyConstructibleValue, MoveAssignableValue, |
| CopyAssignableValue, destructible::trivial> |
| : ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue, |
| CopyConstructibleValue, MoveAssignableValue, |
| CopyAssignableValue> { |
| explicit ArchetypeDestructor(MakeArchetypeState, |
| ArchetypeState state) noexcept |
| : ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue, |
| CopyConstructibleValue, MoveAssignableValue, |
| CopyAssignableValue>(MakeArchetypeState(), state) {} |
| |
| ArchetypeDestructor() = default; |
| }; |
| |
| // An alias to the top of the chain of bases for special-member functions. |
| // NOTE: move_constructible::maybe, move_assignable::maybe, and |
| // destructible::maybe are handled in the top-level type by way of SFINAE. |
| // Because of this, we never instantiate the base classes with |
| // move_constructible::maybe, move_assignable::maybe, or destructible::maybe so |
| // that we minimize the number of different possible type-template |
| // instantiations. |
| template <default_constructible DefaultConstructibleValue, |
| move_constructible MoveConstructibleValue, |
| copy_constructible CopyConstructibleValue, |
| move_assignable MoveAssignableValue, |
| copy_assignable CopyAssignableValue, destructible DestructibleValue> |
| using ArchetypeSpecialMembersBase = ArchetypeDestructor< |
| DefaultConstructibleValue, |
| MoveConstructibleValue != move_constructible::maybe |
| ? MoveConstructibleValue |
| : move_constructible::nothrow, |
| CopyConstructibleValue, |
| MoveAssignableValue != move_assignable::maybe ? MoveAssignableValue |
| : move_assignable::nothrow, |
| CopyAssignableValue, |
| DestructibleValue != destructible::maybe ? DestructibleValue |
| : destructible::nothrow>; |
| |
| // A function that is used to create an archetype with some associated state. |
| template <class Arch> |
| Arch MakeArchetype(ArchetypeState state) noexcept { |
| static_assert(IsArchetype<Arch>::value, |
| "The explicit template argument to MakeArchetype is required " |
| "to be an Archetype."); |
| return Arch(MakeArchetypeState(), state); |
| } |
| |
| // This is used to conditionally delete "copy" and "move" constructors in a way |
| // that is consistent with what the ConformanceProfile requires and that also |
| // strictly enforces the arguments to the copy/move to not come from implicit |
| // conversions when dealing with the Archetype. |
| template <class Prof, class T> |
| constexpr bool ShouldDeleteConstructor() { |
| return !((PropertiesOfT<Prof>::move_constructible_support != |
| move_constructible::maybe && |
| std::is_same<T, Archetype<Prof>>::value) || |
| (PropertiesOfT<Prof>::copy_constructible_support != |
| copy_constructible::maybe && |
| (std::is_same<T, const Archetype<Prof>&>::value || |
| std::is_same<T, Archetype<Prof>&>::value || |
| std::is_same<T, const Archetype<Prof>>::value))); |
| } |
| |
| // This is used to conditionally delete "copy" and "move" assigns in a way |
| // that is consistent with what the ConformanceProfile requires and that also |
| // strictly enforces the arguments to the copy/move to not come from implicit |
| // conversions when dealing with the Archetype. |
| template <class Prof, class T> |
| constexpr bool ShouldDeleteAssign() { |
| return !( |
| (PropertiesOfT<Prof>::move_assignable_support != move_assignable::maybe && |
| std::is_same<T, Archetype<Prof>>::value) || |
| (PropertiesOfT<Prof>::copy_assignable_support != copy_assignable::maybe && |
| (std::is_same<T, const Archetype<Prof>&>::value || |
| std::is_same<T, Archetype<Prof>&>::value || |
| std::is_same<T, const Archetype<Prof>>::value))); |
| } |
| |
| // TODO(calabrese) Inherit from a chain of secondary bases to pull in the |
| // associated functions of other concepts. |
| template <class Prof, class Enabler> |
| class Archetype : ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support> { |
| static_assert(std::is_same<Enabler, void>::value, |
| "An explicit type must not be passed as the second template " |
| "argument to 'Archetype`."); |
| |
| // The cases mentioned in these static_asserts are expected to be handled in |
| // the partial template specializations of Archetype that follow this |
| // definition. |
| static_assert(PropertiesOfT<Prof>::destructible_support != |
| destructible::maybe, |
| ""); |
| static_assert(PropertiesOfT<Prof>::move_constructible_support != |
| move_constructible::maybe || |
| PropertiesOfT<Prof>::copy_constructible_support == |
| copy_constructible::maybe, |
| ""); |
| static_assert(PropertiesOfT<Prof>::move_assignable_support != |
| move_assignable::maybe || |
| PropertiesOfT<Prof>::copy_assignable_support == |
| copy_assignable::maybe, |
| ""); |
| |
| public: |
| Archetype() = default; |
| |
| // Disallow moves when requested, and disallow implicit conversions. |
| template <class T, typename std::enable_if< |
| ShouldDeleteConstructor<Prof, T>()>::type* = nullptr> |
| Archetype(T&&) = delete; |
| |
| // Disallow moves when requested, and disallow implicit conversions. |
| template <class T, typename std::enable_if< |
| ShouldDeleteAssign<Prof, T>()>::type* = nullptr> |
| Archetype& operator=(T&&) = delete; |
| |
| using ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support>::archetype_state; |
| |
| private: |
| explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept |
| : ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(), |
| state) {} |
| |
| friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept; |
| }; |
| |
| template <class Prof> |
| class Archetype<Prof, typename std::enable_if< |
| PropertiesOfT<Prof>::move_constructible_support != |
| move_constructible::maybe && |
| PropertiesOfT<Prof>::move_assignable_support == |
| move_assignable::maybe && |
| PropertiesOfT<Prof>::destructible_support != |
| destructible::maybe>::type> |
| : ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support> { |
| public: |
| Archetype() = default; |
| Archetype(Archetype&&) = default; |
| Archetype(const Archetype&) = default; |
| Archetype& operator=(Archetype&&) = delete; |
| Archetype& operator=(const Archetype&) = default; |
| |
| // Disallow moves when requested, and disallow implicit conversions. |
| template <class T, typename std::enable_if< |
| ShouldDeleteConstructor<Prof, T>()>::type* = nullptr> |
| Archetype(T&&) = delete; |
| |
| // Disallow moves when requested, and disallow implicit conversions. |
| template <class T, typename std::enable_if< |
| ShouldDeleteAssign<Prof, T>()>::type* = nullptr> |
| Archetype& operator=(T&&) = delete; |
| |
| using ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support>::archetype_state; |
| |
| private: |
| explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept |
| : ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(), |
| state) {} |
| |
| friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept; |
| }; |
| |
| template <class Prof> |
| class Archetype<Prof, typename std::enable_if< |
| PropertiesOfT<Prof>::move_constructible_support == |
| move_constructible::maybe && |
| PropertiesOfT<Prof>::move_assignable_support == |
| move_assignable::maybe && |
| PropertiesOfT<Prof>::destructible_support != |
| destructible::maybe>::type> |
| : ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support> { |
| public: |
| Archetype() = default; |
| Archetype(Archetype&&) = delete; |
| Archetype(const Archetype&) = default; |
| Archetype& operator=(Archetype&&) = delete; |
| Archetype& operator=(const Archetype&) = default; |
| |
| // Disallow moves when requested, and disallow implicit conversions. |
| template <class T, typename std::enable_if< |
| ShouldDeleteConstructor<Prof, T>()>::type* = nullptr> |
| Archetype(T&&) = delete; |
| |
| // Disallow moves when requested, and disallow implicit conversions. |
| template <class T, typename std::enable_if< |
| ShouldDeleteAssign<Prof, T>()>::type* = nullptr> |
| Archetype& operator=(T&&) = delete; |
| |
| using ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support>::archetype_state; |
| |
| private: |
| explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept |
| : ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(), |
| state) {} |
| |
| friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept; |
| }; |
| |
| template <class Prof> |
| class Archetype<Prof, typename std::enable_if< |
| PropertiesOfT<Prof>::move_constructible_support == |
| move_constructible::maybe && |
| PropertiesOfT<Prof>::move_assignable_support != |
| move_assignable::maybe && |
| PropertiesOfT<Prof>::destructible_support != |
| destructible::maybe>::type> |
| : ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support> { |
| public: |
| Archetype() = default; |
| Archetype(Archetype&&) = delete; |
| Archetype(const Archetype&) = default; |
| Archetype& operator=(Archetype&&) = default; |
| Archetype& operator=(const Archetype&) = default; |
| |
| // Disallow moves when requested, and disallow implicit conversions. |
| template <class T, typename std::enable_if< |
| ShouldDeleteConstructor<Prof, T>()>::type* = nullptr> |
| Archetype(T&&) = delete; |
| |
| // Disallow moves when requested, and disallow implicit conversions. |
| template <class T, typename std::enable_if< |
| ShouldDeleteAssign<Prof, T>()>::type* = nullptr> |
| Archetype& operator=(T&&) = delete; |
| |
| using ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support>::archetype_state; |
| |
| private: |
| explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept |
| : ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(), |
| state) {} |
| |
| friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept; |
| }; |
| |
| template <class Prof> |
| class Archetype<Prof, typename std::enable_if< |
| PropertiesOfT<Prof>::move_constructible_support != |
| move_constructible::maybe && |
| PropertiesOfT<Prof>::move_assignable_support == |
| move_assignable::maybe && |
| PropertiesOfT<Prof>::destructible_support == |
| destructible::maybe>::type> |
| : ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support> { |
| public: |
| Archetype() = default; |
| Archetype(Archetype&&) = default; |
| Archetype(const Archetype&) = default; |
| Archetype& operator=(Archetype&&) = delete; |
| Archetype& operator=(const Archetype&) = default; |
| ~Archetype() = delete; |
| |
| // Disallow moves when requested, and disallow implicit conversions. |
| template <class T, typename std::enable_if< |
| ShouldDeleteConstructor<Prof, T>()>::type* = nullptr> |
| Archetype(T&&) = delete; |
| |
| // Disallow moves when requested, and disallow implicit conversions. |
| template <class T, typename std::enable_if< |
| ShouldDeleteAssign<Prof, T>()>::type* = nullptr> |
| Archetype& operator=(T&&) = delete; |
| |
| using ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support>::archetype_state; |
| |
| private: |
| explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept |
| : ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(), |
| state) {} |
| |
| friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept; |
| }; |
| |
| template <class Prof> |
| class Archetype<Prof, typename std::enable_if< |
| PropertiesOfT<Prof>::move_constructible_support == |
| move_constructible::maybe && |
| PropertiesOfT<Prof>::move_assignable_support == |
| move_assignable::maybe && |
| PropertiesOfT<Prof>::destructible_support == |
| destructible::maybe>::type> |
| : ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support> { |
| public: |
| Archetype() = default; |
| Archetype(Archetype&&) = delete; |
| Archetype(const Archetype&) = default; |
| Archetype& operator=(Archetype&&) = delete; |
| Archetype& operator=(const Archetype&) = default; |
| ~Archetype() = delete; |
| |
| // Disallow moves when requested, and disallow implicit conversions. |
| template <class T, typename std::enable_if< |
| ShouldDeleteConstructor<Prof, T>()>::type* = nullptr> |
| Archetype(T&&) = delete; |
| |
| // Disallow moves when requested, and disallow implicit conversions. |
| template <class T, typename std::enable_if< |
| ShouldDeleteAssign<Prof, T>()>::type* = nullptr> |
| Archetype& operator=(T&&) = delete; |
| |
| using ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support>::archetype_state; |
| |
| private: |
| explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept |
| : ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(), |
| state) {} |
| |
| friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept; |
| }; |
| |
| template <class Prof> |
| class Archetype<Prof, typename std::enable_if< |
| PropertiesOfT<Prof>::move_constructible_support == |
| move_constructible::maybe && |
| PropertiesOfT<Prof>::move_assignable_support != |
| move_assignable::maybe && |
| PropertiesOfT<Prof>::destructible_support == |
| destructible::maybe>::type> |
| : ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support> { |
| public: |
| Archetype() = default; |
| Archetype(Archetype&&) = delete; |
| Archetype(const Archetype&) = default; |
| Archetype& operator=(Archetype&&) = default; |
| Archetype& operator=(const Archetype&) = default; |
| ~Archetype() = delete; |
| |
| // Disallow moves when requested, and disallow implicit conversions. |
| template <class T, typename std::enable_if< |
| ShouldDeleteConstructor<Prof, T>()>::type* = nullptr> |
| Archetype(T&&) = delete; |
| |
| // Disallow moves when requested, and disallow implicit conversions. |
| template <class T, typename std::enable_if< |
| ShouldDeleteAssign<Prof, T>()>::type* = nullptr> |
| Archetype& operator=(T&&) = delete; |
| |
| using ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support>::archetype_state; |
| |
| private: |
| explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept |
| : ArchetypeSpecialMembersBase< |
| PropertiesOfT<Prof>::default_constructible_support, |
| PropertiesOfT<Prof>::move_constructible_support, |
| PropertiesOfT<Prof>::copy_constructible_support, |
| PropertiesOfT<Prof>::move_assignable_support, |
| PropertiesOfT<Prof>::copy_assignable_support, |
| PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(), |
| state) {} |
| |
| friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept; |
| }; |
| |
| // Explicitly deleted swap for Archetype if the profile does not require swap. |
| // It is important to delete it rather than simply leave it out so that the |
| // "using std::swap;" idiom will result in this deleted overload being picked. |
| template <class Prof, |
| absl::enable_if_t<!PropertiesOfT<Prof>::is_swappable, int> = 0> |
| void swap(Archetype<Prof>&, Archetype<Prof>&) = delete; // NOLINT |
| |
| // A conditionally-noexcept swap implementation for Archetype when the profile |
| // supports swap. |
| template <class Prof, |
| absl::enable_if_t<PropertiesOfT<Prof>::is_swappable, int> = 0> |
| void swap(Archetype<Prof>& lhs, Archetype<Prof>& rhs) // NOLINT |
| noexcept(PropertiesOfT<Prof>::swappable_support != swappable::yes) { |
| std::swap(lhs.archetype_state, rhs.archetype_state); |
| } |
| |
| // A convertible-to-bool type that is used as the return type of comparison |
| // operators since the standard doesn't always require exactly bool. |
| struct NothrowBool { |
| explicit NothrowBool() = delete; |
| ~NothrowBool() = default; |
| |
| // TODO(calabrese) Delete the copy constructor in C++17 mode since guaranteed |
| // elision makes it not required when returning from a function. |
| // NothrowBool(NothrowBool const&) = delete; |
| |
| NothrowBool& operator=(NothrowBool const&) = delete; |
| |
| explicit operator bool() const noexcept { return value; } |
| |
| static NothrowBool make(bool const value) noexcept { |
| return NothrowBool(value); |
| } |
| |
| private: |
| explicit NothrowBool(bool const value) noexcept : value(value) {} |
| |
| bool value; |
| }; |
| |
| // A convertible-to-bool type that is used as the return type of comparison |
| // operators since the standard doesn't always require exactly bool. |
| // Note: ExceptionalBool has a conversion operator that is not noexcept, so |
| // that even when a comparison operator is noexcept, that operation may still |
| // potentially throw when converted to bool. |
| struct ExceptionalBool { |
| explicit ExceptionalBool() = delete; |
| ~ExceptionalBool() = default; |
| |
| // TODO(calabrese) Delete the copy constructor in C++17 mode since guaranteed |
| // elision makes it not required when returning from a function. |
| // ExceptionalBool(ExceptionalBool const&) = delete; |
| |
| ExceptionalBool& operator=(ExceptionalBool const&) = delete; |
| |
| explicit operator bool() const { return value; } // NOLINT |
| |
| static ExceptionalBool make(bool const value) noexcept { |
| return ExceptionalBool(value); |
| } |
| |
| private: |
| explicit ExceptionalBool(bool const value) noexcept : value(value) {} |
| |
| bool value; |
| }; |
| |
| // The following macro is only used as a helper in this file to stamp out |
| // comparison operator definitions. It is undefined after usage. |
| // |
| // NOTE: Non-nothrow operators throw via their result's conversion to bool even |
| // though the operation itself is noexcept. |
| #define ABSL_TYPES_INTERNAL_OP(enum_name, op) \ |
| template <class Prof> \ |
| absl::enable_if_t<!PropertiesOfT<Prof>::is_##enum_name, bool> operator op( \ |
| const Archetype<Prof>&, const Archetype<Prof>&) = delete; \ |
| \ |
| template <class Prof> \ |
| typename absl::enable_if_t< \ |
| PropertiesOfT<Prof>::is_##enum_name, \ |
| std::conditional<PropertiesOfT<Prof>::enum_name##_support == \ |
| enum_name::nothrow, \ |
| NothrowBool, ExceptionalBool>>::type \ |
| operator op(const Archetype<Prof>& lhs, \ |
| const Archetype<Prof>& rhs) noexcept { \ |
| return absl::conditional_t< \ |
| PropertiesOfT<Prof>::enum_name##_support == enum_name::nothrow, \ |
| NothrowBool, ExceptionalBool>::make(lhs.archetype_state op \ |
| rhs.archetype_state); \ |
| } |
| |
| ABSL_TYPES_INTERNAL_OP(equality_comparable, ==); |
| ABSL_TYPES_INTERNAL_OP(inequality_comparable, !=); |
| ABSL_TYPES_INTERNAL_OP(less_than_comparable, <); |
| ABSL_TYPES_INTERNAL_OP(less_equal_comparable, <=); |
| ABSL_TYPES_INTERNAL_OP(greater_equal_comparable, >=); |
| ABSL_TYPES_INTERNAL_OP(greater_than_comparable, >); |
| |
| #undef ABSL_TYPES_INTERNAL_OP |
| |
| // Base class for std::hash specializations when an Archetype doesn't support |
| // hashing. |
| struct PoisonedHash { |
| PoisonedHash() = delete; |
| PoisonedHash(const PoisonedHash&) = delete; |
| PoisonedHash& operator=(const PoisonedHash&) = delete; |
| }; |
| |
| // Base class for std::hash specializations when an Archetype supports hashing. |
| template <class Prof> |
| struct EnabledHash { |
| using argument_type = Archetype<Prof>; |
| using result_type = std::size_t; |
| result_type operator()(const argument_type& arg) const { |
| return std::hash<ArchetypeState>()(arg.archetype_state); |
| } |
| }; |
| |
| } // namespace types_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| namespace std { |
| |
| template <class Prof> // NOLINT |
| struct hash<::absl::types_internal::Archetype<Prof>> |
| : conditional<::absl::types_internal::PropertiesOfT<Prof>::is_hashable, |
| ::absl::types_internal::EnabledHash<Prof>, |
| ::absl::types_internal::PoisonedHash>::type {}; |
| |
| } // namespace std |
| |
| #endif // ABSL_TYPES_INTERNAL_CONFORMANCE_ARCHETYPE_H_ |