// 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 #include #include #include #include "absl/meta/type_traits.h" #include "absl/types/internal/conformance_profile.h" namespace absl { namespace types_internal { // A minimum-conforming implementation of a type with properties specified in // `Prof`, where `Prof` is a valid Conformance Profile. template class Archetype; // Given an Archetype, obtain the properties of the profile associated with that // archetype. template struct PropertiesOfArchetype; template struct PropertiesOfArchetype> { using type = PropertiesOfT; }; template using PropertiesOfArchetypeT = typename PropertiesOfArchetype::type; // A metafunction to determine if a type is an `Archetype`. template struct IsArchetype : std::false_type {}; template struct IsArchetype> : 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 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 { explicit ArchetypeStateBase() = delete; explicit ArchetypeStateBase(MakeArchetypeState, ArchetypeState state) noexcept : archetype_state(state) {} ArchetypeState archetype_state; }; template <> struct ArchetypeStateBase { ArchetypeStateBase() = default; explicit ArchetypeStateBase(MakeArchetypeState, ArchetypeState state) noexcept : archetype_state(state) {} ArchetypeState archetype_state; }; // The move-constructor base template struct ArchetypeMoveConstructor : ArchetypeStateBase { static_assert(MoveConstructibleValue == move_constructible::yes || MoveConstructibleValue == move_constructible::nothrow, ""); explicit ArchetypeMoveConstructor(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeStateBase(MakeArchetypeState(), state) {} ArchetypeMoveConstructor() = default; ArchetypeMoveConstructor(ArchetypeMoveConstructor&& other) noexcept( MoveConstructibleValue == move_constructible::nothrow) : ArchetypeStateBase(MakeArchetypeState(), other.archetype_state) {} ArchetypeMoveConstructor(const ArchetypeMoveConstructor&) = default; ArchetypeMoveConstructor& operator=(ArchetypeMoveConstructor&&) = default; ArchetypeMoveConstructor& operator=(const ArchetypeMoveConstructor&) = default; }; template struct ArchetypeMoveConstructor : ArchetypeStateBase { explicit ArchetypeMoveConstructor(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeStateBase(MakeArchetypeState(), state) {} ArchetypeMoveConstructor() = default; }; // The copy-constructor base template struct ArchetypeCopyConstructor : ArchetypeMoveConstructor { static_assert(CopyConstructibleValue == copy_constructible::yes || CopyConstructibleValue == copy_constructible::nothrow, ""); explicit ArchetypeCopyConstructor(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeMoveConstructor(MakeArchetypeState(), state) {} ArchetypeCopyConstructor() = default; ArchetypeCopyConstructor(ArchetypeCopyConstructor&&) = default; ArchetypeCopyConstructor(const ArchetypeCopyConstructor& other) noexcept( CopyConstructibleValue == copy_constructible::nothrow) : ArchetypeMoveConstructor( MakeArchetypeState(), other.archetype_state) {} ArchetypeCopyConstructor& operator=(ArchetypeCopyConstructor&&) = default; ArchetypeCopyConstructor& operator=(const ArchetypeCopyConstructor&) = default; }; template struct ArchetypeCopyConstructor : ArchetypeMoveConstructor { explicit ArchetypeCopyConstructor(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeMoveConstructor(MakeArchetypeState(), state) {} ArchetypeCopyConstructor() = default; ArchetypeCopyConstructor(ArchetypeCopyConstructor&&) = default; ArchetypeCopyConstructor(const ArchetypeCopyConstructor&) = delete; ArchetypeCopyConstructor& operator=(ArchetypeCopyConstructor&&) = default; ArchetypeCopyConstructor& operator=(const ArchetypeCopyConstructor&) = default; }; template struct ArchetypeCopyConstructor : ArchetypeMoveConstructor { explicit ArchetypeCopyConstructor(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeMoveConstructor(MakeArchetypeState(), state) {} ArchetypeCopyConstructor() = default; }; // The move-assign base template struct ArchetypeMoveAssign : ArchetypeCopyConstructor { static_assert(MoveAssignableValue == move_assignable::yes || MoveAssignableValue == move_assignable::nothrow, ""); explicit ArchetypeMoveAssign(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeCopyConstructor(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 struct ArchetypeMoveAssign : ArchetypeCopyConstructor { explicit ArchetypeMoveAssign(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeCopyConstructor(MakeArchetypeState(), state) {} ArchetypeMoveAssign() = default; }; // The copy-assign base template struct ArchetypeCopyAssign : ArchetypeMoveAssign { static_assert(CopyAssignableValue == copy_assignable::yes || CopyAssignableValue == copy_assignable::nothrow, ""); explicit ArchetypeCopyAssign(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeMoveAssign( 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 struct ArchetypeCopyAssign : ArchetypeMoveAssign { explicit ArchetypeCopyAssign(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeMoveAssign( MakeArchetypeState(), state) {} ArchetypeCopyAssign() = default; ArchetypeCopyAssign(ArchetypeCopyAssign&&) = default; ArchetypeCopyAssign(const ArchetypeCopyAssign&) = default; ArchetypeCopyAssign& operator=(ArchetypeCopyAssign&&) = default; ArchetypeCopyAssign& operator=(const ArchetypeCopyAssign&) = delete; }; template struct ArchetypeCopyAssign : ArchetypeMoveAssign { explicit ArchetypeCopyAssign(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeMoveAssign( MakeArchetypeState(), state) {} ArchetypeCopyAssign() = default; }; // The destructor base template struct ArchetypeDestructor : ArchetypeCopyAssign { static_assert(DestructibleValue == destructible::yes || DestructibleValue == destructible::nothrow, ""); explicit ArchetypeDestructor(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeCopyAssign(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 struct ArchetypeDestructor : ArchetypeCopyAssign { explicit ArchetypeDestructor(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeCopyAssign(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 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 Arch MakeArchetype(ArchetypeState state) noexcept { static_assert(IsArchetype::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 constexpr bool ShouldDeleteConstructor() { return !((PropertiesOfT::move_constructible_support != move_constructible::maybe && std::is_same>::value) || (PropertiesOfT::copy_constructible_support != copy_constructible::maybe && (std::is_same&>::value || std::is_same&>::value || std::is_same>::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 constexpr bool ShouldDeleteAssign() { return !( (PropertiesOfT::move_assignable_support != move_assignable::maybe && std::is_same>::value) || (PropertiesOfT::copy_assignable_support != copy_assignable::maybe && (std::is_same&>::value || std::is_same&>::value || std::is_same>::value))); } // TODO(calabrese) Inherit from a chain of secondary bases to pull in the // associated functions of other concepts. template class Archetype : ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::destructible_support> { static_assert(std::is_same::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::destructible_support != destructible::maybe, ""); static_assert(PropertiesOfT::move_constructible_support != move_constructible::maybe || PropertiesOfT::copy_constructible_support == copy_constructible::maybe, ""); static_assert(PropertiesOfT::move_assignable_support != move_assignable::maybe || PropertiesOfT::copy_assignable_support == copy_assignable::maybe, ""); public: Archetype() = default; // Disallow moves when requested, and disallow implicit conversions. template ()>::type* = nullptr> Archetype(T&&) = delete; // Disallow moves when requested, and disallow implicit conversions. template ()>::type* = nullptr> Archetype& operator=(T&&) = delete; using ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::destructible_support>::archetype_state; private: explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::destructible_support>(MakeArchetypeState(), state) {} friend Archetype MakeArchetype(ArchetypeState) noexcept; }; template class Archetype::move_constructible_support != move_constructible::maybe && PropertiesOfT::move_assignable_support == move_assignable::maybe && PropertiesOfT::destructible_support != destructible::maybe>::type> : ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::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 ()>::type* = nullptr> Archetype(T&&) = delete; // Disallow moves when requested, and disallow implicit conversions. template ()>::type* = nullptr> Archetype& operator=(T&&) = delete; using ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::destructible_support>::archetype_state; private: explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::destructible_support>(MakeArchetypeState(), state) {} friend Archetype MakeArchetype(ArchetypeState) noexcept; }; template class Archetype::move_constructible_support == move_constructible::maybe && PropertiesOfT::move_assignable_support == move_assignable::maybe && PropertiesOfT::destructible_support != destructible::maybe>::type> : ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::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 ()>::type* = nullptr> Archetype(T&&) = delete; // Disallow moves when requested, and disallow implicit conversions. template ()>::type* = nullptr> Archetype& operator=(T&&) = delete; using ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::destructible_support>::archetype_state; private: explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::destructible_support>(MakeArchetypeState(), state) {} friend Archetype MakeArchetype(ArchetypeState) noexcept; }; template class Archetype::move_constructible_support == move_constructible::maybe && PropertiesOfT::move_assignable_support != move_assignable::maybe && PropertiesOfT::destructible_support != destructible::maybe>::type> : ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::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 ()>::type* = nullptr> Archetype(T&&) = delete; // Disallow moves when requested, and disallow implicit conversions. template ()>::type* = nullptr> Archetype& operator=(T&&) = delete; using ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::destructible_support>::archetype_state; private: explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::destructible_support>(MakeArchetypeState(), state) {} friend Archetype MakeArchetype(ArchetypeState) noexcept; }; template class Archetype::move_constructible_support != move_constructible::maybe && PropertiesOfT::move_assignable_support == move_assignable::maybe && PropertiesOfT::destructible_support == destructible::maybe>::type> : ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::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 ()>::type* = nullptr> Archetype(T&&) = delete; // Disallow moves when requested, and disallow implicit conversions. template ()>::type* = nullptr> Archetype& operator=(T&&) = delete; using ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::destructible_support>::archetype_state; private: explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::destructible_support>(MakeArchetypeState(), state) {} friend Archetype MakeArchetype(ArchetypeState) noexcept; }; template class Archetype::move_constructible_support == move_constructible::maybe && PropertiesOfT::move_assignable_support == move_assignable::maybe && PropertiesOfT::destructible_support == destructible::maybe>::type> : ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::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 ()>::type* = nullptr> Archetype(T&&) = delete; // Disallow moves when requested, and disallow implicit conversions. template ()>::type* = nullptr> Archetype& operator=(T&&) = delete; using ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::destructible_support>::archetype_state; private: explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::destructible_support>(MakeArchetypeState(), state) {} friend Archetype MakeArchetype(ArchetypeState) noexcept; }; template class Archetype::move_constructible_support == move_constructible::maybe && PropertiesOfT::move_assignable_support != move_assignable::maybe && PropertiesOfT::destructible_support == destructible::maybe>::type> : ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::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 ()>::type* = nullptr> Archetype(T&&) = delete; // Disallow moves when requested, and disallow implicit conversions. template ()>::type* = nullptr> Archetype& operator=(T&&) = delete; using ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::destructible_support>::archetype_state; private: explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept : ArchetypeSpecialMembersBase< PropertiesOfT::default_constructible_support, PropertiesOfT::move_constructible_support, PropertiesOfT::copy_constructible_support, PropertiesOfT::move_assignable_support, PropertiesOfT::copy_assignable_support, PropertiesOfT::destructible_support>(MakeArchetypeState(), state) {} friend Archetype MakeArchetype(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 ::is_swappable, int> = 0> void swap(Archetype&, Archetype&) = delete; // NOLINT // A conditionally-noexcept swap implementation for Archetype when the profile // supports swap. template ::is_swappable, int> = 0> void swap(Archetype& lhs, Archetype& rhs) // NOLINT noexcept(PropertiesOfT::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 \ absl::enable_if_t::is_##enum_name, bool> operator op( \ const Archetype&, const Archetype&) = delete; \ \ template \ typename absl::enable_if_t< \ PropertiesOfT::is_##enum_name, \ std::conditional::enum_name##_support == \ enum_name::nothrow, \ NothrowBool, ExceptionalBool>>::type \ operator op(const Archetype& lhs, \ const Archetype& rhs) noexcept { \ return absl::conditional_t< \ PropertiesOfT::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 struct EnabledHash { using argument_type = Archetype; using result_type = std::size_t; result_type operator()(const argument_type& arg) const { return std::hash()(arg.archetype_state); } }; } // namespace types_internal } // namespace absl namespace std { template // NOLINT struct hash<::absl::types_internal::Archetype> : conditional<::absl::types_internal::PropertiesOfT::is_hashable, ::absl::types_internal::EnabledHash, ::absl::types_internal::PoisonedHash>::type {}; } // namespace std #endif // ABSL_TYPES_INTERNAL_CONFORMANCE_ARCHETYPE_H_