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