InStream
InStream
performs buffered input from an arbitrary input source.
InStream
is similar to FILE
in C or std::istream
in C++. It maintains an internal input buffer
on the heap, and provides functions to quickly read small amounts of data incrementally, making it
suitable for application-level parsing of text and binary formats. InPipe
, on the other hand, is a
lower-level class more akin to a Unix file descriptor.
The parse
and readString
member functions are intended for reading text in an 8-bit format
compatible with ASCII, such as UTF-8, ISO 8859-1 or Windows-1252. For more information, see
Parsing Text.
Some InStream
objects contain adapters that perform conversions. For example, the InStream
returned by FileSystem::openTextForRead
can normalize endings and convert from UTF-16 to UTF-8.
For more information, see Unicode Support.
If the InStream
's underlying input comes from an InPipe
, the internal input buffer is managed by
a ChunkListNode
, and you can call getCursor()
at any time to create a ChunkCursor
. You can
then rewind the InStream
to an earlier point using rewind()
, or copy some data between two
ChunkCursor
s into a single contiguous memory buffer.
To create an InStream
that reads from a contiguous memory block, use ViewInStream
.
Header File
#include <ply-runtime/io/InStream.h>
Also included from <ply-runtime/Base.h>
.
Data Members
-
A pointer to the next byte in the input buffer. If this pointer is equal to
endByte
, it is not safe to read from the pointer. Use member functions such astryMakeBytesAvailable()
to ensure that this pointer can be read safely. -
A pointer to the last byte in the input buffer. This pointer does not necessarily represent the end of the input stream; for example, it still might be possible to read more data from the underlying
InPipe
, or to advance to the next chunk in aChunkList
, by callingtryMakeBytesAvailable()
.
Member Functions
-
Constructs an empty
InStream
. You can replace it with a validInStream
later using move assignment. -
Move constructor.
-
Constructs an
InStream
from anInPipe
. IfinPipe
is an owned pointer, theInStream
takes ownership of theInPipe
and will automatically destroy it in its destructor. IfinPipe
is a borrowed pointer, theInStream
does not take ownership of theInPipe
. void InStream::operator=(InStream&& other)
[code]-
Move assignment operator.
-
Return
true
if theInStream
is aViewInStream
. -
Returns
true
if no further data can be read from the stream, such as when the end of-file is encountered. This function also returnstrue
if there's an error in the underlyingInPipe
that prevents further reading, such as when a network socket is closed prematurely. -
Returns the number of bytes between
curByte
andendByte
. Equivalent toviewAvailable().numBytes
. -
Returns the memory region between
curByte
andendByte
as aStringView
. -
Returns a number that increases each time a byte is read from the
InStream
. If the underlyingInPipe
is a file, this number typically corresponds to the file offset. -
Returns a
ChunkCursor
at the current input position. TheChunkCursor
increments the reference count of theInStream
's internalChunkListNode
, preventing it from being destroyed when reading past the end of the chunk. This function is used internally byStringReader::readString
in order to copy some region of the input to aString
. In particular,StringReader::readString<fmt::Line>
returns a single line of input as aString
even if it originally spanned multipleChunkListNode
s. -
Rewinds the
InStream
back to a previously saved position. This also clears theInStream
's end-of-file status. -
Attempts to make at least
numBytes
available to read contiguously atcurByte
. Returns the number of bytes actually made available. If the underlyingInPipe
is waiting for data, this function will block until at leastnumBytes
bytes arrive. If EOF/error is encountered, the return value will be less thannumBytes
; otherwise, it will be greater than or equal tonumBytes
. -
Equivalent to
curByte[index]
, with bounds checking performed onindex
at runtime. The caller is responsible for ensuring that it's safe to read from the input buffer at this index by callingtryMakeBytesAvailable()
beforehand.if (ins->tryMakeBytesAvailable() && ins->peekByte() == '.') { // Handle this input character... ins->advanceByte(); }
-
Equivalent to
curByte += numBytes
, with bounds checking performed onnumBytes
at runtime. The caller is responsible for ensuring that there are actuallynumBytes
available in the input buffer by callingtryMakeBytesAvailable()
beforehand. -
Reads and returns the next byte from the input stream, or
0
if no more bytes are available. UseatEOF()
to determine whether the read was actually successful. -
Attempts to fill
dst
with data from the input stream. If the underlyingInPipe
is waiting for data, this function will block untildst
is filled. Returnstrue
if the buffer is filled successfully. If EOF/error is encountered beforedst
can be filled, the remainder ofdst
is filled with zeros andfalse
is returned. -
Attempts to skip
numBytes
bytes the input stream. If the underlyingInPipe
is waiting for data, this function will block until the specified number of bytes arrive. Returnstrue
if successful. Returnsfalse
if EOF/error is encountered before the specified number of bytes are skipped. -
Reads all the remaining data from the input stream and returns the contents as a
String
. -
Casts the
InStream
to various other types. It's always legal to callasStringReader()
, but it's only legal to call the other functions ifisView()
returnstrue
. template <typename Type>
Type InStream::parse(const decltype(fmt::TypeParser<Type>::defaultFormat())& format = fmt::TypeParser<Type>::defaultFormat())
[code]-
A template function to parse the data type given by
Type
. It currently supportss8
,s16
,s32
,s64
,u8
,u16
,u32
,u64
,float
anddouble
. You can extend it to support additional types by specializing thefmt::TypeParser
class template.u32 a = ins.parse<u32>(); // parse an integer such as "123" double b = ins.parse<double>(); // parse a floating-point number such as "-123.456"
This function accepts an optional argument
format
whose type depends on the data type being parsed. Fors8
,s16
,s32
,s64
,u8
,u16
,u32
,u64
,float
anddouble
, the expected type of this argument isfmt::Radix
.u32 a = ins.parse<u32>(fmt::Radix{16}); // parse hex integer such as "badf00d" u32 b = ins.parse<u32>(fmt::Radix{2}); // parse binary integer such as "1101101"
For more information, see Parsing Text.
template <typename Format, typename = void_t<decltype(fmt::FormatParser<Format>::parse)>>
auto InStream::parse(const Format& format = {})
[code]-
A template function to parse text in the format specified by
Format
. The return type depends on the format being parsed. It currently supports the following built-in formats:fmt::QuotedString
fmt::Identifier
fmt::Line
fmt::WhiteSpace
fmt::NonWhiteSpace
Example:
ins.parse<fmt::WhiteSpace>(); // returns nothing; whitespace is skipped
This function accepts an optional argument
format
of typeFormat
. When this argument is passed, you can leave out the function template argument and let the compiler deduce it from the argument type:bool success = ins.parse(fmt::QuotedString{fmt::AllowSingleQuote});
You can extend this function to support additional formats by specializing the
fmt::FormatParser
class template.For more information, see Parsing Text.
-
These functions are similar to the family of
parse()
functions, except that they return aString
containing the input that was consumed by the parse operation. For example,readString<fmt::Line>()
returns a single line of text terminated by'\n'
.String line = ins.readString<fmt::Line>();
Internally,
readString()
usesgetCursor()
to return a newString
. If you would like both theString
and the value returned by the parse function, you can usegetCursor()
yourself:ChunkCursor startCursor = ins.getCursor(); u32 value = ins.parse<u32>(); String str = ChunkCursor::toString(std::move(startCursor), ins.getCursor());
-
Returns
true
if an error occurred in a previously called parse function.