Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
InputStream.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Streams_InputStream_h_
5#define _Stroika_Foundation_Streams_InputStream_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <memory>
10#include <optional>
11
12#include "Stroika/Foundation/Common/Common.h"
13#include "Stroika/Foundation/Memory/Common.h"
18
19/**
20 * \file
21 *
22 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
23 *
24 * TODO:
25 * @todo Consider making LineEnd format (LF,CR,CRLF, or Auto) an optional param to ReadLine().
26 * Then it would ONLY require Seekable() for CRLF or Auto.
27 *
28 * @todo Consider if IsAtEOF() should be added to the virtual rep? Easy, and can provide (current) default implementation. But
29 * putting it there allows it to be much cheaper and its called pretty often (avoid seek logic). Wouldn't change semantics (about possibly blocking).
30 */
31
33 class Character;
34 class String;
35}
36namespace Stroika::Foundation::Memory {
37 class BLOB;
38}
39
40namespace Stroika::Foundation::Streams::InputStream {
41
42 using Characters::Character;
43 using Characters::String;
44 using Traversal::Iterable;
45
46 template <typename ELEMENT_TYPE>
47 class IRep;
48
49 /**
50 * \em Design Overview
51 *
52 * o @See Streams::Ptr<T>
53 *
54 * o Nearly all read's on an InputStream::Ptr<T> are BLOCKING. If there is a desire to have a
55 * non-blocking read, then call ReadNonBlocking (). All operations block except ReadNonBlocking (),
56 * and Read () methods with NoDataAvailableHandling parameter.
57 *
58 * o EOF is handled by a return value of zero. Once EOF is returned - any subsequent
59 * calls to Read () will return EOF (unless some other mechanism is used to tweak
60 * the state of the object, like a mixed in Seekable class and calling SEEK, or a MemoryStream where
61 * someone writes more data to it).
62 *
63 * Seek called on an input stream that has already returned EOF, may cause
64 * subsequent Read() calls to NOT be at EOF.
65 *
66 * o Exceptions indicate something went wrong - like an IO error, or possibly in some cases
67 * a formatting effort (e.g. if the source is encrypted, and the stream is decrypting,
68 * then it might detect a format error and throw).
69 *
70 * o InputStream::Ptr and OutputStream may be logically be mixed together to make an
71 * input/output stream: @see InputOutputStream
72 *
73 * @see Stroika::Foundation::Streams::iostream for adapters to work with std::iostream.
74 *
75 * @see MemoryStream for most common stream applications.
76 *
77 * @see StreamReader for utility to more easily, and more efficiently, consume the contents
78 * of an input stream.
79 *
80 * @see ExternallyOwnedMemoryInputStream for a more efficient, but slightly less safe
81 * mapping to streams.
82 *
83 * o ReadString/Seekable/PutBack Design Choices:
84 * o Some common read methods with TextStreams (parsing) - involve some amount of lookahead.
85 * Lookahead COULD be implemented a number of ways:
86 * o Seek backwards after fetching
87 * o Special 'put back' variable/API - which allows you to put back either one,
88 * or a number of characters back into the input Q
89 * o A special proxy object which stores the extra data, and maintains the context
90 * of the state of pre-reading.
91 *
92 * Each of these approaches has some advantages and disadvantages. Just using Seek() is
93 * the simplest approach. IF all your streams support seeking, there is no reason for another
94 * mechanism. But we don't want to always require seeking.
95 *
96 * PutBack () is like Seek, but then the question is - do we support just a PutBack of
97 * one character? So only lookahead of one character? That deals with many cases, but not all.
98 * And how does it interact with Seek - if the stream happens to be seekable? And is the
99 * PutBack buffer stored in the letter or envelope class? If in Letter, that is extra work
100 * in every rep (barrier to providing your own stream subtypes). If in the envelope, it doesn't
101 * work intuitively if two variables have separate smart pointers to the same underlying stream.
102 * Reads and writes affect each other EXCPET for the putback buffer!
103 *
104 * A special Proxy object is a good choice - but requires the caller todo a lot of extra
105 * work. To some extent that can be automated by somewhat automatically managing
106 * the proxy storage object in the smart pointer, but that's a lot of work and concept
107 * for very little gain.
108 *
109 * In the end - at least for now - I've decided on KISS - ReadLine() simply requires it
110 * is Seekable. And there are plenty of wrapper stream classes you can use with any stream
111 * to make them Seekable.
112 *
113 * o BLOCKING/NON-BLOCKING Design Choices:
114 * Berkeley sockets have the same API, but a flag that turns the socket from blocking to non-blocking.
115 *
116 * This pattern is widely copied, and somewhat of a compelling default choice.
117 *
118 * But - it suffers from the grave flaw that when you write generic code or routines, you must write it
119 * to handle both blocking and non-blocking cases, and these are really quite different.
120 *
121 * Mostly - blocking is MUCH simpler to read/write/debug. But you NEED non-blocking sometimes for efficiency
122 * reasons (to manage progress through a long operation).
123 *
124 * Stroika Stream's approach to this is to essentially everywhere in the InputStream::Ptr API, have the methods
125 * take a flag indicating if the caller expects blocking or not (defaulting to blocking).
126 *
127 * This adds very little complexity to the implementation classes (reps) and essentially zero to the callers
128 * (since they default to blocking behavior).
129 *
130 * And with only modest effort (explicit flag in call) you can get the non-blocking behavior.
131 *
132 * One twist has todo with what todo in the non-blocking case when data isn't available. One
133 * choice would be to return optional (or some other flagging / sentinel approach) and the other is to throw.
134 * Throw behavior is much simpler to write code and reason about. Returning a flag/optional is possibly
135 * more efficient (depends - you have extra flag being copied around, but you avoid the cost of handling exceptions
136 * - which wins the performance balance depends on the costs of a throw, and the frequency of a throw.
137 *
138 * Stroika Streams generally use the throw (EWouldBlock) approach. However, in the 'Rep' classes, they use the
139 * return optional approach, and this is exposed through the ReadNonBlocking Ptr API. Plus they expose an
140 * AvailableToRead () API;
141 *
142 * So generally - the Stroika approach is that for the casual observer (defaults) - things just work with blocking
143 * reads, but if you need to do non-blocking reads, this is pretty straightforward.
144 *
145 * \note For better performance, but some slight usage restrictions, consider using @see StreamReader
146 *
147 * \note ***Cancelation Point***
148 * @todo not 100% sure we want to require this as part of API - but tentatively lets say
149 * All subtypes of InputStream () must have the Read (and related Peek etc) methods implementation be a cancelation point so that those reads can be aborted.
150 * @todo think out Seek () - not sure about this - but probably
151 */
152
153 /**
154 * \brief InputStream<>::Ptr is Smart pointer (with abstract Rep) class defining the interface to reading from
155 * a Stream source of data.
156 *
157 * @see InputStream<ELEMENT_TYPE>
158 *
159 * \note Since InputStream::Ptr<ELEMENT_TYPE> is a smart pointer, the constness of the methods depends on whether they modify the smart pointer itself, not
160 * the underlying thread object.
161 *
162 * \note \em Thread-Safety <a href="Thread-Safety.md#C++-Standard-Thread-Safety-For-Envelope-But-Ambiguous-Thread-Safety-For-Letter">C++-Standard-Thread-Safety-For-Envelope-But-Ambiguous-Thread-Safety-For-Letter/a>
163 */
164 template <typename ELEMENT_TYPE>
165 class Ptr : public Streams::Ptr<ELEMENT_TYPE> {
166 private:
167 using inherited = typename Streams::Ptr<ELEMENT_TYPE>;
168
169 public:
170 using ElementType = ELEMENT_TYPE;
171
172 public:
173 /**
174 * defaults to null (empty ())
175 *
176 * shared_ptr<IRep> rep is the underlying shared input Stream object.
177 */
178 Ptr () = default;
179 Ptr (nullptr_t);
180 Ptr (const Ptr&) = default;
181 Ptr (Ptr&&) noexcept = default;
182 Ptr (const shared_ptr<IRep<ELEMENT_TYPE>>& rep);
183 template <typename ASSTREAMABLE>
184 Ptr (ASSTREAMABLE&& src)
185 requires
186 // NOTE qCompilerAndStdLib_template_requires_doesnt_work_with_specialization_Buggy workaround NOT required DIRECTLY HERE but due to similar hack in Memory::BLOB::As()...
187#if qCompilerAndStdLib_template_requires_doesnt_work_with_specialization_Buggy
188 same_as<byte, ELEMENT_TYPE> and
189#endif
190 requires (ASSTREAMABLE) { src.template As<Ptr<ELEMENT_TYPE>> (); }
191
192#if qCompilerAndStdLib_template_requires_doesnt_work_with_specialization_Buggy
193 : inherited{src.template As<Ptr<ELEMENT_TYPE>> ()} {}
194#endif
195 ;
196
197 public:
198 /**
199 */
200 nonvirtual Ptr& operator= (Ptr&&) noexcept = default;
201 nonvirtual Ptr& operator= (const Ptr&) = default;
202
203 public:
204 /**
205 * Put the input stream in a state where it cannot be read from anymore.
206 * If argument 'reset' is true, this also clears the smart pointer (calls Stream<>::reset()).
207 *
208 * It is generally unneeded to ever call Close () - as streams are closed automatically when the final
209 * reference to them is released (smart ptr).
210 *
211 * But - this can be handy to signal to the reader from the stream (how this works depends on subtype) - that there
212 * will be no more reading done.
213 *
214 * \note Most calls on an InputStream after it is closed are illegal, and result in Require () errors. It is up
215 * to the caller/user of the shared output streams to assure they don't use them after being closed. Note - if that
216 * sounds hard its not: it naturally falls out of normal usage.
217 *
218 * The rationale is just that I can think of no useful case where a caller might want to allow writing after close, and
219 * have that translated into an exception, and this choice is more performant (and could be reversed more easily
220 * than the opposite policy if I change my mind).
221 *
222 * \note Close () - and IsOpen () are intentionally duplicated in InputStream () and OutputStream () classes. This is so
223 * you can close down the OutputStream side of an InputOutputStream, and leave open the InputStream side - so it sees EOF.
224 *
225 * \note When a subtype stream (like BufferedInputStream) aggregates another stream, it is left to that subclass
226 * whether or not closing the top level stream also Closes the sub-stream. Typically, if the class designer intends
227 * you to think of the ownership as 'aggregation' - close of this stream will close any aggregated streams, but
228 * if this class is designed to 'reference' other streams, it will not close them.
229 *
230 * See the stream documentation for that stream class to see how it handles Close.
231 *
232 * \note Since Stroika v3.0d12, it is legal to call Close () even when a stream is already closed, because it can make
233 * logic needlessly complex to only check in callers of Close () that the stream hasn't been closed.
234 */
235 nonvirtual void Close () const;
236 nonvirtual void Close (bool reset);
237
238 public:
239 /**
240 * Return true, unless a call to Close () has been done on the underlying stream (not just Ptr).
241 *
242 * \note InputStream and OutputStream (when mixed in InputOutputStream) have separate IsOpen/IsClosed flags, so you
243 * can call Close on the write side of the stream and still read from the InputStream side.
244 *
245 * @see Close ()
246 */
247 nonvirtual bool IsOpen () const;
248
249 public:
250 /**
251 * GetOffset () returns the currently seeked offset. This is the same as Seek (eFromCurrent, 0).
252 *
253 * \pre IsOpen ()
254 *
255 * \note does NOT require IsSeekable () so always must be supported by rep
256 */
257 nonvirtual SeekOffsetType GetOffset () const;
258
259 public:
260 /**
261 * The new position, measured in Stream element increments, is obtained by adding offset value to the position
262 * specified by whence.
263 *
264 * Seek () past the end of stream or before the start is legal (not assertion error) - but may result in an exception (possibly not until next read).
265 *
266 * Seek () returns the new resulting position (measured from the start of the stream - same as GetOffset).
267 *
268 * \pre IsSeekable ()
269 */
270 nonvirtual SeekOffsetType Seek (SeekOffsetType offset) const;
271 nonvirtual SeekOffsetType Seek (Whence whence, SignedSeekOffsetType offset) const;
272
273 public:
274 /**
275 * \brief returns nullopt if nothing known available, zero if known EOF, and any other number of elements (typically 1) if that number know to be available to read
276 *
277 * \see also (different) RemainingLength ()
278 */
279 nonvirtual optional<size_t> AvailableToRead () const;
280
281 public:
282 /**
283 * return nullopt if nothing available
284 * else do Read() of all elements available and return that buffer
285 */
286 nonvirtual optional<Memory::InlineBuffer<ELEMENT_TYPE>> ReadAllAvailable () const;
287
288 public:
289 /**
290 * \brief returns nullopt if not known (typical, and the default) - but sometimes it is known, and quite helpful)
291 *
292 * \note - Similar to AvailableToRead, but different. For example, on a socket-stream, you can tell how many bytes
293 * are available to read (buffered by kernel). But no guess about the remaining length of the stream (how many bytes
294 * will appear before end).
295 *
296 * But for a disk file, you MIGHT (not always - like unix special files) know the length of the file. This is for that case.
297 */
298 nonvirtual optional<SeekOffsetType> RemainingLength () const;
299
300 public:
301 /**
302 * \brief Read into data referenced by span argument - and using argument blocking strategy (default blocking)
303 *
304 * returns nullopt ONLY if blockFlag = eNonBlocking AND there is NO data available without blocking.
305 *
306 * a return of NOT missing, but an empty span implies EOF.
307 *
308 * BLOCKING until data is available, but can return with fewer elements than argument span-size
309 * without prejudice about how much more is available.
310 *
311 * \note It is legal to call Read () if its already returned EOF, but then it MUST return EOF again.
312 *
313 * \pre not intoBuffer.empty ()
314 *
315 * @see ReadAll () to read all the data from the stream at once.
316 *
317 * @see ReadBlocking () - often simplest to use API
318 * @see ReadOrThrow ()
319 * @see ReadNonBlocking ()
320 */
321 nonvirtual optional<span<ElementType>> Read (span<ElementType> intoBuffer, NoDataAvailableHandling blockFlag) const;
322
323 public:
324 /**
325 * \brief ReadBlocking () reads either a single element, or fills in argument intoBuffer - but never blocks (nor throws EWouldBlock)
326 *
327 * ReadBlocking ():
328 * Reads a single element (blocking as long as needed) - or nullopt when at EOF.
329 *
330 * ReadBlocking(span<ElementType> intoBuffer)
331 * fills in subspan with at least one element (or zero if at EOF)
332 *
333 * ReadBlocking(...ElementType upToSentinel) - reads one element at a time into intoBuffer, including copying the sentinel
334 * and returns the span of elements read (NOT including the sentinel). Could be the building block of something like ReadLine()...
335 */
336 nonvirtual optional<ElementType> ReadBlocking () const;
337 nonvirtual span<ElementType> ReadBlocking (span<ElementType> intoBuffer) const;
338 nonvirtual span<ElementType> ReadBlocking (Memory::InlineBuffer<ElementType>* intoBuffer, ElementType upToSentinel) const;
339
340 public:
341 /**
342 * \brief read into intoBuffer - returning nullopt if would block, and else returning subspan of input with read data present
343 *
344 * same as Read (intoBuffer, NoDataAvailableHandling::eDontBlock)
345 */
346 nonvirtual optional<span<ElementType>> ReadNonBlocking (span<ElementType> intoBuffer) const;
347
348 public:
349 /**
350 * \brief Read (either one or into argument span) and taking NoDataAvailableHandling blockFlag option arg), and throw if would block
351 *
352 * same as Read() APIs, but instead of returning optional, for cases where nullopt would be returned, throw EWouldBlock
353 *
354 * \note if blockFlag == eBlockIfNoDataAvailable, this amounts to *Read(...args), since it will never generate an
355 * eWouldBlock exception;
356 *
357 * when to use this variant? If implementing API where you are handed a blockFlag, but want to KISS, and
358 * just throw if EWouldBlock ..
359 */
360 nonvirtual span<ElementType> ReadOrThrow (span<ElementType> intoBuffer, NoDataAvailableHandling blockFlag) const;
361
362 public:
363 /**
364 * \brief block until one item available, read it and return it (seeking back before returning) - and returns nullopt for EOF.
365 *
366 * Same as ReadBlocking () - reading one element, but \pre IsSeekable, and seeks back to original position - nullopt implies
367 * \note PeekBlocking will block if no data available
368 *
369 * \pre IsSeekable ()
370 */
371 nonvirtual optional<ElementType> PeekBlocking () const;
372
373 public:
374 /**
375 * \brief check if the stream is currently at EOF
376 *
377 * \note - IsAtEOF/0 does a blocking Read () call.
378 * \note - IsAtEOF (eDontBlock) returns optional<bool> - nullopt if would block, and false if known not at EOF, and true if known EOF;
379 * this differs from most Stroika streams APIs - in that nullopt here means 'EWouldBlock';
380 *
381 * \pre IsSeekable ()
382 */
383 nonvirtual bool IsAtEOF () const;
384 nonvirtual optional<bool> IsAtEOF (NoDataAvailableHandling blockFlag) const;
385
386 public:
387 /**
388 * \brief Read a single (or span of) POD_TYPE objects, like with Read () - except always blocking, and treating stream of bytes as composing a single POD_TYPE object
389 *
390 * \note ReadRaw(span > 1 element) requires IsSeekable()
391 *
392 * \note If not enough data available to return a single POD_TYPE, EOFException will be thrown.
393 * \note Only defined on Binary Streams (InputStream::Ptr<byte>), but POD_TYPE can be any (is_pod) type.
394 * \note ReadRaw will read a whole number of records requested (> 0, seeking to adjust if necessary. but it may
395 * return any number (>=1 but <= size of input span).
396 * It may result in Seek being called to return a smaller number of records than requested.
397 *
398 * This API is always blocking (see ReadAll () for reasons why - need way to undo - seek or buffer - but may extend this API in the future).
399 */
400 template <typename POD_TYPE>
401 nonvirtual POD_TYPE ReadRaw () const
402 requires (same_as<ELEMENT_TYPE, byte> and is_standard_layout_v<POD_TYPE>);
403 template <typename POD_TYPE>
404 nonvirtual span<POD_TYPE> ReadRaw (span<POD_TYPE> intoBuffer) const
405 requires (same_as<ELEMENT_TYPE, byte> and is_standard_layout_v<POD_TYPE>);
406
407 public:
408 /**
409 * Readline looks for a trailing bare CR, or bare LF, or CRLF. It returns whatever line-terminator
410 * it encounters as part of the read line.
411 *
412 * ReadLine() will return an empty string iff EOF.
413 *
414 * \pre IsSeekable () to implement read-ahead required for CRLF mapping support
415 *
416 * This API is always blocking.
417 */
418 nonvirtual String ReadLine () const
419 requires (same_as<ELEMENT_TYPE, Character>);
420
421 public:
422 /**
423 * Returns Iterable<String> object, so you can
424 * write code:
425 * for (String line : stream.ReadLines ()) {
426 * }
427 *
428 * Like ReadLine(), the returned lines include trailing newlines/etc.
429 *
430 * However, UNLIKE ReadLine(), this function does NOT require the input stream be seekable!
431 *
432 * This API is always blocking.
433 */
434 nonvirtual Iterable<String> ReadLines () const
435 requires (same_as<ELEMENT_TYPE, Character>);
436
437 public:
438 /**
439 * ReadAll/size_t upTo
440 * Read from the current seek position, until EOF or upTo elements read (whichever comes first),
441 * and accumulate all of it into a String or BLOB (depending on stream type).
442 *
443 * Note - since the stream may not start at the beginning, this isn't necessarily ALL
444 * that was in the stream -just all that remains.
445 *
446 * Also - since upTo elements may be read before EOF, the stream may or may not be at the
447 * EOF state/position after ReadAll ().
448 *
449 * \pre upTo >= 1
450 *
451 * ReadAll/span<ElementType> intoBuffer
452 * Like Read, in that it reads all the elements that will fit into the range intoBuffer.
453 * However, this guarantees to read all the data that will fit before returning (Read () only
454 * guarantees to read at least one element).
455 *
456 * So this can be handy when you KNOW you have a buffer large enough to read all the data in
457 * the file, you can read without having to check the number of elements read and re-call Read().
458 *
459 * ReadAll will always return a subspan of intoBuffer (or empty).
460 *
461 * \pre intoEnd-intoStart >= 1
462 *
463 * \note ReadAll () will block if the stream is not KNOWN to be at EOF, and we just ran out of data. Use
464 * @see ReadNonBlocking () or Read (eDontBlock) to get non-blocking read behavior.
465 *
466 * \note ReadAll is ONLY available in a blocking form, because to handle to handle the non-blocking case
467 * we might need to either seek back, or have internal buffering to manage a partial read (could possibly
468 * extend API like this in the future but no need).
469 *
470 * @see ReadRaw()
471 * @see Streams::CopyAll()
472 *
473 * \note ReadAll -> BLOB <template> in cpp file and templated just due to deadly include embrace.
474 * cannot get working with require() since to be in CPP file, need to use template
475 * specialization, and cannot specify requires with template specialization (or I cannot figure out how)
476 */
477 nonvirtual String ReadAll (size_t upTo = numeric_limits<size_t>::max ()) const
478 requires (same_as<ELEMENT_TYPE, Character>);
479 nonvirtual Memory::BLOB ReadAll (size_t upTo = numeric_limits<size_t>::max ()) const
480#if 0
481 requires (same_as<ELEMENT_TYPE, byte>) // get compile error on vis studio when we specailize - not sure if LGP bug or compiler bug...--LGP 2023-12-28
482#endif
483 ;
484 template <typename ELEMENT_TYPE2, size_t EXTENT2_T>
485 nonvirtual span<ElementType> ReadAll (span<ELEMENT_TYPE2, EXTENT2_T> intoBuffer) const
486 requires (same_as<ELEMENT_TYPE, ELEMENT_TYPE2>);
487
488 public:
489 /**
490 * \brief access to underlying stream smart pointer
491 */
492 nonvirtual shared_ptr<IRep<ELEMENT_TYPE>> GetSharedRep () const;
493
494 public:
495 /**
496 * \pre *this != nullptr
497 */
498 nonvirtual const IRep<ELEMENT_TYPE>& GetRepConstRef () const;
499
500 public:
501 /**
502 * \pre *this != nullptr
503 */
504 nonvirtual IRep<ELEMENT_TYPE>& GetRepRWRef () const;
505
506 public:
507 [[deprecated ("Since Stroika v3.0d14 use ReadBlocking().value_or(0) typically")]] Characters::Character
508 ReadCharacter (NoDataAvailableHandling blockFlag = NoDataAvailableHandling::eBlockIfNoDataAvailable) const
509 requires (same_as<ELEMENT_TYPE, Characters::Character>)
510 {
512 if (ReadOrThrow (span{&c, 1}, blockFlag).size () == 1) [[likely]] {
513 return c;
514 }
515 return '\0';
516 }
517 [[deprecated ("Since Stroika v3.0d14 Instead call ReadBlocking()to get nullopt result for EOF - or ReadOrThrow() if ever called "
518 "with eNonBlocking")]] optional<ElementType>
519 Read (NoDataAvailableHandling blockFlag = NoDataAvailableHandling::eBlockIfNoDataAvailable) const
520 {
521 ELEMENT_TYPE b; // intentionally uninitialized in case POD-type, filled in by Read or not used
522 return this->ReadOrThrow (span{&b, 1}, blockFlag).size () == 0 ? optional<ElementType>{} : b;
523 }
524 [[deprecated ("Since Stroika v3.0d14 Consider PeekBlocking")]] optional<ElementType>
525 Peek (NoDataAvailableHandling blockFlag = NoDataAvailableHandling::eBlockIfNoDataAvailable) const
526 {
527 Debug::AssertExternallySynchronizedMutex::ReadContext declareContext{this->_fThisAssertExternallySynchronized};
528 Require (this->IsSeekable ());
529 Require (IsOpen ());
530 SeekOffsetType saved = GetOffset ();
531 auto result = this->Read (blockFlag);
532 this->Seek (saved);
533 return result;
534 }
535 [[deprecated ("Since Stroika v3.0d14 maybe")]] span<ElementType>
536 Peek (span<ElementType> intoBuffer, NoDataAvailableHandling blockFlag = NoDataAvailableHandling::eBlockIfNoDataAvailable) const
537 {
538 Debug::AssertExternallySynchronizedMutex::ReadContext declareContext{this->_fThisAssertExternallySynchronized};
539 Require (this->IsSeekable ());
540 Require (IsOpen ());
541 SeekOffsetType saved = GetOffset ();
542 auto result = this->Read (intoBuffer, blockFlag);
543 this->Seek (saved);
544 return result;
545 }
546 [[deprecated ("Since Stroika v3.0d5 use IsDataAvailableToRead ()")]] optional<size_t> ReadNonBlocking () const;
547 [[deprecated ("Since Stroika v3.0d5 use Read (span, NoDataAvailableHandling::eDontBlock )")]] optional<size_t>
548 ReadNonBlocking (ElementType* intoStart, ElementType* intoEnd) const;
549 [[deprecated ("Since Strokka v3.0d5 deprecated since not widely used and very specific purpose and directly implementingable given "
550 "apis")]] SeekOffsetType
551 GetOffsetToEndOfStream () const
552 {
553 Debug::AssertExternallySynchronizedMutex::ReadContext declareContext{this->_fThisAssertExternallySynchronized};
554 Require (IsOpen ());
555 SeekOffsetType savedReadFrom = GetOffset ();
556 SeekOffsetType size = Seek (eFromEnd, 0);
557 Seek (eFromStart, savedReadFrom);
558 Assert (size >= savedReadFrom);
559 size -= savedReadFrom;
560 return size;
561 }
562 [[deprecated ("Since Stroika v3.0d5 use span overload")]] size_t Read (ElementType* intoStart, ElementType* intoEnd) const
563 {
564 return Read (span{intoStart, intoEnd}).size ();
565 }
566 [[deprecated ("Since Stroika v3.0d5 use span overload")]] size_t Peek (ElementType* intoStart, ElementType* intoEnd) const
567 {
568 return Peek (span{intoStart, intoEnd}).size ();
569 }
570 template <typename POD_TYPE>
571 [[deprecated ("Since Stroika v3.0d5 use span overload")]] void ReadRaw (POD_TYPE* start, POD_TYPE* end) const
572 requires (same_as<ELEMENT_TYPE, byte> and is_standard_layout_v<POD_TYPE>)
573 {
574 ReadRaw (span{start, end});
575 }
576 [[deprecated ("Since Stroika v3.0d5 use span overload")]] size_t ReadAll (ElementType* intoStart, ElementType* intoEnd) const
577 {
578 return ReadAll (span{intoStart, intoEnd}).size ();
579 }
580 };
581
582 /**
583 * \note \em Thread-Safety <a href="Thread-Safety.md#Thread-Safety-Rules-Depends-On-Subtype">Thread-Safety-Rules-Depends-On-Subtype/a>
584 *
585 */
586 template <typename ELEMENT_TYPE>
587 class IRep : public Streams::IRep<ELEMENT_TYPE> {
588 public:
589 using ElementType = ELEMENT_TYPE;
590
591 public:
592 IRep () = default;
593 IRep (const IRep&) = delete;
594
595 public:
596 virtual ~IRep () = default;
597
598 public:
599 nonvirtual IRep& operator= (const IRep&) = delete;
600
601 public:
602 /**
603 * May (but typically not) called before destruction. If called, \pre no other read or seek etc operations.
604 *
605 * \note - 'Require (IsOpen()) automatically checked in Ptr wrappers for things like Read, so subclassers don't need to
606 * do that in implementing reps, but probably good docs/style todo in both places.'
607 *
608 * \note this could have just be called 'close' but we want to be able to mix InputStream::IRep and OutputStream::IRep without conflict.
609 */
610 virtual void CloseRead () = 0;
611
612 public:
613 /**
614 * return true iff CloseRead () has not been called (cannot construct closed stream)
615 *
616 * \note this could have just be called 'IsOpen' but we want to be able to mix InputStream::IRep and OutputStream::IRep without conflict.
617 */
618 virtual bool IsOpenRead () const = 0;
619
620 public:
621 /**
622 * \note this could have just be called 'GetOffset' but we want to be able to mix InputStream::IRep and OutputStream::IRep without conflict.
623 */
624 virtual SeekOffsetType GetReadOffset () const = 0;
625
626 public:
627 /*
628 * \pre IsSeekable ()
629 *
630 * \note this could have just be called 'Seek' but we want to be able to mix InputStream::IRep and OutputStream::IRep without conflict.
631 *
632 * \note if not seekable (what method) - default does AssertNotImplemented (); so must override iff IsSeekable
633 */
634 virtual SeekOffsetType SeekRead (Whence whence, SignedSeekOffsetType offset);
635
636 public:
637 /**
638 * \brief returns nullopt if nothing known available, zero if known EOF, and any other number of elements (typically 1) if that number know to be available to read
639 *
640 * Default implementation - if seekable - does a read, and then seeks back, so flexible, but fairly inefficient.
641 * Subclassers MUST re-implement this function if not IsSeekable (); and should re-implement for efficiency sake.
642 */
643 virtual optional<size_t> AvailableToRead ();
644
645 public:
646 /**
647 * \brief returns nullopt if not known (typical, and the default) - but sometimes it is known, and quite helpful)
648 */
649 virtual optional<SeekOffsetType> RemainingLength ();
650
651 public:
652 /**
653 * incoming intoBuffer must be a valid, non-empty span of elements (to be overwritten).
654 *
655 * Returns empty span iff EOF, and otherwise intoBuffer.subspan(0,number of ELEMENT_TYPE elements read).
656 * BLOCKING until data is available, but can return with fewer bytes than bufSize
657 * without prejudice about how much more is available.
658 *
659 * Blocking:
660 * o If blockFlag == eBlockIfNoDataAvailable, always blocks until data available and returns non-nullopt span
661 * o if blockFlag == eDontBlock, will return nullopt if would block, and else number of elements read
662 * In EITHER case, NEVER throws EWouldBlock (can throw other stuff). That is done by Ptr wrapper.
663 */
664 virtual optional<span<ElementType>> Read (span<ElementType> intoBuffer, NoDataAvailableHandling blockFlag) = 0;
665 };
666
667}
668
669/*
670 ********************************************************************************
671 ***************************** Implementation Details ***************************
672 ********************************************************************************
673 */
674#include "InputStream.inl"
675
676#endif /*_Stroika_Foundation_Streams_InputStream_h_*/
NoDataAvailableHandling
If eDontBlock passed to most Stream APIs, then when the code would do a blocking read,...
Definition Stream.h:90
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
shared_lock< const AssertExternallySynchronizedMutex > ReadContext
Instantiate AssertExternallySynchronizedMutex::ReadContext to designate an area of code where protect...
virtual SeekOffsetType GetReadOffset() const =0
virtual optional< span< ElementType > > Read(span< ElementType > intoBuffer, NoDataAvailableHandling blockFlag)=0
virtual optional< SeekOffsetType > RemainingLength()
returns nullopt if not known (typical, and the default) - but sometimes it is known,...
virtual optional< size_t > AvailableToRead()
returns nullopt if nothing known available, zero if known EOF, and any other number of elements (typi...
InputStream<>::Ptr is Smart pointer (with abstract Rep) class defining the interface to reading from ...
nonvirtual String ReadAll(size_t upTo=numeric_limits< size_t >::max()) const
nonvirtual optional< ElementType > ReadBlocking() const
ReadBlocking () reads either a single element, or fills in argument intoBuffer - but never blocks (no...
nonvirtual optional< size_t > AvailableToRead() const
returns nullopt if nothing known available, zero if known EOF, and any other number of elements (typi...
nonvirtual optional< Memory::InlineBuffer< ELEMENT_TYPE > > ReadAllAvailable() const
nonvirtual SeekOffsetType Seek(SeekOffsetType offset) const
nonvirtual bool IsAtEOF() const
check if the stream is currently at EOF
nonvirtual Iterable< String > ReadLines() const
nonvirtual SeekOffsetType GetOffset() const
nonvirtual optional< span< ElementType > > Read(span< ElementType > intoBuffer, NoDataAvailableHandling blockFlag) const
Read into data referenced by span argument - and using argument blocking strategy (default blocking)
nonvirtual POD_TYPE ReadRaw() const
Read a single (or span of) POD_TYPE objects, like with Read () - except always blocking,...
nonvirtual optional< ElementType > PeekBlocking() const
block until one item available, read it and return it (seeking back before returning) - and returns n...
nonvirtual optional< span< ElementType > > ReadNonBlocking(span< ElementType > intoBuffer) const
read into intoBuffer - returning nullopt if would block, and else returning subspan of input with rea...
nonvirtual shared_ptr< IRep< ELEMENT_TYPE > > GetSharedRep() const
access to underlying stream smart pointer
nonvirtual optional< SeekOffsetType > RemainingLength() const
returns nullopt if not known (typical, and the default) - but sometimes it is known,...
nonvirtual span< ElementType > ReadOrThrow(span< ElementType > intoBuffer, NoDataAvailableHandling blockFlag) const
Read (either one or into argument span) and taking NoDataAvailableHandling blockFlag option arg),...
nonvirtual const IRep< ELEMENT_TYPE > & GetRepConstRef() const
nonvirtual IRep< ELEMENT_TYPE > & GetRepRWRef() const
A Streams::Ptr<ELEMENT_TYPE> is a smart-pointer to a stream of elements of type T.
Definition Stream.h:170
nonvirtual void reset() noexcept
Definition Stream.inl:50
nonvirtual bool IsSeekable() const
Returns true iff this object was constructed with a seekable input stream rep.
Definition Stream.inl:44
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237