@@ -6,39 +6,98 @@ use std::marker::PhantomData;
6
6
use std:: num:: NonZeroUsize ;
7
7
use log:: debug;
8
8
9
- /// Random-access position table, allowing encoding in an arbitrary order
10
- /// (e.g. while visiting the definitions of a crate), and on-demand decoding
11
- /// of specific indices (e.g. queries for per-definition data).
12
- /// Similar to `Vec<Lazy<T>>`, but with zero-copy decoding.
13
- // FIXME(eddyb) newtype `[u8]` here, such that `Box<Table<T>>` would be used
9
+ /// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
10
+ /// Used mainly for Lazy positions and lengths.
11
+ /// Unchecked invariant: `Self::default()` should encode as `[0; BYTE_LEN]`,
12
+ /// but this has no impact on safety.
13
+ pub trait FixedSizeEncoding : Default {
14
+ const BYTE_LEN : usize ;
15
+
16
+ // FIXME(eddyb) convert to and from `[u8; Self::BYTE_LEN]` instead,
17
+ // once that starts being allowed by the compiler (i.e. lazy normalization).
18
+ fn from_bytes ( b : & [ u8 ] ) -> Self ;
19
+ fn write_to_bytes ( self , b : & mut [ u8 ] ) ;
20
+ }
21
+
22
+ impl FixedSizeEncoding for u32 {
23
+ const BYTE_LEN : usize = 4 ;
24
+
25
+ fn from_bytes ( b : & [ u8 ] ) -> Self {
26
+ let mut bytes = [ 0 ; Self :: BYTE_LEN ] ;
27
+ bytes. copy_from_slice ( & b[ ..Self :: BYTE_LEN ] ) ;
28
+ Self :: from_le_bytes ( bytes)
29
+ }
30
+
31
+ fn write_to_bytes ( self , b : & mut [ u8 ] ) {
32
+ b[ ..Self :: BYTE_LEN ] . copy_from_slice ( & self . to_le_bytes ( ) ) ;
33
+ }
34
+ }
35
+
36
+ // NOTE(eddyb) there could be an impl for `usize`, which would enable a more
37
+ // generic `Lazy<T>` impl, but in the general case we might not need / want to
38
+ // fit every `usize` in `u32`.
39
+ impl < T : Encodable > FixedSizeEncoding for Option < Lazy < T > > {
40
+ const BYTE_LEN : usize = u32:: BYTE_LEN ;
41
+
42
+ fn from_bytes ( b : & [ u8 ] ) -> Self {
43
+ Some ( Lazy :: from_position ( NonZeroUsize :: new ( u32:: from_bytes ( b) as usize ) ?) )
44
+ }
45
+
46
+ fn write_to_bytes ( self , b : & mut [ u8 ] ) {
47
+ let position = self . map_or ( 0 , |lazy| lazy. position . get ( ) ) ;
48
+ let position_u32 = position as u32 ;
49
+ assert_eq ! ( position_u32 as usize , position) ;
50
+
51
+ position_u32. write_to_bytes ( b)
52
+ }
53
+ }
54
+
55
+ impl < T : Encodable > FixedSizeEncoding for Option < Lazy < [ T ] > > {
56
+ const BYTE_LEN : usize = u32:: BYTE_LEN * 2 ;
57
+
58
+ fn from_bytes ( b : & [ u8 ] ) -> Self {
59
+ Some ( Lazy :: from_position_and_meta (
60
+ <Option < Lazy < T > > >:: from_bytes ( b) ?. position ,
61
+ u32:: from_bytes ( & b[ u32:: BYTE_LEN ..] ) as usize ,
62
+ ) )
63
+ }
64
+
65
+ fn write_to_bytes ( self , b : & mut [ u8 ] ) {
66
+ self . map ( |lazy| Lazy :: < T > :: from_position ( lazy. position ) )
67
+ . write_to_bytes ( b) ;
68
+
69
+ let len = self . map_or ( 0 , |lazy| lazy. meta ) ;
70
+ let len_u32 = len as u32 ;
71
+ assert_eq ! ( len_u32 as usize , len) ;
72
+
73
+ len_u32. write_to_bytes ( & mut b[ u32:: BYTE_LEN ..] ) ;
74
+ }
75
+ }
76
+
77
+ /// Random-access table, similar to `Vec<Option<T>>`, but without requiring
78
+ /// encoding or decoding all the values eagerly and in-order.
79
+ // FIXME(eddyb) replace `Vec` with `[_]` here, such that `Box<Table<T>>` would be used
14
80
// when building it, and `Lazy<Table<T>>` or `&Table<T>` when reading it.
15
81
// Sadly, that doesn't work for `DefPerTable`, which is `(Table<T>, Table<T>)`,
16
82
// and so would need two lengths in its metadata, which is not supported yet.
17
- pub struct Table < T : LazyMeta < Meta = ( ) > > {
83
+ pub struct Table < T > where Option < T > : FixedSizeEncoding {
84
+ // FIXME(eddyb) store `[u8; <Option<T>>::BYTE_LEN]` instead of `u8` in `Vec`,
85
+ // once that starts being allowed by the compiler (i.e. lazy normalization).
18
86
bytes : Vec < u8 > ,
19
87
_marker : PhantomData < T > ,
20
88
}
21
89
22
- impl < T : LazyMeta < Meta = ( ) > > Table < T > {
90
+ impl < T > Table < T > where Option < T > : FixedSizeEncoding {
23
91
pub fn new ( len : usize ) -> Self {
24
92
Table {
25
- bytes : vec ! [ 0 ; len * 4 ] ,
93
+ // FIXME(eddyb) only allocate and encode as many entries as needed.
94
+ bytes : vec ! [ 0 ; len * <Option <T >>:: BYTE_LEN ] ,
26
95
_marker : PhantomData ,
27
96
}
28
97
}
29
98
30
- pub fn record ( & mut self , i : usize , entry : Lazy < T > ) {
31
- let position = entry. position . get ( ) as u32 ;
32
- assert_eq ! ( position as usize , entry. position. get( ) ) ;
33
-
34
- let bytes = & mut self . bytes [ i * 4 ..] ;
35
- assert ! ( read_le_u32( bytes) == 0 ,
36
- "recorded position for index {:?} twice, first at {:?} and now at {:?}" ,
37
- i,
38
- read_le_u32( bytes) ,
39
- position) ;
40
-
41
- write_le_u32 ( bytes, position) ;
99
+ pub fn set ( & mut self , i : usize , value : T ) {
100
+ Some ( value) . write_to_bytes ( & mut self . bytes [ i * <Option < T > >:: BYTE_LEN ..] ) ;
42
101
}
43
102
44
103
pub fn encode ( & self , buf : & mut Encoder ) -> Lazy < Self > {
@@ -51,58 +110,45 @@ impl<T: LazyMeta<Meta = ()>> Table<T> {
51
110
}
52
111
}
53
112
54
- impl < T : LazyMeta < Meta = ( ) > > LazyMeta for Table < T > {
113
+ impl < T > LazyMeta for Table < T > where Option < T > : FixedSizeEncoding {
55
114
type Meta = usize ;
56
115
57
116
fn min_size ( len : usize ) -> usize {
58
117
len
59
118
}
60
119
}
61
120
62
- impl < T : Encodable > Lazy < Table < T > > {
63
- /// Given the metadata, extract out the offset of a particular index (if any).
121
+ impl < T > Lazy < Table < T > > where Option < T > : FixedSizeEncoding {
122
+ /// Given the metadata, extract out the value at a particular index (if any).
64
123
#[ inline( never) ]
65
- pub fn lookup ( & self , bytes : & [ u8 ] , i : usize ) -> Option < Lazy < T > > {
124
+ pub fn get ( & self , bytes : & [ u8 ] , i : usize ) -> Option < T > {
66
125
debug ! ( "Table::lookup: index={:?} len={:?}" , i, self . meta) ;
67
126
68
127
let bytes = & bytes[ self . position . get ( ) ..] [ ..self . meta ] ;
69
- let position = read_le_u32 ( & bytes[ i * 4 ..] ) ;
70
- debug ! ( "Table::lookup: position={:?}" , position) ;
71
-
72
- NonZeroUsize :: new ( position as usize ) . map ( Lazy :: from_position)
128
+ <Option < T > >:: from_bytes ( & bytes[ i * <Option < T > >:: BYTE_LEN ..] )
73
129
}
74
130
}
75
131
76
- fn read_le_u32 ( b : & [ u8 ] ) -> u32 {
77
- let mut bytes = [ 0 ; 4 ] ;
78
- bytes. copy_from_slice ( & b[ ..4 ] ) ;
79
- u32:: from_le_bytes ( bytes)
80
- }
81
-
82
- fn write_le_u32 ( b : & mut [ u8 ] , x : u32 ) {
83
- b[ ..4 ] . copy_from_slice ( & x. to_le_bytes ( ) ) ;
84
- }
85
-
86
132
/// Per-definition table, similar to `Table` but keyed on `DefIndex`.
87
133
/// Needed because of the two `DefIndexAddressSpace`s a `DefIndex` can be in.
88
- pub struct PerDefTable < T : LazyMeta < Meta = ( ) > > {
134
+ pub struct PerDefTable < T > where Option < T > : FixedSizeEncoding {
89
135
lo : Table < T > ,
90
136
hi : Table < T > ,
91
137
}
92
138
93
- impl < T : LazyMeta < Meta = ( ) > > PerDefTable < T > {
139
+ impl < T > PerDefTable < T > where Option < T > : FixedSizeEncoding {
94
140
pub fn new ( ( max_index_lo, max_index_hi) : ( usize , usize ) ) -> Self {
95
141
PerDefTable {
96
142
lo : Table :: new ( max_index_lo) ,
97
143
hi : Table :: new ( max_index_hi) ,
98
144
}
99
145
}
100
146
101
- pub fn record ( & mut self , def_id : DefId , entry : Lazy < T > ) {
147
+ pub fn set ( & mut self , def_id : DefId , value : T ) {
102
148
assert ! ( def_id. is_local( ) ) ;
103
149
let space_index = def_id. index . address_space ( ) . index ( ) ;
104
150
let array_index = def_id. index . as_array_index ( ) ;
105
- [ & mut self . lo , & mut self . hi ] [ space_index] . record ( array_index, entry ) ;
151
+ [ & mut self . lo , & mut self . hi ] [ space_index] . set ( array_index, value ) ;
106
152
}
107
153
108
154
pub fn encode ( & self , buf : & mut Encoder ) -> Lazy < Self > {
@@ -117,15 +163,15 @@ impl<T: LazyMeta<Meta = ()>> PerDefTable<T> {
117
163
}
118
164
}
119
165
120
- impl < T : LazyMeta < Meta = ( ) > > LazyMeta for PerDefTable < T > {
166
+ impl < T > LazyMeta for PerDefTable < T > where Option < T > : FixedSizeEncoding {
121
167
type Meta = [ <Table < T > as LazyMeta >:: Meta ; 2 ] ;
122
168
123
169
fn min_size ( [ lo, hi] : Self :: Meta ) -> usize {
124
170
Table :: < T > :: min_size ( lo) + Table :: < T > :: min_size ( hi)
125
171
}
126
172
}
127
173
128
- impl < T : Encodable > Lazy < PerDefTable < T > > {
174
+ impl < T > Lazy < PerDefTable < T > > where Option < T > : FixedSizeEncoding {
129
175
fn table_for_space ( & self , space : DefIndexAddressSpace ) -> Lazy < Table < T > > {
130
176
let space_index = space. index ( ) ;
131
177
let offset = space_index. checked_sub ( 1 ) . map_or ( 0 , |i| self . meta [ i] ) ;
@@ -135,11 +181,10 @@ impl<T: Encodable> Lazy<PerDefTable<T>> {
135
181
)
136
182
}
137
183
138
- /// Given the metadata, extract out the offset of a particular DefIndex (if any).
184
+ /// Given the metadata, extract out the value at a particular DefIndex (if any).
139
185
#[ inline( never) ]
140
- pub fn lookup ( & self , bytes : & [ u8 ] , def_index : DefIndex ) -> Option < Lazy < T > > {
186
+ pub fn get ( & self , bytes : & [ u8 ] , def_index : DefIndex ) -> Option < T > {
141
187
self . table_for_space ( def_index. address_space ( ) )
142
- . lookup ( bytes, def_index. as_array_index ( ) )
188
+ . get ( bytes, def_index. as_array_index ( ) )
143
189
}
144
190
}
145
-
0 commit comments