1 // Copyright 2020 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 16 #include <array> 17 #include <cstddef> 18 19 #include "pw_bytes/span.h" 20 #include "pw_result/result.h" 21 #include "pw_span/span.h" 22 #include "pw_stream/seek.h" 23 #include "pw_stream/stream.h" 24 25 namespace pw::stream { 26 27 class MemoryWriter : public SeekableWriter { 28 public: 29 using difference_type = ptrdiff_t; 30 using reference = const std::byte&; 31 using const_reference = const std::byte&; 32 using pointer = const std::byte*; 33 using const_pointer = const std::byte*; 34 using iterator = const std::byte*; 35 using const_iterator = const std::byte*; 36 MemoryWriter(ByteSpan dest)37 constexpr MemoryWriter(ByteSpan dest) : dest_(dest) {} 38 39 // Construct writer with prepopulated data in the buffer. The number of 40 // pre-written bytes is provided as `bytes_written`. 41 // 42 // Precondition: The number of pre-written bytes must not be greater than the 43 // size of the provided buffer. MemoryWriter(ByteSpan dest,size_t bytes_written)44 constexpr MemoryWriter(ByteSpan dest, size_t bytes_written) 45 : dest_(dest), position_(bytes_written) { 46 PW_ASSERT(position_ <= dest.size_bytes()); 47 } 48 WrittenData()49 ConstByteSpan WrittenData() const { return dest_.first(position_); } 50 clear()51 void clear() { position_ = 0; } 52 data()53 std::byte* data() { return dest_.data(); } data()54 const std::byte* data() const { return dest_.data(); } 55 56 const std::byte& operator[](size_t index) const { return dest_[index]; } 57 empty()58 [[nodiscard]] bool empty() const { return size() == 0u; } 59 size()60 size_t size() const { return position_; } bytes_written()61 size_t bytes_written() const { return size(); } 62 capacity()63 size_t capacity() const { return dest_.size(); } 64 begin()65 const std::byte* begin() const { return dest_.data(); } end()66 const std::byte* end() const { return dest_.data() + position_; } 67 68 private: ConservativeLimit(LimitType type)69 size_t ConservativeLimit(LimitType type) const override { 70 return type == LimitType::kWrite ? dest_.size_bytes() - position_ : 0; 71 } 72 73 // Implementation for writing data to this stream. 74 // 75 // If the in-memory buffer is exhausted in the middle of a write, this will 76 // perform a partial write and Status::ResourceExhausted() will be returned. 77 Status DoWrite(ConstByteSpan data) final; 78 DoSeek(ptrdiff_t offset,Whence origin)79 Status DoSeek(ptrdiff_t offset, Whence origin) final { 80 return CalculateSeek(offset, origin, dest_.size(), position_); 81 } 82 DoTell()83 size_t DoTell() final { return position_; } 84 85 ByteSpan dest_; 86 size_t position_ = 0; 87 }; 88 89 template <size_t kSizeBytes> 90 class MemoryWriterBuffer final : public MemoryWriter { 91 public: MemoryWriterBuffer()92 constexpr MemoryWriterBuffer() : MemoryWriter(buffer_) {} 93 94 /// MemoryWriterBuffer is not movable, as MemoryWriter stores a pointer to 95 /// the current buffer. 96 /// 97 /// The buffer could be copied, but this is usually undesirable. 98 MemoryWriterBuffer(MemoryWriterBuffer&&) = delete; 99 100 /// MemoryWriterBuffer is not movable, as MemoryWriter stores a pointer to 101 /// the current buffer. 102 /// 103 /// The buffer could be copied, but this is usually undesirable. 104 MemoryWriterBuffer& operator=(MemoryWriter&&) = delete; 105 106 private: 107 std::array<std::byte, kSizeBytes> buffer_; 108 }; 109 110 class MemoryReader final : public SeekableReader { 111 public: MemoryReader(ConstByteSpan source)112 constexpr MemoryReader(ConstByteSpan source) 113 : source_(source), position_(0) {} 114 bytes_read()115 size_t bytes_read() const { return position_; } 116 data()117 const std::byte* data() const { return source_.data(); } 118 119 private: ConservativeLimit(LimitType type)120 size_t ConservativeLimit(LimitType type) const override { 121 return type == LimitType::kRead ? source_.size_bytes() - position_ : 0; 122 } 123 DoSeek(ptrdiff_t offset,Whence origin)124 Status DoSeek(ptrdiff_t offset, Whence origin) override { 125 return CalculateSeek(offset, origin, source_.size(), position_); 126 } 127 DoTell()128 size_t DoTell() override { return position_; } 129 130 // Implementation for reading data from this stream. 131 // 132 // If the in-memory buffer does not have enough remaining bytes for what was 133 // requested, this will perform a partial read and OK will still be returned. 134 StatusWithSize DoRead(ByteSpan dest) override; 135 136 ConstByteSpan source_; 137 size_t position_; 138 }; 139 140 } // namespace pw::stream 141