• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <ftl/mixins.h>
18 #include <gtest/gtest.h>
19 
20 #include <chrono>
21 #include <functional>
22 #include <type_traits>
23 #include <utility>
24 
25 namespace android::test {
26 namespace {
27 
28 // Keep in sync with example usage in header file.
29 
30 struct Id : ftl::Constructible<Id, std::int32_t>, ftl::Equatable<Id> {
31   using Constructible::Constructible;
32 };
33 
34 static_assert(!std::is_default_constructible_v<Id>);
35 
36 struct Color : ftl::DefaultConstructible<Color, std::uint8_t>,
37                ftl::Equatable<Color>,
38                ftl::Orderable<Color> {
39   using DefaultConstructible::DefaultConstructible;
40 };
41 
42 static_assert(Color() == Color(0u));
43 static_assert(ftl::to_underlying(Color(-1)) == 255u);
44 static_assert(Color(1u) < Color(2u));
45 
46 struct Sequence : ftl::DefaultConstructible<Sequence, std::int8_t, -1>,
47                   ftl::Equatable<Sequence>,
48                   ftl::Orderable<Sequence>,
49                   ftl::Incrementable<Sequence> {
50   using DefaultConstructible::DefaultConstructible;
51 };
52 
53 static_assert(Sequence() == Sequence(-1));
54 
55 struct Timeout : ftl::DefaultConstructible<Timeout, std::chrono::seconds, 10>,
56                  ftl::Equatable<Timeout>,
57                  ftl::Addable<Timeout> {
58   using DefaultConstructible::DefaultConstructible;
59 };
60 
61 using namespace std::chrono_literals;
62 static_assert(Timeout() + Timeout(5s) == Timeout(15s));
63 
64 // Construction.
65 constexpr Id kId{1234};
66 constexpr Sequence kSequence;
67 
68 // Underlying value.
69 static_assert(ftl::to_underlying(Id(-42)) == -42);
70 static_assert(ftl::to_underlying(kSequence) == -1);
71 
72 // Casting.
73 static_assert(static_cast<std::int32_t>(Id(-1)) == -1);
74 static_assert(static_cast<std::int8_t>(kSequence) == -1);
75 
76 static_assert(!std::is_convertible_v<std::int32_t, Id>);
77 static_assert(!std::is_convertible_v<Id, std::int32_t>);
78 
79 // Equality.
80 static_assert(kId == Id(1234));
81 static_assert(kId != Id(123));
82 static_assert(kSequence == Sequence(-1));
83 
84 // Ordering.
85 static_assert(Sequence(1) < Sequence(2));
86 static_assert(Sequence(2) > Sequence(1));
87 static_assert(Sequence(3) <= Sequence(4));
88 static_assert(Sequence(4) >= Sequence(3));
89 static_assert(Sequence(5) <= Sequence(5));
90 static_assert(Sequence(6) >= Sequence(6));
91 
92 // Incrementing.
93 template <typename Op, typename T, typename... Ts>
mutable_op(Op op,T lhs,Ts...rhs)94 constexpr auto mutable_op(Op op, T lhs, Ts... rhs) {
95   const T result = op(lhs, rhs...);
96   return std::make_pair(lhs, result);
97 }
98 
__anon4f5555200202(auto& lhs) 99 static_assert(mutable_op([](auto& lhs) { return ++lhs; }, Sequence()) ==
100               std::make_pair(Sequence(0), Sequence(0)));
101 
__anon4f5555200302(auto& lhs) 102 static_assert(mutable_op([](auto& lhs) { return lhs++; }, Sequence()) ==
103               std::make_pair(Sequence(0), Sequence(-1)));
104 
105 // Addition.
106 
107 // `Addable` implies `Incrementable`.
__anon4f5555200402(auto& lhs) 108 static_assert(mutable_op([](auto& lhs) { return ++lhs; }, Timeout()) ==
109               std::make_pair(Timeout(11s), Timeout(11s)));
110 
__anon4f5555200502(auto& lhs) 111 static_assert(mutable_op([](auto& lhs) { return lhs++; }, Timeout()) ==
112               std::make_pair(Timeout(11s), Timeout(10s)));
113 
114 static_assert(Timeout(5s) + Timeout(6s) == Timeout(11s));
115 
__anon4f5555200602(auto& lhs, const auto& rhs) 116 static_assert(mutable_op([](auto& lhs, const auto& rhs) { return lhs += rhs; }, Timeout(7s),
117                          Timeout(8s)) == std::make_pair(Timeout(15s), Timeout(15s)));
118 
119 // Type safety.
120 
121 namespace traits {
122 
123 template <typename, typename = void>
124 struct is_incrementable : std::false_type {};
125 
126 template <typename T>
127 struct is_incrementable<T, std::void_t<decltype(++std::declval<T&>())>> : std::true_type {};
128 
129 template <typename T>
130 constexpr bool is_incrementable_v = is_incrementable<T>{};
131 
132 template <typename, typename, typename, typename = void>
133 struct has_binary_op : std::false_type {};
134 
135 template <typename Op, typename T, typename U>
136 struct has_binary_op<Op, T, U, std::void_t<decltype(Op{}(std::declval<T&>(), std::declval<U&>()))>>
137     : std::true_type {};
138 
139 template <typename T, typename U>
140 constexpr bool is_equatable_v =
141     has_binary_op<std::equal_to<void>, T, U>{} && has_binary_op<std::not_equal_to<void>, T, U>{};
142 
143 template <typename T, typename U>
144 constexpr bool is_orderable_v =
145     has_binary_op<std::less<void>, T, U>{} && has_binary_op<std::less_equal<void>, T, U>{} &&
146     has_binary_op<std::greater<void>, T, U>{} && has_binary_op<std::greater_equal<void>, T, U>{};
147 
148 template <typename T, typename U>
149 constexpr bool is_addable_v = has_binary_op<std::plus<void>, T, U>{};
150 
151 }  // namespace traits
152 
153 struct Real : ftl::Constructible<Real, float> {
154   using Constructible::Constructible;
155 };
156 
157 static_assert(traits::is_equatable_v<Id, Id>);
158 static_assert(!traits::is_equatable_v<Real, Real>);
159 static_assert(!traits::is_equatable_v<Id, Color>);
160 static_assert(!traits::is_equatable_v<Sequence, Id>);
161 static_assert(!traits::is_equatable_v<Id, std::int32_t>);
162 static_assert(!traits::is_equatable_v<std::chrono::seconds, Timeout>);
163 
164 static_assert(traits::is_orderable_v<Color, Color>);
165 static_assert(!traits::is_orderable_v<Id, Id>);
166 static_assert(!traits::is_orderable_v<Real, Real>);
167 static_assert(!traits::is_orderable_v<Color, Sequence>);
168 static_assert(!traits::is_orderable_v<Color, std::uint8_t>);
169 static_assert(!traits::is_orderable_v<std::chrono::seconds, Timeout>);
170 
171 static_assert(traits::is_incrementable_v<Sequence>);
172 static_assert(traits::is_incrementable_v<Timeout>);
173 static_assert(!traits::is_incrementable_v<Id>);
174 static_assert(!traits::is_incrementable_v<Color>);
175 static_assert(!traits::is_incrementable_v<Real>);
176 
177 static_assert(traits::is_addable_v<Timeout, Timeout>);
178 static_assert(!traits::is_addable_v<Id, Id>);
179 static_assert(!traits::is_addable_v<Real, Real>);
180 static_assert(!traits::is_addable_v<Sequence, Sequence>);
181 static_assert(!traits::is_addable_v<Timeout, Sequence>);
182 static_assert(!traits::is_addable_v<Color, Timeout>);
183 
184 }  // namespace
185 }  // namespace android::test
186