Stroika Library 3.0d23
 
Loading...
Searching...
No Matches
ExternallyOwnedSpanInputStream.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
6#include "Stroika/Foundation/Memory/Common.h"
8
9#include "InternallySynchronizedInputStream.h"
10
11namespace Stroika::Foundation::Streams::ExternallyOwnedSpanInputStream {
12
13 namespace Private_ {
14 template <typename ELEMENT_TYPE>
15 class Rep_ : public InputStream::IRep<ELEMENT_TYPE> {
16 public:
17 Rep_ () = delete;
18 Rep_ (const Rep_&) = delete;
19 template <size_t EXTENT_T>
20 Rep_ (span<const ELEMENT_TYPE, EXTENT_T> s)
21 : fStart_{s.data ()}
22 , fEnd_{fStart_ + s.size ()}
23 , fCursor_{fStart_}
24 {
25 }
26
27 public:
28 nonvirtual Rep_& operator= (const Rep_&) = delete;
29
30 private:
31 bool fIsOpenForRead_{true};
32
33 protected:
34 virtual bool IsSeekable () const override
35 {
36 return true;
37 }
38 virtual void CloseRead () override
39 {
40 fIsOpenForRead_ = false;
41 Ensure (not IsOpenRead ());
42 }
43 virtual bool IsOpenRead () const override
44 {
45 return fIsOpenForRead_;
46 }
47 virtual optional<size_t> AvailableToRead () override
48 {
49 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
50 Require (IsOpenRead ());
51 Ensure (fEnd_ >= fCursor_);
52 return static_cast<size_t> (fEnd_ - fCursor_);
53 }
54 virtual optional<SeekOffsetType> RemainingLength () override
55 {
56 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
57 Require (IsOpenRead ());
58 Ensure (fEnd_ >= fCursor_);
59 return static_cast<size_t> (fEnd_ - fCursor_);
60 }
61 virtual optional<span<ELEMENT_TYPE>> Read (span<ELEMENT_TYPE> intoBuffer, [[maybe_unused]] NoDataAvailableHandling blockFlag) override
62 {
63 Require (not intoBuffer.empty ());
64 Require (IsOpenRead ());
65 size_t nRequested = intoBuffer.size ();
66 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
67 Assert ((fStart_ <= fCursor_) and (fCursor_ <= fEnd_));
68 size_t nAvail = fEnd_ - fCursor_;
69 size_t nCopied = min (nAvail, nRequested);
70 copy (fCursor_, fCursor_ + nCopied, intoBuffer.data ());
71 fCursor_ += nCopied;
72 return intoBuffer.subspan (0, nCopied); // this can be empty on EOF
73 }
74 virtual SeekOffsetType GetReadOffset () const override
75 {
76 Debug::AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
77 Require (IsOpenRead ());
78 return fCursor_ - fStart_;
79 }
80 virtual SeekOffsetType SeekRead (Whence whence, SignedSeekOffsetType offset) override
81 {
82 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
83 Require (IsOpenRead ());
84 static const auto kRangeException_ = range_error{"seek"};
85 switch (whence) {
86 case eFromStart: {
87 if (offset < 0) [[unlikely]] {
88 Execution::Throw (kRangeException_);
89 }
90 if (offset > (fEnd_ - fStart_)) [[unlikely]] {
91 Execution::Throw (kRangeException_);
92 }
93 fCursor_ = fStart_ + offset;
94 } break;
95 case eFromCurrent: {
96 Streams::SeekOffsetType curOffset = fCursor_ - fStart_;
97 Streams::SignedSeekOffsetType newOffset = curOffset + offset;
98 if (newOffset < 0) [[unlikely]] {
99 Execution::Throw (kRangeException_);
100 }
101 if (newOffset > (fEnd_ - fStart_)) [[unlikely]] {
102 Execution::Throw (kRangeException_);
103 }
104 fCursor_ = fStart_ + newOffset;
105 } break;
106 case eFromEnd: {
107 Streams::SignedSeekOffsetType newOffset = (fEnd_ - fStart_) + offset;
108 if (newOffset < 0) [[unlikely]] {
109 Execution::Throw (kRangeException_);
110 }
111 if (newOffset > (fEnd_ - fStart_)) [[unlikely]] {
112 Execution::Throw (kRangeException_);
113 }
114 fCursor_ = fStart_ + newOffset;
115 } break;
116 }
117 Ensure ((fStart_ <= fCursor_) and (fCursor_ <= fEnd_));
118 return fCursor_ - fStart_;
119 }
120
121 private:
122 const ELEMENT_TYPE* fStart_;
123 const ELEMENT_TYPE* fEnd_;
124 const ELEMENT_TYPE* fCursor_;
125 qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS_VCFORCE Debug::AssertExternallySynchronizedMutex fThisAssertExternallySynchronized_;
126 };
127 }
128
129 /*
130 ********************************************************************************
131 ************ Streams::ExternallyOwnedSpanInputStream<ELEMENT_TYPE> *************
132 ********************************************************************************
133 */
134 template <typename ELEMENT_TYPE, Memory::ISpanBytesCastable<span<const ELEMENT_TYPE>> FROM_SPAN>
135 Ptr<ELEMENT_TYPE> New (FROM_SPAN s)
136 {
137 return Ptr<ELEMENT_TYPE>{Memory::MakeSharedPtr<Private_::Rep_<ELEMENT_TYPE>> (Memory::SpanBytesCast<span<const ELEMENT_TYPE>> (s))};
138 }
139 template <typename ELEMENT_TYPE, Memory::ISpanBytesCastable<span<const ELEMENT_TYPE>> FROM_SPAN>
140 inline Ptr<ELEMENT_TYPE> New (Execution::InternallySynchronized internallySynchronized, FROM_SPAN s)
141 {
142 switch (internallySynchronized) {
143 case Execution::eInternallySynchronized:
144 return InternallySynchronizedInputStream::New<Private_::Rep_<ELEMENT_TYPE>> ({}, Memory::SpanBytesCast<span<const ELEMENT_TYPE>> (s));
145 case Execution::eNotKnownInternallySynchronized:
146 return New<ELEMENT_TYPE> (s);
147 default:
149 return nullptr;
150 }
151 }
152
153}
#define RequireNotReached()
Definition Assertions.h:386
#define qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS_VCFORCE
[[msvc::no_unique_address]] isn't always broken in MSVC. Annotate with this on things where its not b...
Definition StdCompat.h:445
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...
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