MT Core (C++)
Core library for replacing C++ standard in project usage
Loading...
Searching...
No Matches
mtcore::io::Reader< Impl > Struct Template Reference

A reader that reads data from some sort of stream or buffer Note: the data elements read should be trivially constructible, trivially destructible, and trivially copyable. More...

#include <reader.hpp>

Inheritance diagram for mtcore::io::Reader< Impl >:
Collaboration diagram for mtcore::io::Reader< Impl >:

Public Types

using ReadElem = typename Impl::ReadElem
 
using ErrType = typename Impl::ErrType
 
using BuffSlice = Slice<std::remove_const_t<ReadElem>>
 
using ResSlice = Slice<std::add_const_t<ReadElem>>
 

Public Member Functions

Result< ResSlice, ErrTyperead (BuffSlice buff)
 Tries to read data from a reader into a buffer It will stop once the buffer is full, or once the EOF is reached If EOF is reached, the resulting subslice may be smaller than the buff Will simply return smaller buffers if EOF is met (buffers may be empty)
 
Result< ResSlice, ErrTyperead_no_eof (BuffSlice buff)
 Tries to read data from a reader into a buffer It will stop once the buffer is full, or once the EOF is reached If EOF is reached, will return the error END_OF_FILE.
 
Result< ResSlice, ErrTyperead_all (BuffSlice buff)
 Tries to read all data from a reader into a buffer It will stop once the EOF is reached If the buffer is not big enough, will return the error SIZE_EXCEEDED.
 
Result< BuffSlice, ErrTyperead_all (Allocator &alloc, size_t maxSize=std::numeric_limits< size_t >::max())
 Tries to read all data from a reader into an internally allocated buffer Will try to shrink the buffer before returning (so an extra copy) It will stop once the EOF is reached If the buffer required would exceed maxSize, will return the error SIZE_EXCEEDED If there is an allocation error at some point, will return the error ALLOCATION_FAILED May return an empty buffer if there is no data to read The caller MUST deallocate the returned Slice with alloc.destroy_many()
 
Result< ReadElem, ErrTyperead_one ()
 Will try to read a single item from the reader If there is no item to read (aka at EOF), will return the error END_OF_FILE.
 
Result< void, ErrTypeskip (size_t n)
 Will skip n items (basically reads and discards them) If there are not n items left to skip (aka it hits an EOF), will return the error END_OF_FILE.
 

Public Attributes

Impl underlying
 

Detailed Description

template<ReaderImpl Impl>
struct mtcore::io::Reader< Impl >

A reader that reads data from some sort of stream or buffer Note: the data elements read should be trivially constructible, trivially destructible, and trivially copyable.

Template Parameters
ImplReader Implementation (
See also
ReaderImpl concept)

Definition at line 42 of file io/reader.hpp.

Member Typedef Documentation

◆ BuffSlice

template<ReaderImpl Impl>
using mtcore::io::Reader< Impl >::BuffSlice = Slice<std::remove_const_t<ReadElem>>

Definition at line 46 of file io/reader.hpp.

◆ ErrType

template<ReaderImpl Impl>
using mtcore::io::Reader< Impl >::ErrType = typename Impl::ErrType

Definition at line 44 of file io/reader.hpp.

◆ ReadElem

template<ReaderImpl Impl>
using mtcore::io::Reader< Impl >::ReadElem = typename Impl::ReadElem

Definition at line 43 of file io/reader.hpp.

◆ ResSlice

template<ReaderImpl Impl>
using mtcore::io::Reader< Impl >::ResSlice = Slice<std::add_const_t<ReadElem>>

Definition at line 47 of file io/reader.hpp.

Member Function Documentation

◆ read()

template<ReaderImpl Impl>
Result< ResSlice, ErrType > mtcore::io::Reader< Impl >::read ( BuffSlice buff)
inline

Tries to read data from a reader into a buffer It will stop once the buffer is full, or once the EOF is reached If EOF is reached, the resulting subslice may be smaller than the buff Will simply return smaller buffers if EOF is met (buffers may be empty)

Parameters
buffBuffer to place read data into
Returns
Result of subslice over buff of what was read into, or the error which happened

Definition at line 59 of file io/reader.hpp.

59{ return underlying.read(buff); }
A reader that reads data from some sort of stream or buffer Note: the data elements read should be tr...
Definition io/reader.hpp:42
Here is the caller graph for this function:

◆ read_all() [1/2]

