2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/util/assertions.h"
18 #include "hphp/util/bitops.h"
25 ///////////////////////////////////////////////////////////////////////////////
28 multibitset
<N
>::multibitset() {}
31 multibitset
<N
>::multibitset(size_t nelms
) {
37 multibitset
<N
>::~multibitset() {
42 void multibitset
<N
>::resize(size_t nelms
) {
43 auto const prev_nwords
= m_nwords
;
44 auto const prev_size
= m_size
;
46 auto const nbits
= N
* nelms
;
47 auto const whole_words
= nbits
/ 64;
48 m_nwords
= whole_words
+ (whole_words
* 64 != nbits
);
50 m_bits
= reinterpret_cast<uint64_t*>(
51 realloc(m_bits
, m_nwords
* sizeof(*m_bits
))
54 if (prev_nwords
< m_nwords
) {
55 memset(m_bits
+ prev_nwords
, 0,
56 (m_nwords
- prev_nwords
) * sizeof(*m_bits
));
57 } else if (m_size
< prev_size
) {
58 // f{f,l}s() rely on the out-of-range bits being zeroed.
59 if (whole_words
!= m_nwords
) {
60 auto const tail_nbits
= N
* m_size
- whole_words
* 64;
61 auto const tail_mask
= (1ull << tail_nbits
) - 1;
62 m_bits
[m_nwords
- 1] &= tail_mask
;
68 void multibitset
<N
>::reset() {
69 memset(m_bits
, 0, m_nwords
* sizeof(*m_bits
));
73 multibitset
<N
>::reference::reference(multibitset
<N
>& mbs
, size_t pos
)
75 , m_word(N
* pos
/ 64)
76 , m_bit(N
* pos
- m_word
* 64)
80 multibitset
<N
>::reference::operator uint64_t() const {
81 constexpr auto mask
= (1ull << N
) - 1;
83 if (m_bit
+ N
<= 64) {
84 return (m_mbs
.m_bits
[m_word
] >> m_bit
) & mask
;
87 auto const head_nbits
= 64 - m_bit
;
88 auto const head_mask
= (1ull << head_nbits
) - 1;
90 auto const head
= (m_mbs
.m_bits
[m_word
] >> m_bit
) & head_mask
;
91 auto const tail
= m_mbs
.m_bits
[m_word
+ 1] << head_nbits
;
93 return (head
| tail
) & mask
;
97 typename multibitset
<N
>::reference
&
98 multibitset
<N
>::reference::operator=(uint64_t val
) {
99 constexpr auto mask
= (1ull << N
) - 1;
100 assertx((val
& mask
) == val
);
103 auto& word
= m_mbs
.m_bits
[m_word
];
104 word
= (word
& ~(mask
<< m_bit
)) | ((val
& mask
) << m_bit
);
107 if (m_bit
+ N
> 64) {
108 auto const head_nbits
= 64 - m_bit
;
110 auto& word
= m_mbs
.m_bits
[m_word
+ 1];
111 word
= (word
& ~(mask
>> head_nbits
)) | ((val
& mask
) >> head_nbits
);
117 uint64_t multibitset
<N
>::operator[](size_t pos
) const {
118 assertx(pos
< m_size
);
119 return reference(*const_cast<multibitset
<N
>*>(this), pos
);
123 typename multibitset
<N
>::reference multibitset
<N
>::operator[](size_t pos
) {
124 assertx(pos
< m_size
);
125 return reference(*this, pos
);
129 size_t multibitset
<N
>::size() const { return m_size
; }
132 size_t multibitset
<N
>::ffs(size_t pos
) const {
133 assertx(pos
< m_size
);
136 auto const ref
= reference(*const_cast<multibitset
<N
>*>(this), pos
);
138 auto const mask
= ~((1ull << ref
.m_bit
) - 1);
139 auto const word
= m_bits
[ref
.m_word
] & mask
;
140 if (ffs64(word
, b
)) return (ref
.m_word
* 64 + b
) / N
;
142 for (auto d
= ref
.m_word
+ 1; d
< m_nwords
; ++d
) {
143 if (ffs64(m_bits
[d
], b
)) return (d
* 64 + b
) / N
;
149 size_t multibitset
<N
>::fls(size_t pos
) const {
150 if (pos
== npos
) pos
= m_size
- 1;
151 assertx(pos
< m_size
);
154 // We use a reference to the next position to take care of the case where the
155 // N-bit at `pos' straddles a word boundary.
156 auto const ref
= reference(*const_cast<multibitset
<N
>*>(this), pos
+ 1);
158 auto const mask
= (1ull << ref
.m_bit
) - 1;
159 auto const word
= m_bits
[ref
.m_word
] & mask
;
160 if (fls64(word
, b
)) return (ref
.m_word
* 64 + b
) / N
;
162 for (auto d
= ref
.m_word
; d
-- > 0; ) {
163 if (fls64(m_bits
[d
], b
)) return (d
* 64 + b
) / N
;
168 ///////////////////////////////////////////////////////////////////////////////
171 chunked_multibitset
<N
>::chunked_multibitset(size_t chunk_sz
)
172 : m_chunk_sz
{chunk_sz
}
174 always_assert(m_chunk_sz
> 0);
178 chunked_multibitset
<N
>::reference::reference(chunked_multibitset
<N
>& cmbs
,
185 void chunked_multibitset
<N
>::reset() {
192 multibitset
<N
>& chunked_multibitset
<N
>::chunk_for(size_t pos
) {
193 auto const c
= pos
/ m_chunk_sz
;
194 if (m_chunks
[c
].size() == 0) {
195 m_chunks
[c
].resize(m_chunk_sz
);
196 m_highwater
= std::max(c
, m_highwater
);
197 m_lowwater
= std::min(c
, m_lowwater
);
203 chunked_multibitset
<N
>::reference::operator uint64_t() const {
204 auto const it
= m_cmbs
.m_chunks
.find(m_pos
/ m_cmbs
.m_chunk_sz
);
205 return it
!= m_cmbs
.m_chunks
.end()
206 ? it
->second
[m_pos
% m_cmbs
.m_chunk_sz
]
211 typename chunked_multibitset
<N
>::reference
&
212 chunked_multibitset
<N
>::reference::operator=(uint64_t val
) {
213 m_cmbs
.chunk_for(m_pos
)[m_pos
% m_cmbs
.m_chunk_sz
] = val
;
218 uint64_t chunked_multibitset
<N
>::operator[](size_t pos
) const {
219 return reference(*const_cast<chunked_multibitset
<N
>*>(this), pos
);
223 typename chunked_multibitset
<N
>::reference
224 chunked_multibitset
<N
>::operator[](size_t pos
) {
225 return reference(*this, pos
);
229 size_t chunked_multibitset
<N
>::ffs(size_t pos
) const {
231 auto const c
= std::max(pos
/ m_chunk_sz
, m_lowwater
);
232 auto const it
= m_chunks
.find(c
);
233 if (it
!= m_chunks
.end()) {
234 auto const res
= it
->second
.ffs(pos
% m_chunk_sz
);
235 if (res
!= npos
) return c
* m_chunk_sz
+ res
;
239 for (auto c
= pos
/ m_chunk_sz
+ 1; c
<= m_highwater
; ++c
) {
240 auto const it
= m_chunks
.find(c
);
241 if (it
!= m_chunks
.end()) {
242 auto const res
= it
->second
.ffs();
243 if (res
!= npos
) return c
* m_chunk_sz
+ res
;
250 size_t chunked_multibitset
<N
>::fls(size_t pos
) const {
252 auto const c
= std::min(pos
/ m_chunk_sz
, m_highwater
);
253 auto const it
= m_chunks
.find(c
);
254 if (it
!= m_chunks
.end()) {
255 auto const res
= it
->second
.fls(pos
!= npos
? pos
% m_chunk_sz
: npos
);
256 if (res
!= npos
) return c
* m_chunk_sz
+ res
;
260 for (auto c
= pos
/ m_chunk_sz
; c
-- > m_lowwater
; ) {
261 auto const it
= m_chunks
.find(c
);
262 if (it
!= m_chunks
.end()) {
263 auto const res
= it
->second
.fls();
264 if (res
!= npos
) return c
* m_chunk_sz
+ res
;
270 ///////////////////////////////////////////////////////////////////////////////