| // 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. |
| #pragma once |
| |
| #include <array> |
| #include <cstddef> |
| |
| #include "pw_bytes/span.h" |
| #include "pw_result/result.h" |
| #include "pw_span/span.h" |
| #include "pw_stream/seek.h" |
| #include "pw_stream/stream.h" |
| |
| namespace pw::stream { |
| |
| class MemoryWriter : public SeekableWriter { |
| public: |
| using difference_type = ptrdiff_t; |
| using reference = const std::byte&; |
| using const_reference = const std::byte&; |
| using pointer = const std::byte*; |
| using const_pointer = const std::byte*; |
| using iterator = const std::byte*; |
| using const_iterator = const std::byte*; |
| |
| constexpr MemoryWriter(ByteSpan dest) : dest_(dest) {} |
| |
| // Construct writer with prepopulated data in the buffer. The number of |
| // pre-written bytes is provided as `bytes_written`. |
| // |
| // Precondition: The number of pre-written bytes must not be greater than the |
| // size of the provided buffer. |
| constexpr MemoryWriter(ByteSpan dest, size_t bytes_written) |
| : dest_(dest), position_(bytes_written) { |
| PW_ASSERT(position_ <= dest.size_bytes()); |
| } |
| |
| ConstByteSpan WrittenData() const { return dest_.first(position_); } |
| |
| void clear() { position_ = 0; } |
| |
| std::byte* data() { return dest_.data(); } |
| const std::byte* data() const { return dest_.data(); } |
| |
| const std::byte& operator[](size_t index) const { return dest_[index]; } |
| |
| [[nodiscard]] bool empty() const { return size() == 0u; } |
| |
| size_t size() const { return position_; } |
| size_t bytes_written() const { return size(); } |
| |
| size_t capacity() const { return dest_.size(); } |
| |
| const std::byte* begin() const { return dest_.data(); } |
| const std::byte* end() const { return dest_.data() + position_; } |
| |
| private: |
| size_t ConservativeLimit(LimitType type) const override { |
| return type == LimitType::kWrite ? dest_.size_bytes() - position_ : 0; |
| } |
| |
| // Implementation for writing data to this stream. |
| // |
| // If the in-memory buffer is exhausted in the middle of a write, this will |
| // perform a partial write and Status::ResourceExhausted() will be returned. |
| Status DoWrite(ConstByteSpan data) final; |
| |
| Status DoSeek(ptrdiff_t offset, Whence origin) final { |
| return CalculateSeek(offset, origin, dest_.size(), position_); |
| } |
| |
| size_t DoTell() final { return position_; } |
| |
| ByteSpan dest_; |
| size_t position_ = 0; |
| }; |
| |
| template <size_t kSizeBytes> |
| class MemoryWriterBuffer final : public MemoryWriter { |
| public: |
| constexpr MemoryWriterBuffer() : MemoryWriter(buffer_) {} |
| |
| private: |
| std::array<std::byte, kSizeBytes> buffer_; |
| }; |
| |
| class MemoryReader final : public SeekableReader { |
| public: |
| constexpr MemoryReader(ConstByteSpan source) |
| : source_(source), position_(0) {} |
| |
| size_t bytes_read() const { return position_; } |
| |
| const std::byte* data() const { return source_.data(); } |
| |
| private: |
| size_t ConservativeLimit(LimitType type) const override { |
| return type == LimitType::kRead ? source_.size_bytes() - position_ : 0; |
| } |
| |
| Status DoSeek(ptrdiff_t offset, Whence origin) override { |
| return CalculateSeek(offset, origin, source_.size(), position_); |
| } |
| |
| size_t DoTell() override { return position_; } |
| |
| // Implementation for reading data from this stream. |
| // |
| // If the in-memory buffer does not have enough remaining bytes for what was |
| // requested, this will perform a partial read and OK will still be returned. |
| StatusWithSize DoRead(ByteSpan dest) override; |
| |
| ConstByteSpan source_; |
| size_t position_; |
| }; |
| |
| } // namespace pw::stream |