-
Notifications
You must be signed in to change notification settings - Fork 404
/
ffs.hpp
149 lines (121 loc) · 3 KB
/
ffs.hpp
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
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012- OpenVPN Inc.
//
// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
//
#ifndef OPENVPN_COMMON_FFS_H
#define OPENVPN_COMMON_FFS_H
// find_first_set: find the one-based position of the first 1 bit in
// a word (scanning from least significant bit to most significant)
// find_last_set: find the one-based position of the last 1 bit in
// a word (scanning from most significant bit to least significant)
namespace openvpn {
#if defined(__GNUC__)
template <typename T>
inline constexpr int n_bits_type()
{
return sizeof(T) * 8;
}
template <typename T>
inline constexpr int n_bits_type(const T &v)
{
return sizeof(v) * 8;
}
inline int find_first_set(const unsigned int v)
{
if (!v)
return 0;
return __builtin_ffs(v);
}
inline int find_first_set(const int v)
{
return find_first_set(static_cast<unsigned int>(v));
}
inline int find_last_set(const unsigned int v)
{
if (!v)
return 0;
return n_bits_type(v) - __builtin_clz(v);
}
inline int find_last_set(const int v)
{
return find_last_set(static_cast<unsigned int>(v));
}
inline int find_first_set(const unsigned long v)
{
if (!v)
return 0;
return __builtin_ffsl(v);
}
inline int find_first_set(const long v)
{
return find_first_set(static_cast<unsigned long>(v));
}
inline int find_last_set(const unsigned long v)
{
if (!v)
return 0;
return n_bits_type(v) - __builtin_clzl(v);
}
inline int find_last_set(const long v)
{
return find_last_set(static_cast<unsigned long>(v));
}
inline int find_first_set(const unsigned long long v)
{
if (!v)
return 0;
return __builtin_ffsll(v);
}
inline int find_first_set(const long long v)
{
return find_first_set(static_cast<unsigned long long>(v));
}
inline int find_last_set(const unsigned long long v)
{
if (!v)
return 0;
return n_bits_type(v) - __builtin_clzll(v);
}
inline int find_last_set(const long long v)
{
return find_last_set(static_cast<unsigned long long>(v));
}
#elif defined(_MSC_VER)
#include <intrin.h>
inline int find_first_set(unsigned int x)
{
if (!x)
return 0;
unsigned int r = 0;
_BitScanForward((unsigned long *)&r, x);
return r + 1;
}
inline int find_last_set(unsigned int x)
{
if (!x)
return 0;
unsigned int r = 0;
_BitScanReverse((unsigned long *)&r, x);
return r + 1;
}
#else
#error no find_first_set / find_last_set implementation for this platform
#endif
template <typename T>
inline bool is_pow2(const T v)
{
return v && find_first_set(v) == find_last_set(v);
}
template <typename T>
inline int log2(const T v)
{
return find_last_set(v) - 1;
}
} // namespace openvpn
#endif // OPENVPN_COMMON_FFS_H