forked from scylladb/seastar
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bitset-iter.hh
181 lines (154 loc) · 3.9 KB
/
bitset-iter.hh
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/*
* Copyright (C) 2014 Cloudius Systems, Ltd.
*/
/*
* Imported from OSv:
*
* Copyright (C) 2014 Cloudius Systems, Ltd.
*
* This work is open source software, licensed under the terms of the
* BSD license as described in the LICENSE file in the top-level directory.
*/
#ifndef __OSV_BITSET_ITER
#define __OSV_BITSET_ITER
#include <bitset>
#include <limits>
namespace seastar {
namespace bitsets {
static constexpr int ulong_bits = std::numeric_limits<unsigned long>::digits;
/**
* Returns the number of leading zeros in value's binary representation.
*
* If value == 0 the result is undefied. If T is signed and value is negative
* the result is undefined.
*
* The highest value that can be returned is std::numeric_limits<T>::digits - 1,
* which is returned when value == 1.
*/
template<typename T>
inline size_t count_leading_zeros(T value);
/**
* Returns the number of trailing zeros in value's binary representation.
*
* If value == 0 the result is undefied. If T is signed and value is negative
* the result is undefined.
*
* The highest value that can be returned is std::numeric_limits<T>::digits - 1.
*/
template<typename T>
static inline size_t count_trailing_zeros(T value);
template<>
inline size_t count_leading_zeros<unsigned long>(unsigned long value)
{
return __builtin_clzl(value);
}
template<>
inline size_t count_leading_zeros<long>(long value)
{
return __builtin_clzl((unsigned long)value) - 1;
}
template<>
inline size_t count_leading_zeros<long long>(long long value)
{
return __builtin_clzll((unsigned long long)value) - 1;
}
template<>
inline
size_t count_trailing_zeros<unsigned long>(unsigned long value)
{
return __builtin_ctzl(value);
}
template<>
inline
size_t count_trailing_zeros<long>(long value)
{
return __builtin_ctzl((unsigned long)value);
}
/**
* Returns the index of the first set bit.
* Result is undefined if bitset.any() == false.
*/
template<size_t N>
static inline size_t get_first_set(const std::bitset<N>& bitset)
{
static_assert(N <= ulong_bits, "bitset too large");
return count_trailing_zeros(bitset.to_ulong());
}
/**
* Returns the index of the last set bit in the bitset.
* Result is undefined if bitset.any() == false.
*/
template<size_t N>
static inline size_t get_last_set(const std::bitset<N>& bitset)
{
static_assert(N <= ulong_bits, "bitset too large");
return ulong_bits - 1 - count_leading_zeros(bitset.to_ulong());
}
template<size_t N>
class set_iterator : public std::iterator<std::input_iterator_tag, int>
{
private:
void advance()
{
if (_bitset.none()) {
_index = -1;
} else {
auto shift = get_first_set(_bitset) + 1;
_index += shift;
_bitset >>= shift;
}
}
public:
set_iterator(std::bitset<N> bitset, int offset = 0)
: _bitset(bitset)
, _index(offset - 1)
{
static_assert(N <= ulong_bits, "This implementation is inefficient for large bitsets");
_bitset >>= offset;
advance();
}
void operator++()
{
advance();
}
int operator*() const
{
return _index;
}
bool operator==(const set_iterator& other) const
{
return _index == other._index;
}
bool operator!=(const set_iterator& other) const
{
return !(*this == other);
}
private:
std::bitset<N> _bitset;
int _index;
};
template<size_t N>
class set_range
{
public:
using iterator = set_iterator<N>;
using value_type = int;
set_range(std::bitset<N> bitset, int offset = 0)
: _bitset(bitset)
, _offset(offset)
{
}
iterator begin() const { return iterator(_bitset, _offset); }
iterator end() const { return iterator(0); }
private:
std::bitset<N> _bitset;
int _offset;
};
template<size_t N>
static inline set_range<N> for_each_set(std::bitset<N> bitset, int offset = 0)
{
return set_range<N>(bitset, offset);
}
}
}
#endif