33// For the full copyright and license information, please view the LICENSE
44// file that was distributed with this source code.
55
6- // spell-checker:ignore (ToDO) seekable seek'd tail'ing ringbuffer ringbuf unwatch Uncategorized filehandle Signum
6+ // spell-checker:ignore (ToDO) seekable seek'd tail'ing ringbuffer ringbuf unwatch
7+ // spell-checker:ignore (ToDO) Uncategorized filehandle Signum memrchr
78// spell-checker:ignore (libs) kqueue
89// spell-checker:ignore (acronyms)
910// spell-checker:ignore (env/flags)
@@ -24,11 +25,12 @@ pub use args::uu_app;
2425use args:: { FilterMode , Settings , Signum , parse_args} ;
2526use chunks:: ReverseChunks ;
2627use follow:: Observer ;
28+ use memchr:: { memchr_iter, memrchr_iter} ;
2729use paths:: { FileExtTail , HeaderPrinter , Input , InputKind , MetadataExtTail } ;
2830use same_file:: Handle ;
2931use std:: cmp:: Ordering ;
3032use std:: fs:: File ;
31- use std:: io:: { self , BufRead , BufReader , BufWriter , Read , Seek , SeekFrom , Write , stdin, stdout} ;
33+ use std:: io:: { self , BufReader , BufWriter , ErrorKind , Read , Seek , SeekFrom , Write , stdin, stdout} ;
3234use std:: path:: { Path , PathBuf } ;
3335use uucore:: display:: Quotable ;
3436use uucore:: error:: { FromIo , UResult , USimpleError , get_exit_code, set_exit_code} ;
@@ -293,26 +295,29 @@ fn forwards_thru_file<R>(
293295where
294296 R : Read ,
295297{
296- let mut reader = BufReader :: new ( reader) ;
297-
298- let mut buf = vec ! [ ] ;
298+ if num_delimiters == 0 {
299+ return Ok ( 0 ) ;
300+ }
301+ // Use a 32K buffer.
302+ let mut buf = [ 0 ; 32 * 1024 ] ;
299303 let mut total = 0 ;
300- for _ in 0 ..num_delimiters {
301- match reader. read_until ( delimiter, & mut buf) {
302- Ok ( 0 ) => {
303- return Ok ( total) ;
304- }
304+ let mut count = 0 ;
305+ loop {
306+ match reader. read ( & mut buf) {
307+ Ok ( 0 ) => return Ok ( total) ,
305308 Ok ( n) => {
309+ for offset in memchr_iter ( delimiter, & buf[ ..n] ) {
310+ count += 1 ;
311+ if count == num_delimiters {
312+ return Ok ( total + offset + 1 ) ;
313+ }
314+ }
306315 total += n;
307- buf. clear ( ) ;
308- continue ;
309- }
310- Err ( e) => {
311- return Err ( e) ;
312316 }
317+ Err ( e) if e. kind ( ) == ErrorKind :: Interrupted => continue ,
318+ Err ( e) => return Err ( e) ,
313319 }
314320 }
315- Ok ( total)
316321}
317322
318323/// Iterate over bytes in the file, in reverse, until we find the
@@ -322,35 +327,36 @@ fn backwards_thru_file(file: &mut File, num_delimiters: u64, delimiter: u8) {
322327 // This variable counts the number of delimiters found in the file
323328 // so far (reading from the end of the file toward the beginning).
324329 let mut counter = 0 ;
325-
326- for ( block_idx , slice) in ReverseChunks :: new ( file) . enumerate ( ) {
330+ let mut first_slice = true ;
331+ for slice in ReverseChunks :: new ( file) {
327332 // Iterate over each byte in the slice in reverse order.
328- let mut iter = slice . iter ( ) . enumerate ( ) . rev ( ) ;
333+ let mut iter = memrchr_iter ( delimiter , & slice ) ;
329334
330335 // Ignore a trailing newline in the last block, if there is one.
331- if block_idx == 0 {
336+ if first_slice {
332337 if let Some ( c) = slice. last ( ) {
333338 if * c == delimiter {
334339 iter. next ( ) ;
335340 }
336341 }
342+ first_slice = false ;
337343 }
338344
339345 // For each byte, increment the count of the number of
340346 // delimiters found. If we have found more than the specified
341347 // number of delimiters, terminate the search and seek to the
342348 // appropriate location in the file.
343- for ( i , ch ) in iter {
344- if * ch == delimiter {
345- counter += 1 ;
346- if counter >= num_delimiters {
347- // After each iteration of the outer loop, the
348- // cursor in the file is at the *beginning* of the
349- // block, so seeking forward by `i + 1` bytes puts
350- // us right after the found delimiter.
351- file . seek ( SeekFrom :: Current ( ( i + 1 ) as i64 ) ) . unwrap ( ) ;
352- return ;
353- }
349+ for i in iter {
350+ counter += 1 ;
351+ if counter >= num_delimiters {
352+ // We should never over-count - assert that.
353+ assert_eq ! ( counter , num_delimiters ) ;
354+ // After each iteration of the outer loop, the
355+ // cursor in the file is at the *beginning* of the
356+ // block, so seeking forward by `i + 1` bytes puts
357+ // us right after the found delimiter.
358+ file . seek ( SeekFrom :: Current ( ( i + 1 ) as i64 ) ) . unwrap ( ) ;
359+ return ;
354360 }
355361 }
356362 }
0 commit comments