@@ -59,12 +59,18 @@ impl CStr {
59
59
/// Returns the length of this string excluding `NUL`.
60
60
#[ inline]
61
61
pub const fn len ( & self ) -> usize {
62
- self . 0 . len ( ) - 1
62
+ self . len_with_nul ( ) - 1
63
63
}
64
64
65
65
/// Returns the length of this string with `NUL`.
66
66
#[ inline]
67
67
pub const fn len_with_nul ( & self ) -> usize {
68
+ // SAFETY: This is one of the invariant of `CStr`.
69
+ // We add a `unreachable_unchecked` here to hint the optimizer that
70
+ // the value returned from this function is non-zero.
71
+ if self . 0 . is_empty ( ) {
72
+ unsafe { core:: hint:: unreachable_unchecked ( ) } ;
73
+ }
68
74
self . 0 . len ( )
69
75
}
70
76
@@ -99,7 +105,9 @@ impl CStr {
99
105
return Err ( CStrConvertError :: NotNulTerminated ) ;
100
106
}
101
107
let mut i = 0 ;
102
- while i < bytes. len ( ) - 1 {
108
+ // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking,
109
+ // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`.
110
+ while i + 1 < bytes. len ( ) {
103
111
if bytes[ i] == 0 {
104
112
return Err ( CStrConvertError :: InteriorNul ) ;
105
113
}
@@ -148,7 +156,7 @@ impl CStr {
148
156
/// Convert the string to a byte slice without the trailing 0 byte.
149
157
#[ inline]
150
158
pub fn as_bytes ( & self ) -> & [ u8 ] {
151
- & self . 0 [ ..self . 0 . len ( ) - 1 ]
159
+ & self . 0 [ ..self . len ( ) ]
152
160
}
153
161
154
162
/// Convert the string to a byte slice containing the trailing 0 byte.
@@ -178,14 +186,12 @@ impl Index<ops::RangeFrom<usize>> for CStr {
178
186
type Output = CStr ;
179
187
180
188
#[ inline]
189
+ // Clippy false positive
190
+ #[ allow( clippy:: unnecessary_operation) ]
181
191
fn index ( & self , index : ops:: RangeFrom < usize > ) -> & Self :: Output {
182
- assert ! (
183
- index. start <= self . len( ) ,
184
- "range start index {} out of range for slice of length {}" ,
185
- index. start,
186
- self . len( )
187
- ) ;
188
- // SAFETY: We just checked the length.
192
+ // Delegate bounds checking to slice.
193
+ & self . as_bytes ( ) [ index. start ..] ;
194
+ // SAFETY: We just checked the bounds.
189
195
unsafe { Self :: from_bytes_with_nul_unchecked ( & self . 0 [ index. start ..] ) }
190
196
}
191
197
}
0 commit comments