1
1
//! Common utilities, for internal use only.
2
2
3
- use crate :: ptr;
4
-
5
3
/// Helper methods to process immutable bytes.
6
- pub ( crate ) trait ByteSlice : AsRef < [ u8 ] > {
7
- unsafe fn first_unchecked ( & self ) -> u8 {
8
- debug_assert ! ( !self . is_empty( ) ) ;
9
- // SAFETY: safe as long as self is not empty
10
- unsafe { * self . as_ref ( ) . get_unchecked ( 0 ) }
11
- }
12
-
13
- /// Get if the slice contains no elements.
14
- fn is_empty ( & self ) -> bool {
15
- self . as_ref ( ) . is_empty ( )
16
- }
17
-
18
- /// Check if the slice at least `n` length.
19
- fn check_len ( & self , n : usize ) -> bool {
20
- n <= self . as_ref ( ) . len ( )
21
- }
22
-
23
- /// Check if the first character in the slice is equal to c.
24
- fn first_is ( & self , c : u8 ) -> bool {
25
- self . as_ref ( ) . first ( ) == Some ( & c)
26
- }
27
-
28
- /// Check if the first character in the slice is equal to c1 or c2.
29
- fn first_is2 ( & self , c1 : u8 , c2 : u8 ) -> bool {
30
- if let Some ( & c) = self . as_ref ( ) . first ( ) { c == c1 || c == c2 } else { false }
31
- }
32
-
33
- /// Bounds-checked test if the first character in the slice is a digit.
34
- fn first_isdigit ( & self ) -> bool {
35
- if let Some ( & c) = self . as_ref ( ) . first ( ) { c. is_ascii_digit ( ) } else { false }
36
- }
37
-
38
- /// Check if self starts with u with a case-insensitive comparison.
39
- fn starts_with_ignore_case ( & self , u : & [ u8 ] ) -> bool {
40
- debug_assert ! ( self . as_ref( ) . len( ) >= u. len( ) ) ;
41
- let iter = self . as_ref ( ) . iter ( ) . zip ( u. iter ( ) ) ;
42
- let d = iter. fold ( 0 , |i, ( & x, & y) | i | ( x ^ y) ) ;
43
- d == 0 || d == 32
44
- }
45
-
46
- /// Get the remaining slice after the first N elements.
47
- fn advance ( & self , n : usize ) -> & [ u8 ] {
48
- & self . as_ref ( ) [ n..]
49
- }
50
-
51
- /// Get the slice after skipping all leading characters equal c.
52
- fn skip_chars ( & self , c : u8 ) -> & [ u8 ] {
53
- let mut s = self . as_ref ( ) ;
54
- while s. first_is ( c) {
55
- s = s. advance ( 1 ) ;
56
- }
57
- s
58
- }
59
-
60
- /// Get the slice after skipping all leading characters equal c1 or c2.
61
- fn skip_chars2 ( & self , c1 : u8 , c2 : u8 ) -> & [ u8 ] {
62
- let mut s = self . as_ref ( ) ;
63
- while s. first_is2 ( c1, c2) {
64
- s = s. advance ( 1 ) ;
65
- }
66
- s
67
- }
68
-
4
+ pub ( crate ) trait ByteSlice {
69
5
/// Read 8 bytes as a 64-bit integer in little-endian order.
70
- unsafe fn read_u64_unchecked ( & self ) -> u64 {
71
- debug_assert ! ( self . check_len( 8 ) ) ;
72
- let src = self . as_ref ( ) . as_ptr ( ) as * const u64 ;
73
- // SAFETY: safe as long as self is at least 8 bytes
74
- u64:: from_le ( unsafe { ptr:: read_unaligned ( src) } )
75
- }
6
+ fn read_u64 ( & self ) -> u64 ;
76
7
77
- /// Try to read the next 8 bytes from the slice.
78
- fn read_u64 ( & self ) -> Option < u64 > {
79
- if self . check_len ( 8 ) {
80
- // SAFETY: self must be at least 8 bytes.
81
- Some ( unsafe { self . read_u64_unchecked ( ) } )
82
- } else {
83
- None
84
- }
85
- }
86
-
87
- /// Calculate the offset of slice from another.
88
- fn offset_from ( & self , other : & Self ) -> isize {
89
- other. as_ref ( ) . len ( ) as isize - self . as_ref ( ) . len ( ) as isize
90
- }
91
- }
92
-
93
- impl ByteSlice for [ u8 ] { }
94
-
95
- /// Helper methods to process mutable bytes.
96
- pub ( crate ) trait ByteSliceMut : AsMut < [ u8 ] > {
97
8
/// Write a 64-bit integer as 8 bytes in little-endian order.
98
- unsafe fn write_u64_unchecked ( & mut self , value : u64 ) {
99
- debug_assert ! ( self . as_mut( ) . len( ) >= 8 ) ;
100
- let dst = self . as_mut ( ) . as_mut_ptr ( ) as * mut u64 ;
101
- // NOTE: we must use `write_unaligned`, since dst is not
102
- // guaranteed to be properly aligned. Miri will warn us
103
- // if we use `write` instead of `write_unaligned`, as expected.
104
- // SAFETY: safe as long as self is at least 8 bytes
105
- unsafe {
106
- ptr:: write_unaligned ( dst, u64:: to_le ( value) ) ;
107
- }
108
- }
109
- }
9
+ fn write_u64 ( & mut self , value : u64 ) ;
110
10
111
- impl ByteSliceMut for [ u8 ] { }
11
+ /// Calculate the offset of a slice from another.
12
+ fn offset_from ( & self , other : & Self ) -> isize ;
112
13
113
- /// Bytes wrapper with specialized methods for ASCII characters .
114
- # [ derive ( Debug , Clone , Copy , PartialEq , Eq ) ]
115
- pub ( crate ) struct AsciiStr < ' a > {
116
- slc : & ' a [ u8 ] ,
14
+ /// Iteratively parse and consume digits from bytes .
15
+ /// Returns the same bytes with consumed digits being
16
+ /// elided.
17
+ fn parse_digits ( & self , func : impl FnMut ( u8 ) ) -> & Self ;
117
18
}
118
19
119
- impl < ' a > AsciiStr < ' a > {
120
- pub fn new ( slc : & ' a [ u8 ] ) -> Self {
121
- Self { slc }
20
+ impl ByteSlice for [ u8 ] {
21
+ #[ inline( always) ] // inlining this is crucial to remove bound checks
22
+ fn read_u64 ( & self ) -> u64 {
23
+ let mut tmp = [ 0 ; 8 ] ;
24
+ tmp. copy_from_slice ( & self [ ..8 ] ) ;
25
+ u64:: from_le_bytes ( tmp)
122
26
}
123
27
124
- /// Advance the view by n, advancing it in-place to (n..).
125
- pub unsafe fn step_by ( & mut self , n : usize ) -> & mut Self {
126
- // SAFETY: safe as long n is less than the buffer length
127
- self . slc = unsafe { self . slc . get_unchecked ( n..) } ;
128
- self
28
+ #[ inline( always) ] // inlining this is crucial to remove bound checks
29
+ fn write_u64 ( & mut self , value : u64 ) {
30
+ self [ ..8 ] . copy_from_slice ( & value. to_le_bytes ( ) )
129
31
}
130
32
131
- /// Advance the view by n, advancing it in-place to (1..).
132
- pub unsafe fn step ( & mut self ) -> & mut Self {
133
- // SAFETY: safe as long as self is not empty
134
- unsafe { self . step_by ( 1 ) }
33
+ #[ inline]
34
+ fn offset_from ( & self , other : & Self ) -> isize {
35
+ other. len ( ) as isize - self . len ( ) as isize
135
36
}
136
37
137
- /// Iteratively parse and consume digits from bytes.
138
- pub fn parse_digits ( & mut self , mut func : impl FnMut ( u8 ) ) {
139
- while let Some ( & c) = self . as_ref ( ) . first ( ) {
38
+ #[ inline]
39
+ fn parse_digits ( & self , mut func : impl FnMut ( u8 ) ) -> & Self {
40
+ let mut s = self ;
41
+
42
+ // FIXME: Can't use s.split_first() here yet,
43
+ // see https://github.com/rust-lang/rust/issues/109328
44
+ while let [ c, s_next @ ..] = s {
140
45
let c = c. wrapping_sub ( b'0' ) ;
141
46
if c < 10 {
142
47
func ( c) ;
143
- // SAFETY: self cannot be empty
144
- unsafe {
145
- self . step ( ) ;
146
- }
48
+ s = s_next;
147
49
} else {
148
50
break ;
149
51
}
150
52
}
151
- }
152
- }
153
53
154
- impl < ' a > AsRef < [ u8 ] > for AsciiStr < ' a > {
155
- #[ inline]
156
- fn as_ref ( & self ) -> & [ u8 ] {
157
- self . slc
54
+ s
158
55
}
159
56
}
160
57
161
- impl < ' a > ByteSlice for AsciiStr < ' a > { }
162
-
163
58
/// Determine if 8 bytes are all decimal digits.
164
59
/// This does not care about the order in which the bytes were loaded.
165
60
pub ( crate ) fn is_8digits ( v : u64 ) -> bool {
@@ -168,19 +63,6 @@ pub(crate) fn is_8digits(v: u64) -> bool {
168
63
( a | b) & 0x8080_8080_8080_8080 == 0
169
64
}
170
65
171
- /// Iteratively parse and consume digits from bytes.
172
- pub ( crate ) fn parse_digits ( s : & mut & [ u8 ] , mut f : impl FnMut ( u8 ) ) {
173
- while let Some ( & c) = s. get ( 0 ) {
174
- let c = c. wrapping_sub ( b'0' ) ;
175
- if c < 10 {
176
- f ( c) ;
177
- * s = s. advance ( 1 ) ;
178
- } else {
179
- break ;
180
- }
181
- }
182
- }
183
-
184
66
/// A custom 64-bit floating point type, representing `f * 2^e`.
185
67
/// e is biased, so it be directly shifted into the exponent bits.
186
68
#[ derive( Debug , Copy , Clone , PartialEq , Eq , Default ) ]
0 commit comments