Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
IterableToInputStream.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
5
6namespace Stroika::Foundation::Streams::IterableToInputStream {
7
8 /*
9 ********************************************************************************
10 **************** Streams::IterableToInputStream::New ***************************
11 ********************************************************************************
12 */
13 template <typename ELEMENT_TYPE>
15 {
19 // Simply iterate over the 'iterable' of characacters, but allow seekability (by saving original iteration start)
20 class IterableAdapterStreamRep_ final : public InputStream::IRep<ELEMENT_TYPE> {
21 public:
22 IterableAdapterStreamRep_ (const Traversal::Iterable<ELEMENT_TYPE>& src)
23 : fSource_{src}
24 , fSrcIter_{fSource_.begin ()}
25 {
26 }
27
28 private:
29 bool fIsOpen_{true};
30
31 protected:
32 virtual bool IsSeekable () const override
33 {
34 return true;
35 }
36 virtual void CloseRead () override
37 {
38 fIsOpen_ = false;
39 Ensure (not IsOpenRead ());
40 }
41 virtual bool IsOpenRead () const override
42 {
43 return fIsOpen_;
44 }
45 virtual optional<size_t> AvailableToRead () override
46 {
47 Require (IsOpenRead ());
48 AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
49 // usually just want to know 0 or >= 1, so don't bother computing full length
50 return fSrcIter_.Done () ? 0 : 1;
51 }
52 virtual optional<SeekOffsetType> RemainingLength () override
53 {
54 AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
55 Require (IsOpenRead ());
57 return nullopt; // pretty easy, but @todo
58 }
59 virtual optional<span<ELEMENT_TYPE>> Read (span<ELEMENT_TYPE> intoBuffer, [[maybe_unused]] NoDataAvailableHandling blockFlag) override
60 {
61 Require (not intoBuffer.empty ());
62 AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
63 Require (IsOpenRead ());
64 ELEMENT_TYPE* outI = intoBuffer.data ();
65 if (fPutBack_) {
66 *outI = *fPutBack_;
67 fPutBack_ = nullopt;
68 ++outI;
69 // fOffset_ doesn't take into account putback
70 }
71 for (; fSrcIter_ != fSource_.end () and outI != intoBuffer.data () + intoBuffer.size (); ++fSrcIter_, ++outI) {
72 *outI = *fSrcIter_;
73 ++fOffset_;
74 }
75 if (outI > intoBuffer.data ()) {
76 fPrevCharCached_ = *(outI - 1);
77 }
78 else {
79 fPrevCharCached_ = nullopt;
80 }
81 return intoBuffer.subspan (0, outI - intoBuffer.data ());
82 }
83 virtual SeekOffsetType GetReadOffset () const override
84 {
85 AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
86 Require (IsOpenRead ());
87 if (fPutBack_) {
88 Assert (fOffset_ >= 1);
89 return fOffset_ - 1;
90 }
91 return fOffset_;
92 }
93 virtual SeekOffsetType SeekRead (Whence whence, SignedSeekOffsetType offset) override
94 {
95 Require (IsOpenRead ());
96 static const auto kException_ = range_error{"seek"};
97 AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
98 size_t sourceLen = fSource_.size ();
99 SeekOffsetType newOffset{};
100 switch (whence) {
101 case eFromStart: {
102 if (offset < 0) [[unlikely]] {
103 Execution::Throw (kException_);
104 }
105 if (static_cast<SeekOffsetType> (offset) > sourceLen) [[unlikely]] {
106 Execution::Throw (kException_);
107 }
108 newOffset = static_cast<SeekOffsetType> (offset);
109 } break;
110 case eFromCurrent: {
111 Streams::SignedSeekOffsetType tmpOffset = fOffset_ + offset;
112 if (tmpOffset < 0) [[unlikely]] {
113 Execution::Throw (kException_);
114 }
115 if (static_cast<SeekOffsetType> (tmpOffset) > sourceLen) [[unlikely]] {
116 Execution::Throw (kException_);
117 }
118 newOffset = static_cast<SeekOffsetType> (tmpOffset);
119 } break;
120 case eFromEnd: {
121 Streams::SignedSeekOffsetType tmpOffset = fSource_.size () + offset;
122 if (tmpOffset < 0) [[unlikely]] {
123 Execution::Throw (kException_);
124 }
125 if (static_cast<SeekOffsetType> (tmpOffset) > sourceLen) [[unlikely]] {
126 Execution::Throw (kException_);
127 }
128 newOffset = static_cast<SeekOffsetType> (tmpOffset);
129 } break;
130 }
131 if (newOffset == fOffset_ - 1 and fPrevCharCached_) {
132 fPutBack_ = fPrevCharCached_;
133 fPrevCharCached_ = nullopt;
134 return GetReadOffset ();
135 }
136 else if (newOffset < fOffset_) {
137 fSrcIter_ = fSource_.begin ();
138 fOffset_ = 0;
139 }
140 while (fOffset_ < newOffset) {
141 if (fSrcIter_.Done ()) {
142 AssertNotReached (); // because we checked within maxlen above
143 //Execution::Throw (Execution::RuntimeErrorException {"Seek past end of input"sv}); // @todo clarify - docuemnt - not sure if/how to handle this
144 }
145 ++fSrcIter_;
146 ++fOffset_;
147 }
148 return fOffset_;
149 }
150
151 private:
152 Iterable<ELEMENT_TYPE> fSource_;
153 Iterator<ELEMENT_TYPE> fSrcIter_;
154 size_t fOffset_{};
155 optional<ELEMENT_TYPE> fPrevCharCached_{}; // fPrevCharCached_/fPutBack_ speed hack to support IsAtEOF (), and Peek () more efficiently, little cost, big cost avoidance for seek
156 optional<ELEMENT_TYPE> fPutBack_{};
157 [[no_unique_address]] Debug::AssertExternallySynchronizedMutex fThisAssertExternallySynchronized_;
158 };
159 return Ptr<ELEMENT_TYPE>{make_shared<IterableAdapterStreamRep_> (it)};
160 }
161
162}
#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