1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/util/typify.h>
#include <vespa/vespalib/gtest/gtest.h>
using namespace vespalib;
struct A { static constexpr int value_from_type = 1; };
struct B { static constexpr int value_from_type = 2; };
struct MyIntA { int value; };
struct MyIntB { int value; };
struct MyIntC { int value; }; // no typifier for this type
// MyIntA -> A or B
struct TypifyMyIntA {
template <typename T> using Result = TypifyResultType<T>;
template <typename F> static decltype(auto) resolve(MyIntA value, F &&f) {
if (value.value == 1) {
return f(Result<A>());
} else if (value.value == 2) {
return f(Result<B>());
}
abort();
}
};
// MyIntB -> TypifyResultValue<int,1> or TypifyResultValue<int,2>
struct TypifyMyIntB {
template <int VALUE> using Result = TypifyResultValue<int,VALUE>;
template <typename F> static decltype(auto) resolve(MyIntB value, F &&f) {
if (value.value == 1) {
return f(Result<1>());
} else if (value.value == 2) {
return f(Result<2>());
}
abort();
}
};
using TX = TypifyValue<TypifyBool, TypifyMyIntA, TypifyMyIntB>;
//-----------------------------------------------------------------------------
struct GetFromType {
template <typename T> static int invoke() { return T::value_from_type; }
};
TEST(TypifyTest, simple_type_typification_works) {
auto res1 = typify_invoke<1,TX,GetFromType>(MyIntA{1});
auto res2 = typify_invoke<1,TX,GetFromType>(MyIntA{2});
EXPECT_EQ(res1, 1);
EXPECT_EQ(res2, 2);
}
struct GetFromValue {
template <typename R> static int invoke() { return R::value; }
};
TEST(TypifyTest, simple_value_typification_works) {
auto res1 = typify_invoke<1,TX,GetFromValue>(MyIntB{1});
auto res2 = typify_invoke<1,TX,GetFromValue>(MyIntB{2});
EXPECT_EQ(res1, 1);
EXPECT_EQ(res2, 2);
}
struct MaybeSum {
template <typename F1, typename V1, typename F2, typename V2> static int invoke(MyIntC v3) {
int res = 0;
if (F1::value) {
res += V1::value_from_type;
}
if (F2::value) {
res += V2::value;
}
res += v3.value;
return res;
}
};
TEST(TypifyTest, complex_typification_works) {
auto res1 = typify_invoke<4,TX,MaybeSum>(false, MyIntA{2}, false, MyIntB{1}, MyIntC{4});
auto res2 = typify_invoke<4,TX,MaybeSum>(false, MyIntA{2}, true, MyIntB{1}, MyIntC{4});
auto res3 = typify_invoke<4,TX,MaybeSum>(true, MyIntA{2}, false, MyIntB{1}, MyIntC{4});
auto res4 = typify_invoke<4,TX,MaybeSum>(true, MyIntA{2}, true, MyIntB{1}, MyIntC{4});
EXPECT_EQ(res1, 4);
EXPECT_EQ(res2, 5);
EXPECT_EQ(res3, 6);
EXPECT_EQ(res4, 7);
}
struct Singleton {
virtual int get() const = 0;
virtual ~Singleton() {}
};
template <int A, int B>
struct MySingleton : Singleton {
MySingleton() = default;
MySingleton(const MySingleton &) = delete;
MySingleton &operator=(const MySingleton &) = delete;
int get() const override { return A + B; }
};
struct GetSingleton {
template <typename A, typename B>
static const Singleton &invoke() {
static MySingleton<A::value, B::value> obj;
return obj;
}
};
TEST(TypifyTest, typify_invoke_can_return_object_reference) {
const Singleton &s1 = typify_invoke<2,TX,GetSingleton>(MyIntB{1}, MyIntB{1});
const Singleton &s2 = typify_invoke<2,TX,GetSingleton>(MyIntB{2}, MyIntB{2});
const Singleton &s3 = typify_invoke<2,TX,GetSingleton>(MyIntB{2}, MyIntB{2});
EXPECT_EQ(s1.get(), 2);
EXPECT_EQ(s2.get(), 4);
EXPECT_EQ(s3.get(), 4);
EXPECT_NE(&s1, &s2);
EXPECT_EQ(&s2, &s3);
}
GTEST_MAIN_RUN_ALL_TESTS()
|