xref: /aosp_15_r20/external/pigweed/pw_stream/public/pw_stream/interval_reader.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2021 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 //
15 // The header provides a set of helper utils for protobuf related operations.
16 // The APIs may not be finalized yet.
17 
18 #pragma once
19 
20 #include <cstddef>
21 #include <string_view>
22 
23 #include "pw_assert/assert.h"
24 #include "pw_status/status.h"
25 #include "pw_stream/stream.h"
26 
27 namespace pw::stream {
28 
29 // A reader wrapper that reads from a sub-interval of a given seekable
30 // source reader. The IntervalReader tracks and maintains its own read offset.
31 // It seeks the source reader to its current read offset before reading. In
32 // this way, multiple IntervalReaders can share the same source reader without
33 // interfering with each other.
34 class IntervalReader : public SeekableReader {
35  public:
IntervalReader()36   constexpr IntervalReader() : status_(Status::Unavailable()) {}
37 
38   // Create an IntervalReader with an error status.
IntervalReader(Status status)39   constexpr IntervalReader(Status status) : status_(status) {
40     PW_ASSERT(!status.ok());
41   }
42 
43   // source_reader -- The source reader to read from.
44   // start -- starting offset to read in `source_reader`
45   // end -- ending offset in `source_reader`.
IntervalReader(SeekableReader & source_reader,size_t start,size_t end)46   constexpr IntervalReader(SeekableReader& source_reader,
47                            size_t start,
48                            size_t end)
49       : source_reader_(&source_reader),
50         start_(start),
51         end_(end),
52         current_(start) {}
53 
54   // Reset the read offset to the start of the interval
Reset()55   IntervalReader& Reset() {
56     current_ = start_;
57     return *this;
58   }
59 
60   // Move the read offset to the end of the interval;
Exhaust()61   IntervalReader& Exhaust() {
62     current_ = end_;
63     return *this;
64   }
65 
66   // Get a reference to the source reader.
source_reader()67   SeekableReader& source_reader() { return *source_reader_; }
start()68   size_t start() const { return start_; }
end()69   size_t end() const { return end_; }
current()70   size_t current() const { return current_; }
interval_size()71   size_t interval_size() const { return end_ - start_; }
ok()72   bool ok() const { return status_.ok(); }
status()73   Status status() const { return status_; }
74 
75   // For iterator comparison in Message.
76   bool operator==(const IntervalReader& other) const {
77     return source_reader_ == other.source_reader_ && start_ == other.start_ &&
78            end_ == other.end_ && current_ == other.current_;
79   }
80 
81  private:
82   StatusWithSize DoRead(ByteSpan destination) final;
83   Status DoSeek(ptrdiff_t offset, Whence origin) final;
DoTell()84   size_t DoTell() final { return current_ - start_; }
ConservativeLimit(LimitType limit)85   size_t ConservativeLimit(LimitType limit) const override {
86     if (limit == LimitType::kRead) {
87       return end_ - current_;
88     }
89     return 0;
90   }
91 
92   SeekableReader* source_reader_ = nullptr;
93   size_t start_ = 0;
94   size_t end_ = 0;
95   size_t current_ = 0;
96   Status status_ = OkStatus();
97 };
98 
99 }  // namespace pw::stream
100