Skip to content

Commit e5f7af3

Browse files
committed
Add C++23 byteswap()
1 parent f57baec commit e5f7af3

File tree

5 files changed

+149
-60
lines changed

5 files changed

+149
-60
lines changed

README.md

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,27 @@
44

55
**Contents**
66

7-
- [Example usage](#example-usage)
8-
- [In a nutshell](#in-a-nutshell)
9-
- [License](#license)
10-
- [Dependencies](#dependencies)
11-
- [Installation](#installation)
12-
- [Synopsis](#synopsis)
13-
- [Features](#features)
14-
- [Reported to work with](#reported-to-work-with)
15-
- [Building the tests](#building-the-tests)
16-
- [Other implementations of bit](#other-implementations-of-bit)
17-
- [Notes and references](#notes-and-references)
18-
- [Appendix](#appendix)
7+
- [bit-lite - C++20 bit operations for C++98 and later in a single-file header-only library.](#bit-lite---c20-bit-operations-for-c98-and-later-in-a-single-file-header-only-library)
8+
- [Example usage](#example-usage)
9+
- [Compile and run](#compile-and-run)
10+
- [In a nutshell](#in-a-nutshell)
11+
- [License](#license)
12+
- [Dependencies](#dependencies)
13+
- [Installation](#installation)
14+
- [Synopsis](#synopsis)
15+
- [Documentation of standard header `<bit>`](#documentation-of-standard-header-bit)
16+
- [Non-standard extensions](#non-standard-extensions)
17+
- [Configuration](#configuration)
18+
- [Standard selection macro](#standard-selection-macro)
19+
- [Select C++20 standard `<bit>` or nonstd `<bit>`](#select-c20-standard-bit-or-nonstd-bit)
20+
- [Strict C++20 mode](#strict-c20-mode)
21+
- [Reported to work with](#reported-to-work-with)
22+
- [Building the tests](#building-the-tests)
23+
- [Other implementations of `<bit>`](#other-implementations-of-bit)
24+
- [Notes and references](#notes-and-references)
25+
- [Appendix](#appendix)
26+
- [A.1 Compile-time information](#a1-compile-time-information)
27+
- [A.2 Bit lite test specification](#a2-bit-lite-test-specification)
1928

2029
## Example usage
2130

@@ -71,7 +80,7 @@ Bit width of 0x13: 5
7180

7281
### Documentation of standard header `<bit>`
7382

74-
Depending on the compiler and C++-standard used, *bit lite* behaves less or more like C++20 standard `<bit>`. To get an idea of the capabilities of *bit lite* with your configuration, look at the output of the [tests](test/bit.t.cpp), issuing `bit-main.t --pass @`. For C++20 standard `<bit>`, see its [documentation at cppreference](https://en.cppreference.com/w/cpp/header/bit).
83+
Depending on the compiler and C++-standard used, *bit lite* behaves less or more like C++20 standard `<bit>`. To get an idea of the capabilities of *bit lite* with your configuration, look at the output of the [tests](test/bit.t.cpp), issuing `bit-main.t --pass @`. For C++20 standard `<bit>` and its C++23 extension, see its [documentation at cppreference](https://en.cppreference.com/w/cpp/header/bit).
7584

7685
### Non-standard extensions
7786

@@ -153,12 +162,13 @@ The version of *bit lite* is available via tag `[.version]`. The following tags
153162

154163
```Text
155164
bit_cast<>(): successfully roundtrips uint64_t via double [bit.cast]
165+
byteswap(): allow to swap bytes in 1, 2, 4, 8-byte integrals [bit.byteswap]
156166
has_single_bit(): single bit yields false for no bits set [bit.pow.two]
157167
has_single_bit(): single bit yields true for single bits set [bit.pow.two]
158168
has_single_bit(): single bit yields false for multiple bits set [bit.pow.two]
159169
bit_ceil(): let N be the smallest power of 2 greater than or equal to x [bit.pow.two]
160170
bit_floor(): x == 0, 0; otherwise the maximal value y such that has_single_bit(y) is true and y <= x [bit.pow.two]
161-
bit_width: x == 0, 0; otherwise one plus the base-2 logarithm of x, with any fractional part discarded [bit.pow.two]
171+
bit_width(): x == 0, 0; otherwise one plus the base-2 logarithm of x, with any fractional part discarded [bit.pow.two]
162172
rotl(): r is 0, x; if r is positive, (x << r) | (x >> (N - r)); if r is negative, rotr(x, -r) [bit.rotate]
163173
rotr(): r is 0, x; if r is positive, (x >> r) | (x << (N - r)); if r is negative, rotl(x, -r) [bit.rotate]
164174
countl_zero(): the number of consecutive 0 bits in the value of x, starting from the most significant bit [bit.count]

include/nonstd/bit.hpp

Lines changed: 93 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2020-2020 Martin Moene
2+
// Copyright (c) 2020-2025 Martin Moene
33
//
44
// https://github.com/martinmoene/bit-lite
55
//
@@ -72,6 +72,13 @@
7272

7373
#include <bit>
7474

75+
#if bit_CPP20_OR_GREATER
76+
# include <version>
77+
# define bit_HAVE_BYTESWAP __cpp_lib_byteswap
78+
#else
79+
# define bit_HAVE_BYTESWAP 0
80+
#endif
81+
7582
namespace nonstd
7683
{
7784
using std::bit_cast;
@@ -90,6 +97,10 @@ namespace nonstd
9097
using std::countr_one;
9198
using std::popcount;
9299

100+
#if bit_HAVE_BYTESWAP || bit_CPP23_OR_GREATER
101+
using std::byteswap;
102+
#endif
103+
93104
using std::endian;
94105
}
95106

@@ -210,6 +221,10 @@ namespace nonstd
210221

211222
#define bit_HAVE_NODISCARD bit_CPP17_000
212223

224+
// Presence of C++23 library features:
225+
226+
#define bit_HAVE_BYTESWAP 1 // self-supplied
227+
213228
// Presence of C++ language features:
214229

215230
#if bit_HAVE_CONSTEXPR_11
@@ -248,6 +263,21 @@ namespace nonstd
248263
# include <tr1/type_traits>
249264
#endif
250265

266+
#ifdef _MSC_VER
267+
# include <cstdlib>
268+
# define bit_byteswap16 _byteswap_ushort
269+
# define bit_byteswap32 _byteswap_ulong
270+
# define bit_byteswap64 _byteswap_uint64
271+
#else
272+
# define bit_byteswap16 __builtin_bswap16
273+
# define bit_byteswap32 __builtin_bswap32
274+
# define bit_byteswap64 __builtin_bswap64
275+
#endif
276+
277+
#if bit_HAVE( CSTDINT )
278+
# include <cstdint>
279+
#endif
280+
251281
// Method enabling (return type):
252282

253283
#if bit_HAVE( TYPE_TRAITS )
@@ -290,6 +320,20 @@ bit_constexpr T bitmask( int i )
290320

291321
namespace std11 {
292322

323+
#if bit_HAVE( CSTDINT )
324+
using std::uint8_t;
325+
using std::uint16_t;
326+
using std::uint32_t;
327+
using std::uint64_t;
328+
#else
329+
typedef unsigned char uint8_t;
330+
typedef unsigned short int uint16_t;
331+
typedef unsigned int uint32_t;
332+
# if bit_CPP11_OR_GREATER
333+
typedef unsigned long long uint64_t;
334+
# endif
335+
#endif
336+
293337
template< class T, T v > struct integral_constant { enum { value = v }; };
294338
typedef integral_constant< bool, true > true_type;
295339
typedef integral_constant< bool, false > false_type;
@@ -353,19 +397,22 @@ struct same_as : std11::integral_constant<bool, std11::is_same<T,U>::value && st
353397

354398
template< class To, class From > constexpr To bit_cast( From const & from ) noexcept;
355399

356-
// 26.5.4, integral powers of 2
400+
// 26.5.4, byteswap
401+
template< class T > constexpr T byteswap(T value) noexcept;
402+
403+
// 26.5.5, integral powers of 2
357404

358405
template< class T > constexpr bool has_single_bit(T x) noexcept;
359406
template< class T > constexpr T bit_ceil(T x);
360407
template< class T > constexpr T bit_floor(T x) noexcept;
361408
template< class T > constexpr T bit_width(T x) noexcept;
362409

363-
// 26.5.5, rotating
410+
// 26.5.6, rotating
364411

365412
template< class T > [[nodiscard]] constexpr T rotl(T x, int s) noexcept;
366413
template< class T > [[nodiscard]] constexpr T rotr(T x, int s) noexcept;
367414

368-
// 26.5.6, counting
415+
// 26.5.7, counting
369416

370417
template< class T > constexpr int countl_zero(T x) noexcept;
371418
template< class T > constexpr int countl_one(T x) noexcept;
@@ -400,7 +447,33 @@ bit_cast( From const & src ) bit_noexcept
400447
return dst;
401448
}
402449

403-
// 26.5.5, rotating
450+
// 26.5.4, byteswap (C++23, p1272)
451+
452+
inline bit_constexpr std11::uint8_t byteswap ( std11::uint8_t value ) bit_noexcept
453+
{
454+
return value;
455+
}
456+
457+
inline /*bit_constexpr*/ std11::uint16_t byteswap ( std11::uint16_t value ) bit_noexcept
458+
{
459+
return bit_byteswap16( value );
460+
}
461+
462+
inline /*bit_constexpr*/ std11::uint32_t byteswap ( std11::uint32_t value ) bit_noexcept
463+
{
464+
return bit_byteswap32( value );
465+
}
466+
467+
#if bit_CPP11_OR_GREATER
468+
469+
inline /*bit_constexpr*/ std11::uint64_t byteswap ( std11::uint64_t value ) bit_noexcept
470+
{
471+
return bit_byteswap64( value );
472+
}
473+
474+
#endif
475+
476+
// 26.5.6, rotating
404477

405478
// clang 3.5 - 3.8: Infinite recursive template instantiation when using Clang while GCC works fine?
406479
// https://stackoverflow.com/questions/37931284/infinite-recursive-template-instantiation-when-using-clang-while-gcc-works-fine
@@ -462,7 +535,7 @@ bit_nodiscard bit_constexpr14 T rotr(T x, int s) bit_noexcept
462535
return rotr_impl( x, s );
463536
}
464537

465-
// 26.5.6, counting
538+
// 26.5.7, counting
466539

467540
template< class T
468541
bit_ENABLE_IF_(
@@ -554,7 +627,7 @@ bit_constexpr14 int popcount(T x) bit_noexcept
554627
return result;
555628
}
556629

557-
// 26.5.4, integral powers of 2
630+
// 26.5.5, integral powers of 2
558631

559632
template< class T
560633
bit_ENABLE_IF_(
@@ -633,7 +706,7 @@ bit_constexpr T bit_floor(T x) bit_noexcept
633706
: 0;
634707
}
635708

636-
// 26.5.7, endian
709+
// 26.5.8, endian
637710

638711
#if bit_HAVE( ENUM_CLASS )
639712

@@ -689,21 +762,6 @@ class endian
689762

690763
#if !bit_CONFIG_STRICT
691764

692-
#ifdef _MSC_VER
693-
# include <cstdlib>
694-
# define bit_byteswap16 _byteswap_ushort
695-
# define bit_byteswap32 _byteswap_ulong
696-
# define bit_byteswap64 _byteswap_uint64
697-
#else
698-
# define bit_byteswap16 __builtin_bswap16
699-
# define bit_byteswap32 __builtin_bswap32
700-
# define bit_byteswap64 __builtin_bswap64
701-
#endif
702-
703-
#if bit_HAVE( CSTDINT )
704-
# include <cstdint>
705-
#endif
706-
707765
namespace nonstd {
708766
namespace bit {
709767

@@ -716,26 +774,13 @@ typedef std11::integral_constant<int, static_cast<int>(endian::native)> native_e
716774
// make sure all unsigned types are covered, see
717775
// http://ithare.com/c-on-using-int_t-as-overload-and-template-parameters/
718776

719-
namespace std11 {
720-
721-
#if bit_HAVE( CSTDINT )
722-
using std::uint8_t;
723-
using std::uint16_t;
724-
using std::uint32_t;
725-
using std::uint64_t;
726-
#else
727-
typedef unsigned char uint8_t;
728-
typedef unsigned short int uint16_t;
729-
typedef unsigned int uint32_t;
730-
typedef unsigned long long uint64_t;
731-
#endif
732-
} // namespace std11
733-
734777
template< size_t N > struct uint_by_size;
735778
template<> struct uint_by_size< 8> { typedef std11::uint8_t type; };
736779
template<> struct uint_by_size<16> { typedef std11::uint16_t type; };
737780
template<> struct uint_by_size<32> { typedef std11::uint32_t type; };
781+
#if bit_CPP11_OR_GREATER
738782
template<> struct uint_by_size<64> { typedef std11::uint64_t type; };
783+
#endif
739784

740785
template< typename T >
741786
struct normalized_uint_type
@@ -766,11 +811,15 @@ inline std11::uint32_t to_big_endian_( std11::uint32_t v, little_endian_type )
766811
return bit_byteswap32( v );
767812
}
768813

814+
#if bit_CPP11_OR_GREATER
815+
769816
inline std11::uint64_t to_big_endian_( std11::uint64_t v, little_endian_type )
770817
{
771818
return bit_byteswap64( v );
772819
}
773820

821+
#endif
822+
774823
template< typename T >
775824
inline T to_big_endian_( T v, big_endian_type )
776825
{
@@ -794,11 +843,15 @@ inline std11::uint32_t to_little_endian_( std11::uint32_t v, big_endian_type )
794843
return bit_byteswap32( v );
795844
}
796845

846+
#if bit_CPP11_OR_GREATER
847+
797848
inline std11::uint64_t to_little_endian_( std11::uint64_t v, big_endian_type )
798849
{
799850
return bit_byteswap64( v );
800851
}
801852

853+
#endif
854+
802855
template< typename T >
803856
inline T to_little_endian_( T v, little_endian_type )
804857
{
@@ -909,6 +962,8 @@ namespace nonstd
909962
using bit::countr_one;
910963
using bit::popcount;
911964

965+
using bit::byteswap;
966+
912967
using bit::endian;
913968
}
914969

test/bit-main.t.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2020-2020 Martin Moene
2+
// Copyright (c) 2020-2025 Martin Moene
33
//
44
// https://github.com/martinmoene/bit-lite
55
//

test/bit-main.t.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2020-2020 Martin Moene
2+
// Copyright (c) 2020-2025 Martin Moene
33
//
44
// https://github.com/martinmoene/bit-lite
55
//

0 commit comments

Comments
 (0)