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 auto const tail_nbits
= N
* m_size
- m_nwords
* 64;
60 auto const tail_mask
= (1ull << tail_nbits
) - 1;
61 m_bits
[m_nwords
- 1] &= tail_mask
;
66 void multibitset
<N
>::reset() {
67 memset(m_bits
, 0, m_nwords
* sizeof(*m_bits
));
71 multibitset
<N
>::reference::reference(multibitset
<N
>& mbs
, size_t pos
)
73 , m_word(N
* pos
/ 64)
74 , m_bit(N
* pos
- m_word
* 64)
78 multibitset
<N
>::reference::operator uint64_t() const {
79 constexpr auto mask
= (1ull << N
) - 1;
81 if (m_bit
+ N
<= 64) {
82 return (m_mbs
.m_bits
[m_word
] >> m_bit
) & mask
;
85 auto const head_nbits
= 64 - m_bit
;
86 auto const head_mask
= (1ull << head_nbits
) - 1;
88 auto const head
= (m_mbs
.m_bits
[m_word
] >> m_bit
) & head_mask
;
89 auto const tail
= m_mbs
.m_bits
[m_word
+ 1] << head_nbits
;
91 return (head
| tail
) & mask
;
95 typename multibitset
<N
>::reference
&
96 multibitset
<N
>::reference::operator=(uint64_t val
) {
97 constexpr auto mask
= (1ull << N
) - 1;
98 assertx((val
& mask
) == val
);
101 auto& word
= m_mbs
.m_bits
[m_word
];
102 word
= (word
& ~(mask
<< m_bit
)) | ((val
& mask
) << m_bit
);
105 if (m_bit
+ N
> 64) {
106 auto const head_nbits
= 64 - m_bit
;
108 auto& word
= m_mbs
.m_bits
[m_word
+ 1];
109 word
= (word
& ~(mask
>> head_nbits
)) | ((val
& mask
) >> head_nbits
);
115 uint64_t multibitset
<N
>::operator[](size_t pos
) const {
116 assertx(pos
< m_size
);
117 return reference(*const_cast<multibitset
<N
>*>(this), pos
);
121 typename multibitset
<N
>::reference multibitset
<N
>::operator[](size_t pos
) {
122 assertx(pos
< m_size
);
123 return reference(*this, pos
);
127 size_t multibitset
<N
>::size() const { return m_size
; }
130 size_t multibitset
<N
>::ffs(size_t pos
) const {
131 assertx(pos
< m_size
);
134 auto const ref
= reference(*const_cast<multibitset
<N
>*>(this), pos
);
136 auto const mask
= ~((1ull << ref
.m_bit
) - 1);
137 auto const word
= m_bits
[ref
.m_word
] & mask
;
138 if (ffs64(word
, b
)) return (ref
.m_word
* 64 + b
) / N
;
140 for (auto d
= ref
.m_word
+ 1; d
< m_nwords
; ++d
) {
141 if (ffs64(m_bits
[d
], b
)) return (d
* 64 + b
) / N
;
147 size_t multibitset
<N
>::fls(size_t pos
) const {
148 if (pos
== npos
) pos
= m_size
- 1;
149 assertx(pos
< m_size
);
152 // We use a reference to the next position to take care of the case where the
153 // N-bit at `pos' straddles a word boundary.
154 auto const ref
= reference(*const_cast<multibitset
<N
>*>(this), pos
+ 1);
156 auto const mask
= (1ull << ref
.m_bit
) - 1;
157 auto const word
= m_bits
[ref
.m_word
] & mask
;
158 if (fls64(word
, b
)) return (ref
.m_word
* 64 + b
) / N
;
160 for (auto d
= ref
.m_word
; d
-- > 0; ) {
161 if (fls64(m_bits
[d
], b
)) return (d
* 64 + b
) / N
;
166 ///////////////////////////////////////////////////////////////////////////////
169 chunked_multibitset
<N
>::chunked_multibitset(size_t chunk_sz
)
170 : m_chunk_sz
{chunk_sz
}
172 always_assert(m_chunk_sz
> 0);
176 chunked_multibitset
<N
>::reference::reference(chunked_multibitset
<N
>& cmbs
,
183 void chunked_multibitset
<N
>::reset() {
190 multibitset
<N
>& chunked_multibitset
<N
>::chunk_for(size_t pos
) {
191 auto const c
= pos
/ m_chunk_sz
;
192 if (m_chunks
[c
].size() == 0) {
193 m_chunks
[c
].resize(m_chunk_sz
);
194 m_highwater
= std::max(c
, m_highwater
);
195 m_lowwater
= std::min(c
, m_lowwater
);
201 chunked_multibitset
<N
>::reference::operator uint64_t() const {
202 auto const it
= m_cmbs
.m_chunks
.find(m_pos
/ m_cmbs
.m_chunk_sz
);
203 return it
!= m_cmbs
.m_chunks
.end()
204 ? it
->second
[m_pos
% m_cmbs
.m_chunk_sz
]
209 typename chunked_multibitset
<N
>::reference
&
210 chunked_multibitset
<N
>::reference::operator=(uint64_t val
) {
211 m_cmbs
.chunk_for(m_pos
)[m_pos
% m_cmbs
.m_chunk_sz
] = val
;
216 uint64_t chunked_multibitset
<N
>::operator[](size_t pos
) const {
217 return reference(*const_cast<chunked_multibitset
<N
>*>(this), pos
);
221 typename chunked_multibitset
<N
>::reference
222 chunked_multibitset
<N
>::operator[](size_t pos
) {
223 return reference(*this, pos
);
227 size_t chunked_multibitset
<N
>::ffs(size_t pos
) const {
229 auto const c
= std::max(pos
/ m_chunk_sz
, m_lowwater
);
230 auto const it
= m_chunks
.find(c
);
231 if (it
!= m_chunks
.end()) {
232 auto const res
= it
->second
.ffs(pos
% m_chunk_sz
);
233 if (res
!= npos
) return c
* m_chunk_sz
+ res
;
237 for (auto c
= pos
/ m_chunk_sz
+ 1; c
<= m_highwater
; ++c
) {
238 auto const it
= m_chunks
.find(c
);
239 if (it
!= m_chunks
.end()) {
240 auto const res
= it
->second
.ffs();
241 if (res
!= npos
) return c
* m_chunk_sz
+ res
;
248 size_t chunked_multibitset
<N
>::fls(size_t pos
) const {
250 auto const c
= std::min(pos
/ m_chunk_sz
, m_highwater
);
251 auto const it
= m_chunks
.find(c
);
252 if (it
!= m_chunks
.end()) {
253 auto const res
= it
->second
.fls(pos
!= npos
? pos
% m_chunk_sz
: npos
);
254 if (res
!= npos
) return c
* m_chunk_sz
+ res
;
258 for (auto c
= pos
/ m_chunk_sz
; c
-- > m_lowwater
; ) {
259 auto const it
= m_chunks
.find(c
);
260 if (it
!= m_chunks
.end()) {
261 auto const res
= it
->second
.fls();
262 if (res
!= npos
) return c
* m_chunk_sz
+ res
;
268 ///////////////////////////////////////////////////////////////////////////////