Add template I/O for streams

This commit is contained in:
Vinnie Falco
2013-07-20 19:11:12 -07:00
parent cb22f63c08
commit 2f929373c3
4 changed files with 258 additions and 3 deletions

View File

@@ -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 <char> () { return readByte (); }
template <>
short InputStream::readType <short> () { return readShort (); }
template <>
int32 InputStream::readType <int32> () { return readInt32 (); }
template <>
int64 InputStream::readType <int64> () { return readInt64 (); }
template <>
unsigned char InputStream::readType <unsigned char> () { return static_cast <unsigned char> (readByte ()); }
template <>
unsigned short InputStream::readType <unsigned short> () { return static_cast <unsigned short> (readShort ()); }
template <>
uint32 InputStream::readType <uint32> () { return static_cast <uint32> (readInt32 ()); }
template <>
uint64 InputStream::readType <uint64> () { return static_cast <uint64> (readInt64 ()); }
template <>
float InputStream::readType <float> () { return readFloat (); }
template <>
double InputStream::readType <double> () { return readDouble (); }
//------------------------------------------------------------------------------
template <>
char InputStream::readTypeBigEndian <char> () { return readByte (); }
template <>
short InputStream::readTypeBigEndian <short> () { return readShortBigEndian (); }
template <>
int32 InputStream::readTypeBigEndian <int32> () { return readInt32BigEndian (); }
template <>
int64 InputStream::readTypeBigEndian <int64> () { return readInt64BigEndian (); }
template <>
unsigned char InputStream::readTypeBigEndian <unsigned char> () { return static_cast <unsigned char> (readByte ()); }
template <>
unsigned short InputStream::readTypeBigEndian <unsigned short> () { return static_cast <unsigned short> (readShortBigEndian ()); }
template <>
uint32 InputStream::readTypeBigEndian <uint32> () { return static_cast <uint32> (readInt32BigEndian ()); }
template <>
uint64 InputStream::readTypeBigEndian <uint64> () { return static_cast <uint64> (readInt64BigEndian ()); }
template <>
float InputStream::readTypeBigEndian <float> () { return readFloatBigEndian (); }
template <>
double InputStream::readTypeBigEndian <double> () { return readDoubleBigEndian (); }

View File

@@ -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 <class T>
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 <class T>
void readTypeInto (T* p)
{
*p = readType <T> ();
}
/** 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 <class T>
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 <class T>
void readTypeBigEndianInto (T* p)
{
*p = readTypeBigEndian <T> ();
}
//==============================================================================
/** 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

View File

@@ -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);
}
@@ -329,3 +347,70 @@ BEAST_API OutputStream& BEAST_CALLTYPE operator<< (OutputStream& stream, const N
{
return stream << stream.getNewLineString();
}
//------------------------------------------------------------------------------
// Unfortunately, putting these in the header causes duplicate
// definition linker errors, even with the inline keyword!
template <>
BEAST_API bool OutputStream::writeType <char> (char v) { return writeByte (v); }
template <>
BEAST_API bool OutputStream::writeType <short> (short v) { return writeShort (v); }
template <>
BEAST_API bool OutputStream::writeType <int32> (int32 v) { return writeInt32 (v); }
template <>
BEAST_API bool OutputStream::writeType <int64> (int64 v) { return writeInt64 (v); }
template <>
BEAST_API bool OutputStream::writeType <unsigned char> (unsigned char v) { return writeByte (static_cast <char> (v)); }
template <>
BEAST_API bool OutputStream::writeType <unsigned short> (unsigned short v) { return writeShort (static_cast <short> (v)); }
template <>
BEAST_API bool OutputStream::writeType <uint32> (uint32 v) { return writeInt32 (static_cast <int32> (v)); }
template <>
BEAST_API bool OutputStream::writeType <uint64> (uint64 v) { return writeInt64 (static_cast <int64> (v)); }
template <>
BEAST_API bool OutputStream::writeType <float> (float v) { return writeFloat (v); }
template <>
BEAST_API bool OutputStream::writeType <double> (double v) { return writeDouble (v); }
//------------------------------------------------------------------------------
template <>
BEAST_API bool OutputStream::writeTypeBigEndian <char> (char v) { return writeByte (v); }
template <>
BEAST_API bool OutputStream::writeTypeBigEndian <short> (short v) { return writeShortBigEndian (v); }
template <>
BEAST_API bool OutputStream::writeTypeBigEndian <int32> (int32 v) { return writeInt32BigEndian (v); }
template <>
BEAST_API bool OutputStream::writeTypeBigEndian <int64> (int64 v) { return writeInt64BigEndian (v); }
template <>
BEAST_API bool OutputStream::writeTypeBigEndian <unsigned char> (unsigned char v) { return writeByte (static_cast <char> (v)); }
template <>
BEAST_API bool OutputStream::writeTypeBigEndian <unsigned short> (unsigned short v) { return writeShortBigEndian (static_cast <short> (v)); }
template <>
BEAST_API bool OutputStream::writeTypeBigEndian <uint32> (uint32 v) { return writeInt32BigEndian (static_cast <int32> (v)); }
template <>
BEAST_API bool OutputStream::writeTypeBigEndian <uint64> (uint64 v) { return writeInt64BigEndian (static_cast <int64> (v)); }
template <>
BEAST_API bool OutputStream::writeTypeBigEndian <float> (float v) { return writeFloatBigEndian (v); }
template <>
BEAST_API bool OutputStream::writeTypeBigEndian <double> (double v) { return writeDoubleBigEndian (v); }

View File

@@ -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 <class T>
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 <class T>
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
*/