Skip to content

Commit

Permalink
pw_stream: Implement StdFileReader::ConservativeLimit
Browse files Browse the repository at this point in the history
The ConservativeLimit method returns an estimate of how much data is
available to be read or written in a pw::stream. The default
implementation returns a very large value ("unlimited").

This commit implements a file-specific implementation for StdFileReader.
It determines the size of the file (and thus how much data is left to
read) by seeking to the end and getting the current file position. This
makes the ConservativeReadLimit method much more useful for users of the
class.

Change-Id: I55b2518d3dc17ca8c4f98847dc7c3557eb9fda74
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/106130
Commit-Queue: Auto-Submit <[email protected]>
Reviewed-by: Wyatt Hepler <[email protected]>
Pigweed-Auto-Submit: Eli Lipsitz <[email protected]>
  • Loading branch information
elipsitz authored and CQ Bot Account committed Aug 15, 2022
1 parent 26e2105 commit 3bac75d
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 0 deletions.
1 change: 1 addition & 0 deletions pw_stream/public/pw_stream/std_file_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class StdFileReader final : public stream::SeekableReader {
StatusWithSize DoRead(ByteSpan dest) override;
Status DoSeek(ptrdiff_t offset, Whence origin) override;
size_t DoTell() override;
size_t ConservativeLimit(LimitType limit) const override;

std::ifstream stream_;
};
Expand Down
24 changes: 24 additions & 0 deletions pw_stream/std_file_stream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,30 @@ size_t StdFileReader::DoTell() {
return pos < 0 ? kUnknownPosition : pos;
}

size_t StdFileReader::ConservativeLimit(LimitType limit) const {
if (limit == LimitType::kWrite) {
return 0;
}

// Attempt to determine the number of bytes left in the file by seeking
// to the end and checking where we end up.
if (stream_.eof()) {
return 0;
}
auto stream = const_cast<std::ifstream*>(&this->stream_);
auto start = stream->tellg();
if (start == -1) {
return 0;
}
stream->seekg(0, std::ios::end);
auto end = stream->tellg();
if (end == -1) {
return 0;
}
stream->seekg(start, std::ios::beg);
return end - start;
}

Status StdFileWriter::DoWrite(ConstByteSpan data) {
if (stream_.eof()) {
return Status::OutOfRange();
Expand Down
5 changes: 5 additions & 0 deletions pw_stream/std_file_stream_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ TEST_F(StdFileStreamTest, SeekAtEnd) {
writer.Close();

StdFileReader reader(TempFilename());
ASSERT_EQ(reader.ConservativeReadLimit(), kTestData.size());

std::array<char, 3> read_buffer;
size_t read_offset = 0;
while (read_offset < kTestData.size()) {
Expand All @@ -156,17 +158,20 @@ TEST_F(StdFileStreamTest, SeekAtEnd) {
as_bytes(span(kTestData)).subspan(read_offset, result.value().size());
EXPECT_TRUE(pw::containers::Equal(result.value(), expect_window));
read_offset += result.value().size();
ASSERT_EQ(reader.ConservativeReadLimit(), kTestData.size() - read_offset);
}
// After data has been read, do a final read to trigger EOF.
Result<ConstByteSpan> result =
reader.Read(as_writable_bytes(span(read_buffer)));
EXPECT_EQ(result.status(), Status::OutOfRange());
ASSERT_EQ(reader.ConservativeReadLimit(), 0u);

EXPECT_EQ(read_offset, kTestData.size());

// Seek backwards and read again to ensure seek at EOF works.
ASSERT_EQ(reader.Seek(-1 * read_buffer.size(), Stream::Whence::kEnd),
OkStatus());
ASSERT_EQ(reader.ConservativeReadLimit(), read_buffer.size());
result = reader.Read(as_writable_bytes(span(read_buffer)));
EXPECT_EQ(result.status(), OkStatus());

Expand Down

0 comments on commit 3bac75d

Please sign in to comment.