Skip to content

Commit 8b5f3b9

Browse files
committed
Change byteswap() to function template, returning parameter type
Also use unsigned type normalization and catch non-integral types via static_assert
1 parent eb046b3 commit 8b5f3b9

File tree

2 files changed

+46
-27
lines changed

2 files changed

+46
-27
lines changed

include/nonstd/bit.hpp

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,31 @@ struct same_as : std11::integral_constant<bool, std11::is_same<T,U>::value && st
387387

388388
} // namespace std20
389389

390+
// Other detail:
391+
392+
// make sure all unsigned types are covered, see
393+
// http://ithare.com/c-on-using-int_t-as-overload-and-template-parameters/
394+
395+
template< size_t N > struct uint_by_size;
396+
template<> struct uint_by_size< 8> { typedef std11::uint8_t type; };
397+
template<> struct uint_by_size<16> { typedef std11::uint16_t type; };
398+
template<> struct uint_by_size<32> { typedef std11::uint32_t type; };
399+
#if bit_CPP11_OR_GREATER
400+
template<> struct uint_by_size<64> { typedef std11::uint64_t type; };
401+
#endif
402+
403+
template< typename T >
404+
struct normalized_uint_type
405+
{
406+
typedef typename uint_by_size< CHAR_BIT * sizeof( T ) >::type type;
407+
408+
#if bit_HAVE( STATIC_ASSERT )
409+
static_assert( std::is_integral<T>::value, "integral type required.");
410+
static_assert( std11::is_unsigned<type>::value, "unsigned type result expected.");
411+
static_assert( sizeof( type ) == sizeof( T ), "size of determined type differs from type derived from.");
412+
#endif
413+
};
414+
390415
//
391416
// For reference:
392417
//
@@ -449,30 +474,36 @@ bit_cast( From const & src ) bit_noexcept
449474

450475
// 26.5.4, byteswap (C++23, p1272)
451476

452-
inline bit_constexpr std11::uint8_t byteswap ( std11::uint8_t value ) bit_noexcept
477+
inline bit_constexpr std11::uint8_t byteswap_( std11::uint8_t value ) bit_noexcept
453478
{
454479
return value;
455480
}
456481

457-
inline /*bit_constexpr*/ std11::uint16_t byteswap ( std11::uint16_t value ) bit_noexcept
482+
inline /*bit_constexpr*/ std11::uint16_t byteswap_( std11::uint16_t value ) bit_noexcept
458483
{
459484
return bit_byteswap16( value );
460485
}
461486

462-
inline /*bit_constexpr*/ std11::uint32_t byteswap ( std11::uint32_t value ) bit_noexcept
487+
inline /*bit_constexpr*/ std11::uint32_t byteswap_( std11::uint32_t value ) bit_noexcept
463488
{
464489
return bit_byteswap32( value );
465490
}
466491

467492
#if bit_CPP11_OR_GREATER
468493

469-
inline /*bit_constexpr*/ std11::uint64_t byteswap ( std11::uint64_t value ) bit_noexcept
494+
inline /*bit_constexpr*/ std11::uint64_t byteswap_( std11::uint64_t value ) bit_noexcept
470495
{
471496
return bit_byteswap64( value );
472497
}
473498

474499
#endif
475500

501+
template< typename T >
502+
inline /*bit_constexpr*/ T byteswap( T v ) bit_noexcept
503+
{
504+
return static_cast<T>( byteswap_( static_cast< typename normalized_uint_type<T>::type >( v ) ) );
505+
}
506+
476507
// 26.5.6, rotating
477508

478509
// clang 3.5 - 3.8: Infinite recursive template instantiation when using Clang while GCC works fine?
@@ -771,29 +802,6 @@ typedef std11::integral_constant<int, static_cast<int>(endian::big )> big_endi
771802
typedef std11::integral_constant<int, static_cast<int>(endian::little)> little_endian_type;
772803
typedef std11::integral_constant<int, static_cast<int>(endian::native)> native_endian_type;
773804

774-
// make sure all unsigned types are covered, see
775-
// http://ithare.com/c-on-using-int_t-as-overload-and-template-parameters/
776-
777-
template< size_t N > struct uint_by_size;
778-
template<> struct uint_by_size< 8> { typedef std11::uint8_t type; };
779-
template<> struct uint_by_size<16> { typedef std11::uint16_t type; };
780-
template<> struct uint_by_size<32> { typedef std11::uint32_t type; };
781-
#if bit_CPP11_OR_GREATER
782-
template<> struct uint_by_size<64> { typedef std11::uint64_t type; };
783-
#endif
784-
785-
template< typename T >
786-
struct normalized_uint_type
787-
{
788-
typedef typename uint_by_size< CHAR_BIT * sizeof( T ) >::type type;
789-
790-
#if bit_HAVE( STATIC_ASSERT )
791-
static_assert( sizeof( type ) == sizeof( T ), "");
792-
static_assert( std::is_integral<T>::value, "");
793-
static_assert( std11::is_unsigned<type>::value, "");
794-
#endif
795-
};
796-
797805
// to big endian (implementation):
798806

799807
inline std11::uint8_t to_big_endian_( std11::uint8_t v, little_endian_type )

test/bit.t.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
#include <climits> // CHAR_BIT, when bit_USES_STD_BIT
1212
#include <iostream>
1313

14+
#ifndef bit_COMPILE_TIME_TEST
15+
# define bit_COMPILE_TIME_TEST 0
16+
#endif
17+
1418
#define dimension_of(a) ( sizeof(a) / sizeof(0[a]) )
1519

1620
#if bit_CPP11_90
@@ -89,10 +93,17 @@ CASE( "bit_cast<>(): successfully roundtrips uint64_t via double" " [bit.cast]"
8993
CASE( "byteswap(): allow to swap bytes in 1, 2, 4, 8-byte integrals" " [bit.byteswap]" )
9094
{
9195
#if bit_HAVE_BYTESWAP
96+
#if bit_COMPILE_TIME_TEST
97+
EXPECT( byteswap( float (0x0 ) ) == float (0x0 ) );
98+
#endif
99+
EXPECT( byteswap( int8_t (0x12 ) ) == int8_t (0x12 ) );
92100
EXPECT( byteswap( uint8_t (0x12u) ) == uint8_t (0x12u ) );
101+
EXPECT( byteswap( int16_t (0x1234 ) ) == int16_t (0x3412 ) );
93102
EXPECT( byteswap( uint16_t(0x1234u) ) == uint16_t(0x3412u) );
103+
EXPECT( byteswap( int32_t (0x12345678l ) ) == uint32_t(0x78563412l ) );
94104
EXPECT( byteswap( uint32_t(0x12345678ul) ) == uint32_t(0x78563412ul) );
95105
#if bit_CPP11_OR_GREATER
106+
EXPECT( byteswap( int64_t (0x12345678AABBCCDDll ) ) == int64_t (0xDDCCBBAA78563412ll ) );
96107
EXPECT( byteswap( uint64_t(0x12345678AABBCCDDull) ) == uint64_t(0xDDCCBBAA78563412ull ) );
97108
#endif
98109
#else

0 commit comments

Comments
 (0)