diff options
| author | bors <bors@rust-lang.org> | 2018-01-14 00:42:11 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-01-14 00:42:11 +0000 |
| commit | 80e2e67f4c6fbbef5e4789df7fc96804e6a84196 (patch) | |
| tree | cf6a0db2e93141482275f32a9dd83eb499ef9625 /src/libstd | |
| parent | cf4c3cbe5524608fd3a8fcd626f3c73223022be7 (diff) | |
| parent | c96f30257aa7e86fd5b7f657d7b0bc21dcf45b1f (diff) | |
| download | rust-80e2e67f4c6fbbef5e4789df7fc96804e6a84196.tar.gz rust-80e2e67f4c6fbbef5e4789df7fc96804e6a84196.zip | |
Auto merge of #46832 - Diggsey:bufread-cheaper-seek, r=alexcrichton
BufRead: Only flush the internal buffer if seeking outside of it. Fixes #31100 r? @dtolnay
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/io/buffered.rs | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 7001d8e0421..16fbf0c6ba6 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -194,6 +194,31 @@ impl<R: Read> BufReader<R> { pub fn into_inner(self) -> R { self.inner } } +impl<R: Seek> BufReader<R> { + /// Seeks relative to the current position. If the new position lies within the buffer, + /// the buffer will not be flushed, allowing for more efficient seeks. + /// This method does not return the location of the underlying reader, so the caller + /// must track this information themselves if it is required. + #[unstable(feature = "bufreader_seek_relative", issue = "31100")] + pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> { + let pos = self.pos as u64; + if offset < 0 { + if let Some(new_pos) = pos.checked_sub((-offset) as u64) { + self.pos = new_pos as usize; + return Ok(()) + } + } else { + if let Some(new_pos) = pos.checked_add(offset as u64) { + if new_pos <= self.cap as u64 { + self.pos = new_pos as usize; + return Ok(()) + } + } + } + self.seek(SeekFrom::Current(offset)).map(|_|()) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<R: Read> Read for BufReader<R> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { @@ -260,6 +285,8 @@ impl<R: Seek> Seek for BufReader<R> { /// `.into_inner()` immediately after a seek yields the underlying reader /// at the same position. /// + /// To seek without discarding the internal buffer, use [`seek_relative`]. + /// /// See `std::io::Seek` for more details. /// /// Note: In the edge case where you're seeking with `SeekFrom::Current(n)` @@ -267,6 +294,8 @@ impl<R: Seek> Seek for BufReader<R> { /// seeks will be performed instead of one. If the second seek returns /// `Err`, the underlying reader will be left at the same position it would /// have if you seeked to `SeekFrom::Current(0)`. + /// + /// [`seek_relative`]: #method.seek_relative fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { let result: u64; if let SeekFrom::Current(n) = pos { @@ -954,6 +983,23 @@ mod tests { } #[test] + fn test_buffered_reader_seek_relative() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); + + assert!(reader.seek_relative(3).is_ok()); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert!(reader.seek_relative(0).is_ok()); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert!(reader.seek_relative(1).is_ok()); + assert_eq!(reader.fill_buf().ok(), Some(&[1][..])); + assert!(reader.seek_relative(-1).is_ok()); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert!(reader.seek_relative(2).is_ok()); + assert_eq!(reader.fill_buf().ok(), Some(&[2, 3][..])); + } + + #[test] fn test_buffered_reader_seek_underflow() { // gimmick reader that yields its position modulo 256 for each byte struct PositionReader { |
