@@ -15,6 +15,7 @@ pub struct Buffer {
1515}
1616
1717impl Buffer {
18+ /// Create an empty buffer
1819 #[ inline]
1920 pub const fn new ( ) -> Buffer {
2021 Self {
@@ -24,17 +25,15 @@ impl Buffer {
2425 }
2526 }
2627
27- #[ cfg_attr ( feature = "perf- inline" , inline ) ]
28+ #[ inline]
2829 pub fn with_capacity ( n : usize ) -> Buffer {
29- unsafe {
30- if unlikely ! ( n == 0 ) {
31- Self :: new ( )
32- } else {
33- Self {
34- data : safe_alloc ( n) ,
35- len : 0 ,
36- capacity : n,
37- }
30+ if unlikely ! ( n == 0 ) {
31+ Self :: new ( )
32+ } else {
33+ Self {
34+ data : safe_alloc ( n) ,
35+ len : 0 ,
36+ capacity : n,
3837 }
3938 }
4039 }
@@ -68,6 +67,11 @@ impl Buffer {
6867 self . len = new_len;
6968 }
7069
70+ /// Same as String::truncate
71+ ///
72+ /// # Panics
73+ ///
74+ /// This method panics if `new_len > self.len()`.
7175 pub ( crate ) fn truncate ( & mut self , new_len : usize ) {
7276 assert ! ( new_len <= self . len) ;
7377 self . len = new_len;
@@ -89,12 +93,19 @@ impl Buffer {
8993 self . len == 0
9094 }
9195
96+ /// Same as String::reserve
97+ ///
98+ /// # Panics
99+ ///
100+ /// This method panics if `size` overflows `isize::MAX`.
92101 #[ inline]
93102 pub fn reserve ( & mut self , size : usize ) {
94103 assert ! ( size <= isize :: MAX as usize ) ;
95104 unsafe { self . reserve_small ( size) } ;
96105 }
97106
107+ /// Same as String::reserve except that undefined behaviour can result if `size`
108+ /// overflows `isize::MAX`.
98109 #[ inline]
99110 pub ( crate ) unsafe fn reserve_small ( & mut self , size : usize ) {
100111 debug_assert ! ( size <= isize :: MAX as usize ) ;
@@ -110,13 +121,14 @@ impl Buffer {
110121 self . len = 0 ;
111122 }
112123
113- /// Converts a `Buffer` into a `String`.
114- ///
115- /// This consumes the `Buffer`, so we do not need to copy its contents.
124+ /// Converts a `Buffer` into a `String` without copy/realloc operation.
116125 #[ inline]
117126 pub fn into_string ( self ) -> String {
118127 debug_assert ! ( self . len <= self . capacity) ;
119128 let buf = ManuallyDrop :: new ( self ) ;
129+
130+ // SAFETY: This operations satisfy all requirements specified in
131+ // https://doc.rust-lang.org/std/string/struct.String.html#safety
120132 unsafe { String :: from_raw_parts ( buf. data , buf. len , buf. capacity ) }
121133 }
122134
@@ -145,31 +157,44 @@ impl Buffer {
145157 #[ cold]
146158 fn reserve_internal ( & mut self , size : usize ) {
147159 debug_assert ! ( size <= isize :: MAX as usize ) ;
148- unsafe {
149- let new_capacity = std:: cmp:: max ( self . capacity * 2 , self . capacity + size) ;
150- debug_assert ! ( new_capacity > self . capacity) ;
151- self . data = safe_realloc ( self . data , self . capacity , new_capacity) ;
152- self . capacity = new_capacity;
153- }
160+
161+ let new_capacity = std:: cmp:: max ( self . capacity * 2 , self . capacity + size) ;
162+ debug_assert ! ( new_capacity > self . capacity) ;
163+ self . data = unsafe { safe_realloc ( self . data , self . capacity , new_capacity) } ;
164+ self . capacity = new_capacity;
165+
154166 debug_assert ! ( !self . data. is_null( ) ) ;
155167 debug_assert ! ( self . len <= self . capacity) ;
156168 }
157169}
158170
159- unsafe fn safe_alloc ( capacity : usize ) -> * mut u8 {
171+ #[ inline( never) ]
172+ fn safe_alloc ( capacity : usize ) -> * mut u8 {
173+ assert ! ( capacity > 0 ) ;
160174 assert ! ( capacity <= isize :: MAX as usize , "capacity is too large" ) ;
161- let layout = Layout :: from_size_align_unchecked ( capacity, 1 ) ;
162- let data = alloc ( layout) ;
163- if data. is_null ( ) {
164- handle_alloc_error ( layout) ;
165- }
166175
167- data
176+ // SAFETY: capacity is non-zero, and always multiple of alignment (1).
177+ unsafe {
178+ let layout = Layout :: from_size_align_unchecked ( capacity, 1 ) ;
179+ let data = alloc ( layout) ;
180+ if data. is_null ( ) {
181+ handle_alloc_error ( layout) ;
182+ }
183+
184+ data
185+ }
168186}
169187
188+ /// # Safety
189+ ///
190+ /// - if `capacity > 0`, `capacity` is the same value that was used to allocate the block
191+ /// of memory pointed by `ptr`.
170192#[ cold]
193+ #[ inline( never) ]
171194unsafe fn safe_realloc ( ptr : * mut u8 , capacity : usize , new_capacity : usize ) -> * mut u8 {
195+ assert ! ( new_capacity > 0 ) ;
172196 assert ! ( new_capacity <= isize :: MAX as usize , "capacity is too large" ) ;
197+
173198 let data = if unlikely ! ( capacity == 0 ) {
174199 let new_layout = Layout :: from_size_align_unchecked ( new_capacity, 1 ) ;
175200 alloc ( new_layout)
@@ -188,7 +213,7 @@ unsafe fn safe_realloc(ptr: *mut u8, capacity: usize, new_capacity: usize) -> *m
188213impl Clone for Buffer {
189214 fn clone ( & self ) -> Self {
190215 unsafe {
191- if self . capacity == 0 {
216+ if self . is_empty ( ) {
192217 Self :: new ( )
193218 } else {
194219 let buf = Self {
@@ -213,6 +238,8 @@ impl fmt::Debug for Buffer {
213238impl Drop for Buffer {
214239 fn drop ( & mut self ) {
215240 if self . capacity != 0 {
241+ // SAFETY: when `self.capacity > 0`, `self.capacity` is the same value
242+ // used for allocate the block of memory pointed by `self.data`.
216243 unsafe {
217244 let layout = Layout :: from_size_align_unchecked ( self . capacity , 1 ) ;
218245 dealloc ( self . data , layout) ;
@@ -236,7 +263,7 @@ impl From<String> for Buffer {
236263 #[ inline]
237264 fn from ( other : String ) -> Buffer {
238265 let bs = other. into_boxed_str ( ) ;
239- let data = unsafe { & mut * Box :: into_raw ( bs) } ;
266+ let data = Box :: leak ( bs) ;
240267 Buffer {
241268 data : data. as_mut_ptr ( ) ,
242269 len : data. len ( ) ,
@@ -249,10 +276,16 @@ impl From<&str> for Buffer {
249276 #[ inline]
250277 fn from ( other : & str ) -> Buffer {
251278 let mut buf = Buffer :: with_capacity ( other. len ( ) ) ;
252- unsafe {
253- ptr:: copy_nonoverlapping ( other. as_ptr ( ) , buf. as_mut_ptr ( ) , other. len ( ) ) ;
254- buf. advance ( other. len ( ) ) ;
279+
280+ if !other. is_empty ( ) {
281+ // SAFETY: `Buffer.capacity()` should be same as `other.len()`, so if `other`
282+ // is not empty, `buf.as_mut_ptr()` is supporsed to point to valid memory.
283+ unsafe {
284+ ptr:: copy_nonoverlapping ( other. as_ptr ( ) , buf. as_mut_ptr ( ) , other. len ( ) ) ;
285+ buf. advance ( other. len ( ) ) ;
286+ }
255287 }
288+
256289 buf
257290 }
258291}
@@ -363,5 +396,8 @@ mod tests {
363396
364397 assert_eq ! ( s1. as_str( ) , "foobar" ) ;
365398 assert_eq ! ( s2. as_str( ) , "foobaz" ) ;
399+
400+ s2. clear ( ) ;
401+ let _ = s2. clone ( ) ;
366402 }
367403}
0 commit comments