Stroika Library 3.0d23x
 
Loading...
Searching...
No Matches
IterableToInputStream.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
6
7namespace Stroika::Foundation::Streams::IterableToInputStream {
8
9 /*
10 ********************************************************************************
11 **************** Streams::IterableToInputStream::New ***************************
12 ********************************************************************************
13 */
14 template <typename ELEMENT_TYPE>
16 {
20 // Simply iterate over the 'iterable' of characters, but allow seekability (by saving original iteration start)
21 class IterableAdapterStreamRep_ final : public InputStream::IRep<ELEMENT_TYPE> {
22 public:
23 IterableAdapterStreamRep_ (const Traversal::Iterable<ELEMENT_TYPE>& src)
24 : fSource_{src}
25 , fSrcIter_{fSource_.begin ()}
26 {
27 }
28
29 private:
30 bool fIsOpen_{true};
31
32 protected:
33 virtual bool IsSeekable () const override
34 {
35 return true;
36 }
37 virtual void CloseRead () override
38 {
39 fIsOpen_ = false;
40 Ensure (not IsOpenRead ());
41 }
42 virtual bool IsOpenRead () const override
43 {
44 return fIsOpen_;
45 }
46 virtual optional<size_t> AvailableToRead () override
47 {
48 Require (IsOpenRead ());
49 AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
50 // usually just want to know 0 or >= 1, so don't bother computing full length
51 return fSrcIter_.Done () ? 0 : 1;
52 }
53 virtual optional<SeekOffsetType> RemainingLength () override
54 {
55 AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
56 Require (IsOpenRead ());
58 return nullopt; // pretty easy, but @todo
59 }
60 virtual optional<span<ELEMENT_TYPE>> Read (span<ELEMENT_TYPE> intoBuffer, [[maybe_unused]] NoDataAvailableHandling blockFlag) override
61 {
62 Require (not intoBuffer.empty ());
63 AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
64 Require (IsOpenRead ());
65 ELEMENT_TYPE* outI = intoBuffer.data ();
66 if (fPutBack_) {
67 *outI = *fPutBack_;
68 fPutBack_ = nullopt;
69 ++outI;
70 // fOffset_ doesn't take into account putback
71 }
72 for (; fSrcIter_ != fSource_.end () and outI != intoBuffer.data () + intoBuffer.size (); ++fSrcIter_, ++outI) {
73 *outI = *fSrcIter_;
74 ++fOffset_;
75 }
76 if (outI > intoBuffer.data ()) {
77 fPrevCharCached_ = *(outI - 1);
78 }
79 else {
80 fPrevCharCached_ = nullopt;
81 }
82 return intoBuffer.subspan (0, outI - intoBuffer.data ());
83 }
84 virtual SeekOffsetType GetReadOffset () const override
85 {
86 AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
87 Require (IsOpenRead ());
88 if (fPutBack_) {
89 Assert (fOffset_ >= 1);
90 return fOffset_ - 1;
91 }
92 return fOffset_;
93 }
94 virtual SeekOffsetType SeekRead (Whence whence, SignedSeekOffsetType offset) override
95 {
96 Require (IsOpenRead ());
97 static const auto kException_ = range_error{"seek"};
98 AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
99 size_t sourceLen = fSource_.size ();
100 SeekOffsetType newOffset{};
101 switch (whence) {
102 case eFromStart: {
103 if (offset < 0) [[unlikely]] {
104 Execution::Throw (kException_);
105 }
106 if (static_cast<SeekOffsetType> (offset) > sourceLen) [[unlikely]] {
107 Execution::Throw (kException_);
108 }
109 newOffset = static_cast<SeekOffsetType> (offset);
110 } break;
111 case eFromCurrent: {
112 Streams::SignedSeekOffsetType tmpOffset = fOffset_ + offset;
113 if (tmpOffset < 0) [[unlikely]] {
114 Execution::Throw (kException_);
115 }
116 if (static_cast<SeekOffsetType> (tmpOffset) > sourceLen) [[unlikely]] {
117 Execution::Throw (kException_);
118 }
119 newOffset = static_cast<SeekOffsetType> (tmpOffset);
120 } break;
121 case eFromEnd: {
122 Streams::SignedSeekOffsetType tmpOffset = fSource_.size () + offset;
123 if (tmpOffset < 0) [[unlikely]] {
124 Execution::Throw (kException_);
125 }
126 if (static_cast<SeekOffsetType> (tmpOffset) > sourceLen) [[unlikely]] {
127 Execution::Throw (kException_);
128 }
129 newOffset = static_cast<SeekOffsetType> (tmpOffset);
130 } break;
131 }
132 if (newOffset == fOffset_ - 1 and fPrevCharCached_) {
133 fPutBack_ = fPrevCharCached_;
134 fPrevCharCached_ = nullopt;
135 return GetReadOffset ();
136 }
137 else if (newOffset < fOffset_) {
138 fSrcIter_ = fSource_.begin ();
139 fOffset_ = 0;
140 }
141 while (fOffset_ < newOffset) {
142 if (fSrcIter_.Done ()) {
143 AssertNotReached (); // because we checked within maxlen above
144 //Execution::Throw (Execution::RuntimeErrorException {"Seek past end of input"sv}); // @todo clarify - docuemnt - not sure if/how to handle this
145 }
146 ++fSrcIter_;
147 ++fOffset_;
148 }
149 return fOffset_;
150 }
151
152 private:
153 Iterable<ELEMENT_TYPE> fSource_;
154 Iterator<ELEMENT_TYPE> fSrcIter_;
155 size_t fOffset_{};
156 optional<ELEMENT_TYPE> fPrevCharCached_{}; // fPrevCharCached_/fPutBack_ speed hack to support IsAtEOF (), and Peek () more efficiently, little cost, big cost avoidance for seek
157 optional<ELEMENT_TYPE> fPutBack_{};
158 [[no_unique_address]] Debug::AssertExternallySynchronizedMutex fThisAssertExternallySynchronized_;
159 };
160 return Ptr<ELEMENT_TYPE>{Memory::MakeSharedPtr<IterableAdapterStreamRep_> (it)};
161 }
162
163}
#define AssertNotImplemented()
Definition Assertions.h:401
#define AssertNotReached()
Definition Assertions.h:355
NoDataAvailableHandling
If eDontBlock passed to most Stream APIs, then when the code would do a blocking read,...
Definition Stream.h:90
NOT a real mutex - just a debugging infrastructure support tool so in debug builds can be assured thr...
InputStream<>::Ptr is Smart pointer (with abstract Rep) class defining the interface to reading from ...
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237
nonvirtual Iterator< T > begin() const
Support for ranged for, and STL syntax in general.
An Iterator<T> is a copyable object which allows traversing the contents of some container....
Definition Iterator.h:225