template<ReaderImpl Impl>
Result< BuffSlice, ErrType > mtcore::io::Reader< Impl >::read_all ( Allocator & alloc,
size_t maxSize = std::numeric_limits<size_t>::max() )
inline

Tries to read all data from a reader into an internally allocated buffer Will try to shrink the buffer before returning (so an extra copy) It will stop once the EOF is reached If the buffer required would exceed maxSize, will return the error SIZE_EXCEEDED If there is an allocation error at some point, will return the error ALLOCATION_FAILED May return an empty buffer if there is no data to read The caller MUST deallocate the returned Slice with alloc.destroy_many()

Parameters
allocAllocator to allocate data with
maxSizeMaximum size for allocation. Default is no limit. If over 100MB, will allocate in 8,000 item chunks while reading
Returns
Result of allocated Slice on success, or the error which happened

Definition at line 113 of file io/reader.hpp.

113 {
114 ensure(maxSize > 0, "BAD MAX SIZE");
115 // If we have no limit or a really high limit (> 100MB), we're going to allocate in chunks
116 if (maxSize == std::numeric_limits<size_t>::max() || maxSize >= 100000000) {
117 // A segmented list will be use to track the chunks
118 // We'll store the actual chunks here rather than copy the individual items
120 if (auto res = fullBuff.init(alloc, 10); res.is_error()) {
122 }
123 // We will do a full copy before a successful return
124 // So we can safely set it up to always clean up the full buff
125 mtdefer {
127 auto iter = fullBuff.iter();
128 while (iter.next().copy_if_present(curSlice)) {
129 alloc.destroy_many(curSlice);
130 }
131 fullBuff.deinit(alloc);
132 };
133
134 size_t count = 0;
135
136 bool atEnd = false;
137 do {
138 bool added = false;
139 // We do chunks of around 8,000 items
140 auto curRes = alloc.create_many<std::remove_const_t<ReadElem>>(8000);
141 if (curRes.is_error()) {
143 }
144
145 auto cur = curRes.value();
146 mtdefer {
147 if (!added) {
148 alloc.destroy_many(cur);
149 }
150 };
151
152 auto readRes = read(cur);
153 if (readRes.is_error()) {
155 }
156
157 auto readData = readRes.value();
158 if (readData.empty()) {
159 atEnd = true;
160 }
161 else {
162 auto toPush = cur.sub(0, readData.size());
163 if (auto pushRes = fullBuff.push(alloc, toPush); pushRes.is_error()) {
165 }
166
167 added = true;
168 count += readData.size();
169
170 if (readData.size() < cur.size()) {
171 atEnd = true;
172 }
173 }
174 } while (!atEnd);
175
176 if (count == 0) {
177 return BuffSlice{nullptr, 0};
178 }
179
180 // We have everything chunked in memory, but our contract is to return a contiguous set of bytes
181 // To do this, we need to do one final copy into contiguous memory
183 if (finalRes.is_error()) {
185 }
186
187 auto finalSlice = finalRes.value();
188 // We'll use a Slice writer to make things a little simpler
190 // Since we stored the chunks, we can just iterate each chunk and write the entire chunk at once
191 auto iter = fullBuff.iter();
193 while (iter.next().copy_if_present(curBuff)) {
194 if (auto r = finalWriter.write_all(curBuff); r.is_error()) {
195 alloc.destroy_many(finalSlice);
197 }
198 }
199
200 // Return our Result
201 return finalSlice;
202 }
203 else {
204 // If we have a smal enough max size, just read it all into one chunk of memory
206 if (outRes.is_error()) {
208 }
209 auto out = outRes.value();
210 auto res = read_all(out);
211 if (res.is_error()) {
212 alloc.destroy_many(out);
213 return res.error();
214 }
215 auto finalRes = res.value();
216
217 // Check to see if we can save memory if we shrink things down
218 // This is more CPU time, but less memory pressure
219 if (finalRes.size() + alignof(ReadElem) < out.size()) {
220 if (finalRes.size() == 0) {
221 alloc.destroy_many(out);
222 return BuffSlice{nullptr, 0};
223 }
224 // Try to create a sub optimal buffer
225 auto smallerRes = alloc.create_many<std::remove_const_t<ReadElem>>(finalRes.size());
226 if (smallerRes.is_error()) {
227 // we have it already in memory, it's just suboptimal. Return it anyway
228 return out.sub(0, finalRes.size());
229 }
230 auto smaller = smallerRes.value();
231 auto w = slice_writer(smaller);
232 ensure(w.write_all(finalRes).is_success(), "SOMETHING IS WRONG WITH SLICE WRITER!");
233 alloc.destroy_many(out);
234 return success(smaller);
235 }
236 return success(out.sub(0, finalRes.size()));
237 }
238 }
#define ensure(check,...)
Ensures that a check holds true, aborts the program if not true Will print error if the condition is ...
Success< void > success()
Creates a successful void Result object.
Definition result.hpp:398
Error< Underlying > error(Underlying err)
Creates an error.
Definition result.hpp:425
io::Writer< impl::SliceWriterImpl< T > > slice_writer(Slice< T > out)
Creates a writer to write to a Slice.
Slice< std::remove_const_t< ReadElem > > BuffSlice
Definition io/reader.hpp:46
Result< ResSlice, ErrType > read(BuffSlice buff)
Tries to read data from a reader into a buffer It will stop once the buffer is full,...
Definition io/reader.hpp:59
Result< ResSlice, ErrType > read_all(BuffSlice buff)
Tries to read all data from a reader into a buffer It will stop once the EOF is reached If the buffer...
Definition io/reader.hpp:83
typename Impl::ReadElem ReadElem
Definition io/reader.hpp:43
Here is the call graph for this function:

