From 95bbaa1ec2c2fa39ecea4dc3c685f771551c59ff Mon Sep 17 00:00:00 2001 From: Kris Date: Sun, 28 Aug 2016 21:55:58 +0100 Subject: [PATCH 1/3] Added to_byte method for issue #329 I have added the to_byte method and updated the unit tests. This gives slightly nicer syntax than static_cast, is better than the c-style cast used in the unit test. See: https://github.com/Microsoft/GSL/issues/329#issuecomment-240588515 --- gsl/gsl_byte | 6 ++++++ tests/byte_tests.cpp | 41 +++++++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/gsl/gsl_byte b/gsl/gsl_byte index 91ce9d2..98749a7 100644 --- a/gsl/gsl_byte +++ b/gsl/gsl_byte @@ -106,6 +106,12 @@ constexpr IntegerType to_integer(byte b) noexcept return {b}; } +constexpr byte to_byte(unsigned char i) noexcept +{ + return static_cast(i); +} + + } // namespace gsl #ifdef _MSC_VER diff --git a/tests/byte_tests.cpp b/tests/byte_tests.cpp index f2f8026..d6d4823 100644 --- a/tests/byte_tests.cpp +++ b/tests/byte_tests.cpp @@ -43,6 +43,11 @@ SUITE(byte_tests) byte b = byte(12); CHECK(static_cast(b) == 12); } + + { + byte b = to_byte(12); + CHECK(static_cast(b) == 12); + } // waiting for C++17 enum class direct initializer support //{ @@ -53,38 +58,38 @@ SUITE(byte_tests) TEST(bitwise_operations) { - byte b = byte(0xFF); + byte b = to_byte(0xFF); - byte a = byte(0x00); - CHECK((b | a) == byte(0xFF)); - CHECK(a == byte(0x00)); + byte a = to_byte(0x00); + CHECK((b | a) == to_byte(0xFF)); + CHECK(a == to_byte(0x00)); a |= b; - CHECK(a == byte(0xFF)); + CHECK(a == to_byte(0xFF)); - a = byte(0x01); - CHECK((b & a) == byte(0x01)); + a = to_byte(0x01); + CHECK((b & a) == to_byte(0x01)); a &= b; - CHECK(a == byte(0x01)); + CHECK(a == to_byte(0x01)); - CHECK((b ^ a) == byte(0xFE)); + CHECK((b ^ a) == to_byte(0xFE)); - CHECK(a == byte(0x01)); + CHECK(a == to_byte(0x01)); a ^= b; - CHECK(a == byte(0xFE)); + CHECK(a == to_byte(0xFE)); - a = byte(0x01); - CHECK(~a == byte(0xFE)); + a = to_byte(0x01); + CHECK(~a == to_byte(0xFE)); - a = byte(0xFF); - CHECK((a << 4) == byte(0xF0)); - CHECK((a >> 4) == byte(0x0F)); + a = to_byte(0xFF); + CHECK((a << 4) == to_byte(0xF0)); + CHECK((a >> 4) == to_byte(0x0F)); a <<= 4; - CHECK(a == byte(0xF0)); + CHECK(a == to_byte(0xF0)); a >>= 4; - CHECK(a == byte(0x0F)); + CHECK(a == to_byte(0x0F)); } } From 55b232dde4189525fe211d0e7c8f952a3e3e061d Mon Sep 17 00:00:00 2001 From: Kris Cruickshank Date: Wed, 7 Sep 2016 21:38:43 +0100 Subject: [PATCH 2/3] Issue: #329 This is my best attempt at fixing the issues raised by @gdr-at-ms while supporting VS2013, VS2015, providing shorter syntax than the static_cast and giving developer meaningful errors when they do the wrong thing. --- gsl/gsl_byte | 26 ++++++++++++++++++++++++-- tests/byte_tests.cpp | 43 ++++++++++++++++++++++++------------------- 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/gsl/gsl_byte b/gsl/gsl_byte index 98749a7..c973320 100644 --- a/gsl/gsl_byte +++ b/gsl/gsl_byte @@ -106,11 +106,33 @@ constexpr IntegerType to_integer(byte b) noexcept return {b}; } -constexpr byte to_byte(unsigned char i) noexcept +template +constexpr byte to_byte_impl(T t) noexcept { - return static_cast(i); + static_assert( + false, + "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." + ) +} +template<> +constexpr byte to_byte_impl(unsigned char t) noexcept +{ + return byte(t); } +template +constexpr byte to_byte(T t) noexcept +{ + return to_byte_impl::value, T>(t); +} + +template +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); +} } // namespace gsl diff --git a/tests/byte_tests.cpp b/tests/byte_tests.cpp index d6d4823..59ff0cd 100644 --- a/tests/byte_tests.cpp +++ b/tests/byte_tests.cpp @@ -45,7 +45,12 @@ SUITE(byte_tests) } { - byte b = to_byte(12); + byte b = to_byte<12>(); + CHECK(static_cast(b) == 12); + } + { + unsigned char uc = 12; + byte b = to_byte(uc); CHECK(static_cast(b) == 12); } @@ -58,38 +63,38 @@ SUITE(byte_tests) TEST(bitwise_operations) { - byte b = to_byte(0xFF); + byte b = to_byte<0xFF>(); - byte a = to_byte(0x00); - CHECK((b | a) == to_byte(0xFF)); - CHECK(a == to_byte(0x00)); + byte a = to_byte<0x00>(); + CHECK((b | a) == to_byte<0xFF>()); + CHECK(a == to_byte<0x00>()); a |= b; - CHECK(a == to_byte(0xFF)); + CHECK(a == to_byte<0xFF>()); - a = to_byte(0x01); - CHECK((b & a) == to_byte(0x01)); + a = to_byte<0x01>(); + CHECK((b & a) == to_byte<0x01>()); a &= b; - CHECK(a == to_byte(0x01)); + CHECK(a == to_byte<0x01>()); - CHECK((b ^ a) == to_byte(0xFE)); + CHECK((b ^ a) == to_byte<0xFE>()); - CHECK(a == to_byte(0x01)); + CHECK(a == to_byte<0x01>()); a ^= b; - CHECK(a == to_byte(0xFE)); + CHECK(a == to_byte<0xFE>()); - a = to_byte(0x01); - CHECK(~a == to_byte(0xFE)); + a = to_byte<0x01>(); + CHECK(~a == to_byte<0xFE>()); - a = to_byte(0xFF); - CHECK((a << 4) == to_byte(0xF0)); - CHECK((a >> 4) == to_byte(0x0F)); + a = to_byte<0xFF>(); + CHECK((a << 4) == to_byte<0xF0>()); + CHECK((a >> 4) == to_byte<0x0F>()); a <<= 4; - CHECK(a == to_byte(0xF0)); + CHECK(a == to_byte<0xF0>()); a >>= 4; - CHECK(a == to_byte(0x0F)); + CHECK(a == to_byte<0x0F>()); } } From 7d083fd08cb5fbf1e5e953adf72c2c38c258c888 Mon Sep 17 00:00:00 2001 From: Kris Date: Wed, 7 Sep 2016 22:16:10 +0100 Subject: [PATCH 3/3] Issue #329, fixed build issues on clang Fixed build issues that clang shows up the MS VS accepts. --- gsl/gsl_byte | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gsl/gsl_byte b/gsl/gsl_byte index c973320..f502ab0 100644 --- a/gsl/gsl_byte +++ b/gsl/gsl_byte @@ -106,14 +106,15 @@ constexpr IntegerType to_integer(byte b) noexcept return {b}; } -template +template constexpr byte to_byte_impl(T t) noexcept { static_assert( - false, + 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<> constexpr byte to_byte_impl(unsigned char t) noexcept