From 7d7fd44427d71497f2688dc32adfc6c9468962ed Mon Sep 17 00:00:00 2001 From: Sandu Liviu Catalin Date: Tue, 9 Mar 2021 00:18:07 +0200 Subject: [PATCH] Initial draft for I/O streams. --- module/CMakeLists.txt | 1 + module/Library/IO.cpp | 2 + module/Library/IO/Stream.cpp | 346 ++++++++++++++ module/Library/IO/Stream.hpp | 882 +++++++++++++++++++++++++++++++++++ 4 files changed, 1231 insertions(+) create mode 100644 module/Library/IO/Stream.cpp create mode 100644 module/Library/IO/Stream.hpp diff --git a/module/CMakeLists.txt b/module/CMakeLists.txt index cc8925cb..5c6a12be 100644 --- a/module/CMakeLists.txt +++ b/module/CMakeLists.txt @@ -68,6 +68,7 @@ add_library(SqModule MODULE SqBase.hpp Main.cpp Library/IO/Buffer.cpp Library/IO/Buffer.hpp Library/IO/File.cpp Library/IO/File.hpp Library/IO/INI.cpp Library/IO/INI.hpp + Library/IO/Stream.cpp Library/IO/Stream.hpp Library/MMDB.cpp Library/MMDB.hpp Library/Numeric.cpp Library/Numeric.hpp Library/Numeric/Long.cpp Library/Numeric/Long.hpp diff --git a/module/Library/IO.cpp b/module/Library/IO.cpp index c2f5b28c..10241028 100644 --- a/module/Library/IO.cpp +++ b/module/Library/IO.cpp @@ -6,12 +6,14 @@ namespace SqMod { // ------------------------------------------------------------------------------------------------ extern void Register_Buffer(HSQUIRRELVM vm); +extern void Register_Stream(HSQUIRRELVM vm); extern void Register_INI(HSQUIRRELVM vm); // ================================================================================================ void Register_IO(HSQUIRRELVM vm) { Register_Buffer(vm); + Register_Stream(vm); Register_INI(vm); } diff --git a/module/Library/IO/Stream.cpp b/module/Library/IO/Stream.cpp new file mode 100644 index 00000000..68c97fe9 --- /dev/null +++ b/module/Library/IO/Stream.cpp @@ -0,0 +1,346 @@ +// ------------------------------------------------------------------------------------------------ +#include "Library/IO/Stream.hpp" + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +SQMOD_DECL_TYPENAME(StringStreamTn, _SC("SqStringStream")) +SQMOD_DECL_TYPENAME(FileStreamTn, _SC("SqFileStream")) +SQMOD_DECL_TYPENAME(OStringStreamTn, _SC("SqOStringStream")) +SQMOD_DECL_TYPENAME(OFileStreamTn, _SC("SqOFileStream")) +SQMOD_DECL_TYPENAME(IStringStreamTn, _SC("SqIStringStream")) +SQMOD_DECL_TYPENAME(IFileStreamTn, _SC("SqIFileStream")) + +// ------------------------------------------------------------------------------------------------ +SQMOD_DECL_TYPENAME(CInStreamTn, _SC("SqCInStream")) +SQMOD_DECL_TYPENAME(COutStreamTn, _SC("SqCOutStream")) +SQMOD_DECL_TYPENAME(CErrStreamTn, _SC("SqCErrStream")) +SQMOD_DECL_TYPENAME(CLogStreamTn, _SC("SqCLogStream")) + +// ------------------------------------------------------------------------------------------------ +static LightObj FileToString(StackStrF & name) +{ + // Open file + std::ifstream t(name.mPtr); + String str; + // Pre-allocate buffer + t.seekg(0, std::ios::end); + str.reserve(t.tellg()); + t.seekg(0, std::ios::beg); + // Read contents + str.assign((std::istreambuf_iterator< SQChar >(t)), std::istreambuf_iterator< SQChar >()); + // Transform to object + return LightObj(str.data(), static_cast< SQInteger >(str.size())); +} + +// ------------------------------------------------------------------------------------------------ +static void StringToFile(StackStrF & name, StackStrF & str) +{ + // Open file + std::ofstream out(name.mPtr); + // Write contents + out.write(str.mPtr, static_cast< std::streamsize >(str.mLen)); + // Close file + out.close(); +} + +// ------------------------------------------------------------------------------------------------ +using StringStream = SqStream< std::stringstream >; +using FileStream = SqStream< std::fstream >; +using OStringStream = SqStream< std::ostringstream >; +using OFileStream = SqStream< std::ofstream >; +using IStringStream = SqStream< std::istringstream >; +using IFileStream = SqStream< std::ifstream >; + +// ------------------------------------------------------------------------------------------------ +using CInStream = SqStream< SqGlobalStream< CInTag > >; +using COutStream = SqStream< SqGlobalStream< COutTag > >; +using CErrStream = SqStream< SqGlobalStream< CErrTag > >; +using CLogStream = SqStream< SqGlobalStream< CLogTag > >; + +/* ================================================================================================ + * Utility used to reduce code duplication when registering streams. +*/ +template < class T > struct RegisterStream +{ + /* -------------------------------------------------------------------------------------------- + * Class object to be registered. + */ + Class< T, NoCopy< T > > mCls; + /* -------------------------------------------------------------------------------------------- + * Base constructor. + */ + RegisterStream(HSQUIRRELVM vm, const SQChar * tn) + : mCls(vm, tn) + { + } + /* -------------------------------------------------------------------------------------------- + * Base members. + */ + template < class Tn > RegisterStream & Base() + { + mCls + // Core Meta-methods + .SquirrelFunc(_SC("_typename"), &Tn::Fn) + // Properties + .Prop(_SC("Flags"), &T::GetFlags, &T::SetFlags) + .Prop(_SC("Width"), &T::GetWidth, &T::SetWidth) + .Prop(_SC("Precision"), &T::GetPrecision, &T::SetPrecision) + .Prop(_SC("Good"), &T::Good) + .Prop(_SC("EOF"), &T::EOF_) + .Prop(_SC("Fail"), &T::Fail) + .Prop(_SC("Bad"), &T::Bad) + .Prop(_SC("Fill"), &T::GetFill, &T::SetFill) + .Prop(_SC("State"), &T::GetState, &T::SetState) + .Prop(_SC("Exceptions"), &T::GetExceptions, &T::SetExceptions) + // Member Methods + .Func(_SC("UnSetF"), &T::UnSetF) + .Func(_SC("SetWidth"), &T::SetWidth) + .Func(_SC("SetPrecision"), &T::SetPrecision) + .Func(_SC("SetFill"), &T::SetFill) + .Func(_SC("AdjustBuffer"), &T::AdjustBuffer) + .Func(_SC("ReclaimBuffer"), &T::ReclaimBuffer) + // Member Overloads + .Overload(_SC("SetF"), &T::SetF) + .Overload(_SC("SetF"), &T::SetF_) + .Overload(_SC("Clear"), &T::Clear) + .Overload(_SC("Clear"), &T::ClearEx) + ; + // Allow chaining + return *this; + } + /* -------------------------------------------------------------------------------------------- + * Output members. + */ + RegisterStream & Output() + { + mCls + // Member Methods + .Func(_SC("TellP"), &T::TellP) + .Func(_SC("Put"), &T::Put) + .Func(_SC("Flush"), &T::Flush) + .Func(_SC("Write"), &T::WriteString) + .Func(_SC("WriteBuffer"), &T::WriteBuffer) + // Member Overloads + .Overload(_SC("SeekP"), &T::SeekP) + .Overload(_SC("SeekP"), &T::SeekP_) + ; + // Allow chaining + return *this; + } + /* -------------------------------------------------------------------------------------------- + * Input members. + */ + RegisterStream & Input() + { + mCls + // Properties + .Prop(_SC("GCount"), &T::GCount) + // Member Methods + .Func(_SC("TellG"), &T::TellG) + .Func(_SC("Peek"), &T::Peek) + .Func(_SC("UnGet"), &T::UnGet) + .Func(_SC("PutBack"), &T::PutBack) + .Func(_SC("Read"), &T::ReadString) + .Func(_SC("ReadBuffer"), &T::ReadBuffer) + .Func(_SC("ReadSome"), &T::ReadSomeString) + .Func(_SC("ReadSomeBuffer"), &T::ReadSomeBuffer) + // Member Overloads + .Overload(_SC("SeekG"), &T::SeekG) + .Overload(_SC("SeekG"), &T::SeekG_) + .Overload(_SC("Get"), &T::GetString0) + .Overload(_SC("Get"), &T::GetString1) + .Overload(_SC("Get"), &T::GetString2) + .Overload(_SC("GetBuffer"), &T::GetBuffer1) + .Overload(_SC("GetBuffer"), &T::GetBuffer2) + .Overload(_SC("GetLine"), &T::GetLineString1) + .Overload(_SC("GetLine"), &T::GetLineString2) + .Overload(_SC("GetLineBuffer"), &T::GetLineBuffer1) + .Overload(_SC("GetLineBuffer"), &T::GetLineBuffer2) + .Overload(_SC("Ignore"), &T::Ignore0) + .Overload(_SC("Ignore"), &T::Ignore1) + .Overload(_SC("Ignore"), &T::Ignore2) + ; + // Allow chaining + return *this; + } + /* -------------------------------------------------------------------------------------------- + * String type members. + */ + RegisterStream & StringType() + { + mCls + // Constructors + .template Ctor() + .template Ctor< SQInteger >() + // Properties + .Prop(_SC("Str"), &T::GetStr, &T::SetStr) + ; + // Allow chaining + return *this; + } + /* -------------------------------------------------------------------------------------------- + * File type members. + */ + RegisterStream & FileType() + { + mCls + // Constructors + .template Ctor< StackStrF & >() + .template Ctor< SQInteger, StackStrF & >() + // Properties + .Prop(_SC("IsOpen"), &T::IsOpen) + // Member Methods + .Func(_SC("Close"), &T::Close) + // Member Overloads + .Overload(_SC("Open"), &T::Open) + .Overload(_SC("Open"), &T::Open_) + ; + // Allow chaining + return *this; + } + /* -------------------------------------------------------------------------------------------- + * Global stream type members. + */ + RegisterStream & GlobalType() + { + mCls + // Constructors + .template Ctor() + ; + // Allow chaining + return *this; + } + /* -------------------------------------------------------------------------------------------- + * Bind the class object to a table. + */ + void Bind(Table & ns, const SQChar * name) + { + ns.Bind(name, mCls); + } +}; +// ================================================================================================ +void Register_Stream(HSQUIRRELVM vm) +{ + Table sns(vm); + // -------------------------------------------------------------------------------------------- + RegisterStream< StringStream >(vm, StringStreamTn::Str) + .Base< StringStreamTn >() + .Output() + .Input() + .StringType() + .Bind(sns, "String"); + // -------------------------------------------------------------------------------------------- + RegisterStream< FileStream >(vm, FileStreamTn::Str) + .Base< FileStreamTn >() + .Output() + .Input() + .FileType() + .Bind(sns, "File"); + // -------------------------------------------------------------------------------------------- + RegisterStream< OStringStream >(vm, OStringStreamTn::Str) + .Base< OStringStreamTn >() + .Output() + .StringType() + .Bind(sns, "OutputString"); + // -------------------------------------------------------------------------------------------- + RegisterStream< OFileStream >(vm, OFileStreamTn::Str) + .Base< OFileStreamTn >() + .Output() + .FileType() + .Bind(sns, "OutputFile"); + // -------------------------------------------------------------------------------------------- + RegisterStream< IStringStream >(vm, IStringStreamTn::Str) + .Base< IStringStreamTn >() + .Input() + .StringType() + .Bind(sns, "InputString"); + // -------------------------------------------------------------------------------------------- + RegisterStream< IFileStream >(vm, IFileStreamTn::Str) + .Base< IFileStreamTn >() + .Input() + .FileType() + .Bind(sns, "InputFile"); + // -------------------------------------------------------------------------------------------- + sns.FmtFunc(_SC("FileToString"), FileToString); + sns.FmtFunc(_SC("StringToFile"), StringToFile); + // -------------------------------------------------------------------------------------------- + /* This feature is implemented but not enabled because it's rather pointless */ + //RegisterStream< CInStream >(vm, CInStreamTn::Str) + // .Base< CInStreamTn >() + // .Input() + // .GlobalType() + // .Bind(sns, "CIn"); + // -------------------------------------------------------------------------------------------- + //RegisterStream< COutStream >(vm, COutStreamTn::Str) + // .Base< COutStreamTn >() + // .Output() + // .GlobalType() + // .Bind(sns, "COut"); + // -------------------------------------------------------------------------------------------- + //RegisterStream< CErrStream >(vm, CErrStreamTn::Str) + // .Base< CErrStreamTn >() + // .Output() + // .GlobalType() + // .Bind(sns, "CErr"); + // -------------------------------------------------------------------------------------------- + //RegisterStream< CLogStream >(vm, CLogStreamTn::Str) + // .Base< CLogStreamTn >() + // .Output() + // .GlobalType() + // .Bind(sns, "CLog"); + // -------------------------------------------------------------------------------------------- + RootTable(vm).Bind(_SC("SqStream"), sns); + // -------------------------------------------------------------------------------------------- + ConstTable(vm).Enum(_SC("SqIoState"), Enumeration(vm) + .Const(_SC("GoodBit"), SQInteger(std::ios_base::goodbit)) + .Const(_SC("BadBit"), SQInteger(std::ios_base::badbit)) + .Const(_SC("FailBit"), SQInteger(std::ios_base::failbit)) + .Const(_SC("EofBit"), SQInteger(std::ios_base::eofbit)) + ); + // -------------------------------------------------------------------------------------------- + ConstTable(vm).Enum(_SC("SqFmtFlags"), Enumeration(vm) + .Const(_SC("Dec"), SQInteger(std::ios_base::dec)) + .Const(_SC("Oct"), SQInteger(std::ios_base::oct)) + .Const(_SC("Hex"), SQInteger(std::ios_base::hex)) + .Const(_SC("BaseField"), SQInteger(std::ios_base::basefield)) + .Const(_SC("Left"), SQInteger(std::ios_base::left)) + .Const(_SC("Right"), SQInteger(std::ios_base::right)) + .Const(_SC("Internal"), SQInteger(std::ios_base::internal)) + .Const(_SC("AdjustField"), SQInteger(std::ios_base::adjustfield)) + .Const(_SC("Scientific"), SQInteger(std::ios_base::scientific)) + .Const(_SC("Fixed"), SQInteger(std::ios_base::fixed)) + .Const(_SC("FloatField"), SQInteger(std::ios_base::floatfield)) + .Const(_SC("BoolAlpha"), SQInteger(std::ios_base::boolalpha)) + .Const(_SC("ShowBase"), SQInteger(std::ios_base::showbase)) + .Const(_SC("ShowPoint"), SQInteger(std::ios_base::showpoint)) + .Const(_SC("ShowPos"), SQInteger(std::ios_base::showpos)) + .Const(_SC("SkipWS"), SQInteger(std::ios_base::skipws)) + .Const(_SC("UnitBuf"), SQInteger(std::ios_base::unitbuf)) + .Const(_SC("UpperCase"), SQInteger(std::ios_base::uppercase)) + ); + // -------------------------------------------------------------------------------------------- + ConstTable(vm).Enum(_SC("SqOpenMode"), Enumeration(vm) + .Const(_SC("App"), SQInteger(std::ios_base::app)) + .Const(_SC("Ate"), SQInteger(std::ios_base::ate)) + .Const(_SC("AtEnd"), SQInteger(std::ios_base::ate)) + .Const(_SC("Binary"), SQInteger(std::ios_base::binary)) + .Const(_SC("In"), SQInteger(std::ios_base::in)) + .Const(_SC("Out"), SQInteger(std::ios_base::out)) + .Const(_SC("Trunc"), SQInteger(std::ios_base::trunc)) + ); + // -------------------------------------------------------------------------------------------- + ConstTable(vm).Enum(_SC("SqSeekDir"), Enumeration(vm) + .Const(_SC("Beg"), SQInteger(std::ios_base::beg)) + .Const(_SC("Beginning"), SQInteger(std::ios_base::beg)) + .Const(_SC("Cur"), SQInteger(std::ios_base::cur)) + .Const(_SC("Current"), SQInteger(std::ios_base::cur)) + .Const(_SC("End"), SQInteger(std::ios_base::end)) + ); +} + +} // Namespace:: SqMod diff --git a/module/Library/IO/Stream.hpp b/module/Library/IO/Stream.hpp new file mode 100644 index 00000000..d9455091 --- /dev/null +++ b/module/Library/IO/Stream.hpp @@ -0,0 +1,882 @@ +#pragma once + +// ------------------------------------------------------------------------------------------------ +#include "Library/IO/Buffer.hpp" + +// ------------------------------------------------------------------------------------------------ +#include +#include +#include +#include +#include + +// ------------------------------------------------------------------------------------------------ +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()) + { + } +}; + +/* ------------------------------------------------------------------------------------------------ + * Stream-based input/output class. +*/ +template < class T > struct SqStream : public SqStreamStorage< T > +{ + using SqStreamStorage< T >::Stream; + // -------------------------------------------------------------------------------------------- + using Type = 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 & name) + : SqStreamStorage< T >(name.mPtr), m_Buffer() + { + } + + /* -------------------------------------------------------------------------------------------- + * Explicit file constructor. + */ + SqStream(SQInteger m, StackStrF & name) + : SqStreamStorage< T >(name.mPtr, 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