From f125c3a3c820e5fdbb89c1296dec878e2d9cc002 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sat, 20 Jul 2013 19:11:12 -0700 Subject: [PATCH] Add template I/O for streams --- .../beast_core/streams/beast_InputStream.cpp | 90 +++++++++++++++++++ .../beast_core/streams/beast_InputStream.h | 61 ++++++++++++- .../beast_core/streams/beast_OutputStream.cpp | 87 +++++++++++++++++- .../beast_core/streams/beast_OutputStream.h | 23 +++++ 4 files changed, 258 insertions(+), 3 deletions(-) diff --git a/modules/beast_core/streams/beast_InputStream.cpp b/modules/beast_core/streams/beast_InputStream.cpp index ebefef3171..ac47e96991 100644 --- a/modules/beast_core/streams/beast_InputStream.cpp +++ b/modules/beast_core/streams/beast_InputStream.cpp @@ -65,6 +65,8 @@ short InputStream::readShortBigEndian() int InputStream::readInt() { + static_bassert (sizeof (int) == 4); + char temp[4]; if (read (temp, 4) == 4) @@ -73,6 +75,16 @@ int InputStream::readInt() return 0; } +int32 InputStream::readInt32() +{ + char temp[4]; + + if (read (temp, 4) == 4) + return (int32) ByteOrder::littleEndianInt (temp); + + return 0; +} + int InputStream::readIntBigEndian() { char temp[4]; @@ -83,6 +95,16 @@ int InputStream::readIntBigEndian() return 0; } +int32 InputStream::readInt32BigEndian() +{ + char temp[4]; + + if (read (temp, 4) == 4) + return (int32) ByteOrder::bigEndianInt (temp); + + return 0; +} + int InputStream::readCompressedInt() { const uint8 sizeByte = (uint8) readByte(); @@ -229,3 +251,71 @@ void InputStream::skipNextBytes (int64 numBytesToSkip) numBytesToSkip -= read (temp, (int) bmin (numBytesToSkip, (int64) skipBufferSize)); } } + +//------------------------------------------------------------------------------ + +// Unfortunately, putting these in the header causes duplicate +// definition linker errors, even with the inline keyword! + +template <> +char InputStream::readType () { return readByte (); } + +template <> +short InputStream::readType () { return readShort (); } + +template <> +int32 InputStream::readType () { return readInt32 (); } + +template <> +int64 InputStream::readType () { return readInt64 (); } + +template <> +unsigned char InputStream::readType () { return static_cast (readByte ()); } + +template <> +unsigned short InputStream::readType () { return static_cast (readShort ()); } + +template <> +uint32 InputStream::readType () { return static_cast (readInt32 ()); } + +template <> +uint64 InputStream::readType () { return static_cast (readInt64 ()); } + +template <> +float InputStream::readType () { return readFloat (); } + +template <> +double InputStream::readType () { return readDouble (); } + +//------------------------------------------------------------------------------ + +template <> +char InputStream::readTypeBigEndian () { return readByte (); } + +template <> +short InputStream::readTypeBigEndian () { return readShortBigEndian (); } + +template <> +int32 InputStream::readTypeBigEndian () { return readInt32BigEndian (); } + +template <> +int64 InputStream::readTypeBigEndian () { return readInt64BigEndian (); } + +template <> +unsigned char InputStream::readTypeBigEndian () { return static_cast (readByte ()); } + +template <> +unsigned short InputStream::readTypeBigEndian () { return static_cast (readShortBigEndian ()); } + +template <> +uint32 InputStream::readTypeBigEndian () { return static_cast (readInt32BigEndian ()); } + +template <> +uint64 InputStream::readTypeBigEndian () { return static_cast (readInt64BigEndian ()); } + +template <> +float InputStream::readTypeBigEndian () { return readFloatBigEndian (); } + +template <> +double InputStream::readTypeBigEndian () { return readDoubleBigEndian (); } + diff --git a/modules/beast_core/streams/beast_InputStream.h b/modules/beast_core/streams/beast_InputStream.h index 7d7e643234..30df5ac567 100644 --- a/modules/beast_core/streams/beast_InputStream.h +++ b/modules/beast_core/streams/beast_InputStream.h @@ -92,7 +92,7 @@ public: /** Reads a boolean from the stream. - The bool is encoded as a single byte - 1 for true, 0 for false. + The bool is encoded as a single byte - 0 for false, nonzero for true. If the stream is exhausted, this will return false. @@ -111,6 +111,10 @@ public: */ virtual short readShort(); + // VFALCO TODO Implement these functions + //virtual int16 readInt16 (); + //virtual uint16 readUInt16 (); + /** Reads two bytes from the stream as a little-endian 16-bit value. If the next two bytes read are byte1 and byte2, this returns @@ -131,6 +135,13 @@ public: @see OutputStream::writeInt, readIntBigEndian */ + virtual int32 readInt32(); + + // VFALCO TODO Implement these functions + //virtual int16 readInt16BigEndian (); + //virtual uint16 readUInt16BigEndian (); + + // DEPRECATED, assumes sizeof(int) == 4! virtual int readInt(); /** Reads four bytes from the stream as a big-endian 32-bit value. @@ -142,6 +153,9 @@ public: @see OutputStream::writeIntBigEndian, readInt */ + virtual int32 readInt32BigEndian(); + + // DEPRECATED, assumes sizeof(int) == 4! virtual int readIntBigEndian(); /** Reads eight bytes from the stream as a little-endian 64-bit value. @@ -216,6 +230,49 @@ public: */ virtual int readCompressedInt(); + /** Reads a type using a template specialization. + + This is useful when doing template meta-programming. + */ + template + T readType (); + + /** Reads a type using a template specialization. + + The variable is passed as a parameter so that the template type + can be deduced. + + This is useful when doing template meta-programming. + */ + template + void readTypeInto (T* p) + { + *p = readType (); + } + + /** Reads a type from a big endian stream using a template specialization. + + The raw encoding of the type is read from the stream as a big-endian value + where applicable. + + This is useful when doing template meta-programming. + */ + template + T readTypeBigEndian (); + + /** Reads a type using a template specialization. + + The variable is passed as a parameter so that the template type + can be deduced. + + This is useful when doing template meta-programming. + */ + template + void readTypeBigEndianInto (T* p) + { + *p = readTypeBigEndian (); + } + //============================================================================== /** Reads a UTF-8 string from the stream, up to the next linefeed or carriage return. @@ -289,4 +346,4 @@ protected: InputStream() noexcept {} }; -#endif // BEAST_INPUTSTREAM_BEASTHEADER +#endif diff --git a/modules/beast_core/streams/beast_OutputStream.cpp b/modules/beast_core/streams/beast_OutputStream.cpp index c1ac44c04c..614b32e1db 100644 --- a/modules/beast_core/streams/beast_OutputStream.cpp +++ b/modules/beast_core/streams/beast_OutputStream.cpp @@ -93,14 +93,32 @@ bool OutputStream::writeShortBigEndian (short value) return write (&v, 2); } +bool OutputStream::writeInt32 (int32 value) +{ + static_bassert (sizeof (int32) == 4); + + const unsigned int v = ByteOrder::swapIfBigEndian ((uint32) value); + return write (&v, 4); +} + bool OutputStream::writeInt (int value) { + static_bassert (sizeof (int) == 4); + const unsigned int v = ByteOrder::swapIfBigEndian ((unsigned int) value); return write (&v, 4); } +bool OutputStream::writeInt32BigEndian (int value) +{ + static_bassert (sizeof (int32) == 4); + const uint32 v = ByteOrder::swapIfLittleEndian ((uint32) value); + return write (&v, 4); +} + bool OutputStream::writeIntBigEndian (int value) { + static_bassert (sizeof (int) == 4); const unsigned int v = ByteOrder::swapIfLittleEndian ((unsigned int) value); return write (&v, 4); } @@ -328,4 +346,71 @@ BEAST_API OutputStream& BEAST_CALLTYPE operator<< (OutputStream& stream, InputSt BEAST_API OutputStream& BEAST_CALLTYPE operator<< (OutputStream& stream, const NewLine&) { return stream << stream.getNewLineString(); -} \ No newline at end of file +} + +//------------------------------------------------------------------------------ + +// Unfortunately, putting these in the header causes duplicate +// definition linker errors, even with the inline keyword! + +template <> +BEAST_API bool OutputStream::writeType (char v) { return writeByte (v); } + +template <> +BEAST_API bool OutputStream::writeType (short v) { return writeShort (v); } + +template <> +BEAST_API bool OutputStream::writeType (int32 v) { return writeInt32 (v); } + +template <> +BEAST_API bool OutputStream::writeType (int64 v) { return writeInt64 (v); } + +template <> +BEAST_API bool OutputStream::writeType (unsigned char v) { return writeByte (static_cast (v)); } + +template <> +BEAST_API bool OutputStream::writeType (unsigned short v) { return writeShort (static_cast (v)); } + +template <> +BEAST_API bool OutputStream::writeType (uint32 v) { return writeInt32 (static_cast (v)); } + +template <> +BEAST_API bool OutputStream::writeType (uint64 v) { return writeInt64 (static_cast (v)); } + +template <> +BEAST_API bool OutputStream::writeType (float v) { return writeFloat (v); } + +template <> +BEAST_API bool OutputStream::writeType (double v) { return writeDouble (v); } + +//------------------------------------------------------------------------------ + +template <> +BEAST_API bool OutputStream::writeTypeBigEndian (char v) { return writeByte (v); } + +template <> +BEAST_API bool OutputStream::writeTypeBigEndian (short v) { return writeShortBigEndian (v); } + +template <> +BEAST_API bool OutputStream::writeTypeBigEndian (int32 v) { return writeInt32BigEndian (v); } + +template <> +BEAST_API bool OutputStream::writeTypeBigEndian (int64 v) { return writeInt64BigEndian (v); } + +template <> +BEAST_API bool OutputStream::writeTypeBigEndian (unsigned char v) { return writeByte (static_cast (v)); } + +template <> +BEAST_API bool OutputStream::writeTypeBigEndian (unsigned short v) { return writeShortBigEndian (static_cast (v)); } + +template <> +BEAST_API bool OutputStream::writeTypeBigEndian (uint32 v) { return writeInt32BigEndian (static_cast (v)); } + +template <> +BEAST_API bool OutputStream::writeTypeBigEndian (uint64 v) { return writeInt64BigEndian (static_cast (v)); } + +template <> +BEAST_API bool OutputStream::writeTypeBigEndian (float v) { return writeFloatBigEndian (v); } + +template <> +BEAST_API bool OutputStream::writeTypeBigEndian (double v) { return writeDoubleBigEndian (v); } diff --git a/modules/beast_core/streams/beast_OutputStream.h b/modules/beast_core/streams/beast_OutputStream.h index 0528f0fcac..b536c48a57 100644 --- a/modules/beast_core/streams/beast_OutputStream.h +++ b/modules/beast_core/streams/beast_OutputStream.h @@ -120,12 +120,18 @@ public: @returns false if the write operation fails for some reason @see InputStream::readInt */ + virtual bool writeInt32 (int32 value); + + // DEPRECATED, assumes sizeof (int) == 4! virtual bool writeInt (int value); /** Writes a 32-bit integer to the stream in a big-endian byte order. @returns false if the write operation fails for some reason @see InputStream::readIntBigEndian */ + virtual bool writeInt32BigEndian (int32 value); + + // DEPRECATED, assumes sizeof (int) == 4! virtual bool writeIntBigEndian (int value); /** Writes a 64-bit integer to the stream in a little-endian byte order. @@ -168,6 +174,23 @@ public: */ virtual bool writeDoubleBigEndian (double value); + /** Write a type using a template specialization. + + This is useful when doing template meta-programming. + */ + template + bool writeType (T value); + + /** Write a type using a template specialization. + + The raw encoding of the type is written to the stream as a big-endian value + where applicable. + + This is useful when doing template meta-programming. + */ + template + bool writeTypeBigEndian (T value); + /** Writes a byte to the output stream a given number of times. @returns false if the write operation fails for some reason */