#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()) { } }; /* ------------------------------------------------------------------------------------------------ * 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