mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 00:37:15 +01:00
919 lines
34 KiB
C++
919 lines
34 KiB
C++
#pragma once
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
#include "Library/IO/Buffer.hpp"
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
#include <ios>
|
|
#include <sstream>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <streambuf>
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
namespace SqMod {
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Implements specialized storage for the specified stream type.
|
|
*/
|
|
template < class T > struct SqStreamStorage
|
|
{
|
|
using Type = T;
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Move constructor (disabled).
|
|
*/
|
|
SqStreamStorage(SqStreamStorage && o) = delete;
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Copy constructor (disabled).
|
|
*/
|
|
SqStreamStorage(const SqStreamStorage & o) = delete;
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Move assignment operator (disabled).
|
|
*/
|
|
SqStreamStorage & operator = (SqStreamStorage && o) = delete;
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Copy assignment operator (disabled).
|
|
*/
|
|
SqStreamStorage & operator = (const SqStreamStorage & o) = delete;
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve a reference to the managed stream.
|
|
*/
|
|
inline Type & Stream()
|
|
{
|
|
return m_Stream;
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve a constant reference to the managed stream.
|
|
*/
|
|
inline const Type & Stream() const
|
|
{
|
|
return m_Stream;
|
|
}
|
|
|
|
protected:
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Wrapped stream object.
|
|
*/
|
|
Type m_Stream;
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Base constructor.
|
|
*/
|
|
template < class... Args > SqStreamStorage(Args &&... args) // NOLINT(google-explicit-constructor)
|
|
: m_Stream(std::forward< Args >(args)...)
|
|
{
|
|
}
|
|
};
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Stream type disambiguation tags.
|
|
*/
|
|
struct CInTag {
|
|
explicit CInTag() = default;
|
|
};
|
|
struct COutTag {
|
|
explicit COutTag() = default;
|
|
};
|
|
struct CErrTag {
|
|
explicit CErrTag() = default;
|
|
};
|
|
struct CLogTag {
|
|
explicit CLogTag() = default;
|
|
};
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Helper used to select the appropriate global stream.
|
|
*/
|
|
template < class > struct SqGlobalStream;
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Specialization of SqGlobalStream for std::cin.
|
|
*/
|
|
template < > struct SqGlobalStream< CInTag >
|
|
{
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Type of stream used internally.
|
|
*/
|
|
using Type = decltype(std::cin);
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve the associated global stream object.
|
|
*/
|
|
static Type & Get() { return std::cin; }
|
|
};
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Specialization of SqGlobalStream for std::cout.
|
|
*/
|
|
template < > struct SqGlobalStream< COutTag >
|
|
{
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Type of stream used internally.
|
|
*/
|
|
using Type = decltype(std::cout);
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve the associated global stream object.
|
|
*/
|
|
static Type & Get() { return std::cout; }
|
|
};
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Specialization of SqGlobalStream for std::cerr.
|
|
*/
|
|
template < > struct SqGlobalStream< CErrTag >
|
|
{
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Type of stream used internally.
|
|
*/
|
|
using Type = decltype(std::cerr);
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve the associated global stream object.
|
|
*/
|
|
static Type & Get() { return std::cerr; }
|
|
};
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Specialization of SqGlobalStream for std::clog.
|
|
*/
|
|
template < > struct SqGlobalStream< CLogTag >
|
|
{
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Type of stream used internally.
|
|
*/
|
|
using Type = decltype(std::clog);
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve the associated global stream object.
|
|
*/
|
|
static Type & Get() { return std::clog; }
|
|
};
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Implements specialized storage for stream reference.
|
|
*/
|
|
template < class T > struct SqStreamStorage< SqGlobalStream< T > >
|
|
{
|
|
using Type = typename SqGlobalStream< T >::Type;
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Move constructor (disabled).
|
|
*/
|
|
SqStreamStorage(SqStreamStorage && o) = delete;
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Copy constructor (disabled).
|
|
*/
|
|
SqStreamStorage(const SqStreamStorage & o) = delete;
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Move assignment operator (disabled).
|
|
*/
|
|
SqStreamStorage & operator = (SqStreamStorage && o) = delete;
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Copy assignment operator (disabled).
|
|
*/
|
|
SqStreamStorage & operator = (const SqStreamStorage & o) = delete;
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve a reference to the managed stream.
|
|
*/
|
|
inline Type & Stream()
|
|
{
|
|
return m_Stream.get();
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve a constant reference to the managed stream.
|
|
*/
|
|
inline const Type & Stream() const
|
|
{
|
|
return m_Stream.get();
|
|
}
|
|
|
|
protected:
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Wrapped stream object.
|
|
*/
|
|
std::reference_wrapper< Type > m_Stream;
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Base constructor.
|
|
*/
|
|
SqStreamStorage()
|
|
: m_Stream(SqGlobalStream< T >::Get())
|
|
{
|
|
}
|
|
};
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Helper used to extract the string from the constructor to the proper type.
|
|
*/
|
|
template < class T > struct StreamConstructorStr
|
|
{
|
|
static auto Get(StackStrF & str)
|
|
{
|
|
return str.ToStr();
|
|
}
|
|
};
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Specializations of `StreamConstructorStr` that return the raw string pointer instead,
|
|
*/
|
|
template < > struct StreamConstructorStr< std::fstream >
|
|
{
|
|
static const SQChar * Get(StackStrF & str)
|
|
{
|
|
return str.mPtr;
|
|
}
|
|
};
|
|
template < > struct StreamConstructorStr< std::ofstream >
|
|
{
|
|
static const SQChar * Get(StackStrF & str)
|
|
{
|
|
return str.mPtr;
|
|
}
|
|
};
|
|
template < > struct StreamConstructorStr< std::ifstream >
|
|
{
|
|
static const SQChar * Get(StackStrF & str)
|
|
{
|
|
return str.mPtr;
|
|
}
|
|
};
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Stream-based input/output class.
|
|
*/
|
|
template < class T > struct SqStream : public SqStreamStorage< T >
|
|
{
|
|
using SqStreamStorage< T >::Stream;
|
|
// --------------------------------------------------------------------------------------------
|
|
using Type = typename SqStreamStorage< T >::Type;
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Default string constructor.
|
|
*/
|
|
SqStream()
|
|
: SqStreamStorage< T >(), m_Buffer()
|
|
{
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Explicit string constructor.
|
|
*/
|
|
explicit SqStream(SQInteger m)
|
|
: SqStreamStorage< T >(static_cast< std::ios_base::openmode >(m)), m_Buffer()
|
|
{
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Base file constructor.
|
|
*/
|
|
explicit SqStream(StackStrF & str)
|
|
: SqStreamStorage< T >(StreamConstructorStr< Type >::Get(str)), m_Buffer()
|
|
{
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Explicit file constructor.
|
|
*/
|
|
SqStream(SQInteger m, StackStrF & str)
|
|
: SqStreamStorage< T >(StreamConstructorStr< Type >::Get(str), static_cast< std::ios_base::openmode >(m)), m_Buffer()
|
|
{
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Manually pre-allocate the size of the internal buffer.
|
|
*/
|
|
void AdjustBuffer(SQInteger len)
|
|
{
|
|
m_Buffer.Adjust(ClampL< SQInteger, Buffer::SzType >(len));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Reclaim memory from the memory buffer.
|
|
*/
|
|
void ReclaimBuffer()
|
|
{
|
|
m_Buffer.Reset();
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve current formatting setting.
|
|
*/
|
|
SQMOD_NODISCARD SQInteger GetFlags() const
|
|
{
|
|
return static_cast< SQInteger >(Stream().flags());
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Modify current settings with given ones.
|
|
*/
|
|
void SetFlags(SQInteger f)
|
|
{
|
|
Stream().flags(static_cast< std::ios_base::fmtflags >(f));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve current field width.
|
|
*/
|
|
SQMOD_NODISCARD SQInteger GetWidth() const
|
|
{
|
|
return static_cast< SQInteger >(Stream().width());
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Modify the field width to the given one. Returns the previous field width.
|
|
*/
|
|
SQInteger SetWidth(SQInteger w)
|
|
{
|
|
return static_cast< SQInteger >(Stream().width(static_cast< std::streamsize >(w)));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve current precision.
|
|
*/
|
|
SQMOD_NODISCARD SQInteger GetPrecision() const
|
|
{
|
|
return static_cast< SQInteger >(Stream().precision());
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Modify the precision to the given one. Returns the previous precision.
|
|
*/
|
|
SQInteger SetPrecision(SQInteger p)
|
|
{
|
|
return static_cast< SQInteger >(Stream().precision(static_cast< std::streamsize >(p)));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Sets the formatting flags identified by `f`.
|
|
*/
|
|
SqStream & SetF(SQInteger f)
|
|
{
|
|
Stream().setf(static_cast< std::ios_base::fmtflags >(f));
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Clears the formatting flags under `m`, and sets the cleared flags to those specified by `f`.
|
|
*/
|
|
SqStream & SetF_(SQInteger f, SQInteger m)
|
|
{
|
|
Stream().setf(static_cast< std::ios_base::fmtflags >(f), static_cast< std::ios_base::fmtflags >(m));
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Unsets the formatting flags identified by `f`.
|
|
*/
|
|
SqStream & UnSetF(SQInteger f)
|
|
{
|
|
Stream().unsetf(static_cast< std::ios_base::fmtflags >(f));
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Returns true if the most recent I/O operation on the stream completed successfully, false otherwise.
|
|
*/
|
|
SQMOD_NODISCARD bool Good() const
|
|
{
|
|
return Stream().good();
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Returns true if the associated stream has reached end-of-file, false otherwise.
|
|
*/
|
|
SQMOD_NODISCARD bool EOF_() const
|
|
{
|
|
return Stream().eof();
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Returns true if an error has occurred on the associated stream, false otherwise.
|
|
*/
|
|
SQMOD_NODISCARD bool Fail() const
|
|
{
|
|
return Stream().fail();
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Returns true if non-recoverable error has occurred on the associated stream.
|
|
*/
|
|
SQMOD_NODISCARD bool Bad() const
|
|
{
|
|
return Stream().bad();
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve the current fill character.
|
|
*/
|
|
SQMOD_NODISCARD SQChar GetFill() const
|
|
{
|
|
return Stream().fill();
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Modify the fill character to `c`, returns previous value of the fill character.
|
|
*/
|
|
SQChar SetFill(SQChar c)
|
|
{
|
|
return Stream().fill(c);
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve the current stream error state.
|
|
*/
|
|
SQMOD_NODISCARD SQInteger GetState() const
|
|
{
|
|
return static_cast< SQInteger >(Stream().rdstate());
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Modify the stream error flags state in addition to currently set flags.
|
|
*/
|
|
void SetState(SQInteger f)
|
|
{
|
|
return Stream().setstate(static_cast< std::ios_base::iostate >(f));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve the exception mask.
|
|
*/
|
|
SQMOD_NODISCARD SQInteger GetExceptions() const
|
|
{
|
|
return static_cast< SQInteger >(Stream().exceptions());
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Modify the exception mask to except.
|
|
*/
|
|
void SetExceptions(SQInteger f)
|
|
{
|
|
Stream().exceptions(static_cast< std::ios_base::iostate >(f));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Sets the stream error state flags by assigning them the value of `SqIoState.GoodBit`.
|
|
*/
|
|
SqStream & Clear()
|
|
{
|
|
Stream().clear();
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Sets the stream error state flags by assigning them the value of `f`.
|
|
*/
|
|
SqStream & ClearEx(SQInteger f)
|
|
{
|
|
Stream().clear(static_cast< std::ios_base::iostate >(f));
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve the output position indicator of the current associated `streambuf` object.
|
|
*/
|
|
SQMOD_NODISCARD SQInteger TellP()
|
|
{
|
|
return static_cast< SQInteger >(Stream().tellp());
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Modify the output position indicator of the current associated `streambuf` object.
|
|
* Sets the output position indicator to absolute (relative to the beginning of the file) value `p`.
|
|
*/
|
|
SqStream & SeekP(SQInteger p)
|
|
{
|
|
Stream().seekp(static_cast< typename Type::pos_type >(p));
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Modify the output position indicator of the current associated `streambuf` object.
|
|
* Sets the output position indicator to position `o`, relative to position, defined by `d`.
|
|
*/
|
|
SqStream & SeekP_(SQInteger o, SQInteger d)
|
|
{
|
|
Stream().seekp(static_cast< typename Type::off_type >(o), static_cast< typename std::ios_base::seekdir >(d));
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve input position indicator of the current associated `streambuf` object.
|
|
*/
|
|
SQMOD_NODISCARD SQInteger TellG()
|
|
{
|
|
return static_cast< SQInteger >(Stream().tellg());
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Modify input position indicator of the current associated `streambuf` object.
|
|
* Sets the input position indicator to absolute (relative to the beginning of the file) value `p`.
|
|
*/
|
|
SqStream & SeekG(SQInteger p)
|
|
{
|
|
Stream().seekg(static_cast< typename Type::pos_type >(p));
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Modify input position indicator of the current associated `streambuf` object.
|
|
* Sets the input position indicator to position `o`, relative to position, defined by `d`.
|
|
*/
|
|
SqStream & SeekG_(SQInteger o, SQInteger d)
|
|
{
|
|
Stream().seekg(static_cast< typename Type::off_type >(o), static_cast< typename std::ios_base::seekdir >(d));
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Write the character `c` to the output stream.
|
|
*/
|
|
SqStream & Put(SQInteger c)
|
|
{
|
|
Stream().put(static_cast< typename Type::char_type >(c));
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Write a string to the output stream.
|
|
*/
|
|
SqStream & WriteString(StackStrF & str)
|
|
{
|
|
Stream().write(str.mPtr, static_cast< std::streamsize >(str.mLen));
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Write a buffer to the output stream.
|
|
*/
|
|
SqStream & WriteBuffer(SqBuffer & buf)
|
|
{
|
|
Stream().write(buf.GetInst().Data(), static_cast< std::streamsize >(buf.GetInst().Position()));
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Write uncommitted changes to the underlying output sequence.
|
|
*/
|
|
SqStream & Flush()
|
|
{
|
|
Stream().flush();
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Reads at most num-1 characters and returns them as character string, until `delim` is found.
|
|
*/
|
|
SQMOD_NODISCARD std::streamsize Get(SQInteger num, SQChar delim)
|
|
{
|
|
// Prevent negative lengths
|
|
if (num < 0)
|
|
{
|
|
STHROWF("Invalid length: {} < 0", num);
|
|
}
|
|
// Prevent overflow of Buffer::SzType
|
|
else
|
|
{
|
|
num = static_cast< SQInteger >(ClampL< SQInteger, Buffer::SzType >(num));
|
|
}
|
|
// Allocate a sufficiently large memory buffer
|
|
m_Buffer.Adjust(static_cast< Buffer::SzType >(num));
|
|
// Read data from the stream
|
|
Stream().get(m_Buffer.Get(), static_cast< std::streamsize >(num), static_cast< typename Type::char_type >(delim));
|
|
// Return the number of characters read
|
|
return Stream().gcount();
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Read one character and return it if available.
|
|
*/
|
|
SQMOD_NODISCARD SQInteger GetString0()
|
|
{
|
|
return static_cast< SQInteger >(Stream().get());
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Reads at most num-1 characters and returns them as character string, until '\n' is found.
|
|
*/
|
|
SQMOD_NODISCARD LightObj GetString1(SQInteger num)
|
|
{
|
|
const std::streamsize len = Get(num, Stream().widen('\n'));
|
|
// Create a string object and return it
|
|
return LightObj(m_Buffer.Get(), static_cast< SQInteger >(len));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Reads at most num-1 characters and returns them as character string, until `delim` is found.
|
|
*/
|
|
SQMOD_NODISCARD LightObj GetString2(SQInteger num, SQChar delim)
|
|
{
|
|
const std::streamsize len = Get(num, delim);
|
|
// Create a string object and return it
|
|
return LightObj(m_Buffer.Get(), static_cast< SQInteger >(len));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Reads at most num-1 characters and returns them as character string, until '\n' is found.
|
|
*/
|
|
SQMOD_NODISCARD LightObj GetBuffer1(SQInteger num)
|
|
{
|
|
const std::streamsize len = Get(num, Stream().widen('\n'));
|
|
// Create a buffer object and return it
|
|
return LightObj(SqTypeIdentity< SqBuffer >{}, SqVM(), m_Buffer.Get(), static_cast< Buffer::SzType >(len));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Reads at most num-1 characters and returns them as character string, until `delim` is found.
|
|
*/
|
|
SQMOD_NODISCARD LightObj GetBuffer2(SQInteger num, SQChar delim)
|
|
{
|
|
const std::streamsize len = Get(num, delim);
|
|
// Create a buffer object and return it
|
|
return LightObj(SqTypeIdentity< SqBuffer >{}, SqVM(), m_Buffer.Get(), static_cast< Buffer::SzType >(len));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Read the next character from the input stream without extracting it.
|
|
*/
|
|
SQMOD_NODISCARD SQInteger Peek()
|
|
{
|
|
return static_cast< SQInteger >(Stream().peek());
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Makes the most recently extracted character available again.
|
|
*/
|
|
SqStream & UnGet()
|
|
{
|
|
Stream().unget();
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Puts the character `c` back to the input stream so the next extracted character will be `c`.
|
|
*/
|
|
SqStream & PutBack(SQInteger c)
|
|
{
|
|
Stream().putback(static_cast< typename Type::char_type >(c));
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Extracts characters from stream until end of line or the specified delimiter `delim`.
|
|
*/
|
|
SQMOD_NODISCARD std::streamsize GetLine(SQInteger num, SQChar delim)
|
|
{
|
|
// Prevent negative lengths
|
|
if (num < 0)
|
|
{
|
|
STHROWF("Invalid length: {} < 0", num);
|
|
}
|
|
// Prevent overflow of Buffer::SzType
|
|
else
|
|
{
|
|
num = static_cast< SQInteger >(ClampL< SQInteger, Buffer::SzType >(num));
|
|
}
|
|
// Allocate a sufficiently large memory buffer
|
|
m_Buffer.Adjust(static_cast< Buffer::SzType >(num));
|
|
// Read data from the stream
|
|
Stream().getline(m_Buffer.Get(), static_cast< std::streamsize >(num), static_cast< typename Type::char_type >(delim));
|
|
// What actually stopped the reading?
|
|
if (Stream().rdstate() & (std::ios_base::eofbit | std::ios_base::failbit))
|
|
{
|
|
// Either end of file or end of count stopped the reading
|
|
return Stream().gcount();
|
|
}
|
|
else
|
|
{
|
|
// The delimiter stopped the reading but is only counted towards
|
|
// the number of elements. Not actually read and stored in the buffer
|
|
return Stream().gcount() > 0 ? (Stream().gcount() - 1) : std::streamsize(0);
|
|
}
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Extracts characters from stream until end of line or the specified delimiter '\n'.
|
|
*/
|
|
SQMOD_NODISCARD LightObj GetLineString1(SQInteger num)
|
|
{
|
|
const std::streamsize len = GetLine(num, Stream().widen('\n'));
|
|
// Create a string object and return it
|
|
return LightObj(m_Buffer.Get(), static_cast< SQInteger >(len));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Extracts characters from stream until end of line or the specified delimiter `delim`.
|
|
*/
|
|
SQMOD_NODISCARD LightObj GetLineString2(SQInteger num, SQChar delim)
|
|
{
|
|
const std::streamsize len = GetLine(num, delim);
|
|
// Create a string object and return it
|
|
return LightObj(m_Buffer.Get(), static_cast< SQInteger >(len));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Extracts characters from stream until end of line or the specified delimiter '\n'.
|
|
*/
|
|
SQMOD_NODISCARD LightObj GetLineBuffer1(SQInteger num)
|
|
{
|
|
const std::streamsize len = GetLine(num, Stream().widen('\n'));
|
|
// Create a buffer object and return it
|
|
return LightObj(SqTypeIdentity< SqBuffer >{}, SqVM(), m_Buffer.Get(), static_cast< Buffer::SzType >(len));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Extracts characters from stream until end of line or the specified delimiter `delim`.
|
|
*/
|
|
SQMOD_NODISCARD LightObj GetLineBuffer2(SQInteger num, SQChar delim)
|
|
{
|
|
const std::streamsize len = GetLine(num, delim);
|
|
// Create a buffer object and return it
|
|
return LightObj(SqTypeIdentity< SqBuffer >{}, SqVM(), m_Buffer.Get(), static_cast< Buffer::SzType >(len));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Extracts and discards one character from the input stream until end of file.
|
|
*/
|
|
SqStream & Ignore0()
|
|
{
|
|
Stream().ignore();
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Extracts and discards `num` characters from the input stream until end of file.
|
|
*/
|
|
SqStream & Ignore1(SQInteger num)
|
|
{
|
|
Stream().ignore(static_cast< std::streamsize >(num));
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Extracts and discards characters from the input stream until and including `delim`.
|
|
*/
|
|
SqStream & Ignore2(SQInteger num, SQChar delim)
|
|
{
|
|
Stream().ignore(static_cast< std::streamsize >(num), static_cast< typename Type::char_type >(delim));
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Extracts characters from stream.
|
|
*/
|
|
SQMOD_NODISCARD std::streamsize Read(SQInteger num)
|
|
{
|
|
// Prevent negative lengths
|
|
if (num < 0)
|
|
{
|
|
STHROWF("Invalid length: {} < 0", num);
|
|
}
|
|
// Prevent overflow of Buffer::SzType
|
|
else
|
|
{
|
|
num = static_cast< SQInteger >(ClampL< SQInteger, Buffer::SzType >(num));
|
|
}
|
|
// Allocate a sufficiently large memory buffer
|
|
m_Buffer.Adjust(static_cast< Buffer::SzType >(num));
|
|
// Read data from the stream
|
|
Stream().read(m_Buffer.Get(), static_cast< std::streamsize >(num));
|
|
// Return the number of characters read
|
|
return Stream().gcount();
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Extracts characters from stream.
|
|
*/
|
|
SQMOD_NODISCARD LightObj ReadString(SQInteger num)
|
|
{
|
|
const std::streamsize len = Read(num);
|
|
// Create a string object and return it
|
|
return LightObj(m_Buffer.Get(), static_cast< SQInteger >(len));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Extracts characters from stream.
|
|
*/
|
|
SQMOD_NODISCARD LightObj ReadBuffer(SQInteger num)
|
|
{
|
|
const std::streamsize len = Read(num);
|
|
// Create a buffer object and return it
|
|
return LightObj(SqTypeIdentity< SqBuffer >{}, SqVM(), m_Buffer.Get(), static_cast< Buffer::SzType >(len));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Extracts up to `num` immediately available characters from the input stream.
|
|
*/
|
|
SQMOD_NODISCARD std::streamsize ReadSome(SQInteger num)
|
|
{
|
|
// Prevent negative lengths
|
|
if (num < 0)
|
|
{
|
|
STHROWF("Invalid length: {} < 0", num);
|
|
}
|
|
// Prevent overflow of Buffer::SzType
|
|
else
|
|
{
|
|
num = static_cast< SQInteger >(ClampL< SQInteger, Buffer::SzType >(num));
|
|
}
|
|
// Allocate a sufficiently large memory buffer
|
|
m_Buffer.Adjust(static_cast< Buffer::SzType >(num));
|
|
// Read data from the stream and return the number of characters read
|
|
return Stream().readsome(m_Buffer.Get(), static_cast< std::streamsize >(num));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Extracts up to `num` immediately available characters from the input stream.
|
|
*/
|
|
SQMOD_NODISCARD LightObj ReadSomeString(SQInteger num)
|
|
{
|
|
const std::streamsize len = ReadSome(num);
|
|
// Create a string object and return it
|
|
return LightObj(m_Buffer.Get(), static_cast< SQInteger >(len));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Extracts up to `num` immediately available characters from the input stream.
|
|
*/
|
|
SQMOD_NODISCARD LightObj ReadSomeBuffer(SQInteger num)
|
|
{
|
|
const std::streamsize len = ReadSome(num);
|
|
// Create a buffer object and return it
|
|
return LightObj(SqTypeIdentity< SqBuffer >{}, SqVM(), m_Buffer.Get(), static_cast< Buffer::SzType >(len));
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Returns the number of characters extracted by the last unformatted input operation.
|
|
*/
|
|
SQMOD_NODISCARD SQInteger GCount() const
|
|
{
|
|
return static_cast< SQInteger >(Stream().gcount());
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Returns a copy of the underlying string.
|
|
*/
|
|
SQMOD_NODISCARD String GetStr() const
|
|
{
|
|
return Stream().str();
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Replaces the contents of the underlying string.
|
|
*/
|
|
void SetStr(StackStrF & s)
|
|
{
|
|
Stream().str(s.ToStr());
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Check if the file stream has an associated file.
|
|
*/
|
|
SQMOD_NODISCARD bool IsOpen() const
|
|
{
|
|
return Stream().is_open();
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Open and associate the file with name `name` with the file stream.
|
|
*/
|
|
SqStream & Open(StackStrF & name)
|
|
{
|
|
Stream().open(name.mPtr);
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Open and associate the file with name `name` with the file stream.
|
|
*/
|
|
SqStream & Open_(SQInteger m, StackStrF & name)
|
|
{
|
|
Stream().open(name.mPtr, static_cast< std::ios_base::openmode >(m));
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Close the associated file.
|
|
*/
|
|
SqStream & Close()
|
|
{
|
|
Stream().close();
|
|
return *this; // Allow chaining
|
|
}
|
|
|
|
protected:
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Reusable memory buffer used internally to avoid having to allocate one repeatedly.
|
|
*/
|
|
Buffer m_Buffer;
|
|
};
|
|
|
|
} // Namespace:: SqMod
|