@@ -24,7 +24,7 @@ pub trait RankedBitsAccess {
24
24
/// This method is unsafe because `idx` must be within the bounds of the bits stored in `RankedBitsAccess`.
25
25
/// An index out of bounds can lead to undefined behavior.
26
26
#[ inline]
27
- unsafe fn rank_impl ( bits : & [ u64 ] , l12_ranks : & [ u128 ] , idx : usize ) -> Option < usize > {
27
+ unsafe fn rank_impl < T : L12RankAccess > ( bits : & [ u64 ] , l12_ranks : & T , idx : usize ) -> Option < usize > {
28
28
let word_idx = idx / 64 ;
29
29
let bit_idx = idx % 64 ;
30
30
let word = * bits. get_unchecked ( word_idx) ;
@@ -36,10 +36,6 @@ pub trait RankedBitsAccess {
36
36
let l1_pos = idx / L1_BIT_SIZE ;
37
37
let l2_pos = ( idx % L1_BIT_SIZE ) / L2_BIT_SIZE ;
38
38
39
- let l12_rank = l12_ranks. get_unchecked ( l1_pos) ;
40
- let l1_rank = ( l12_rank & 0xFFFFFFFFFFF ) as usize ;
41
- let l2_rank = ( ( l12_rank >> ( 32 + 12 * l2_pos) ) & 0xFFF ) as usize ;
42
-
43
39
let idx_within_l2 = idx % L2_BIT_SIZE ;
44
40
let blocks_num = idx_within_l2 / 64 ;
45
41
let offset = ( idx / L2_BIT_SIZE ) * 8 ;
@@ -51,6 +47,7 @@ pub trait RankedBitsAccess {
51
47
let word_mask = ( ( 1u64 << ( idx_within_l2 % 64 ) ) - 1 ) * ( idx_within_l2 > 0 ) as u64 ;
52
48
let word_rank = ( word & word_mask) . count_ones ( ) as usize ;
53
49
50
+ let ( l1_rank, l2_rank) = l12_ranks. l12_ranks ( l1_pos, l2_pos) ;
54
51
let total_rank = l1_rank + l2_rank + block_rank + word_rank;
55
52
56
53
Some ( total_rank)
@@ -64,7 +61,53 @@ pub struct RankedBits {
64
61
/// The bit vector represented as an array of u64 integers.
65
62
bits : Box < [ u64 ] > ,
66
63
/// Precomputed rank information for L1 and L2 blocks.
67
- l12_ranks : Box < [ u128 ] > ,
64
+ l12_ranks : Box < [ L12Rank ] > ,
65
+ }
66
+
67
+ /// L12Rank represents l1 and l2 bit ranks stored inside 16 bytes (little endian).
68
+ /// NB: it's important to use `[u8; 16]` instead of `u128` for `rkyv` versions 0.7.X
69
+ /// because of alignment differences between `x86_64` and `aarch64` architectures.
70
+ /// See https://github.com/rkyv/rkyv/issues/409 for more details.
71
+ #[ derive( Debug ) ]
72
+ #[ cfg_attr( feature = "rkyv_derive" , derive( rkyv:: Archive , rkyv:: Deserialize , rkyv:: Serialize ) ) ]
73
+ #[ cfg_attr( feature = "rkyv_derive" , archive_attr( derive( rkyv:: CheckBytes ) ) ) ]
74
+ pub struct L12Rank ( [ u8 ; 16 ] ) ;
75
+
76
+ /// Trait used to access archived and non-archived L1 and L2 ranks
77
+ pub trait L12RankAccess {
78
+ /// Return `L12Rank` as `u128`
79
+ fn l12_rank ( & self , l1_pos : usize ) -> u128 ;
80
+
81
+ /// Return `l1_rank` and `l2_rank`
82
+ #[ inline]
83
+ fn l12_ranks ( & self , l1_pos : usize , l2_pos : usize ) -> ( usize , usize ) {
84
+ let l12_rank = self . l12_rank ( l1_pos) ;
85
+ let l1_rank = ( l12_rank & 0xFFFFFFFFFFF ) as usize ;
86
+ let l2_rank = ( ( l12_rank >> ( 32 + 12 * l2_pos) ) & 0xFFF ) as usize ;
87
+ ( l1_rank, l2_rank)
88
+ }
89
+ }
90
+
91
+ impl L12RankAccess for Box < [ L12Rank ] > {
92
+ #[ inline]
93
+ fn l12_rank ( & self , l1_pos : usize ) -> u128 {
94
+ u128:: from_le_bytes ( unsafe { self . get_unchecked ( l1_pos) . 0 } )
95
+ }
96
+ }
97
+
98
+ #[ cfg( feature = "rkyv_derive" ) ]
99
+ impl L12RankAccess for rkyv:: boxed:: ArchivedBox < [ ArchivedL12Rank ] > {
100
+ #[ inline]
101
+ fn l12_rank ( & self , l1_pos : usize ) -> u128 {
102
+ u128:: from_le_bytes ( unsafe { self . get_unchecked ( l1_pos) . 0 } )
103
+ }
104
+ }
105
+
106
+ impl From < u128 > for L12Rank {
107
+ #[ inline]
108
+ fn from ( v : u128 ) -> Self {
109
+ L12Rank ( v. to_le_bytes ( ) )
110
+ }
68
111
}
69
112
70
113
impl RankedBits {
@@ -83,7 +126,7 @@ impl RankedBits {
83
126
l12_rank += ( sum as u128 ) << ( i * 12 ) ;
84
127
}
85
128
l12_rank = ( l12_rank << 44 ) | l1_rank;
86
- l12_ranks. push ( l12_rank) ;
129
+ l12_ranks. push ( l12_rank. into ( ) ) ;
87
130
l1_rank += sum as u128 ;
88
131
}
89
132
@@ -95,7 +138,7 @@ impl RankedBits {
95
138
l12_rank += ( sum as u128 ) << ( i * 12 ) ;
96
139
}
97
140
l12_rank = ( l12_rank << 44 ) | l1_rank;
98
- l12_ranks. push ( l12_rank) ;
141
+ l12_ranks. push ( l12_rank. into ( ) ) ;
99
142
}
100
143
101
144
RankedBits { bits, l12_ranks : l12_ranks. into_boxed_slice ( ) }
0 commit comments