about summary refs log tree commit diff
path: root/third_party/abseil_cpp/absl/types/internal/conformance_archetype.h
diff options
context:
space:
mode:
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.h978
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 0000000000..2349e0f726
--- /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_