@@ -5,7 +5,7 @@ use std::mem::transmute;
5
5
use std:: ops:: Range ;
6
6
use std:: path:: Path ;
7
7
8
- use memmap :: { Mmap , MmapMut , MmapOptions } ;
8
+ use memmap2 :: { Mmap , MmapMut , MmapOptions } ;
9
9
10
10
use crate :: bitvec:: BitVector ;
11
11
@@ -59,22 +59,20 @@ pub struct MmapBitVec {
59
59
pub mmap : CommonMmap ,
60
60
pub size : usize ,
61
61
header : Box < [ u8 ] > ,
62
+ is_anon : bool ,
62
63
}
63
64
64
65
impl MmapBitVec {
65
66
/// Creates a new `MmapBitVec` file
66
67
///
67
68
/// The overall size of bit vector (in bits) and a fixed-size header must
68
69
/// also be provided (although the header can be 0-length).
69
- pub fn create < P > (
70
+ pub fn create < P : AsRef < Path > > (
70
71
filename : P ,
71
72
size : usize ,
72
73
magic : [ u8 ; 2 ] ,
73
74
header : & [ u8 ] ,
74
- ) -> Result < Self , io:: Error >
75
- where
76
- P : AsRef < Path > ,
77
- {
75
+ ) -> Result < Self , io:: Error > {
78
76
assert ! (
79
77
header. len( ) < 65_536 ,
80
78
"Headers longer than 65636 bytes not supported"
@@ -94,17 +92,18 @@ impl MmapBitVec {
94
92
// file.seek(io::SeekFrom::Start(0))?;
95
93
96
94
file. write_all ( & magic) ?;
97
- let serialized_header_size: [ u8 ; 2 ] = unsafe { transmute ( ( header. len ( ) as u16 ) . to_be ( ) ) } ;
95
+ let serialized_header_size: [ u8 ; 2 ] = ( header. len ( ) as u16 ) . to_be_bytes ( ) ;
98
96
file. write_all ( & serialized_header_size) ?;
99
97
file. write_all ( header) ?;
100
- let serialized_size: [ u8 ; 8 ] = unsafe { transmute ( ( size as u64 ) . to_be ( ) ) } ;
98
+ let serialized_size: [ u8 ; 8 ] = ( size as u64 ) . to_be_bytes ( ) ;
101
99
file. write_all ( & serialized_size) ?;
102
100
103
101
let mmap = unsafe { MmapOptions :: new ( ) . offset ( total_header_size) . map_mut ( & file) } ?;
104
102
Ok ( MmapBitVec {
105
103
mmap : CommonMmap :: MmapMut ( mmap) ,
106
104
size,
107
105
header : header. to_vec ( ) . into_boxed_slice ( ) ,
106
+ is_anon : false ,
108
107
} )
109
108
}
110
109
@@ -182,6 +181,7 @@ impl MmapBitVec {
182
181
mmap,
183
182
size : size as usize ,
184
183
header : header. into_boxed_slice ( ) ,
184
+ is_anon : false ,
185
185
} )
186
186
}
187
187
@@ -201,6 +201,7 @@ impl MmapBitVec {
201
201
mmap : CommonMmap :: Mmap ( mmap) ,
202
202
size : byte_size * 8 ,
203
203
header : Box :: new ( [ ] ) ,
204
+ is_anon : false ,
204
205
} )
205
206
}
206
207
@@ -215,9 +216,33 @@ impl MmapBitVec {
215
216
mmap : CommonMmap :: MmapMut ( mmap) ,
216
217
size,
217
218
header : vec ! [ ] . into_boxed_slice ( ) ,
219
+ is_anon : true ,
218
220
} )
219
221
}
220
222
223
+ /// Converts an in-memory mmap bitvector to a file-backed one.
224
+ /// This is a no-op if the mmap is already file-backed.
225
+ /// Returns the new mmap after flushing.
226
+ pub fn into_mmap_file < P : AsRef < Path > > (
227
+ self ,
228
+ filename : P ,
229
+ magic : [ u8 ; 2 ] ,
230
+ header : & [ u8 ] ,
231
+ ) -> Result < Self , io:: Error > {
232
+ if !self . is_anon {
233
+ return Ok ( self ) ;
234
+ }
235
+ let mut file_mmap = MmapBitVec :: create ( filename, self . size , magic, header) ?;
236
+
237
+ // Not super efficient
238
+ for i in 0 ..self . size {
239
+ file_mmap. set ( i, self . get ( i) ) ;
240
+ }
241
+ file_mmap. mmap . flush ( ) ?;
242
+
243
+ Ok ( file_mmap)
244
+ }
245
+
221
246
// Returns the header
222
247
pub fn header ( & self ) -> & [ u8 ] {
223
248
& self . header
@@ -533,10 +558,7 @@ impl BitVector for MmapBitVec {
533
558
// u64 is stored in the "right" order in memory
534
559
let main_chunk = ( x << ( 128 - size_main) ) . to_be ( ) ;
535
560
536
- let bytes: [ u8 ; 16 ] ;
537
- unsafe {
538
- bytes = transmute ( main_chunk) ;
539
- }
561
+ let bytes: [ u8 ; 16 ] = main_chunk. to_le_bytes ( ) ;
540
562
for ( byte_idx, byte) in ( ( byte_idx_st + 1 ) ..byte_idx_en) . zip ( bytes. iter ( ) ) {
541
563
unsafe {
542
564
* mmap. add ( byte_idx) |= * byte;
@@ -783,4 +805,20 @@ mod test {
783
805
assert_eq ! ( b. select( 1 , 0 ) , Some ( 7 ) ) ;
784
806
assert_eq ! ( b. select( 3 , 0 ) , Some ( 127 ) ) ;
785
807
}
808
+
809
+ #[ test]
810
+ fn can_convert_memory_to_file ( ) {
811
+ let mut b = MmapBitVec :: from_memory ( 128 ) . unwrap ( ) ;
812
+ b. set ( 7 , true ) ;
813
+ b. set ( 56 , true ) ;
814
+ b. set ( 127 , true ) ;
815
+ let dir = tempfile:: tempdir ( ) . unwrap ( ) ;
816
+ let f = b
817
+ . into_mmap_file ( dir. path ( ) . join ( "test" ) , * b"!!" , & [ ] )
818
+ . unwrap ( ) ;
819
+ assert_eq ! ( f. get( 7 ) , true ) ;
820
+ assert_eq ! ( f. get( 56 ) , true ) ;
821
+ assert_eq ! ( f. get( 127 ) , true ) ;
822
+ assert_eq ! ( f. get( 10 ) , false ) ;
823
+ }
786
824
}
0 commit comments