diff options
Diffstat (limited to 'third_party/abseil_cpp/absl/types/internal/conformance_archetype.h')
-rw-r--r-- | third_party/abseil_cpp/absl/types/internal/conformance_archetype.h | 978 |
1 files changed, 978 insertions, 0 deletions
diff --git a/third_party/abseil_cpp/absl/types/internal/conformance_archetype.h b/third_party/abseil_cpp/absl/types/internal/conformance_archetype.h new file mode 100644 index 000000000000..2349e0f72635 --- /dev/null +++ b/third_party/abseil_cpp/absl/types/internal/conformance_archetype.h @@ -0,0 +1,978 @@ +// 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_ |