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