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>
241 ELEMENT_TYPE ignored{};
242 Require (this->IsSeekable ());
244 [[maybe_unused]]
auto&& cleanup =
Execution::Finally ([&,
this] ()
noexcept { this->Seek (saved); });
245 optional<span<ELEMENT_TYPE>> o = this->ReadNonBlocking (span{&ignored, 1});
248 return not o.has_value ();
260 template <
typename ELEMENT_TYPE>
261 inline optional<size_t> InputStream::Ptr<ELEMENT_TYPE>::ReadNonBlocking ()
const
264 return AvailableToRead ();
266 template <
typename ELEMENT_TYPE>
267 inline optional<size_t> InputStream::Ptr<ELEMENT_TYPE>::ReadNonBlocking (ElementType* intoStart, ElementType* intoEnd)
const
271 return this->Read (span{intoStart, intoEnd}, NoDataAvailableHandling::eDontBlock).size ();
280 template <
typename ELEMENT_TYPE>
281 template <
typename POD_TYPE>
283 requires (same_as<ELEMENT_TYPE,
byte> and is_standard_layout_v<POD_TYPE>)
286 return this->ReadRaw (span{&tmp, 1})[0];
288 template <
typename ELEMENT_TYPE>
289 template <
typename POD_TYPE>
291 requires (same_as<ELEMENT_TYPE, byte> and is_standard_layout_v<POD_TYPE>)
295 Require (intoBuffer.size () == 1 or this->IsSeekable ());
296 auto byteSpan = as_writable_bytes (intoBuffer);
297 size_t n{Read (byteSpan)};
298 if (n <
sizeof (POD_TYPE)) {
300 while (n <
sizeof (POD_TYPE)) {
301 auto ni = this->Read (byteSpan.subspan (n, sizeof (POD_TYPE) - n)).size ();
307 Assert (n ==
sizeof (POD_TYPE));
308 return intoBuffer.subspan (0, 1);
312 if (n %
sizeof (POD_TYPE) != 0) {
317 size_t nObjectsRead = n /
sizeof (POD_TYPE);
318 Assert (1 <= nObjectsRead and nObjectsRead <= intoBuffer.size ());
319 return intoBuffer.subspan (0, nObjectsRead);
322 template <
typename ELEMENT_TYPE>
324 requires (same_as<ELEMENT_TYPE,
Character>)
327 Require (this->IsSeekable ());
328 StringBuilder result;
333 return result.str ();
335 result.push_back (c);
337 return result.str ();
339 else if (c ==
'\r') {
340 c = this->ReadBlocking ().value_or (
Character{});
343 result.push_back (c);
346 this->Seek (eFromCurrent, -1);
348 return result.str ();
352 template <
typename ELEMENT_TYPE>
354 requires (same_as<ELEMENT_TYPE,
Character>)
358 if (this->IsSeekable ()) [[likely]] {
359 return Traversal::CreateGenerator<String> ([copyOfStream] () -> optional<String> {
372 StringBuilder result;
382 return make_tuple (result.str (), nullopt);
384 result.push_back (c);
386 return make_tuple (result.str (), nullopt);
388 else if (c ==
'\r') {
392 result.push_back (c);
393 return make_tuple (result.str (), nullopt);
396 return make_tuple (result.str (), c);
401 optional<Character> prefixLineChar;
402 return Traversal::CreateGenerator<String> ([readLine, copyOfStream, prefixLineChar] ()
mutable -> optional<String> {
403 tuple<String, optional<Character>> lineEtc = readLine (copyOfStream, prefixLineChar);
404 if (get<String> (lineEtc).empty ()) {
408 prefixLineChar = get<optional<Character>> (lineEtc);
409 return get<String> (lineEtc);
414 DISABLE_COMPILER_MSC_WARNING_START (6262)
415 template <typename ELEMENT_TYPE>
416 String InputStream::
Ptr<ELEMENT_TYPE>::ReadAll (
size_t upTo) const
417 requires (same_as<ELEMENT_TYPE,
Character>)
419#if USE_NOISY_TRACE_IN_THIS_MODULE_
424 size_t nEltsLeft = upTo;
425 while (nEltsLeft > 0) {
429 if (nEltsLeft < std::size (buf)) {
432 size_t n = ReadBlocking (span{s, e}).size ();
433 Assert (0 <= n and n <= nEltsLeft);
434 Assert (0 <= n and n <= std::size (buf));
439 Assert (n <= nEltsLeft);
441 result.
Append (span{s, n});
444#if USE_NOISY_TRACE_IN_THIS_MODULE_
445 DbgTrace (L
"Returning {} characters"_f, result.
size ());
449 DISABLE_COMPILER_MSC_WARNING_END (6262)
450 template <typename ELEMENT_TYPE>
451 template <typename ELEMENT_TYPE2,
size_t EXTENT2_T>
452 auto InputStream::Ptr<ELEMENT_TYPE>::ReadAll (span<ELEMENT_TYPE2, EXTENT2_T> intoBuffer) const -> span<ElementType>
453 requires (same_as<ELEMENT_TYPE, ELEMENT_TYPE2>)
456 Require (not intoBuffer.empty ());
467 size_t elementsRead{};
468 ElementType* intoEnd = intoBuffer.data () + intoBuffer.size ();
469 for (ElementType* readCursor = intoBuffer.data (); readCursor < intoEnd;) {
470 size_t eltsReadThisTime = ReadBlocking (span{readCursor, intoEnd}).size ();
471 if (eltsReadThisTime == 0) {
475 elementsRead += eltsReadThisTime;
476 readCursor += eltsReadThisTime;
478 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 >