1*14675a02SAndroid Build Coastguard Worker /*
2*14675a02SAndroid Build Coastguard Worker * Copyright 2019 Google LLC
3*14675a02SAndroid Build Coastguard Worker *
4*14675a02SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*14675a02SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*14675a02SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*14675a02SAndroid Build Coastguard Worker *
8*14675a02SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*14675a02SAndroid Build Coastguard Worker *
10*14675a02SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*14675a02SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*14675a02SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*14675a02SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*14675a02SAndroid Build Coastguard Worker * limitations under the License.
15*14675a02SAndroid Build Coastguard Worker */
16*14675a02SAndroid Build Coastguard Worker
17*14675a02SAndroid Build Coastguard Worker #include "fcp/base/meta.h"
18*14675a02SAndroid Build Coastguard Worker
19*14675a02SAndroid Build Coastguard Worker #include <functional>
20*14675a02SAndroid Build Coastguard Worker #include <memory>
21*14675a02SAndroid Build Coastguard Worker #include <optional>
22*14675a02SAndroid Build Coastguard Worker #include <type_traits>
23*14675a02SAndroid Build Coastguard Worker #include <utility>
24*14675a02SAndroid Build Coastguard Worker #include <vector>
25*14675a02SAndroid Build Coastguard Worker
26*14675a02SAndroid Build Coastguard Worker #include "gmock/gmock.h"
27*14675a02SAndroid Build Coastguard Worker #include "gtest/gtest.h"
28*14675a02SAndroid Build Coastguard Worker
29*14675a02SAndroid Build Coastguard Worker namespace fcp {
30*14675a02SAndroid Build Coastguard Worker
31*14675a02SAndroid Build Coastguard Worker using ::testing::Eq;
32*14675a02SAndroid Build Coastguard Worker using ::testing::Not;
33*14675a02SAndroid Build Coastguard Worker
34*14675a02SAndroid Build Coastguard Worker struct R {
35*14675a02SAndroid Build Coastguard Worker virtual ~R() = default;
36*14675a02SAndroid Build Coastguard Worker virtual bool Virt1(int i) = 0;
37*14675a02SAndroid Build Coastguard Worker virtual bool Virt2(int i, int j) = 0;
38*14675a02SAndroid Build Coastguard Worker virtual void Virt3() = 0;
NonVirt1fcp::R39*14675a02SAndroid Build Coastguard Worker int NonVirt1() { return 1; }
NonVirt2fcp::R40*14675a02SAndroid Build Coastguard Worker int NonVirt2() { return 2; }
41*14675a02SAndroid Build Coastguard Worker char field;
42*14675a02SAndroid Build Coastguard Worker };
43*14675a02SAndroid Build Coastguard Worker
44*14675a02SAndroid Build Coastguard Worker struct S {
45*14675a02SAndroid Build Coastguard Worker virtual ~S() = default;
46*14675a02SAndroid Build Coastguard Worker virtual bool Virt1(int i) = 0;
47*14675a02SAndroid Build Coastguard Worker virtual bool Virt2(int i, int j) = 0;
48*14675a02SAndroid Build Coastguard Worker virtual void Virt3() = 0;
NonVirt1fcp::S49*14675a02SAndroid Build Coastguard Worker int NonVirt1() { return 1; }
NonVirt2fcp::S50*14675a02SAndroid Build Coastguard Worker int NonVirt2() { return 2; }
51*14675a02SAndroid Build Coastguard Worker char field;
52*14675a02SAndroid Build Coastguard Worker };
53*14675a02SAndroid Build Coastguard Worker
54*14675a02SAndroid Build Coastguard Worker //
55*14675a02SAndroid Build Coastguard Worker // Compile-time tests for MemberPointerTraits
56*14675a02SAndroid Build Coastguard Worker //
57*14675a02SAndroid Build Coastguard Worker #define STATIC_ASSERT_TARGET_TYPE(member, type) \
58*14675a02SAndroid Build Coastguard Worker static_assert( \
59*14675a02SAndroid Build Coastguard Worker std::is_same<MemberPointerTraits<decltype(&S::member)>::TargetType, \
60*14675a02SAndroid Build Coastguard Worker type>::value, \
61*14675a02SAndroid Build Coastguard Worker "Incorrect target type from MemberPointerTraits");
62*14675a02SAndroid Build Coastguard Worker
63*14675a02SAndroid Build Coastguard Worker // For some reason the linter otherwise thinks e.g. 'bool(int)' is an old-style
64*14675a02SAndroid Build Coastguard Worker // cast.
65*14675a02SAndroid Build Coastguard Worker template<typename T>
66*14675a02SAndroid Build Coastguard Worker struct Id { using Type = T; };
67*14675a02SAndroid Build Coastguard Worker
68*14675a02SAndroid Build Coastguard Worker STATIC_ASSERT_TARGET_TYPE(Virt1, Id<bool(int)>::Type);
69*14675a02SAndroid Build Coastguard Worker STATIC_ASSERT_TARGET_TYPE(Virt2, Id<bool(int, int)>::Type);
70*14675a02SAndroid Build Coastguard Worker STATIC_ASSERT_TARGET_TYPE(Virt3, Id<void()>::Type);
71*14675a02SAndroid Build Coastguard Worker STATIC_ASSERT_TARGET_TYPE(NonVirt1, Id<int()>::Type);
72*14675a02SAndroid Build Coastguard Worker STATIC_ASSERT_TARGET_TYPE(NonVirt2, Id<int()>::Type);
73*14675a02SAndroid Build Coastguard Worker STATIC_ASSERT_TARGET_TYPE(field, Id<char>::Type);
74*14675a02SAndroid Build Coastguard Worker //
75*14675a02SAndroid Build Coastguard Worker // End compile-time tests for MemberPointerTraits
76*14675a02SAndroid Build Coastguard Worker //
77*14675a02SAndroid Build Coastguard Worker
78*14675a02SAndroid Build Coastguard Worker template<typename T>
79*14675a02SAndroid Build Coastguard Worker struct TypeIdHolder {
80*14675a02SAndroid Build Coastguard Worker static constexpr char kTarget = '\0';
81*14675a02SAndroid Build Coastguard Worker };
82*14675a02SAndroid Build Coastguard Worker template<typename T>
83*14675a02SAndroid Build Coastguard Worker constexpr char TypeIdHolder<T>::kTarget;
84*14675a02SAndroid Build Coastguard Worker
85*14675a02SAndroid Build Coastguard Worker // This gives us a unique runtime value per unique type - with which its much
86*14675a02SAndroid Build Coastguard Worker // easier to verify uniqueness (below).
87*14675a02SAndroid Build Coastguard Worker template<typename T>
TypeId()88*14675a02SAndroid Build Coastguard Worker static constexpr char const* TypeId() {
89*14675a02SAndroid Build Coastguard Worker return &TypeIdHolder<T>::kTarget;
90*14675a02SAndroid Build Coastguard Worker }
91*14675a02SAndroid Build Coastguard Worker
92*14675a02SAndroid Build Coastguard Worker //
93*14675a02SAndroid Build Coastguard Worker // LIFT_MEMBER_TO_TYPE
94*14675a02SAndroid Build Coastguard Worker //
95*14675a02SAndroid Build Coastguard Worker
TEST(MetaTest,MemberTagUniqueness)96*14675a02SAndroid Build Coastguard Worker TEST(MetaTest, MemberTagUniqueness) {
97*14675a02SAndroid Build Coastguard Worker std::vector<char const*> type_ids = {
98*14675a02SAndroid Build Coastguard Worker TypeId<LIFT_MEMBER_TO_TYPE(S, Virt1)>(),
99*14675a02SAndroid Build Coastguard Worker TypeId<LIFT_MEMBER_TO_TYPE(S, Virt2)>(),
100*14675a02SAndroid Build Coastguard Worker TypeId<LIFT_MEMBER_TO_TYPE(S, Virt3)>(),
101*14675a02SAndroid Build Coastguard Worker TypeId<LIFT_MEMBER_TO_TYPE(S, NonVirt1)>(),
102*14675a02SAndroid Build Coastguard Worker TypeId<LIFT_MEMBER_TO_TYPE(S, NonVirt2)>(),
103*14675a02SAndroid Build Coastguard Worker TypeId<LIFT_MEMBER_TO_TYPE(S, field)>(),
104*14675a02SAndroid Build Coastguard Worker TypeId<LIFT_MEMBER_TO_TYPE(R, Virt1)>(),
105*14675a02SAndroid Build Coastguard Worker TypeId<LIFT_MEMBER_TO_TYPE(R, Virt2)>(),
106*14675a02SAndroid Build Coastguard Worker TypeId<LIFT_MEMBER_TO_TYPE(R, Virt3)>(),
107*14675a02SAndroid Build Coastguard Worker TypeId<LIFT_MEMBER_TO_TYPE(R, NonVirt1)>(),
108*14675a02SAndroid Build Coastguard Worker TypeId<LIFT_MEMBER_TO_TYPE(R, NonVirt2)>(),
109*14675a02SAndroid Build Coastguard Worker TypeId<LIFT_MEMBER_TO_TYPE(R, field)>(),
110*14675a02SAndroid Build Coastguard Worker };
111*14675a02SAndroid Build Coastguard Worker
112*14675a02SAndroid Build Coastguard Worker for (int i = 0; i < type_ids.size(); i++) {
113*14675a02SAndroid Build Coastguard Worker for (int j = 0; j < type_ids.size(); j++) {
114*14675a02SAndroid Build Coastguard Worker if (i == j) {
115*14675a02SAndroid Build Coastguard Worker continue;
116*14675a02SAndroid Build Coastguard Worker }
117*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(type_ids[i], Not(Eq(type_ids[j])))
118*14675a02SAndroid Build Coastguard Worker << "Member tags must be unique";
119*14675a02SAndroid Build Coastguard Worker }
120*14675a02SAndroid Build Coastguard Worker }
121*14675a02SAndroid Build Coastguard Worker }
122*14675a02SAndroid Build Coastguard Worker
PokeMemberCase(LIFT_MEMBER_TO_TYPE (S,Virt1))123*14675a02SAndroid Build Coastguard Worker int PokeMemberCase(LIFT_MEMBER_TO_TYPE(S, Virt1)) {
124*14675a02SAndroid Build Coastguard Worker return 1;
125*14675a02SAndroid Build Coastguard Worker }
126*14675a02SAndroid Build Coastguard Worker
PokeMemberCase(LIFT_MEMBER_TO_TYPE (S,Virt2))127*14675a02SAndroid Build Coastguard Worker int PokeMemberCase(LIFT_MEMBER_TO_TYPE(S, Virt2)) {
128*14675a02SAndroid Build Coastguard Worker return 2;
129*14675a02SAndroid Build Coastguard Worker }
130*14675a02SAndroid Build Coastguard Worker
131*14675a02SAndroid Build Coastguard Worker template<typename R, R S::* M>
PokeMember()132*14675a02SAndroid Build Coastguard Worker int PokeMember() {
133*14675a02SAndroid Build Coastguard Worker return PokeMemberCase(LIFT_MEMBER_POINTER_TO_TYPE(M){});
134*14675a02SAndroid Build Coastguard Worker }
135*14675a02SAndroid Build Coastguard Worker
TEST(MetaTest,MemberTagDispatch)136*14675a02SAndroid Build Coastguard Worker TEST(MetaTest, MemberTagDispatch) {
137*14675a02SAndroid Build Coastguard Worker EXPECT_THAT((PokeMember<bool(int), &S::Virt1>()), Eq(1));
138*14675a02SAndroid Build Coastguard Worker EXPECT_THAT((PokeMember<bool(int, int), &S::Virt2>()), Eq(2));
139*14675a02SAndroid Build Coastguard Worker }
140*14675a02SAndroid Build Coastguard Worker
141*14675a02SAndroid Build Coastguard Worker //
142*14675a02SAndroid Build Coastguard Worker // CastContainerElements
143*14675a02SAndroid Build Coastguard Worker //
144*14675a02SAndroid Build Coastguard Worker
145*14675a02SAndroid Build Coastguard Worker struct X {
tagfcp::X146*14675a02SAndroid Build Coastguard Worker static constexpr int tag() { return 1; }
147*14675a02SAndroid Build Coastguard Worker };
148*14675a02SAndroid Build Coastguard Worker
149*14675a02SAndroid Build Coastguard Worker struct Y {
tagfcp::Y150*14675a02SAndroid Build Coastguard Worker static constexpr int tag() { return 2; }
151*14675a02SAndroid Build Coastguard Worker };
152*14675a02SAndroid Build Coastguard Worker
153*14675a02SAndroid Build Coastguard Worker template<typename T>
154*14675a02SAndroid Build Coastguard Worker struct TypedVal {
155*14675a02SAndroid Build Coastguard Worker int value;
156*14675a02SAndroid Build Coastguard Worker
operator ==fcp::TypedVal157*14675a02SAndroid Build Coastguard Worker bool operator==(TypedVal<T> const& other) const {
158*14675a02SAndroid Build Coastguard Worker return other.value == value;
159*14675a02SAndroid Build Coastguard Worker }
operator !=fcp::TypedVal160*14675a02SAndroid Build Coastguard Worker bool operator!=(TypedVal<T> const& other) const { return !(*this == other); }
161*14675a02SAndroid Build Coastguard Worker };
162*14675a02SAndroid Build Coastguard Worker
163*14675a02SAndroid Build Coastguard Worker struct UntypedVal {
164*14675a02SAndroid Build Coastguard Worker int tag;
165*14675a02SAndroid Build Coastguard Worker int value;
166*14675a02SAndroid Build Coastguard Worker };
167*14675a02SAndroid Build Coastguard Worker
168*14675a02SAndroid Build Coastguard Worker struct CastValByTag {
169*14675a02SAndroid Build Coastguard Worker template <typename T>
170*14675a02SAndroid Build Coastguard Worker using TargetType = std::optional<TypedVal<T>>;
171*14675a02SAndroid Build Coastguard Worker
172*14675a02SAndroid Build Coastguard Worker template <typename T>
Castfcp::CastValByTag173*14675a02SAndroid Build Coastguard Worker TargetType<T> Cast(UntypedVal const& val) const {
174*14675a02SAndroid Build Coastguard Worker if (val.tag == T::tag()) {
175*14675a02SAndroid Build Coastguard Worker return TypedVal<T>{val.value};
176*14675a02SAndroid Build Coastguard Worker } else {
177*14675a02SAndroid Build Coastguard Worker return std::nullopt;
178*14675a02SAndroid Build Coastguard Worker }
179*14675a02SAndroid Build Coastguard Worker }
180*14675a02SAndroid Build Coastguard Worker };
181*14675a02SAndroid Build Coastguard Worker
TEST(MetaTest,CastContainerElements_AllSuccess)182*14675a02SAndroid Build Coastguard Worker TEST(MetaTest, CastContainerElements_AllSuccess) {
183*14675a02SAndroid Build Coastguard Worker std::vector<UntypedVal> v{
184*14675a02SAndroid Build Coastguard Worker {X::tag(), 123},
185*14675a02SAndroid Build Coastguard Worker {Y::tag(), 456},
186*14675a02SAndroid Build Coastguard Worker {X::tag(), 789}
187*14675a02SAndroid Build Coastguard Worker };
188*14675a02SAndroid Build Coastguard Worker
189*14675a02SAndroid Build Coastguard Worker auto actual = CastContainerElements<X, Y, X>(v, CastValByTag{});
190*14675a02SAndroid Build Coastguard Worker auto expected = std::make_tuple(absl::make_optional(TypedVal<X>{123}),
191*14675a02SAndroid Build Coastguard Worker absl::make_optional(TypedVal<Y>{456}),
192*14675a02SAndroid Build Coastguard Worker absl::make_optional(TypedVal<X>{789}));
193*14675a02SAndroid Build Coastguard Worker
194*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(actual, Eq(expected));
195*14675a02SAndroid Build Coastguard Worker }
196*14675a02SAndroid Build Coastguard Worker
TEST(MetaTest,CastContainerElements_AllSuccess_Pack)197*14675a02SAndroid Build Coastguard Worker TEST(MetaTest, CastContainerElements_AllSuccess_Pack) {
198*14675a02SAndroid Build Coastguard Worker std::vector<UntypedVal> v{
199*14675a02SAndroid Build Coastguard Worker {X::tag(), 123},
200*14675a02SAndroid Build Coastguard Worker {Y::tag(), 456},
201*14675a02SAndroid Build Coastguard Worker {X::tag(), 789}
202*14675a02SAndroid Build Coastguard Worker };
203*14675a02SAndroid Build Coastguard Worker
204*14675a02SAndroid Build Coastguard Worker // This uses the Pack<> overload instead.
205*14675a02SAndroid Build Coastguard Worker auto actual = CastContainerElements(Pack<X, Y, X>{}, v, CastValByTag{});
206*14675a02SAndroid Build Coastguard Worker auto expected = std::make_tuple(absl::make_optional(TypedVal<X>{123}),
207*14675a02SAndroid Build Coastguard Worker absl::make_optional(TypedVal<Y>{456}),
208*14675a02SAndroid Build Coastguard Worker absl::make_optional(TypedVal<X>{789}));
209*14675a02SAndroid Build Coastguard Worker
210*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(actual, Eq(expected));
211*14675a02SAndroid Build Coastguard Worker }
212*14675a02SAndroid Build Coastguard Worker
TEST(MetaTest,CastContainerElements_OneFails)213*14675a02SAndroid Build Coastguard Worker TEST(MetaTest, CastContainerElements_OneFails) {
214*14675a02SAndroid Build Coastguard Worker std::vector<UntypedVal> v{
215*14675a02SAndroid Build Coastguard Worker {X::tag(), 123},
216*14675a02SAndroid Build Coastguard Worker {X::tag(), 456},
217*14675a02SAndroid Build Coastguard Worker {X::tag(), 789}
218*14675a02SAndroid Build Coastguard Worker };
219*14675a02SAndroid Build Coastguard Worker
220*14675a02SAndroid Build Coastguard Worker // Second element does not have the tag for Y.
221*14675a02SAndroid Build Coastguard Worker auto actual = CastContainerElements<X, Y, X>(v, CastValByTag{});
222*14675a02SAndroid Build Coastguard Worker auto expected = std::make_tuple(absl::make_optional(TypedVal<X>{123}),
223*14675a02SAndroid Build Coastguard Worker std::optional<TypedVal<Y>>(std::nullopt),
224*14675a02SAndroid Build Coastguard Worker absl::make_optional(TypedVal<X>{789}));
225*14675a02SAndroid Build Coastguard Worker
226*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(actual, Eq(expected));
227*14675a02SAndroid Build Coastguard Worker }
228*14675a02SAndroid Build Coastguard Worker
229*14675a02SAndroid Build Coastguard Worker //
230*14675a02SAndroid Build Coastguard Worker // MAKE_LINK and LinkedType<>
231*14675a02SAndroid Build Coastguard Worker //
232*14675a02SAndroid Build Coastguard Worker
233*14675a02SAndroid Build Coastguard Worker namespace links {
234*14675a02SAndroid Build Coastguard Worker
235*14675a02SAndroid Build Coastguard Worker namespace a {
236*14675a02SAndroid Build Coastguard Worker
237*14675a02SAndroid Build Coastguard Worker struct A1 {};
238*14675a02SAndroid Build Coastguard Worker struct A2 {};
239*14675a02SAndroid Build Coastguard Worker struct A3 {};
240*14675a02SAndroid Build Coastguard Worker
241*14675a02SAndroid Build Coastguard Worker MAKE_LINK(A1, A2);
242*14675a02SAndroid Build Coastguard Worker
243*14675a02SAndroid Build Coastguard Worker } // namespace a
244*14675a02SAndroid Build Coastguard Worker
245*14675a02SAndroid Build Coastguard Worker namespace b {
246*14675a02SAndroid Build Coastguard Worker
247*14675a02SAndroid Build Coastguard Worker struct B1 {};
248*14675a02SAndroid Build Coastguard Worker
249*14675a02SAndroid Build Coastguard Worker MAKE_LINK(B1, a::A3);
250*14675a02SAndroid Build Coastguard Worker
251*14675a02SAndroid Build Coastguard Worker } // namespace b
252*14675a02SAndroid Build Coastguard Worker
253*14675a02SAndroid Build Coastguard Worker } // namespace links
254*14675a02SAndroid Build Coastguard Worker
255*14675a02SAndroid Build Coastguard Worker static_assert(std::is_same<LinkedType<links::a::A1>, links::a::A2>::value,
256*14675a02SAndroid Build Coastguard Worker "A1 -> A2");
257*14675a02SAndroid Build Coastguard Worker static_assert(HasLinkedType<links::a::A1>(), "A1 -> A2");
258*14675a02SAndroid Build Coastguard Worker static_assert(std::is_same<LinkedTypeOrVoid<links::a::A2>, void>::value,
259*14675a02SAndroid Build Coastguard Worker "A2 -/>");
260*14675a02SAndroid Build Coastguard Worker static_assert(!HasLinkedType<links::a::A2>(), "A2 -/>");
261*14675a02SAndroid Build Coastguard Worker static_assert(std::is_same<LinkedTypeOrVoid<links::a::A3>, void>::value,
262*14675a02SAndroid Build Coastguard Worker "A3 -/>");
263*14675a02SAndroid Build Coastguard Worker static_assert(!HasLinkedType<links::a::A3>(), "A3 -/>");
264*14675a02SAndroid Build Coastguard Worker static_assert(std::is_same<LinkedType<links::b::B1>, links::a::A3>::value,
265*14675a02SAndroid Build Coastguard Worker "b::B1 -> a::A3");
266*14675a02SAndroid Build Coastguard Worker static_assert(HasLinkedType<links::b::B1>(), "b::B1 -> a::A3");
267*14675a02SAndroid Build Coastguard Worker
268*14675a02SAndroid Build Coastguard Worker //
269*14675a02SAndroid Build Coastguard Worker // Pack<>
270*14675a02SAndroid Build Coastguard Worker //
271*14675a02SAndroid Build Coastguard Worker
272*14675a02SAndroid Build Coastguard Worker template<typename A1, typename A2, size_t I1, size_t I2>
CheckUnpack()273*14675a02SAndroid Build Coastguard Worker constexpr Unit CheckUnpack() {
274*14675a02SAndroid Build Coastguard Worker static_assert(std::is_same<A1, X>::value, "A1 == X");
275*14675a02SAndroid Build Coastguard Worker static_assert(std::is_same<A2, Y>::value, "A2 == Y");
276*14675a02SAndroid Build Coastguard Worker static_assert(I1 == 0, "I1 == 0");
277*14675a02SAndroid Build Coastguard Worker static_assert(I2 == 1, "I2 == 0");
278*14675a02SAndroid Build Coastguard Worker return {};
279*14675a02SAndroid Build Coastguard Worker }
280*14675a02SAndroid Build Coastguard Worker
281*14675a02SAndroid Build Coastguard Worker template<typename... A, size_t... I>
UsePack(Pack<A...>,absl::index_sequence<I...>)282*14675a02SAndroid Build Coastguard Worker constexpr Unit UsePack(Pack<A...>, absl::index_sequence<I...>) {
283*14675a02SAndroid Build Coastguard Worker return CheckUnpack<A..., I...>();
284*14675a02SAndroid Build Coastguard Worker }
285*14675a02SAndroid Build Coastguard Worker
286*14675a02SAndroid Build Coastguard Worker template<typename... A>
MakeAndUsePack()287*14675a02SAndroid Build Coastguard Worker constexpr Unit MakeAndUsePack() {
288*14675a02SAndroid Build Coastguard Worker return UsePack(Pack<A...>{}, Pack<A...>::MakeIndexSequence());
289*14675a02SAndroid Build Coastguard Worker }
290*14675a02SAndroid Build Coastguard Worker
291*14675a02SAndroid Build Coastguard Worker static_assert(MakeAndUsePack<X, Y>().True(), "Pack<>");
292*14675a02SAndroid Build Coastguard Worker
293*14675a02SAndroid Build Coastguard Worker //
294*14675a02SAndroid Build Coastguard Worker // LiftVoidReturn
295*14675a02SAndroid Build Coastguard Worker //
296*14675a02SAndroid Build Coastguard Worker
TEST(MetaTest,LiftVoidReturn_Void)297*14675a02SAndroid Build Coastguard Worker TEST(MetaTest, LiftVoidReturn_Void) {
298*14675a02SAndroid Build Coastguard Worker int counter = 0;
299*14675a02SAndroid Build Coastguard Worker std::function<void()> f = [&counter]() { counter++; };
300*14675a02SAndroid Build Coastguard Worker
301*14675a02SAndroid Build Coastguard Worker f();
302*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(counter, Eq(1));
303*14675a02SAndroid Build Coastguard Worker auto f_wrapped = LiftVoidReturn(f);
304*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(f_wrapped(), Eq(Unit{}));
305*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(counter, Eq(2));
306*14675a02SAndroid Build Coastguard Worker }
307*14675a02SAndroid Build Coastguard Worker
TEST(MetaTest,LiftVoidReturn_Void_Args)308*14675a02SAndroid Build Coastguard Worker TEST(MetaTest, LiftVoidReturn_Void_Args) {
309*14675a02SAndroid Build Coastguard Worker int counter = 0;
310*14675a02SAndroid Build Coastguard Worker std::function<void(int)> f = [&counter](int i) { counter += i; };
311*14675a02SAndroid Build Coastguard Worker
312*14675a02SAndroid Build Coastguard Worker f(10);
313*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(counter, Eq(10));
314*14675a02SAndroid Build Coastguard Worker auto f_wrapped = LiftVoidReturn(f);
315*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(f_wrapped(32), Eq(Unit{}));
316*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(counter, Eq(42));
317*14675a02SAndroid Build Coastguard Worker }
318*14675a02SAndroid Build Coastguard Worker
TEST(MetaTest,LiftVoidReturn_NonVoid)319*14675a02SAndroid Build Coastguard Worker TEST(MetaTest, LiftVoidReturn_NonVoid) {
320*14675a02SAndroid Build Coastguard Worker int counter = 0;
321*14675a02SAndroid Build Coastguard Worker std::function<int(int)> f = [&counter](int i) {
322*14675a02SAndroid Build Coastguard Worker counter += i;
323*14675a02SAndroid Build Coastguard Worker return counter;
324*14675a02SAndroid Build Coastguard Worker };
325*14675a02SAndroid Build Coastguard Worker
326*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(f(10), Eq(10));
327*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(counter, Eq(10));
328*14675a02SAndroid Build Coastguard Worker auto f_wrapped = LiftVoidReturn(f);
329*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(f_wrapped(32), Eq(42));
330*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(counter, Eq(42));
331*14675a02SAndroid Build Coastguard Worker }
332*14675a02SAndroid Build Coastguard Worker
TEST(MetaTest,LiftVoidReturn_Mutable)333*14675a02SAndroid Build Coastguard Worker TEST(MetaTest, LiftVoidReturn_Mutable) {
334*14675a02SAndroid Build Coastguard Worker int r = -1;
335*14675a02SAndroid Build Coastguard Worker auto f = [&r, counter = 0]() mutable {
336*14675a02SAndroid Build Coastguard Worker counter++;
337*14675a02SAndroid Build Coastguard Worker r = counter;
338*14675a02SAndroid Build Coastguard Worker };
339*14675a02SAndroid Build Coastguard Worker
340*14675a02SAndroid Build Coastguard Worker f();
341*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(r, Eq(1));
342*14675a02SAndroid Build Coastguard Worker auto f_wrapped = LiftVoidReturn(f);
343*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(f_wrapped(), Eq(Unit{}));
344*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(r, Eq(2));
345*14675a02SAndroid Build Coastguard Worker }
346*14675a02SAndroid Build Coastguard Worker
TEST(MetaTest,LiftVoidReturn_MutableAndMoveOnly)347*14675a02SAndroid Build Coastguard Worker TEST(MetaTest, LiftVoidReturn_MutableAndMoveOnly) {
348*14675a02SAndroid Build Coastguard Worker int r = -1;
349*14675a02SAndroid Build Coastguard Worker auto f = [&r, counter = std::make_unique<int>(0)]() mutable {
350*14675a02SAndroid Build Coastguard Worker (*counter)++;
351*14675a02SAndroid Build Coastguard Worker r = *counter;
352*14675a02SAndroid Build Coastguard Worker };
353*14675a02SAndroid Build Coastguard Worker
354*14675a02SAndroid Build Coastguard Worker f();
355*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(r, Eq(1));
356*14675a02SAndroid Build Coastguard Worker auto f_wrapped = LiftVoidReturn(std::move(f));
357*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(f_wrapped(), Eq(Unit{}));
358*14675a02SAndroid Build Coastguard Worker EXPECT_THAT(r, Eq(2));
359*14675a02SAndroid Build Coastguard Worker }
360*14675a02SAndroid Build Coastguard Worker
361*14675a02SAndroid Build Coastguard Worker //
362*14675a02SAndroid Build Coastguard Worker // FunctionTraits
363*14675a02SAndroid Build Coastguard Worker //
364*14675a02SAndroid Build Coastguard Worker
365*14675a02SAndroid Build Coastguard Worker #define STATIC_ASSERT_FUNCTION_TRAITS(fn, r, ...) \
366*14675a02SAndroid Build Coastguard Worker static_assert(std::is_same<FunctionTraits<fn>::ResultType, r>::value, \
367*14675a02SAndroid Build Coastguard Worker "Incorrect result type from FunctionTraits"); \
368*14675a02SAndroid Build Coastguard Worker static_assert( \
369*14675a02SAndroid Build Coastguard Worker std::is_same<FunctionTraits<fn>::ArgPackType, Pack<__VA_ARGS__>>::value, \
370*14675a02SAndroid Build Coastguard Worker "Incorrect arg pack from FunctionTraits")
371*14675a02SAndroid Build Coastguard Worker
372*14675a02SAndroid Build Coastguard Worker STATIC_ASSERT_FUNCTION_TRAITS(void(), void);
373*14675a02SAndroid Build Coastguard Worker STATIC_ASSERT_FUNCTION_TRAITS(void(int, char), void, int, char);
374*14675a02SAndroid Build Coastguard Worker STATIC_ASSERT_FUNCTION_TRAITS(Identity<bool(char const*, int)>, bool,
375*14675a02SAndroid Build Coastguard Worker char const*, int);
376*14675a02SAndroid Build Coastguard Worker
TEST(MetaTest,IsTypeOneOf)377*14675a02SAndroid Build Coastguard Worker TEST(MetaTest, IsTypeOneOf) {
378*14675a02SAndroid Build Coastguard Worker static_assert(IsTypeOneOf<int, int>());
379*14675a02SAndroid Build Coastguard Worker static_assert(IsTypeOneOf<int, int, double>());
380*14675a02SAndroid Build Coastguard Worker static_assert(IsTypeOneOf<int, double, int>());
381*14675a02SAndroid Build Coastguard Worker static_assert(!IsTypeOneOf<int, bool>());
382*14675a02SAndroid Build Coastguard Worker static_assert(!IsTypeOneOf<int, double, char>());
383*14675a02SAndroid Build Coastguard Worker }
384*14675a02SAndroid Build Coastguard Worker
TEST(MetaTest,IsSubsetOf)385*14675a02SAndroid Build Coastguard Worker TEST(MetaTest, IsSubsetOf) {
386*14675a02SAndroid Build Coastguard Worker using T1 = Pack<int, double>;
387*14675a02SAndroid Build Coastguard Worker using T2 = Pack<double, int>;
388*14675a02SAndroid Build Coastguard Worker using T3 = Pack<int, double, char>;
389*14675a02SAndroid Build Coastguard Worker
390*14675a02SAndroid Build Coastguard Worker static_assert(IsSubsetOf<T1, T1>::value);
391*14675a02SAndroid Build Coastguard Worker static_assert(IsSubsetOf<T1, T2>::value);
392*14675a02SAndroid Build Coastguard Worker static_assert(IsSubsetOf<T2, T1>::value);
393*14675a02SAndroid Build Coastguard Worker static_assert(IsSubsetOf<T2, T3>::value);
394*14675a02SAndroid Build Coastguard Worker static_assert(!IsSubsetOf<T3, T2>::value);
395*14675a02SAndroid Build Coastguard Worker }
396*14675a02SAndroid Build Coastguard Worker
397*14675a02SAndroid Build Coastguard Worker } // namespace fcp
398