6namespace Stroika::Foundation::Streams {
13 template <
typename ELEMENT_TYPE>
14 inline size_t StreamReader<ELEMENT_TYPE>::CacheBlock_::GetSize ()
const
16 return fCacheWindowBuf_.GetSize ();
18 template <
typename ELEMENT_TYPE>
19 inline SeekOffsetType StreamReader<ELEMENT_TYPE>::CacheBlock_::GetStart ()
const
21 return fCacheWindowBufStart_;
23 template <
typename ELEMENT_TYPE>
24 inline SeekOffsetType StreamReader<ELEMENT_TYPE>::CacheBlock_::GetEnd ()
const
26 return fCacheWindowBufStart_ + fCacheWindowBuf_.GetSize ();
28 template <
typename ELEMENT_TYPE>
29 inline auto StreamReader<ELEMENT_TYPE>::CacheBlock_::Peek1FromCache (SeekOffsetType actualOffset)
const -> optional<ElementType>
31 size_t cacheWindowSize = fCacheWindowBuf_.size ();
32 if (fCacheWindowBufStart_ <= actualOffset and actualOffset < fCacheWindowBufStart_ + cacheWindowSize) [[likely]] {
33 return fCacheWindowBuf_[
static_cast<size_t> (actualOffset - fCacheWindowBufStart_)];
37 template <
typename ELEMENT_TYPE>
38 inline auto StreamReader<ELEMENT_TYPE>::CacheBlock_::Read1FromCache (SeekOffsetType* actualOffset) -> optional<ElementType>
41 auto result = Peek1FromCache (*actualOffset);
42 if (result) [[likely]] {
47 template <
typename ELEMENT_TYPE>
48 optional<size_t> StreamReader<ELEMENT_TYPE>::CacheBlock_::ReadFromCache (SeekOffsetType* actualOffset, span<ElementType> into)
50 using namespace Traversal;
51 size_t cacheWindowSize = fCacheWindowBuf_.size ();
52 if (cacheWindowSize != 0) [[likely]] {
53 Range<SignedSeekOffsetType> cacheWindow{
59 if (cacheWindow.Contains (*actualOffset)) [[likely]] {
61 size_t nToRead = into.size ();
63 size_t nInBufAvail =
static_cast<size_t> (cacheWindow.GetUpperBound () - *actualOffset);
64 nToRead = min (nToRead, nInBufAvail);
67 size_t curSeekPosOffsetIntoCache =
static_cast<size_t> (*actualOffset - cacheWindow.GetLowerBound ());
68 Assert (0 <= curSeekPosOffsetIntoCache and curSeekPosOffsetIntoCache < fCacheWindowBuf_.size ());
69 std::copy (fCacheWindowBuf_.data () + curSeekPosOffsetIntoCache,
70 fCacheWindowBuf_.data () + curSeekPosOffsetIntoCache + nToRead, into.data ());
71 *actualOffset += nToRead;
77 template <
typename ELEMENT_TYPE>
78 void StreamReader<ELEMENT_TYPE>::CacheBlock_::FillCacheWith (SeekOffsetType s, span<InlineBufferElementType_> into)
81 size_t oldCacheSize = fCacheWindowBuf_.GetSize ();
83 size_t nToWrite = into.size ();
84 Require (nToWrite > 0);
85 if (currentEnd == s) {
91 if (oldCacheSize + nToWrite > fCacheWindowBuf_.kMinCapacity) {
92 fCacheWindowBuf_.reserve (kMaxBufferedChunkSize_);
94 fCacheWindowBuf_.resize_uninitialized (oldCacheSize + nToWrite);
95 std::copy (into.begin (), into.end (), fCacheWindowBuf_.begin () + oldCacheSize);
98 fCacheWindowBuf_.resize_uninitialized (nToWrite);
99 fCacheWindowBufStart_ = s;
100 std::copy (into.begin (), into.end (), fCacheWindowBuf_.begin ());
109 template <
typename ELEMENT_TYPE>
111 : fStrm_{underlyingReadFromStreamAdopted}
112 , fOffset_{underlyingReadFromStreamAdopted.GetOffset ()}
114 Require (underlyingReadFromStreamAdopted.
IsSeekable ());
116 template <
typename ELEMENT_TYPE>
120 IgnoreExceptionsForCall (this->SynchronizeToUnderlyingStream ())
122 template <
typename ELEMENT_TYPE>
125 Require (not intoBuffer.empty ());
128 if (optional<size_t> o = ReadFromCache_ (intoBuffer)) {
129 return intoBuffer.subspan (0, *o);
131 if (
auto osz = Read_Slow_Case_ (intoBuffer, blockFlag)) {
132 return intoBuffer.subspan (0, *osz);
134 Assert (blockFlag == NoDataAvailableHandling::eDontBlock);
137 template <
typename ELEMENT_TYPE>
141 span<ElementType> r = ReadBlocking (span{&e, 1});
142 return r.empty () ? optional<ElementType>{} : e;
144 template <
typename ELEMENT_TYPE>
147 return Memory::ValueOf (Read (intoBuffer, NoDataAvailableHandling::eBlockIfNoDataAvailable));
149 template <
typename ELEMENT_TYPE>
152 Require (intoBuffer->size () == 0);
153 while (
auto oe = ReadBlocking ()) {
154 intoBuffer->push_back (*oe);
155 if (*oe == upToSentinel) {
156 return span{intoBuffer->data (), intoBuffer->size () - 1};
159 return span{intoBuffer->data (), intoBuffer->size ()};
161 template <
typename ELEMENT_TYPE>
166 Require (not intoBuffer.empty ());
167 return Read (intoBuffer, NoDataAvailableHandling::eDontBlock);
169 template <
typename ELEMENT_TYPE>
172 if (
auto o = Read (intoBuffer, blockFlag)) [[likely]] {
177 template <
typename ELEMENT_TYPE>
180 if (
auto p = Peek1FromCache_ ()) [[likely]] {
184 auto result = this->ReadBlocking ();
188 template <
typename ELEMENT_TYPE>
193 auto result = this->Read (intoBuffer);
197 template <
typename ELEMENT_TYPE>
202 template <
typename ELEMENT_TYPE>
205 Require (offset <
static_cast<SeekOffsetType> (numeric_limits<SignedSeekOffsetType>::max ()));
208 template <
typename ELEMENT_TYPE>
219 fStrm_.Seek (eFromEnd, offset);
220 fOffset_ = fStrm_.GetOffset ();
225 template <
typename ELEMENT_TYPE>
228 size_t elementsRead{};
229 for (ElementType* readCursor = intoStart; readCursor < intoEnd;) {
230 size_t eltsReadThisTime = ReadBlocking (span{readCursor, intoEnd}).size ();
231 Assert (eltsReadThisTime <=
static_cast<size_t> (intoEnd - readCursor));
232 if (eltsReadThisTime == 0) {
236 elementsRead += eltsReadThisTime;
237 readCursor += eltsReadThisTime;
241 template <
typename ELEMENT_TYPE>
244 if (fFarthestReadInUnderlyingStream_ > fOffset_) {
245 return static_cast<size_t> (fFarthestReadInUnderlyingStream_ - fOffset_);
247 return fStrm_.AvailableToRead ();
249 template <
typename ELEMENT_TYPE>
252 if (
auto underlyingRemaining = fStrm_.RemainingLength ()) {
253 Assert (fOffset_ <= fFarthestReadInUnderlyingStream_);
254 return *underlyingRemaining + (fFarthestReadInUnderlyingStream_ - fOffset_);
258 template <
typename ELEMENT_TYPE>
261 fStrm_.Seek (GetOffset ());
263 template <
typename ELEMENT_TYPE>
266 fOffset_ = fStrm_.GetOffset ();
268 template <
typename ELEMENT_TYPE>
271 if (fOffset_ < fFarthestReadInUnderlyingStream_) [[likely]] {
274 return not Peek ().has_value ();
276 template <
typename ELEMENT_TYPE>
277 inline auto StreamReader<ELEMENT_TYPE>::Peek1FromCache_ () const -> optional<ElementType>
280 for (
size_t i = fCacheBlockLastFilled_; i < Memory::NEltsOf (fCacheBlocks_); ++i) {
281 if (
auto r = fCacheBlocks_[i].Peek1FromCache (this->fOffset_)) [[likely]] {
285 for (
size_t i = 0; i < fCacheBlockLastFilled_; ++i) {
286 if (
auto r = fCacheBlocks_[i].Peek1FromCache (this->fOffset_)) {
292 template <
typename ELEMENT_TYPE>
293 inline auto StreamReader<ELEMENT_TYPE>::Read1FromCache_ () -> optional<ElementType>
296 for (
size_t i = fCacheBlockLastFilled_; i < Memory::NEltsOf (fCacheBlocks_); ++i) {
297 if (
auto r = fCacheBlocks_[i].Read1FromCache (&this->fOffset_)) [[likely]] {
301 for (
size_t i = 0; i < fCacheBlockLastFilled_; ++i) {
302 if (
auto r = fCacheBlocks_[i].Read1FromCache (&this->fOffset_)) {
308 template <
typename ELEMENT_TYPE>
309 optional<size_t> StreamReader<ELEMENT_TYPE>::ReadFromCache_ (span<ElementType> into)
312 for (
size_t i = fCacheBlockLastFilled_; i < Memory::NEltsOf (fCacheBlocks_); ++i) {
313 if (
auto r = fCacheBlocks_[i].ReadFromCache (&this->fOffset_, into)) {
317 for (
size_t i = 0; i < fCacheBlockLastFilled_; ++i) {
318 if (
auto r = fCacheBlocks_[i].ReadFromCache (&this->fOffset_, into)) {
324 template <
typename ELEMENT_TYPE>
325 void StreamReader<ELEMENT_TYPE>::FillCacheWith_ (SeekOffsetType s, span<InlineBufferElementType_> into)
330 size_t thisFillSize = into.size ();
331 if (fCacheBlocks_[fCacheBlockLastFilled_].GetEnd () != this->fOffset_ or
332 fCacheBlocks_[fCacheBlockLastFilled_].GetSize () + thisFillSize > kMaxBufferedChunkSize_) {
333 ++fCacheBlockLastFilled_;
334 if (fCacheBlockLastFilled_ >= Memory::NEltsOf (fCacheBlocks_)) {
335 fCacheBlockLastFilled_ = 0;
338 fCacheBlocks_[fCacheBlockLastFilled_].FillCacheWith (s, into);
340 template <
typename ELEMENT_TYPE>
341 optional<size_t> StreamReader<ELEMENT_TYPE>::Read_Slow_Case_ (span<ElementType> into, NoDataAvailableHandling blockFlag)
343 ElementType buf[kDefaultReadBufferSize_];
344 fStrm_.
Seek (fOffset_);
345 if (optional<span<ElementType>> o = fStrm_.Read (buf, blockFlag)) {
346 size_t nRecordsRead = o->size ();
347 if (nRecordsRead == 0) {
351 fFarthestReadInUnderlyingStream_ = max (fFarthestReadInUnderlyingStream_, fStrm_.GetOffset ());
352 FillCacheWith_ (fOffset_, Memory::SpanBytesCast<span<InlineBufferElementType_>> (span{buf, nRecordsRead}));
353 return Memory::ValueOf (ReadFromCache_ (into));
356 Assert (blockFlag == NoDataAvailableHandling::eDontBlock);
#define RequireNotNull(p)
NoDataAvailableHandling
If eDontBlock passed to most Stream APIs, then when the code would do a blocking read,...
int64_t SignedSeekOffsetType
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
nonvirtual bool IsSeekable() const
Returns true iff this object was constructed with a seekable input stream rep.
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
StreamReader is an non-essential Stream utility, adding simplicity of use for a common use case,...
nonvirtual void SynchronizeFromUnderlyingStream()
nonvirtual optional< size_t > AvailableToRead() const
returns nullopt if nothing known available, zero if known EOF, and any other number of elements (typi...
nonvirtual SeekOffsetType Seek(SeekOffsetType offset)
Logically the same as InputStream::Ptr<ELEMENT_TYPE>::Seek () - but without being 'synchronized' it m...
nonvirtual void SynchronizeToUnderlyingStream()
nonvirtual optional< ElementType > Peek()
Logically the same as InputStream::Ptr<ELEMENT_TYPE>::Peek () but reading cached data.
nonvirtual optional< span< ElementType > > Read(span< ElementType > intoBuffer, NoDataAvailableHandling blockFlag)
Read into data referenced by span argument - and using argument blocking strategy (default blocking)
nonvirtual SeekOffsetType GetOffset() const
Logically the same as InputStream::Ptr<ELEMENT_TYPE>::GetOffset () - but without being 'synchronized'...
nonvirtual size_t ReadAll(ElementType *intoStart, ElementType *intoEnd)
Logically the same as InputStream::Ptr<ELEMENT_TYPE>::ReadAll ()
nonvirtual optional< SeekOffsetType > RemainingLength() const
returns nullopt if not known (typical, and the default) - but sometimes it is known,...
nonvirtual optional< ElementType > ReadBlocking()
ReadBlocking () reads either a single element, or fills in argument intoBuffer - but never blocks (no...
nonvirtual optional< span< ElementType > > ReadNonBlocking(span< ElementType > intoBuffer)
read into intoBuffer - returning nullopt if would block, and else returning subspan of input with rea...
nonvirtual span< ElementType > ReadOrThrow(span< ElementType > intoBuffer, NoDataAvailableHandling blockFlag)
Read (either one or into argument span) and taking NoDataAvailableHandling blockFlag),...