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