From 31421d5cc35541aea61767d544986a31e276db8e Mon Sep 17 00:00:00 2001 From: MikeGitb Date: Sun, 18 Sep 2016 22:32:56 +0200 Subject: [PATCH] Add alternative implementations of gsl::byte --- gsl/gsl_byte | 160 +++++++++++++++++++++++++++++++++++++ tests/byte_tests.cpp | 43 ++++++++-- tests/multi_span_tests.cpp | 2 +- 3 files changed, 199 insertions(+), 6 deletions(-) diff --git a/gsl/gsl_byte b/gsl/gsl_byte index 3f77923..90885f9 100644 --- a/gsl/gsl_byte +++ b/gsl/gsl_byte @@ -41,8 +41,167 @@ #endif // _MSC_VER +#define GSL_BYTE_TYPE_ENUM 0 +#define GSL_BYTE_TYPE_UCHAR 1 +#define GSL_BYTE_TYPE_STRUCT 2 + +#ifndef GSL_USE_BYTE_TYPE +// currently clang++ as well as g++ don't allow a pointer to +// +// < enum class byte : unsigned char > +// +// to alias other types. +// so we have to use a typedef to unsigned char instead. +#ifdef _MSC_VER + #define GSL_USE_BYTE_TYPE GSL_BYTE_TYPE_ENUM +#else + #define GSL_USE_BYTE_TYPE GSL_BYTE_TYPE_STRUCT +#endif + +#endif + namespace gsl { +//################################### implemet byte as unsigned char #################################### +#if GSL_USE_BYTE_TYPE == GSL_BYTE_TYPE_UCHAR + +using byte = unsigned char; + +template ::value>> +inline constexpr IntegerType to_integer(byte b) noexcept +{ + return{ b }; +} + +template +inline constexpr byte to_byte_impl(T t) noexcept +{ + static_assert( + E, + "gsl::to_byte(t) must be provided an unsigned char, otherwise data loss may occur. " + "If you are calling to_byte with an integer contant use: gsl::to_byte() version." + ); + return static_cast(t); +} + +template<> +inline constexpr byte to_byte_impl(unsigned char t) noexcept +{ + return byte(t); +} + +template +inline constexpr byte to_byte(T t) noexcept +{ + return to_byte_impl::value, T>(t); +} + +template +inline constexpr byte to_byte() noexcept +{ + static_assert(I >= 0 && I <= 255, "gsl::byte only has 8 bits of storage, values must be in range 0-255"); + return static_cast(I); +} + +//################################### implemet byte as struct #################################### + +#elif GSL_USE_BYTE_TYPE == GSL_BYTE_TYPE_STRUCT + +// This is a simple definition for now that allows +// use of byte within span<> to be standards-compliant +struct byte { + unsigned char v; + explicit operator unsigned char&() { return v; } + explicit operator const unsigned char&() const { return v; } + friend bool operator==(byte l, byte r) { return l.v == r.v; } + friend bool operator!=(byte l, byte r) { return l.v != r.v; } +}; + +template ::value>> +inline constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept +{ + return b.v <<= shift, b; +} + +template ::value>> +inline constexpr byte operator<<(byte b, IntegerType shift) noexcept +{ + return byte{ static_cast(b.v << shift) }; +} + +template ::value>> +inline constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept +{ + return b.v >>= shift, b; +} + +template ::value>> +inline constexpr byte operator >> (byte b, IntegerType shift) noexcept +{ + return byte{ static_cast(b.v >> shift) }; +} + +inline constexpr byte& operator|=(byte& l, byte r) noexcept +{ + return l.v |= r.v, l; +} + +inline constexpr byte operator|(byte l, byte r) noexcept +{ + return byte{ static_cast(l.v | r.v) }; +} + +inline constexpr byte& operator&=(byte& l, byte r) noexcept +{ + return l.v &= r.v, l; +} + +inline constexpr byte operator&(byte l, byte r) noexcept +{ + return byte{ static_cast(l.v & r.v) }; +} + +inline constexpr byte& operator^=(byte& l, byte r) noexcept +{ + return l.v ^= r.v, l; +} + +inline constexpr byte operator^(byte l, byte r) noexcept +{ + return byte{ static_cast(l.v ^ r.v) }; +} + +inline constexpr byte operator~(byte b) noexcept { return byte{ static_cast(~b.v) }; } + + +template ::value>> +inline constexpr IntegerType to_integer(byte b) noexcept +{ + return static_cast(b.v); +} + +template +inline constexpr byte to_byte(T t) noexcept +{ + static_assert( + std::is_same::value, + "gsl::to_byte(t) must be provided an unsigned char, otherwise data loss may occur. " + "If you are calling to_byte with an integer contant use: gsl::to_byte() version." + ); + return byte{ t }; +} + +template +inline constexpr byte to_byte() noexcept +{ + static_assert(I >= 0 && I <= 255, "gsl::byte only has 8 bits of storage, values must be in range 0-255"); + return byte{ static_cast(I) }; +} + +//################################### implemet byte as enum #################################### + +#elif GSL_USE_BYTE_TYPE == GSL_BYTE_TYPE_ENUM + // This is a simple definition for now that allows // use of byte within span<> to be standards-compliant enum class byte : unsigned char @@ -139,6 +298,7 @@ inline constexpr byte to_byte() noexcept static_assert(I >= 0 && I <= 255, "gsl::byte only has 8 bits of storage, values must be in range 0-255"); return static_cast(I); } +#endif // GSL_USE_ENUM_BYTE } // namespace gsl diff --git a/tests/byte_tests.cpp b/tests/byte_tests.cpp index 32b0957..4d52166 100644 --- a/tests/byte_tests.cpp +++ b/tests/byte_tests.cpp @@ -34,6 +34,17 @@ SUITE(byte_tests) { TEST(construction) { +#if GSL_USE_BYTE_TYPE == GSL_BYTE_TYPE_STRUCT + { + byte b{ 4 }; + CHECK(static_cast(b) == 4); + } + + { + byte b = byte{ 12 }; + CHECK(static_cast(b) == 12); + } +#else { byte b = static_cast(4); CHECK(static_cast(b) == 4); @@ -43,6 +54,7 @@ SUITE(byte_tests) byte b = byte(12); CHECK(static_cast(b) == 12); } +#endif { byte b = to_byte<12>(); @@ -70,7 +82,7 @@ SUITE(byte_tests) TEST(aliasing) { - int i{0}; + int i{ 0 }; int res = modify_both(reinterpret_cast(&i), &i); CHECK(res == i); } @@ -78,32 +90,55 @@ SUITE(byte_tests) TEST(bitwise_operations) { byte b = to_byte<0xFF>(); - byte a = to_byte<0x00>(); + +#if GSL_USE_BYTE_TYPE == GSL_BYTE_TYPE_UCHAR + CHECK(static_cast(b | a) == to_byte<0xFF>()); +#else CHECK((b | a) == to_byte<0xFF>()); +#endif + CHECK(a == to_byte<0x00>()); a |= b; CHECK(a == to_byte<0xFF>()); a = to_byte<0x01>(); + +#if GSL_USE_BYTE_TYPE == GSL_BYTE_TYPE_UCHAR + CHECK(static_cast(b & a) == to_byte<0x01>()); +#else CHECK((b & a) == to_byte<0x01>()); +#endif a &= b; CHECK(a == to_byte<0x01>()); +#if GSL_USE_BYTE_TYPE == GSL_BYTE_TYPE_UCHAR + CHECK(static_cast(b ^ a) == to_byte<0xFE>()); +#else CHECK((b ^ a) == to_byte<0xFE>()); - +#endif CHECK(a == to_byte<0x01>()); + a ^= b; CHECK(a == to_byte<0xFE>()); a = to_byte<0x01>(); +#if GSL_USE_BYTE_TYPE == GSL_BYTE_TYPE_UCHAR + CHECK(static_cast(~a) == to_byte<0xFE>()); +#else CHECK(~a == to_byte<0xFE>()); +#endif a = to_byte<0xFF>(); +#if GSL_USE_BYTE_TYPE == GSL_BYTE_TYPE_UCHAR + CHECK(static_cast(a << 4) == to_byte<0xF0>()); + CHECK(static_cast(a >> 4) == to_byte<0x0F>()); +#else CHECK((a << 4) == to_byte<0xF0>()); CHECK((a >> 4) == to_byte<0x0F>()); +#endif a <<= 4; CHECK(a == to_byte<0xF0>()); @@ -129,7 +164,5 @@ SUITE(byte_tests) // CHECK(0x12 == gsl::to_integer(b)); // expect compile-time error } } - } - int main(int, const char* []) { return UnitTest::RunAllTests(); } diff --git a/tests/multi_span_tests.cpp b/tests/multi_span_tests.cpp index c0240ea..4e00e49 100644 --- a/tests/multi_span_tests.cpp +++ b/tests/multi_span_tests.cpp @@ -1663,7 +1663,7 @@ SUITE(multi_span_tests) multi_span av = a; auto wav = as_writeable_bytes(av); for (auto& b : wav) { - b = byte(0); + b = to_byte<0>(); } for (size_t i = 0; i < 4; ++i) { CHECK(a[i] == 0);