8#include "Stroika/Foundation/Math/Common.h"
12namespace Stroika::Foundation::Streams::InputStream {
19 template <
typename ELEMENT_TYPE>
22 Require (this->IsSeekable ());
25 [[maybe_unused]]
auto&& cleanup =
Execution::Finally ([&,
this] ()
noexcept { this->SeekRead (eFromStart, offset); });
28 optional<span<ELEMENT_TYPE>> o = this->Read (span{elts}, NoDataAvailableHandling::eDontBlock);
29 return o ? o->size () : optional<size_t>{};
38 template <
typename ELEMENT_TYPE>
43 template <
typename ELEMENT_TYPE>
55 template <
typename ELEMENT_TYPE>
60 template <
typename ELEMENT_TYPE>
65#if !qCompilerAndStdLib_template_requires_doesnt_work_with_specialization_Buggy
66 template <
typename ELEMENT_TYPE>
67 template <
typename ASSTREAMABLE>
69 requires requires (ASSTREAMABLE) { src.template As<Ptr<ELEMENT_TYPE>> (); }
70 : inherited{src.template As<Ptr<ELEMENT_TYPE>> ()}
74 template <
typename ELEMENT_TYPE>
78 GetRepRWRef ().CloseRead ();
79 Ensure (not IsOpen ());
81 template <
typename ELEMENT_TYPE>
85 GetRepRWRef ().CloseRead ();
90 template <
typename ELEMENT_TYPE>
94 return GetRepConstRef ().IsOpenRead ();
96 template <
typename ELEMENT_TYPE>
99 return Debug::UncheckedDynamicPointerCast<IRep<ELEMENT_TYPE>> (inherited::GetSharedRep ());
101 template <
typename ELEMENT_TYPE>
104 return Debug::UncheckedDynamicCast<const IRep<ELEMENT_TYPE>&> (inherited::GetRepConstRef ());
106 template <
typename ELEMENT_TYPE>
109 return Debug::UncheckedDynamicCast<IRep<ELEMENT_TYPE>&> (inherited::GetRepRWRef ());
111 template <
typename ELEMENT_TYPE>
116 return GetRepConstRef ().GetReadOffset ();
118 template <
typename ELEMENT_TYPE>
121 Require (offset <
static_cast<SeekOffsetType> (numeric_limits<SignedSeekOffsetType>::max ()));
124 Require (this->IsSeekable ());
127 template <
typename ELEMENT_TYPE>
132 Require (this->IsSeekable ());
133 return GetRepRWRef ().SeekRead (whence, offset);
135 template <
typename ELEMENT_TYPE>
138 return GetRepRWRef ().AvailableToRead ();
140 template <
typename ELEMENT_TYPE>
143 if (
auto o = AvailableToRead ()) {
144 if (*o == 0) [[unlikely]] {
150 constexpr size_t kRoundUpTo_ = max<size_t> (1, 4 * 1024 /
sizeof (ELEMENT_TYPE));
152 span<ELEMENT_TYPE> r = this->ReadBlocking (span<ELEMENT_TYPE>{buf});
153 Assert (r.data () == buf.data ());
154 Assert (r.size () <= buf.size ());
155 buf.ShrinkTo (r.size ());
163 template <
typename ELEMENT_TYPE>
166 return GetRepRWRef ().RemainingLength ();
168 template <
typename ELEMENT_TYPE>
170 -> optional<span<ElementType>>
174 Require (not intoBuffer.empty ());
175 return GetRepRWRef ().Read (intoBuffer, blockFlag);
177 template <
typename ELEMENT_TYPE>
180 if (
auto o = Read (intoBuffer, blockFlag)) [[likely]] {
185 template <
typename ELEMENT_TYPE>
189 span<ElementType> r = ReadBlocking (span{&e, 1});
190 return r.empty () ? optional<ElementType>{} : e;
192 template <
typename ELEMENT_TYPE>
195 return Memory::ValueOf (Read (intoBuffer, NoDataAvailableHandling::eBlockIfNoDataAvailable));
197 template <
typename ELEMENT_TYPE>
201 Require (intoBuffer->size () == 0);
202 while (
auto oe = ReadBlocking ()) {
203 intoBuffer->push_back (*oe);
204 if (*oe == upToSentinel) {
205 return span{intoBuffer->data (), intoBuffer->size () - 1};
208 return span{intoBuffer->data (), intoBuffer->size ()};
210 template <
typename ELEMENT_TYPE>
215 Require (not intoBuffer.empty ());
216 return GetRepRWRef ().Read (intoBuffer, NoDataAvailableHandling::eDontBlock);
218 template <
typename ELEMENT_TYPE>
222 Require (this->IsSeekable ());
225 auto result = this->ReadBlocking ();
229 template <
typename ELEMENT_TYPE>
232 return not PeekBlocking ().has_value ();
234 template <
typename ELEMENT_TYPE>
240 ELEMENT_TYPE ignored{};
241 Require (this->IsSeekable ());
243 auto o = this->ReadNonBlocking (span{&ignored, 1});
245 return not o.has_value ();
247 template <
typename ELEMENT_TYPE>
251 return AvailableToRead ();
253 template <
typename ELEMENT_TYPE>
258 return this->Read (span{intoStart, intoEnd}, NoDataAvailableHandling::eDontBlock).size ();
267 template <
typename ELEMENT_TYPE>
268 template <
typename POD_TYPE>
270 requires (same_as<ELEMENT_TYPE,
byte> and is_standard_layout_v<POD_TYPE>)
273 return this->ReadRaw (span{&tmp, 1})[0];
275 template <
typename ELEMENT_TYPE>
276 template <
typename POD_TYPE>
278 requires (same_as<ELEMENT_TYPE, byte> and is_standard_layout_v<POD_TYPE>)
282 Require (intoBuffer.size () == 1 or this->IsSeekable ());
283 auto byteSpan = as_writable_bytes (intoBuffer);
284 size_t n{Read (byteSpan)};
285 if (n <
sizeof (POD_TYPE)) {
287 while (n <
sizeof (POD_TYPE)) {
288 auto ni = this->Read (byteSpan.subspan (n, sizeof (POD_TYPE) - n)).size ();
294 Assert (n ==
sizeof (POD_TYPE));
295 return intoBuffer.subspan (0, 1);
299 if (n %
sizeof (POD_TYPE) != 0) {
304 size_t nObjectsRead = n /
sizeof (POD_TYPE);
305 Assert (1 <= nObjectsRead and nObjectsRead <= intoBuffer.size ());
306 return intoBuffer.subspan (0, nObjectsRead);
309 template <
typename ELEMENT_TYPE>
311 requires (same_as<ELEMENT_TYPE,
Character>)
314 Require (this->IsSeekable ());
315 StringBuilder result;
320 return result.str ();
322 result.push_back (c);
324 return result.str ();
326 else if (c ==
'\r') {
327 c = this->ReadBlocking ().value_or (
Character{});
330 result.push_back (c);
333 this->Seek (eFromCurrent, -1);
335 return result.str ();
339 template <
typename ELEMENT_TYPE>
341 requires (same_as<ELEMENT_TYPE,
Character>)
345 if (this->IsSeekable ()) [[likely]] {
346 return Traversal::CreateGenerator<String> ([copyOfStream] () -> optional<String> {
359 StringBuilder result;
369 return make_tuple (result.str (), nullopt);
371 result.push_back (c);
373 return make_tuple (result.str (), nullopt);
375 else if (c ==
'\r') {
379 result.push_back (c);
380 return make_tuple (result.str (), nullopt);
383 return make_tuple (result.str (), c);
388 optional<Character> prefixLineChar;
389 return Traversal::CreateGenerator<String> ([readLine, copyOfStream, prefixLineChar] ()
mutable -> optional<String> {
390 tuple<String, optional<Character>> lineEtc = readLine (copyOfStream, prefixLineChar);
391 if (get<String> (lineEtc).empty ()) {
395 prefixLineChar = get<optional<Character>> (lineEtc);
396 return get<String> (lineEtc);
401 DISABLE_COMPILER_MSC_WARNING_START (6262)
402 template <typename ELEMENT_TYPE>
403 String InputStream::
Ptr<ELEMENT_TYPE>::ReadAll (
size_t upTo) const
404 requires (same_as<ELEMENT_TYPE,
Character>)
406#if USE_NOISY_TRACE_IN_THIS_MODULE_
411 size_t nEltsLeft = upTo;
412 while (nEltsLeft > 0) {
416 if (nEltsLeft < Memory::NEltsOf (buf)) {
419 size_t n = ReadBlocking (span{s, e}).size ();
420 Assert (0 <= n and n <= nEltsLeft);
421 Assert (0 <= n and n <= Memory::NEltsOf (buf));
426 Assert (n <= nEltsLeft);
428 result.
Append (span{s, n});
431#if USE_NOISY_TRACE_IN_THIS_MODULE_
432 DbgTrace (L
"Returning {} characters"_f, result.
size ());
436 DISABLE_COMPILER_MSC_WARNING_END (6262)
437 template <typename ELEMENT_TYPE>
438 template <typename ELEMENT_TYPE2,
size_t EXTENT2_T>
439 auto InputStream::
Ptr<ELEMENT_TYPE>::ReadAll (span<ELEMENT_TYPE2, EXTENT2_T> intoBuffer) const -> span<ElementType>
440 requires (same_as<ELEMENT_TYPE, ELEMENT_TYPE2>)
443 Require (not intoBuffer.empty ());
454 size_t elementsRead{};
455 ElementType* intoEnd = intoBuffer.data () + intoBuffer.size ();
456 for (ElementType* readCursor = intoBuffer.data (); readCursor < intoEnd;) {
457 size_t eltsReadThisTime = ReadBlocking (span{readCursor, intoEnd}).size ();
458 if (eltsReadThisTime == 0) {
462 elementsRead += eltsReadThisTime;
463 readCursor += eltsReadThisTime;
465 return intoBuffer.subspan (0, elementsRead);
#define AssertNotImplemented()
NoDataAvailableHandling
If eDontBlock passed to most Stream APIs, then when the code would do a blocking read,...
@ eBlockIfNoDataAvailable
int64_t SignedSeekOffsetType
constexpr char32_t GetCharacterCode() const noexcept
Return the char32_t UNICODE code-point associated with this character.
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
nonvirtual size_t size() const noexcept
nonvirtual void Append(span< const CHAR_T > s)
String is like std::u32string, except it is much easier to use, often much more space efficient,...
shared_lock< const AssertExternallySynchronizedMutex > ReadContext
Instantiate AssertExternallySynchronizedMutex::ReadContext to designate an area of code where protect...
unique_lock< AssertExternallySynchronizedMutex > WriteContext
Instantiate AssertExternallySynchronizedMutex::WriteContext to designate an area of code where protec...
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
the stream ended prematurely, so that the requested operation could not be completed.
a read (typically) or write operation would have blocked, and the XXX flag was passed to a Stream rea...
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
auto Finally(FUNCTION &&f) -> Private_::FinallySentry< FUNCTION >