12
12
13
13
namespace quicr {
14
14
namespace {
15
- constexpr bool kIsBigEndian = std::endian::native == std::endian::big;
16
-
17
15
constexpr std::uint16_t SwapBytes (const std::uint16_t value)
18
16
{
19
- if constexpr (kIsBigEndian )
17
+ if constexpr (std::endian::native == std::endian::big )
20
18
return value;
21
19
22
20
return ((value >> 8 ) & 0x00FF ) | ((value << 8 ) & 0xFF00 );
23
21
}
24
22
25
23
constexpr std::uint32_t SwapBytes (const std::uint32_t value)
26
24
{
27
- if constexpr (kIsBigEndian )
25
+ if constexpr (std::endian::native == std::endian::big )
28
26
return value;
29
27
30
28
return ((value >> 24 ) & 0x000000FF ) | ((value >> 8 ) & 0x0000FF00 ) | ((value << 8 ) & 0x00FF0000 ) |
@@ -33,7 +31,7 @@ namespace quicr {
33
31
34
32
constexpr std::uint64_t SwapBytes (const std::uint64_t value)
35
33
{
36
- if constexpr (kIsBigEndian )
34
+ if constexpr (std::endian::native == std::endian::big )
37
35
return value;
38
36
39
37
return ((value >> 56 ) & 0x00000000000000FF ) | ((value >> 40 ) & 0x000000000000FF00 ) |
@@ -47,42 +45,65 @@ namespace quicr {
47
45
{
48
46
public:
49
47
constexpr UintVar (uint64_t value)
50
- : be_value_{ SwapBytes (value) }
48
+ : be_value_{ std::bit_cast<std::array<std:: uint8_t , sizeof (std:: uint64_t )>>( SwapBytes (value) ) }
51
49
{
52
- constexpr uint64_t kLen1 = (static_cast <uint64_t >(-1 ) << (64 - 6 ) >> (64 - 6 ));
53
- constexpr uint64_t kLen2 = (static_cast <uint64_t >(-1 ) << (64 - 14 ) >> (64 - 14 ));
54
- constexpr uint64_t kLen4 = (static_cast <uint64_t >(-1 ) << (64 - 30 ) >> (64 - 30 ));
50
+ constexpr uint64_t k14bitLength = (static_cast <uint64_t >(-1 ) << (64 - 6 ) >> (64 - 6 ));
51
+ constexpr uint64_t k30bitLength = (static_cast <uint64_t >(-1 ) << (64 - 14 ) >> (64 - 14 ));
52
+ constexpr uint64_t k62bitLength = (static_cast <uint64_t >(-1 ) << (64 - 30 ) >> (64 - 30 ));
55
53
56
- if (static_cast < uint8_t >( be_value_) & 0xC0u ) { // Check if invalid
54
+ if (be_value_. front ( ) & 0xC0u ) { // Check if invalid
57
55
throw std::invalid_argument (" Value greater than uintvar maximum" );
58
56
}
59
57
60
- if (value > kLen4 ) { // 62 bit encoding (8 bytes)
61
- be_value_ |= 0xC0ull ;
62
- } else if (value > kLen2 ) { // 30 bit encoding (4 bytes)
63
- be_value_ >>= 32 ;
64
- be_value_ |= 0x80ull ;
65
- } else if (value > kLen1 ) { // 14 bit encoding (2 bytes)
66
- be_value_ >>= 48 ;
67
- be_value_ |= 0x40ull ;
58
+ std::uint64_t be_v = std::bit_cast<std::uint64_t >(be_value_);
59
+ if (value > k62bitLength) { // 62 bit encoding (8 bytes)
60
+ be_v |= 0xC0ull ;
61
+ } else if (value > k30bitLength) { // 30 bit encoding (4 bytes)
62
+ be_v >>= 32 ;
63
+ be_v |= 0x80ull ;
64
+ } else if (value > k14bitLength) { // 14 bit encoding (2 bytes)
65
+ be_v >>= 48 ;
66
+ be_v |= 0x40ull ;
68
67
} else {
69
- be_value_ >>= 56 ;
68
+ be_v >>= 56 ;
70
69
}
70
+
71
+ be_value_ = std::bit_cast<std::array<std::uint8_t , sizeof (std::uint64_t )>>(be_v);
71
72
}
72
73
73
- UintVar (std::span<const uint8_t > bytes)
74
+ constexpr UintVar (std::span<const std:: uint8_t > bytes)
74
75
: be_value_{ 0 }
75
76
{
76
- if (bytes.empty () || bytes.size () < Size (bytes[ 0 ] )) {
77
+ if (bytes.empty () || bytes.size () < Size (bytes. front () )) {
77
78
throw std::invalid_argument (" Invalid bytes for uintvar" );
78
79
}
79
80
80
- std::memcpy (&be_value_, bytes.data (), Size (bytes[0 ]));
81
+ const std::size_t size = Size (bytes.front ());
82
+ if (std::is_constant_evaluated ()) {
83
+ for (std::size_t i = 0 ; i < size; ++i) {
84
+ be_value_[i] = bytes.data ()[i];
85
+ }
86
+ } else {
87
+ std::memcpy (&be_value_, bytes.data (), size);
88
+ }
89
+ }
90
+
91
+ constexpr UintVar (const UintVar&) noexcept = default;
92
+ constexpr UintVar (UintVar&&) noexcept = default;
93
+ constexpr UintVar& operator =(const UintVar&) noexcept = default ;
94
+ constexpr UintVar& operator =(UintVar&&) noexcept = default ;
95
+
96
+ constexpr UintVar& operator =(std::uint64_t value)
97
+ {
98
+ UintVar t (value);
99
+ this ->be_value_ = t.be_value_ ;
100
+ return *this ;
81
101
}
82
102
83
- explicit constexpr operator uint64_t () const noexcept
103
+ constexpr std:: uint64_t Get () const noexcept
84
104
{
85
- return SwapBytes ((be_value_ & SwapBytes (uint64_t (~(~0x3Full << 56 )))) << (sizeof (uint64_t ) - Size ()) * 8 );
105
+ return SwapBytes ((std::bit_cast<std::uint64_t >(be_value_) & SwapBytes (uint64_t (~(~0x3Full << 56 ))))
106
+ << (sizeof (uint64_t ) - Size ()) * 8 );
86
107
}
87
108
88
109
static constexpr std::size_t Size (uint8_t msb_bytes) noexcept
@@ -98,16 +119,20 @@ namespace quicr {
98
119
return sizeof (uint8_t );
99
120
}
100
121
101
- constexpr std::size_t Size () const noexcept { return UintVar::Size (static_cast < uint8_t >( be_value_)); }
122
+ constexpr std::size_t Size () const noexcept { return UintVar::Size (be_value_. front ( )); }
102
123
103
124
// NOLINTBEGIN(readability-identifier-naming)
104
- auto data () const noexcept { return reinterpret_cast < const uint8_t *>(& be_value_); }
125
+ constexpr const std:: uint8_t * data () const noexcept { return be_value_. data ( ); }
105
126
constexpr std::size_t size () const noexcept { return Size (); }
106
- auto begin () const noexcept { return data (); }
107
- auto end () const noexcept { return data () + Size (); }
127
+ constexpr auto begin () const noexcept { return data (); }
128
+ constexpr auto end () const noexcept { return data () + Size (); }
108
129
// NOLINTEND(readability-identifier-naming)
109
130
131
+ explicit constexpr operator uint64_t () const noexcept { return Get (); }
132
+
133
+ constexpr auto operator <=>(const UintVar&) const noexcept = default ;
134
+
110
135
private:
111
- uint64_t be_value_;
136
+ std::array<std:: uint8_t , sizeof (std:: uint64_t )> be_value_;
112
137
};
113
138
}
0 commit comments