diff --git a/src/PacketReader.h b/src/PacketReader.h index de71de3..c6912f7 100644 --- a/src/PacketReader.h +++ b/src/PacketReader.h @@ -1,6 +1,7 @@ #pragma once #include "Common.h" +#include "util/ByteUtil.h" #include #include @@ -19,20 +20,32 @@ namespace Feather { } - template + // Peek the next value to be read + // If big endian (the default), will reverse byte order. + template inline T Peek() { - return *reinterpret_cast(&m_data[m_offset]); + T value = *reinterpret_cast(&m_data[m_offset]); + + return (endianMode == Endian::Big) ? ReverseBytes(value) : value; } - template + // Read the next value + // If big endian (the default), will reverse byte order. + template inline T Read() { - T value = Peek(); + T value = Peek(); m_offset += sizeof(T); return value; } + // Fast way to peek the next byte + inline uint8_t PeekByte() { return m_data[m_offset]; } + + // Fast way to read a byte + inline uint8_t ReadByte() { return m_data[m_offset++]; } + template inline T ReadVarInt() { @@ -41,7 +54,7 @@ namespace Feather uint8_t read; do { - read = Read(); + read = ReadByte(); int value = (read & 0b01111111); result |= (value << (7 * numRead)); @@ -62,10 +75,8 @@ namespace Feather string str; for (int i = 0; i < size; i++) { - str += Read(); + str += ReadByte(); } - - //printf("Read string of length %d: %s\n", size, str); return str; } @@ -77,4 +88,11 @@ namespace Feather const uint32_t m_length; }; + // Use fast Read and Peek for uint8_t + + template <> + inline uint8_t PacketReader::Peek() { return PeekByte(); } + + template<> + inline uint8_t PacketReader::Read() { return ReadByte(); } } diff --git a/src/util/ByteUtil.h b/src/util/ByteUtil.h new file mode 100644 index 0000000..eda6fb0 --- /dev/null +++ b/src/util/ByteUtil.h @@ -0,0 +1,38 @@ +#pragma once + +#ifdef _MSC_VER +#include +#endif + +enum class Endian +{ + Little, + Big +}; + +// Reverses the byte order of a primitive value of any typical size +template +inline constexpr T ReverseBytes(T n) +{ + // 1 byte, cannot reverse + if constexpr (sizeof(T) == 1) return n; + +#ifdef __GNUC__ + // GCC intrinsic byte swaps + // https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005fbswap16 + + if constexpr (sizeof(T) == 2) return __builtin_bswap16(n); // 2 bytes + else if constexpr (sizeof(T) == 4) return __builtin_bswap32(n); // 4 bytes + else if constexpr (sizeof(T) == 8) return __builtin_bswap64(n); // 8 bytes + +#elif defined(_MSC_VER) + // MSVC intrinsic byteswaps + // https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/byteswap-uint64-byteswap-ulong-byteswap-ushort + + if constexpr (sizeof(T) == 2) return _byteswap_ushort(n); // 2 bytes + else if constexpr (sizeof(T) == 4) return _byteswap_ulong(n); // 4 bytes + else if constexpr (sizeof(T) == 8) return _byteswap_uint64(n); // 8 bytes +#endif + //else static_assert(false, "Attempted to call ReverseBytes() on type with unusual size."); +} +