-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathtemplate_utils.hpp
More file actions
150 lines (127 loc) · 3.51 KB
/
template_utils.hpp
File metadata and controls
150 lines (127 loc) · 3.51 KB
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#ifndef TEMPLATE_UTILS_H__
#define TEMPLATE_UTILS_H__
#include <stdint.h>
// This is a dummy type meaning that there are too many bits in the data type
struct TooManyBits;
// template <int X>
// struct ROUND_UP_INT_SIZE
// {
// static int RESULT = ROUND_UP_INT_SIZE<X+1;
// };
/// RETURNS a signed integer type that has at least as many bits as the value of BITS
template <int BITS>
struct GET_INT_WITH_LENGTH
{
// The default is that an integer with N bits can be represented
// by an integer with N+1 bits
typedef typename GET_INT_WITH_LENGTH<BITS+1>::RESULT RESULT;
};
template <>
struct GET_INT_WITH_LENGTH<8>
{
typedef int8_t RESULT;
};
template <>
struct GET_INT_WITH_LENGTH<16>
{
typedef int16_t RESULT;
};
template <>
struct GET_INT_WITH_LENGTH<32>
{
typedef int32_t RESULT;
};
template <>
struct GET_INT_WITH_LENGTH<64>
{
typedef int64_t RESULT;
};
template <>
struct GET_INT_WITH_LENGTH<128>
{
typedef TooManyBits RESULT;
};
/// Returns X1 if isX1 is true, else return X2
template <int X1, int X2, bool isX1>
struct PICK_ONE
{
static const int RESULT; // Undefined
};
/// Returns X1 if (X1 > X2) else returns X2
template <int X1, int X2>
struct GET_MAX
{
static const int RESULT = PICK_ONE<X1, X2, (X1 > X2)>::RESULT;
};
template <int X1, int X2>
struct PICK_ONE<X1, X2, true>
{
static const int RESULT = X1;
};
template <int X1, int X2>
struct PICK_ONE<X1, X2, false>
{
static const int RESULT = X2;
};
template <typename T, int AMOUNT, bool left>
struct SHIFT_IN_DIRECTION
{
T exec(T value);
};
template <typename T, int AMOUNT>
struct SHIFT_IN_DIRECTION<T, AMOUNT, true>
{
T exec(T value) { return value << AMOUNT; }
};
template <typename T, int AMOUNT>
struct SHIFT_IN_DIRECTION<T, AMOUNT, false>
{
T exec(T value) { return value >> (-AMOUNT); }
};
// Shifts a value by a constant amount. Positive = left, negative = right
template <typename T, int AMOUNT>
struct SHIFT
{
T exec(T value)
{
return SHIFT_IN_DIRECTION<T, AMOUNT, (AMOUNT < 0)>::exec(value);
}
};
template <typename TSRC, typename TDEST, int SHL_AMT, bool IS_LEFT>
struct CONVERT_FIXED_POINT
{
static TDEST exec(TSRC src);
};
// Convert fixed point by shifting the value left
template <typename TSRC, typename TDEST, int SHL_AMT>
struct CONVERT_FIXED_POINT<TSRC, TDEST, SHL_AMT, true>
{
static TDEST exec(TSRC src)
{
// Because we're left shifting, we need to change the target type before
// shifting. If the target type gets smaller, we havent lost anything
// more by changing type first, but if the target type gets bigger then
// we need the bigger type to ensure all the data is preserved in the
// shift
TDEST intermediate = src;
intermediate <<= SHL_AMT;
return intermediate;
}
};
// Convert fixed point by shifting the value right
template <typename TSRC, typename TDEST, int SHL_AMT>
struct CONVERT_FIXED_POINT<TSRC, TDEST, SHL_AMT, false>
{
static TDEST exec(TSRC src)
{
// Because we're right shifting, we need to shift before we change the
// target type. If the target type gets bigger, then the early shift
// doesnt matter because the upper bits are independent of the src, but
// if the target get smaller then the right shift first is important
// in order not to lose data.
TSRC intermediate = src;
intermediate >>= (-SHL_AMT);
return (TDEST)intermediate;
}
};
#endif /* end of include guard: TEMPLATE_UTILS_H__ */