FTL: Add mixins for type-safe wrappers

For now, allow mixing in construction, default construction, equality,
ordering, incrementing, and addition.

Bug: 185536303
Test: ftl_test
Change-Id: I9017e124656ba0e7f13f378814c5b1c19a36655b
diff --git a/include/ftl/mixins.h b/include/ftl/mixins.h
new file mode 100644
index 0000000..0e1d200
--- /dev/null
+++ b/include/ftl/mixins.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * 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
+ *
+ *      http://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.
+ */
+
+#pragma once
+
+#include <ftl/details/mixins.h>
+
+namespace android::ftl {
+
+// CRTP mixins for defining type-safe wrappers that are distinct from their underlying type. Common
+// uses are IDs, opaque handles, and physical quantities. The constructor is provided by (and must
+// be inherited from) the `Constructible` mixin, whereas operators (equality, ordering, arithmetic,
+// etc.) are enabled through inheritance:
+//
+//   struct Id : ftl::Constructible<Id, std::int32_t>, ftl::Equatable<Id> {
+//     using Constructible::Constructible;
+//   };
+//
+//   static_assert(!std::is_default_constructible_v<Id>);
+//
+// Unlike `Constructible`, `DefaultConstructible` allows default construction. The default value is
+// zero-initialized unless specified:
+//
+//   struct Color : ftl::DefaultConstructible<Color, std::uint8_t>,
+//                  ftl::Equatable<Color>,
+//                  ftl::Orderable<Color> {
+//     using DefaultConstructible::DefaultConstructible;
+//   };
+//
+//   static_assert(Color() == Color(0u));
+//   static_assert(ftl::to_underlying(Color(-1)) == 255u);
+//   static_assert(Color(1u) < Color(2u));
+//
+//   struct Sequence : ftl::DefaultConstructible<Sequence, std::int8_t, -1>,
+//                     ftl::Equatable<Sequence>,
+//                     ftl::Orderable<Sequence>,
+//                     ftl::Incrementable<Sequence> {
+//     using DefaultConstructible::DefaultConstructible;
+//   };
+//
+//   static_assert(Sequence() == Sequence(-1));
+//
+// The underlying type need not be a fundamental type:
+//
+//   struct Timeout : ftl::DefaultConstructible<Timeout, std::chrono::seconds, 10>,
+//                    ftl::Equatable<Timeout>,
+//                    ftl::Addable<Timeout> {
+//     using DefaultConstructible::DefaultConstructible;
+//   };
+//
+//   using namespace std::chrono_literals;
+//   static_assert(Timeout() + Timeout(5s) == Timeout(15s));
+//
+template <typename Self, typename T>
+struct Constructible {
+  explicit constexpr Constructible(T value) : value_(value) {}
+
+  explicit constexpr operator const T&() const { return value_; }
+
+ private:
+  template <typename, template <typename> class>
+  friend class details::Mixin;
+
+  T value_;
+};
+
+template <typename Self, typename T, auto kDefault = T{}>
+struct DefaultConstructible : Constructible<Self, T> {
+  using Constructible<Self, T>::Constructible;
+  constexpr DefaultConstructible() : DefaultConstructible(T{kDefault}) {}
+};
+
+// Shorthand for casting a type-safe wrapper to its underlying value.
+template <typename Self, typename T>
+constexpr const T& to_underlying(const Constructible<Self, T>& c) {
+  return static_cast<const T&>(c);
+}
+
+// Comparison operators for equality.
+template <typename Self>
+struct Equatable : details::Mixin<Self, Equatable> {
+  constexpr bool operator==(const Self& other) const {
+    return to_underlying(this->self()) == to_underlying(other);
+  }
+
+  constexpr bool operator!=(const Self& other) const { return !(*this == other); }
+};
+
+// Comparison operators for ordering.
+template <typename Self>
+struct Orderable : details::Mixin<Self, Orderable> {
+  constexpr bool operator<(const Self& other) const {
+    return to_underlying(this->self()) < to_underlying(other);
+  }
+
+  constexpr bool operator>(const Self& other) const { return other < this->self(); }
+  constexpr bool operator>=(const Self& other) const { return !(*this < other); }
+  constexpr bool operator<=(const Self& other) const { return !(*this > other); }
+};
+
+// Pre-increment and post-increment operators.
+template <typename Self>
+struct Incrementable : details::Mixin<Self, Incrementable> {
+  constexpr Self& operator++() {
+    ++this->mut();
+    return this->self();
+  }
+
+  constexpr Self operator++(int) {
+    const Self tmp = this->self();
+    operator++();
+    return tmp;
+  }
+};
+
+// Additive operators, including incrementing.
+template <typename Self>
+struct Addable : details::Mixin<Self, Addable>, Incrementable<Self> {
+  constexpr Self& operator+=(const Self& other) {
+    this->mut() += to_underlying(other);
+    return this->self();
+  }
+
+  constexpr Self operator+(const Self& other) const {
+    Self tmp = this->self();
+    return tmp += other;
+  }
+
+ private:
+  using Base = details::Mixin<Self, Addable>;
+  using Base::mut;
+  using Base::self;
+};
+
+}  // namespace android::ftl