xref: /aosp_15_r20/frameworks/native/libs/ftl/mixins_test.cpp (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 #include <ftl/mixins.h>
18*38e8c45fSAndroid Build Coastguard Worker #include <gtest/gtest.h>
19*38e8c45fSAndroid Build Coastguard Worker 
20*38e8c45fSAndroid Build Coastguard Worker #include <chrono>
21*38e8c45fSAndroid Build Coastguard Worker #include <functional>
22*38e8c45fSAndroid Build Coastguard Worker #include <type_traits>
23*38e8c45fSAndroid Build Coastguard Worker #include <utility>
24*38e8c45fSAndroid Build Coastguard Worker 
25*38e8c45fSAndroid Build Coastguard Worker namespace android::test {
26*38e8c45fSAndroid Build Coastguard Worker namespace {
27*38e8c45fSAndroid Build Coastguard Worker 
28*38e8c45fSAndroid Build Coastguard Worker // Keep in sync with example usage in header file.
29*38e8c45fSAndroid Build Coastguard Worker 
30*38e8c45fSAndroid Build Coastguard Worker struct Id : ftl::Constructible<Id, std::int32_t>, ftl::Equatable<Id> {
31*38e8c45fSAndroid Build Coastguard Worker   using Constructible::Constructible;
32*38e8c45fSAndroid Build Coastguard Worker };
33*38e8c45fSAndroid Build Coastguard Worker 
34*38e8c45fSAndroid Build Coastguard Worker static_assert(!std::is_default_constructible_v<Id>);
35*38e8c45fSAndroid Build Coastguard Worker 
36*38e8c45fSAndroid Build Coastguard Worker struct Color : ftl::DefaultConstructible<Color, std::uint8_t>,
37*38e8c45fSAndroid Build Coastguard Worker                ftl::Equatable<Color>,
38*38e8c45fSAndroid Build Coastguard Worker                ftl::Orderable<Color> {
39*38e8c45fSAndroid Build Coastguard Worker   using DefaultConstructible::DefaultConstructible;
40*38e8c45fSAndroid Build Coastguard Worker };
41*38e8c45fSAndroid Build Coastguard Worker 
42*38e8c45fSAndroid Build Coastguard Worker static_assert(Color() == Color(0u));
43*38e8c45fSAndroid Build Coastguard Worker static_assert(ftl::to_underlying(Color(-1)) == 255u);
44*38e8c45fSAndroid Build Coastguard Worker static_assert(Color(1u) < Color(2u));
45*38e8c45fSAndroid Build Coastguard Worker 
46*38e8c45fSAndroid Build Coastguard Worker struct Sequence : ftl::DefaultConstructible<Sequence, std::int8_t, -1>,
47*38e8c45fSAndroid Build Coastguard Worker                   ftl::Equatable<Sequence>,
48*38e8c45fSAndroid Build Coastguard Worker                   ftl::Orderable<Sequence>,
49*38e8c45fSAndroid Build Coastguard Worker                   ftl::Incrementable<Sequence> {
50*38e8c45fSAndroid Build Coastguard Worker   using DefaultConstructible::DefaultConstructible;
51*38e8c45fSAndroid Build Coastguard Worker };
52*38e8c45fSAndroid Build Coastguard Worker 
53*38e8c45fSAndroid Build Coastguard Worker static_assert(Sequence() == Sequence(-1));
54*38e8c45fSAndroid Build Coastguard Worker 
55*38e8c45fSAndroid Build Coastguard Worker struct Timeout : ftl::DefaultConstructible<Timeout, std::chrono::seconds, 10>,
56*38e8c45fSAndroid Build Coastguard Worker                  ftl::Equatable<Timeout>,
57*38e8c45fSAndroid Build Coastguard Worker                  ftl::Addable<Timeout> {
58*38e8c45fSAndroid Build Coastguard Worker   using DefaultConstructible::DefaultConstructible;
59*38e8c45fSAndroid Build Coastguard Worker };
60*38e8c45fSAndroid Build Coastguard Worker 
61*38e8c45fSAndroid Build Coastguard Worker using namespace std::chrono_literals;
62*38e8c45fSAndroid Build Coastguard Worker static_assert(Timeout() + Timeout(5s) == Timeout(15s));
63*38e8c45fSAndroid Build Coastguard Worker 
64*38e8c45fSAndroid Build Coastguard Worker // Construction.
65*38e8c45fSAndroid Build Coastguard Worker constexpr Id kId{1234};
66*38e8c45fSAndroid Build Coastguard Worker constexpr Sequence kSequence;
67*38e8c45fSAndroid Build Coastguard Worker 
68*38e8c45fSAndroid Build Coastguard Worker // Underlying value.
69*38e8c45fSAndroid Build Coastguard Worker static_assert(ftl::to_underlying(Id(-42)) == -42);
70*38e8c45fSAndroid Build Coastguard Worker static_assert(ftl::to_underlying(kSequence) == -1);
71*38e8c45fSAndroid Build Coastguard Worker 
72*38e8c45fSAndroid Build Coastguard Worker // Casting.
73*38e8c45fSAndroid Build Coastguard Worker static_assert(static_cast<std::int32_t>(Id(-1)) == -1);
74*38e8c45fSAndroid Build Coastguard Worker static_assert(static_cast<std::int8_t>(kSequence) == -1);
75*38e8c45fSAndroid Build Coastguard Worker 
76*38e8c45fSAndroid Build Coastguard Worker static_assert(!std::is_convertible_v<std::int32_t, Id>);
77*38e8c45fSAndroid Build Coastguard Worker static_assert(!std::is_convertible_v<Id, std::int32_t>);
78*38e8c45fSAndroid Build Coastguard Worker 
79*38e8c45fSAndroid Build Coastguard Worker // Equality.
80*38e8c45fSAndroid Build Coastguard Worker static_assert(kId == Id(1234));
81*38e8c45fSAndroid Build Coastguard Worker static_assert(kId != Id(123));
82*38e8c45fSAndroid Build Coastguard Worker static_assert(kSequence == Sequence(-1));
83*38e8c45fSAndroid Build Coastguard Worker 
84*38e8c45fSAndroid Build Coastguard Worker // Ordering.
85*38e8c45fSAndroid Build Coastguard Worker static_assert(Sequence(1) < Sequence(2));
86*38e8c45fSAndroid Build Coastguard Worker static_assert(Sequence(2) > Sequence(1));
87*38e8c45fSAndroid Build Coastguard Worker static_assert(Sequence(3) <= Sequence(4));
88*38e8c45fSAndroid Build Coastguard Worker static_assert(Sequence(4) >= Sequence(3));
89*38e8c45fSAndroid Build Coastguard Worker static_assert(Sequence(5) <= Sequence(5));
90*38e8c45fSAndroid Build Coastguard Worker static_assert(Sequence(6) >= Sequence(6));
91*38e8c45fSAndroid Build Coastguard Worker 
92*38e8c45fSAndroid Build Coastguard Worker // Incrementing.
93*38e8c45fSAndroid Build Coastguard Worker template <typename Op, typename T, typename... Ts>
mutable_op(Op op,T lhs,Ts...rhs)94*38e8c45fSAndroid Build Coastguard Worker constexpr auto mutable_op(Op op, T lhs, Ts... rhs) {
95*38e8c45fSAndroid Build Coastguard Worker   const T result = op(lhs, rhs...);
96*38e8c45fSAndroid Build Coastguard Worker   return std::make_pair(lhs, result);
97*38e8c45fSAndroid Build Coastguard Worker }
98*38e8c45fSAndroid Build Coastguard Worker 
__anon1a57b3110202(auto& lhs) 99*38e8c45fSAndroid Build Coastguard Worker static_assert(mutable_op([](auto& lhs) { return ++lhs; }, Sequence()) ==
100*38e8c45fSAndroid Build Coastguard Worker               std::make_pair(Sequence(0), Sequence(0)));
101*38e8c45fSAndroid Build Coastguard Worker 
__anon1a57b3110302(auto& lhs) 102*38e8c45fSAndroid Build Coastguard Worker static_assert(mutable_op([](auto& lhs) { return lhs++; }, Sequence()) ==
103*38e8c45fSAndroid Build Coastguard Worker               std::make_pair(Sequence(0), Sequence(-1)));
104*38e8c45fSAndroid Build Coastguard Worker 
105*38e8c45fSAndroid Build Coastguard Worker // Addition.
106*38e8c45fSAndroid Build Coastguard Worker 
107*38e8c45fSAndroid Build Coastguard Worker // `Addable` implies `Incrementable`.
__anon1a57b3110402(auto& lhs) 108*38e8c45fSAndroid Build Coastguard Worker static_assert(mutable_op([](auto& lhs) { return ++lhs; }, Timeout()) ==
109*38e8c45fSAndroid Build Coastguard Worker               std::make_pair(Timeout(11s), Timeout(11s)));
110*38e8c45fSAndroid Build Coastguard Worker 
__anon1a57b3110502(auto& lhs) 111*38e8c45fSAndroid Build Coastguard Worker static_assert(mutable_op([](auto& lhs) { return lhs++; }, Timeout()) ==
112*38e8c45fSAndroid Build Coastguard Worker               std::make_pair(Timeout(11s), Timeout(10s)));
113*38e8c45fSAndroid Build Coastguard Worker 
114*38e8c45fSAndroid Build Coastguard Worker static_assert(Timeout(5s) + Timeout(6s) == Timeout(11s));
115*38e8c45fSAndroid Build Coastguard Worker 
__anon1a57b3110602(auto& lhs, const auto& rhs) 116*38e8c45fSAndroid Build Coastguard Worker static_assert(mutable_op([](auto& lhs, const auto& rhs) { return lhs += rhs; }, Timeout(7s),
117*38e8c45fSAndroid Build Coastguard Worker                          Timeout(8s)) == std::make_pair(Timeout(15s), Timeout(15s)));
118*38e8c45fSAndroid Build Coastguard Worker 
119*38e8c45fSAndroid Build Coastguard Worker // Type safety.
120*38e8c45fSAndroid Build Coastguard Worker 
121*38e8c45fSAndroid Build Coastguard Worker namespace traits {
122*38e8c45fSAndroid Build Coastguard Worker 
123*38e8c45fSAndroid Build Coastguard Worker template <typename, typename = void>
124*38e8c45fSAndroid Build Coastguard Worker struct is_incrementable : std::false_type {};
125*38e8c45fSAndroid Build Coastguard Worker 
126*38e8c45fSAndroid Build Coastguard Worker template <typename T>
127*38e8c45fSAndroid Build Coastguard Worker struct is_incrementable<T, std::void_t<decltype(++std::declval<T&>())>> : std::true_type {};
128*38e8c45fSAndroid Build Coastguard Worker 
129*38e8c45fSAndroid Build Coastguard Worker template <typename T>
130*38e8c45fSAndroid Build Coastguard Worker constexpr bool is_incrementable_v = is_incrementable<T>{};
131*38e8c45fSAndroid Build Coastguard Worker 
132*38e8c45fSAndroid Build Coastguard Worker template <typename, typename, typename, typename = void>
133*38e8c45fSAndroid Build Coastguard Worker struct has_binary_op : std::false_type {};
134*38e8c45fSAndroid Build Coastguard Worker 
135*38e8c45fSAndroid Build Coastguard Worker template <typename Op, typename T, typename U>
136*38e8c45fSAndroid Build Coastguard Worker struct has_binary_op<Op, T, U, std::void_t<decltype(Op{}(std::declval<T&>(), std::declval<U&>()))>>
137*38e8c45fSAndroid Build Coastguard Worker     : std::true_type {};
138*38e8c45fSAndroid Build Coastguard Worker 
139*38e8c45fSAndroid Build Coastguard Worker template <typename T, typename U>
140*38e8c45fSAndroid Build Coastguard Worker constexpr bool is_equatable_v =
141*38e8c45fSAndroid Build Coastguard Worker     has_binary_op<std::equal_to<void>, T, U>{} && has_binary_op<std::not_equal_to<void>, T, U>{};
142*38e8c45fSAndroid Build Coastguard Worker 
143*38e8c45fSAndroid Build Coastguard Worker template <typename T, typename U>
144*38e8c45fSAndroid Build Coastguard Worker constexpr bool is_orderable_v =
145*38e8c45fSAndroid Build Coastguard Worker     has_binary_op<std::less<void>, T, U>{} && has_binary_op<std::less_equal<void>, T, U>{} &&
146*38e8c45fSAndroid Build Coastguard Worker     has_binary_op<std::greater<void>, T, U>{} && has_binary_op<std::greater_equal<void>, T, U>{};
147*38e8c45fSAndroid Build Coastguard Worker 
148*38e8c45fSAndroid Build Coastguard Worker template <typename T, typename U>
149*38e8c45fSAndroid Build Coastguard Worker constexpr bool is_addable_v = has_binary_op<std::plus<void>, T, U>{};
150*38e8c45fSAndroid Build Coastguard Worker 
151*38e8c45fSAndroid Build Coastguard Worker }  // namespace traits
152*38e8c45fSAndroid Build Coastguard Worker 
153*38e8c45fSAndroid Build Coastguard Worker struct Real : ftl::Constructible<Real, float> {
154*38e8c45fSAndroid Build Coastguard Worker   using Constructible::Constructible;
155*38e8c45fSAndroid Build Coastguard Worker };
156*38e8c45fSAndroid Build Coastguard Worker 
157*38e8c45fSAndroid Build Coastguard Worker static_assert(traits::is_equatable_v<Id, Id>);
158*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_equatable_v<Real, Real>);
159*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_equatable_v<Id, Color>);
160*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_equatable_v<Sequence, Id>);
161*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_equatable_v<Id, std::int32_t>);
162*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_equatable_v<std::chrono::seconds, Timeout>);
163*38e8c45fSAndroid Build Coastguard Worker 
164*38e8c45fSAndroid Build Coastguard Worker static_assert(traits::is_orderable_v<Color, Color>);
165*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_orderable_v<Id, Id>);
166*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_orderable_v<Real, Real>);
167*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_orderable_v<Color, Sequence>);
168*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_orderable_v<Color, std::uint8_t>);
169*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_orderable_v<std::chrono::seconds, Timeout>);
170*38e8c45fSAndroid Build Coastguard Worker 
171*38e8c45fSAndroid Build Coastguard Worker static_assert(traits::is_incrementable_v<Sequence>);
172*38e8c45fSAndroid Build Coastguard Worker static_assert(traits::is_incrementable_v<Timeout>);
173*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_incrementable_v<Id>);
174*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_incrementable_v<Color>);
175*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_incrementable_v<Real>);
176*38e8c45fSAndroid Build Coastguard Worker 
177*38e8c45fSAndroid Build Coastguard Worker static_assert(traits::is_addable_v<Timeout, Timeout>);
178*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_addable_v<Id, Id>);
179*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_addable_v<Real, Real>);
180*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_addable_v<Sequence, Sequence>);
181*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_addable_v<Timeout, Sequence>);
182*38e8c45fSAndroid Build Coastguard Worker static_assert(!traits::is_addable_v<Color, Timeout>);
183*38e8c45fSAndroid Build Coastguard Worker 
184*38e8c45fSAndroid Build Coastguard Worker }  // namespace
185*38e8c45fSAndroid Build Coastguard Worker }  // namespace android::test
186