@@ -2,10 +2,12 @@ use std::cmp::Ordering;
2
2
#[ cfg( feature = "legacy" ) ]
3
3
use std:: fs:: File ;
4
4
use std:: io;
5
+ use std:: ops:: Range ;
5
6
use std:: path:: Path ;
6
7
7
8
use bincode:: { serialize, deserialize, Infinite } ;
8
9
use mmap_bitvec:: { BitVector , MmapBitVec , BitVecSlice } ;
10
+ use mmap_bitvec:: bitvec:: BIT_VEC_SLICE_SIZE ;
9
11
use murmurhash3:: murmurhash3_x64_128;
10
12
use serde:: Serialize ;
11
13
use serde:: de:: DeserializeOwned ;
@@ -171,7 +173,7 @@ impl<T: Clone + DeserializeOwned + Serialize> BFieldMember<T> {
171
173
let mut merged_marker = BitVecSlice :: max_value ( ) ;
172
174
for marker_ix in 0usize ..self . params . n_hashes as usize {
173
175
let pos = marker_pos ( hash, marker_ix, self . bitvec . size ( ) , marker_width) ;
174
- let marker = self . bitvec . get_range ( pos..pos + marker_width) ;
176
+ let marker = get_range ( & self . bitvec , pos..pos + marker_width) ;
175
177
merged_marker &= marker;
176
178
if merged_marker. count_ones ( ) . cmp ( & k) == Ordering :: Less {
177
179
return 0 ;
@@ -224,6 +226,50 @@ fn marker_pos(hash: (u64, u64), n: usize, total_size: usize, _: usize) -> usize
224
226
i64:: abs ( mashed_hash % ( total_size as i64 - 64 ) ) as usize
225
227
}
226
228
229
+ /// This is totally messed up, but we get a speed bump by doing this
230
+ /// instead of using the _exact same_ function on the struct.
231
+ #[ cfg( not( feature = "legacy" ) ) ]
232
+ fn get_range ( bitvec : & MmapBitVec , r : Range < usize > ) -> BitVecSlice {
233
+ if r. end - r. start > BIT_VEC_SLICE_SIZE as usize {
234
+ panic ! ( format!( "Range too large (>{})" , BIT_VEC_SLICE_SIZE ) )
235
+ } else if r. end > bitvec. size {
236
+ panic ! ( "Range ends outside of BitVec" )
237
+ }
238
+ let byte_idx_st = ( r. start >> 3 ) as usize ;
239
+ let byte_idx_en = ( ( r. end - 1 ) >> 3 ) as usize ;
240
+ let new_size: u8 = ( r. end - r. start ) as u8 ;
241
+
242
+ let mut v;
243
+ let ptr: * const u8 = bitvec. mmap . as_ptr ( ) ;
244
+
245
+ // read the last byte first
246
+ unsafe {
247
+ v = BitVecSlice :: from ( * ptr. offset ( byte_idx_en as isize ) ) ;
248
+ }
249
+ // align the end of the data with the end of the u64/u128
250
+ v >>= 7 - ( ( r. end - 1 ) & 7 ) ;
251
+
252
+ let bit_offset = new_size + ( r. start & 7 ) as u8 ;
253
+ // copy over byte by byte
254
+ // it would be faster to coerce into a u8 and a u64 (in case it spans 9 bytes) and then
255
+ // copy over, but this doesn't work if the start is <8 bytes from the end, so we're doing
256
+ // this for now and we can add a special case for that later
257
+ for ( new_idx, old_idx) in ( byte_idx_st..byte_idx_en) . enumerate ( ) {
258
+ unsafe {
259
+ v |= BitVecSlice :: from ( * ptr. offset ( old_idx as isize ) ) <<
260
+ ( bit_offset - 8u8 * ( new_idx as u8 + 1 ) ) ;
261
+ }
262
+ }
263
+
264
+ // mask out the high bits in case we copied extra
265
+ v & BitVecSlice :: max_value ( ) >> ( BIT_VEC_SLICE_SIZE - new_size)
266
+ }
267
+
268
+ #[ cfg( feature = "legacy" ) ]
269
+ fn get_range ( bitvec : & MmapBitVec , r : Range < usize > ) -> BitVecSlice {
270
+ bitvec. get_range ( r)
271
+ }
272
+
227
273
#[ test]
228
274
fn test_bfield ( ) {
229
275
let mut bfield: BFieldMember < usize > = BFieldMember :: in_memory ( 1024 , 3 , 64 , 4 ) . unwrap ( ) ;
0 commit comments