Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
InputSubStream.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "InternallySynchronizedInputStream.h"
7
8namespace Stroika::Foundation::Streams::InputSubStream {
9
10 namespace Private_ {
11 template <typename ELEMENT_TYPE>
12 class Rep_ : public InputStream::IRep<ELEMENT_TYPE> {
13 public:
14 Rep_ (const typename InputStream::Ptr<ELEMENT_TYPE>& realIn, const optional<SeekOffsetType>& start, const optional<SeekOffsetType>& end)
15 : fRealIn_{realIn}
16 , fOffsetMine2Real_{start.value_or (realIn.GetOffset ())}
17 , fForcedEndInReal_{end}
18 {
19 if (start) {
20 // seek up to zero point, to begin with, avoiding ambiguity about when this gets done (could be done lazily as well, but I think behavior less clear then)
21 if (fRealIn_.IsSeekable ()) {
22 fRealIn_.Seek (Whence::eFromStart, *start);
23 }
24 else {
25 // else read to advance, and silently ignore if already past start. That might make sense? and at any rate is well defined
26 SeekOffsetType realSeekOffset = realIn.GetOffset ();
27 if (realSeekOffset < *start) {
28 Assert (*start - realSeekOffset < sizeof (size_t)); // NYI crazy corner case
29 Memory::StackBuffer<ELEMENT_TYPE> buf;
30 if constexpr (is_trivially_copyable_v<ELEMENT_TYPE>) {
31 buf.resize_uninitialized (static_cast<size_t> (*start - realSeekOffset));
32 }
33 else {
34 buf.resize (static_cast<size_t> (*start - realSeekOffset));
35 }
36 (void)realIn.ReadAll (span{buf}); // read exactly that many elements, and drop them on the floor
37 }
38 }
39 }
40 }
41 Rep_ (const Rep_&) = delete;
42 Rep_ () = delete;
43 virtual bool IsSeekable () const override
44 {
45 return fRealIn_.IsSeekable ();
46 }
47 virtual void CloseRead () override
48 {
49 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
50 if (IsOpenRead ()) {
51 fRealIn_.Close ();
52 }
53 Assert (fRealIn_ == nullptr);
54 Ensure (not IsOpenRead ());
55 }
56 virtual bool IsOpenRead () const override
57 {
58 return fRealIn_ != nullptr;
59 }
60 virtual SeekOffsetType GetReadOffset () const override
61 {
63 Require (IsOpenRead ());
64 SeekOffsetType realOffset = fRealIn_.GetOffset ();
65 ValidateRealOffset_ (realOffset);
66 return realOffset - fOffsetMine2Real_;
67 }
68 virtual SeekOffsetType SeekRead (Whence whence, SignedSeekOffsetType offset) override
69 {
71 Require (IsOpenRead ());
72 if (fForcedEndInReal_) {
73 SignedSeekOffsetType effectiveRealTarget;
74 switch (whence) {
75 case eFromCurrent:
76 effectiveRealTarget = fRealIn_.GetOffset () + offset;
77 break;
78 case eFromStart:
79 effectiveRealTarget = fOffsetMine2Real_ + offset;
80 break;
81 case eFromEnd:
82 if (fForcedEndInReal_) {
83 // Don't go to REAL end - that's likely out of range, and not what caller meant
84 effectiveRealTarget = *fForcedEndInReal_;
85 }
86 else {
87 auto getOffsetToEndOfStream = [] (typename InputStream::Ptr<ELEMENT_TYPE> in) {
88 SeekOffsetType savedReadFrom = in.GetOffset ();
89 SeekOffsetType size = in.Seek (eFromEnd, 0);
90 in.Seek (eFromStart, savedReadFrom);
91 Assert (size >= savedReadFrom);
92 size -= savedReadFrom;
93 return size;
94 };
95 effectiveRealTarget = fRealIn_.GetOffset () + getOffsetToEndOfStream (fRealIn_) + offset;
96 }
97 break;
98 default:
99 effectiveRealTarget = 0; // silence warning
101 }
102 ValidateRealOffset_ (effectiveRealTarget);
103 SignedSeekOffsetType result = fRealIn_.Seek (eFromStart, effectiveRealTarget);
104 ValidateRealOffset_ (result);
105 return result - fOffsetMine2Real_;
106 }
107 else {
108 return fRealIn_.Seek (whence, offset + fOffsetMine2Real_) - fOffsetMine2Real_;
109 }
110 }
111 virtual optional<size_t> AvailableToRead () override
112 {
113 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
114 Require (IsOpenRead ());
115 SeekOffsetType myOffset = fRealIn_.GetOffset ();
116 if (fForcedEndInReal_ and myOffset >= *fForcedEndInReal_) { // could be past end if through another non-substream Ptr we read past
117 return 0;
118 }
119 // otherwise, our answer is same as answer from underlying stream (since we do no buffering)
120 return fRealIn_.AvailableToRead (); // @todo nechnically maybe wrong, in may suggest we can read more than we have but not worth fix cuz can cause no problems I'm aware of
121 }
122 virtual optional<SeekOffsetType> RemainingLength () override
123 {
125 return nullopt; // sb pretty easy
126 }
127 virtual optional<span<ELEMENT_TYPE>> Read (span<ELEMENT_TYPE> intoBuffer, NoDataAvailableHandling blockFlag) override
128 {
129 Require (not intoBuffer.empty ());
130 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
131 Require (IsOpenRead ());
132 if (fForcedEndInReal_) {
133 // @todo clean this code up for switch to spans - simplify!
134 // adjust intoEnd to accomodate shortened stream
135 SeekOffsetType curReal = fRealIn_.GetOffset ();
136 SeekOffsetType maxNewReal = curReal + intoBuffer.size ();
137 if (maxNewReal > *fForcedEndInReal_) {
138 if (curReal == *fForcedEndInReal_) {
139 return span<ELEMENT_TYPE>{}; // EOF
140 }
141 else {
142 ELEMENT_TYPE* newIntoEnd{intoBuffer.data () + *fForcedEndInReal_ - curReal};
143 Assert (newIntoEnd < intoBuffer.data () + intoBuffer.size ());
144 return fRealIn_.ReadOrThrow (span{intoBuffer.data (), newIntoEnd}, blockFlag);
145 }
146 }
147 }
148 return fRealIn_.Read (intoBuffer, blockFlag);
149 }
150
151 private:
152 nonvirtual void ValidateRealOffset_ (SignedSeekOffsetType offset) const
153 {
154 if (offset < static_cast<SignedSeekOffsetType> (fOffsetMine2Real_)) [[unlikely]] {
155 Execution::Throw (range_error ("offset before beginning"));
156 }
157 if (fForcedEndInReal_) {
158 if (offset > static_cast<SignedSeekOffsetType> (*fForcedEndInReal_)) [[unlikely]] {
159 Execution::Throw (EOFException::kThe);
160 }
161 }
162 }
163 typename InputStream::Ptr<ELEMENT_TYPE> fRealIn_;
164 SeekOffsetType fOffsetMine2Real_; // subtract from real offset to get our offset
165 optional<SeekOffsetType> fForcedEndInReal_;
166 [[no_unique_address]] Debug::AssertExternallySynchronizedMutex fThisAssertExternallySynchronized_;
167 };
168 }
169
170 /*
171 ********************************************************************************
172 ********************* Streams::InputSubStream::New *****************************
173 ********************************************************************************
174 */
175 template <typename ELEMENT_TYPE>
176 inline auto New (const typename InputStream::Ptr<ELEMENT_TYPE>& realIn, const optional<SeekOffsetType>& start,
177 const optional<SeekOffsetType>& end) -> Ptr<ELEMENT_TYPE>
178 {
179 return Ptr<ELEMENT_TYPE>{make_shared<Private_::Rep_<ELEMENT_TYPE>> (realIn, start, end)};
180 }
181 template <typename ELEMENT_TYPE>
182 inline auto New (Execution::InternallySynchronized internallySynchronized, const typename InputStream::Ptr<ELEMENT_TYPE>& realIn,
183 const optional<SeekOffsetType>& start, const optional<SeekOffsetType>& end) -> Ptr<ELEMENT_TYPE>
184 {
185 switch (internallySynchronized) {
186 case Execution::eInternallySynchronized:
187 return InternallySynchronizedInputStream::New<Private_::Rep_<ELEMENT_TYPE>> ({}, realIn, start, end);
188 case Execution::eNotKnownInternallySynchronized:
189 return New<ELEMENT_TYPE> (start, end);
190 }
191 }
192
193}
#define AssertNotImplemented()
Definition Assertions.h:401
#define RequireNotReached()
Definition Assertions.h:385
typename InputStream::Ptr< ELEMENT_TYPE > Ptr
InputSubStream is an InputStream::Ptr<ELEMENT_TYPE> which provides buffered access....
unique_lock< AssertExternallySynchronizedMutex > WriteContext
Instantiate AssertExternallySynchronizedMutex::WriteContext to designate an area of code where protec...
InputStream<>::Ptr is Smart pointer (with abstract Rep) class defining the interface to reading from ...
A Streams::Ptr<ELEMENT_TYPE> is a smart-pointer to a stream of elements of type T.
Definition Stream.h:170
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
Definition Throw.inl:43