| // Copyright 2020 The Pigweed Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| // use this file except in compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations under |
| // the License. |
| |
| #include "pw_kvs/alignment.h" |
| |
| #include "pw_status/try.h" |
| |
| namespace pw { |
| |
| StatusWithSize AlignedWriter::Write(std::span<const std::byte> data) { |
| while (!data.empty()) { |
| size_t to_copy = std::min(write_size_ - bytes_in_buffer_, data.size()); |
| |
| std::memcpy(&buffer_[bytes_in_buffer_], data.data(), to_copy); |
| TRY_WITH_SIZE(AddBytesToBuffer(to_copy)); |
| data = data.subspan(to_copy); |
| } |
| |
| return StatusWithSize(bytes_written_); |
| } |
| |
| StatusWithSize AlignedWriter::Flush() { |
| Status status; |
| |
| // If data remains in the buffer, pad it to the alignment size and flush the |
| // remaining data. |
| if (bytes_in_buffer_ != 0u) { |
| const size_t remaining_bytes = AlignUp(bytes_in_buffer_, alignment_bytes_); |
| std::memset(&buffer_[bytes_in_buffer_], |
| int(kPadByte), |
| remaining_bytes - bytes_in_buffer_); |
| status = output_.Write(buffer_, remaining_bytes).status(); |
| |
| bytes_written_ += remaining_bytes; // Include padding in the total. |
| bytes_in_buffer_ = 0; |
| } |
| |
| const StatusWithSize result(status, bytes_written_); |
| bytes_written_ = 0; |
| return result; |
| } |
| |
| StatusWithSize AlignedWriter::Write(Input& input, size_t size) { |
| while (size > 0u) { |
| const size_t to_read = std::min(write_size_ - bytes_in_buffer_, size); |
| StatusWithSize result = input.Read(buffer_ + bytes_in_buffer_, to_read); |
| if (!result.ok()) { |
| return StatusWithSize(result.status(), bytes_written_); |
| } |
| TRY_WITH_SIZE(AddBytesToBuffer(to_read)); |
| size -= result.size(); |
| } |
| |
| return StatusWithSize(bytes_written_); |
| } |
| |
| StatusWithSize AlignedWriter::AddBytesToBuffer(size_t bytes_added) { |
| bytes_in_buffer_ += bytes_added; |
| |
| // If the buffer is full, write it out. |
| if (bytes_in_buffer_ == write_size_) { |
| StatusWithSize result = output_.Write(buffer_, write_size_); |
| |
| // Always use write_size_ for the bytes written. If there was an error |
| // assume the space was written or at least disturbed. |
| bytes_written_ += write_size_; |
| bytes_in_buffer_ = 0; |
| |
| if (!result.ok()) { |
| return StatusWithSize(result.status(), bytes_written_); |
| } |
| } |
| |
| return StatusWithSize(bytes_written_); |
| } |
| |
| } // namespace pw |