xref: /aosp_15_r20/frameworks/native/include/ftl/mixins.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright 2022 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #pragma once
18*38e8c45fSAndroid Build Coastguard Worker 
19*38e8c45fSAndroid Build Coastguard Worker #include <ftl/details/mixins.h>
20*38e8c45fSAndroid Build Coastguard Worker 
21*38e8c45fSAndroid Build Coastguard Worker namespace android::ftl {
22*38e8c45fSAndroid Build Coastguard Worker 
23*38e8c45fSAndroid Build Coastguard Worker // CRTP mixins for defining type-safe wrappers that are distinct from their underlying type. Common
24*38e8c45fSAndroid Build Coastguard Worker // uses are IDs, opaque handles, and physical quantities. The constructor is provided by (and must
25*38e8c45fSAndroid Build Coastguard Worker // be inherited from) the `Constructible` mixin, whereas operators (equality, ordering, arithmetic,
26*38e8c45fSAndroid Build Coastguard Worker // etc.) are enabled through inheritance:
27*38e8c45fSAndroid Build Coastguard Worker //
28*38e8c45fSAndroid Build Coastguard Worker //   struct Id : ftl::Constructible<Id, std::int32_t>, ftl::Equatable<Id> {
29*38e8c45fSAndroid Build Coastguard Worker //     using Constructible::Constructible;
30*38e8c45fSAndroid Build Coastguard Worker //   };
31*38e8c45fSAndroid Build Coastguard Worker //
32*38e8c45fSAndroid Build Coastguard Worker //   static_assert(!std::is_default_constructible_v<Id>);
33*38e8c45fSAndroid Build Coastguard Worker //
34*38e8c45fSAndroid Build Coastguard Worker // Unlike `Constructible`, `DefaultConstructible` allows default construction. The default value is
35*38e8c45fSAndroid Build Coastguard Worker // zero-initialized unless specified:
36*38e8c45fSAndroid Build Coastguard Worker //
37*38e8c45fSAndroid Build Coastguard Worker //   struct Color : ftl::DefaultConstructible<Color, std::uint8_t>,
38*38e8c45fSAndroid Build Coastguard Worker //                  ftl::Equatable<Color>,
39*38e8c45fSAndroid Build Coastguard Worker //                  ftl::Orderable<Color> {
40*38e8c45fSAndroid Build Coastguard Worker //     using DefaultConstructible::DefaultConstructible;
41*38e8c45fSAndroid Build Coastguard Worker //   };
42*38e8c45fSAndroid Build Coastguard Worker //
43*38e8c45fSAndroid Build Coastguard Worker //   static_assert(Color() == Color(0u));
44*38e8c45fSAndroid Build Coastguard Worker //   static_assert(ftl::to_underlying(Color(-1)) == 255u);
45*38e8c45fSAndroid Build Coastguard Worker //   static_assert(Color(1u) < Color(2u));
46*38e8c45fSAndroid Build Coastguard Worker //
47*38e8c45fSAndroid Build Coastguard Worker //   struct Sequence : ftl::DefaultConstructible<Sequence, std::int8_t, -1>,
48*38e8c45fSAndroid Build Coastguard Worker //                     ftl::Equatable<Sequence>,
49*38e8c45fSAndroid Build Coastguard Worker //                     ftl::Orderable<Sequence>,
50*38e8c45fSAndroid Build Coastguard Worker //                     ftl::Incrementable<Sequence> {
51*38e8c45fSAndroid Build Coastguard Worker //     using DefaultConstructible::DefaultConstructible;
52*38e8c45fSAndroid Build Coastguard Worker //   };
53*38e8c45fSAndroid Build Coastguard Worker //
54*38e8c45fSAndroid Build Coastguard Worker //   static_assert(Sequence() == Sequence(-1));
55*38e8c45fSAndroid Build Coastguard Worker //
56*38e8c45fSAndroid Build Coastguard Worker // The underlying type need not be a fundamental type:
57*38e8c45fSAndroid Build Coastguard Worker //
58*38e8c45fSAndroid Build Coastguard Worker //   struct Timeout : ftl::DefaultConstructible<Timeout, std::chrono::seconds, 10>,
59*38e8c45fSAndroid Build Coastguard Worker //                    ftl::Equatable<Timeout>,
60*38e8c45fSAndroid Build Coastguard Worker //                    ftl::Addable<Timeout> {
61*38e8c45fSAndroid Build Coastguard Worker //     using DefaultConstructible::DefaultConstructible;
62*38e8c45fSAndroid Build Coastguard Worker //   };
63*38e8c45fSAndroid Build Coastguard Worker //
64*38e8c45fSAndroid Build Coastguard Worker //   using namespace std::chrono_literals;
65*38e8c45fSAndroid Build Coastguard Worker //   static_assert(Timeout() + Timeout(5s) == Timeout(15s));
66*38e8c45fSAndroid Build Coastguard Worker //
67*38e8c45fSAndroid Build Coastguard Worker template <typename Self, typename T>
68*38e8c45fSAndroid Build Coastguard Worker struct Constructible {
ConstructibleConstructible69*38e8c45fSAndroid Build Coastguard Worker   explicit constexpr Constructible(T value) : value_(value) {}
70*38e8c45fSAndroid Build Coastguard Worker 
71*38e8c45fSAndroid Build Coastguard Worker   explicit constexpr operator const T&() const { return value_; }
72*38e8c45fSAndroid Build Coastguard Worker 
73*38e8c45fSAndroid Build Coastguard Worker  private:
74*38e8c45fSAndroid Build Coastguard Worker   template <typename, template <typename> class>
75*38e8c45fSAndroid Build Coastguard Worker   friend class details::Mixin;
76*38e8c45fSAndroid Build Coastguard Worker 
77*38e8c45fSAndroid Build Coastguard Worker   T value_;
78*38e8c45fSAndroid Build Coastguard Worker };
79*38e8c45fSAndroid Build Coastguard Worker 
80*38e8c45fSAndroid Build Coastguard Worker template <typename Self, typename T, auto kDefault = T{}>
81*38e8c45fSAndroid Build Coastguard Worker struct DefaultConstructible : Constructible<Self, T> {
82*38e8c45fSAndroid Build Coastguard Worker   using Constructible<Self, T>::Constructible;
DefaultConstructibleDefaultConstructible83*38e8c45fSAndroid Build Coastguard Worker   constexpr DefaultConstructible() : DefaultConstructible(T{kDefault}) {}
84*38e8c45fSAndroid Build Coastguard Worker };
85*38e8c45fSAndroid Build Coastguard Worker 
86*38e8c45fSAndroid Build Coastguard Worker // Shorthand for casting a type-safe wrapper to its underlying value.
87*38e8c45fSAndroid Build Coastguard Worker template <typename Self, typename T>
to_underlying(const Constructible<Self,T> & c)88*38e8c45fSAndroid Build Coastguard Worker constexpr const T& to_underlying(const Constructible<Self, T>& c) {
89*38e8c45fSAndroid Build Coastguard Worker   return static_cast<const T&>(c);
90*38e8c45fSAndroid Build Coastguard Worker }
91*38e8c45fSAndroid Build Coastguard Worker 
92*38e8c45fSAndroid Build Coastguard Worker // Comparison operators for equality.
93*38e8c45fSAndroid Build Coastguard Worker template <typename Self>
94*38e8c45fSAndroid Build Coastguard Worker struct Equatable : details::Mixin<Self, Equatable> {
95*38e8c45fSAndroid Build Coastguard Worker   constexpr bool operator==(const Self& other) const {
96*38e8c45fSAndroid Build Coastguard Worker     return to_underlying(this->self()) == to_underlying(other);
97*38e8c45fSAndroid Build Coastguard Worker   }
98*38e8c45fSAndroid Build Coastguard Worker 
99*38e8c45fSAndroid Build Coastguard Worker   constexpr bool operator!=(const Self& other) const { return !(*this == other); }
100*38e8c45fSAndroid Build Coastguard Worker };
101*38e8c45fSAndroid Build Coastguard Worker 
102*38e8c45fSAndroid Build Coastguard Worker // Comparison operators for ordering.
103*38e8c45fSAndroid Build Coastguard Worker template <typename Self>
104*38e8c45fSAndroid Build Coastguard Worker struct Orderable : details::Mixin<Self, Orderable> {
105*38e8c45fSAndroid Build Coastguard Worker   constexpr bool operator<(const Self& other) const {
106*38e8c45fSAndroid Build Coastguard Worker     return to_underlying(this->self()) < to_underlying(other);
107*38e8c45fSAndroid Build Coastguard Worker   }
108*38e8c45fSAndroid Build Coastguard Worker 
109*38e8c45fSAndroid Build Coastguard Worker   constexpr bool operator>(const Self& other) const { return other < this->self(); }
110*38e8c45fSAndroid Build Coastguard Worker   constexpr bool operator>=(const Self& other) const { return !(*this < other); }
111*38e8c45fSAndroid Build Coastguard Worker   constexpr bool operator<=(const Self& other) const { return !(*this > other); }
112*38e8c45fSAndroid Build Coastguard Worker };
113*38e8c45fSAndroid Build Coastguard Worker 
114*38e8c45fSAndroid Build Coastguard Worker // Pre-increment and post-increment operators.
115*38e8c45fSAndroid Build Coastguard Worker template <typename Self>
116*38e8c45fSAndroid Build Coastguard Worker struct Incrementable : details::Mixin<Self, Incrementable> {
117*38e8c45fSAndroid Build Coastguard Worker   constexpr Self& operator++() {
118*38e8c45fSAndroid Build Coastguard Worker     ++this->mut();
119*38e8c45fSAndroid Build Coastguard Worker     return this->self();
120*38e8c45fSAndroid Build Coastguard Worker   }
121*38e8c45fSAndroid Build Coastguard Worker 
122*38e8c45fSAndroid Build Coastguard Worker   constexpr Self operator++(int) {
123*38e8c45fSAndroid Build Coastguard Worker     const Self tmp = this->self();
124*38e8c45fSAndroid Build Coastguard Worker     operator++();
125*38e8c45fSAndroid Build Coastguard Worker     return tmp;
126*38e8c45fSAndroid Build Coastguard Worker   }
127*38e8c45fSAndroid Build Coastguard Worker };
128*38e8c45fSAndroid Build Coastguard Worker 
129*38e8c45fSAndroid Build Coastguard Worker // Additive operators, including incrementing.
130*38e8c45fSAndroid Build Coastguard Worker template <typename Self>
131*38e8c45fSAndroid Build Coastguard Worker struct Addable : details::Mixin<Self, Addable>, Incrementable<Self> {
132*38e8c45fSAndroid Build Coastguard Worker   constexpr Self& operator+=(const Self& other) {
133*38e8c45fSAndroid Build Coastguard Worker     this->mut() += to_underlying(other);
134*38e8c45fSAndroid Build Coastguard Worker     return this->self();
135*38e8c45fSAndroid Build Coastguard Worker   }
136*38e8c45fSAndroid Build Coastguard Worker 
137*38e8c45fSAndroid Build Coastguard Worker   constexpr Self operator+(const Self& other) const {
138*38e8c45fSAndroid Build Coastguard Worker     Self tmp = this->self();
139*38e8c45fSAndroid Build Coastguard Worker     return tmp += other;
140*38e8c45fSAndroid Build Coastguard Worker   }
141*38e8c45fSAndroid Build Coastguard Worker 
142*38e8c45fSAndroid Build Coastguard Worker  private:
143*38e8c45fSAndroid Build Coastguard Worker   using Base = details::Mixin<Self, Addable>;
144*38e8c45fSAndroid Build Coastguard Worker   using Base::mut;
145*38e8c45fSAndroid Build Coastguard Worker   using Base::self;
146*38e8c45fSAndroid Build Coastguard Worker };
147*38e8c45fSAndroid Build Coastguard Worker 
148*38e8c45fSAndroid Build Coastguard Worker }  // namespace android::ftl
149