◆ read_all() [2/2]

template<ReaderImpl Impl>
Result< ResSlice, ErrType > mtcore::io::Reader< Impl >::read_all ( BuffSlice buff)
inline

Tries to read all data from a reader into a buffer It will stop once the EOF is reached If the buffer is not big enough, will return the error SIZE_EXCEEDED.

Parameters
buffBuffer to place read data into
Returns
Result of subslice over buff of what was read into, or the error which happened

Definition at line 83 of file io/reader.hpp.

83 {
84 auto res = read(buff);
85 if (res.is_error()) {
86 return res.error();
87 }
88 auto resSlice = res.value();
89 if (resSlice.size() < buff.size()) {
90 return resSlice;
91 }
92
93 // If there's another element not read, then we didn't read everything
94 if (auto ro = read_one(); ro.is_success() || ro.error().code != ErrType::END_OF_FILE) {
96 }
97 return resSlice;
98 }
Result< ReadElem, ErrType > read_one()
Will try to read a single item from the reader If there is no item to read (aka at EOF),...
Here is the call graph for this function:
Here is the caller graph for this function:

◆ read_no_eof()

template<ReaderImpl Impl>
Result< ResSlice, ErrType > mtcore::io::Reader< Impl >::read_no_eof ( BuffSlice buff)
inline

Tries to read data from a reader into a buffer It will stop once the buffer is full, or once the EOF is reached If EOF is reached, will return the error END_OF_FILE.

Parameters
buffBuffer to place read data into
Returns
Result of subslice over buff of what was read into, or the error which happened

Definition at line 68 of file io/reader.hpp.

68 {
69 auto res = read(buff);
70 if (res.is_success() && res.value().size() < buff.size()) {
72 }
73 return res;
74 }
Here is the call graph for this function:

◆ read_one()

template<ReaderImpl Impl>
Result< ReadElem, ErrType > mtcore::io::Reader< Impl >::read_one ( )
inline

Will try to read a single item from the reader If there is no item to read (aka at EOF), will return the error END_OF_FILE.

Returns
Result of one item read, or error

Definition at line 245 of file io/reader.hpp.

245 {
248 auto readRes = read(s);
249 if (readRes.is_error()) {
250 return readRes.error();
251 }
252 auto res = readRes.value();
253 if (res.empty()) {
255 }
256 return elem;
257 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ skip()

template<ReaderImpl Impl>
Result< void, ErrType > mtcore::io::Reader< Impl >::skip ( size_t n)
inline

Will skip n items (basically reads and discards them) If there are not n items left to skip (aka it hits an EOF), will return the error END_OF_FILE.

Parameters
nNumber of items to skip
Returns
Error if there was one

Definition at line 265 of file io/reader.hpp.

265 {
266 for (size_t i = 0; i < n; ++i) {
267 auto r = read_one();
268 if (r.is_error()) {
269 return r.error();
270 }
271 }
272 return success();
273 }
Here is the call graph for this function:

Member Data Documentation

◆ underlying

template<ReaderImpl Impl>
Impl mtcore::io::Reader< Impl >::underlying

Definition at line 49 of file io/reader.hpp.


The documentation for this struct was generated from the following file: