xref: /aosp_15_r20/external/executorch/backends/apple/coreml/runtime/inmemoryfs/reversed_memory_stream.cpp (revision 523fa7a60841cd1ecfb9cc4201f1ca8b03ed023a)
1 //
2 // reversed_memory_stream.cpp
3 //
4 // Copyright © 2024 Apple Inc. All rights reserved.
5 //
6 // Please refer to the license found in the LICENSE file in the root directory of the source tree.
7 
8 #include "reversed_memory_stream.hpp"
9 
10 #include <limits>
11 
12 namespace inmemoryfs {
13 
ReversedIMemoryStreamBuf(std::shared_ptr<MemoryBuffer> buffer)14 ReversedIMemoryStreamBuf::ReversedIMemoryStreamBuf(std::shared_ptr<MemoryBuffer> buffer) noexcept
15     : buffer_(buffer), start_(static_cast<char*>(buffer->data())), current_(start_), end_(start_ + buffer->size()) {
16     // we are intentionally setting `gptr` to the buffer end, this makes sure
17     // that `underflow` and `uflow` methods are always called.
18     setg(start_, start_, start_);
19 }
20 
iseekoff(std::streambuf::off_type offset,std::ios_base::seekdir dir)21 std::streambuf::pos_type ReversedIMemoryStreamBuf::iseekoff(std::streambuf::off_type offset,
22                                                             std::ios_base::seekdir dir) {
23     std::streambuf::off_type next = std::streambuf::off_type(-1);
24     const std::ptrdiff_t size = std::ptrdiff_t(buffer_->size());
25     switch (dir) {
26         case std::ios_base::beg: {
27             next = offset;
28             break;
29         }
30         case std::ios_base::cur: {
31             next = std::streambuf::off_type(std::ptrdiff_t(current_ - start_)) + offset;
32             break;
33         }
34         case std::ios_base::end: {
35             next = std::streambuf::off_type(size) + offset;
36             break;
37         }
38         default:
39             break;
40     }
41     if (next < 0 || next >= std::streambuf::off_type(size)) {
42         return std::streambuf::pos_type(std::streambuf::off_type(-1));
43     }
44     current_ = start_ + offset;
45     setg(start_, current_, current_);
46     return std::streambuf::pos_type(current_ - start_);
47 }
48 
seekpos(std::streambuf::pos_type pos,std::ios_base::openmode which)49 std::streambuf::pos_type ReversedIMemoryStreamBuf::seekpos(std::streambuf::pos_type pos,
50                                                            std::ios_base::openmode which) {
51     if ((which & std::ios_base::in) == 0) {
52         return std::streambuf::pos_type(std::streambuf::off_type(-1));
53     }
54     return iseekoff(pos - std::streambuf::pos_type(std::streambuf::off_type(0)), std::ios::beg);
55 }
56 
showmanyc()57 std::streamsize ReversedIMemoryStreamBuf::showmanyc() {
58     std::ptrdiff_t n = end_ - current_;
59     std::streamsize max = std::numeric_limits<std::streamsize>::max();
60     return (n <= max ? std::streamsize(n) : max);
61 }
62 
read(char * pos)63 std::streambuf::int_type ReversedIMemoryStreamBuf::read(char* pos) {
64     std::ptrdiff_t offset = pos - start_;
65     // offset from the end
66     std::ptrdiff_t offsetFromEnd = buffer_->size() - offset - 1;
67     return traits_type::to_int_type(start_[offsetFromEnd]);
68 }
69 
pbackfail(std::streambuf::int_type ch)70 std::streambuf::int_type ReversedIMemoryStreamBuf::pbackfail(std::streambuf::int_type ch) {
71     if (current_ == end_ || (ch != traits_type::eof() && ch != read(current_ - 1))) {
72         return traits_type::eof();
73     }
74     --current_;
75     setg(start_, current_, current_);
76     return ch;
77 }
78 
underflow()79 std::streambuf::int_type ReversedIMemoryStreamBuf::underflow() {
80     if (current_ == end_) {
81         return traits_type::eof();
82     }
83     return traits_type::to_int_type(read(current_));
84 }
85 
uflow()86 std::streambuf::int_type ReversedIMemoryStreamBuf::uflow() {
87     if (current_ == end_) {
88         return traits_type::eof();
89     }
90     auto ch = read(current_);
91     ++current_;
92     setg(start_, current_, current_);
93     return ch;
94 }
95 
xsgetn(char * s,std::streamsize n)96 std::streamsize ReversedIMemoryStreamBuf::xsgetn(char* s, std::streamsize n) {
97     const ptrdiff_t remaining = (static_cast<char*>(buffer_->data()) + buffer_->size()) - current_;
98     n = std::min(n, remaining);
99     if (n <= 0) {
100         return std::streamsize(0);
101     }
102     std::ptrdiff_t offset = current_ - start_;
103     std::ptrdiff_t pos = buffer_->size() - 1 - offset;
104     for (std::streamsize i = 0; i < n; i++) {
105         s[i] = start_[pos - i];
106     }
107     current_ += n;
108     setg(start_, current_, current_);
109     return n;
110 }
111 
ReversedIMemoryStream(const std::shared_ptr<MemoryBuffer> & buffer)112 ReversedIMemoryStream::ReversedIMemoryStream(const std::shared_ptr<MemoryBuffer>& buffer) noexcept
113     : std::istream(nullptr), streambuf(buffer) {
114     rdbuf(&streambuf);
115 }
116 } // namespace inmemoryfs
117