BitStream
integral_traits.h
Go to the documentation of this file.
1 #pragma once
2 #include "../utility/assert.h"
3 #include "../utility/bits.h"
4 #include "../utility/meta.h"
5 #include "../utility/parameter.h"
6 
7 #include "../stream/serialize_traits.h"
8 
9 #include <cstdint>
10 #include <limits>
11 #include <type_traits>
12 
13 namespace bitstream
14 {
19  template<typename T, T = (std::numeric_limits<T>::min)(), T = (std::numeric_limits<T>::max)()>
20  struct bounded_int;
21 
22 #pragma region integral types
27  template<typename T>
28  struct serialize_traits<T, typename std::enable_if_t<std::is_integral_v<T> && !std::is_const_v<T>>>
29  {
30  static_assert(sizeof(T) <= 8, "Integers larger than 8 bytes are currently not supported. You will have to write this functionality yourself");
31 
40  template<typename Stream>
42  static serialize(Stream& writer, in<T> value, T min = (std::numeric_limits<T>::min)(), T max = (std::numeric_limits<T>::max)()) noexcept
43  {
44  BS_ASSERT(min < max);
45 
46  BS_ASSERT(value >= min && value <= max);
47 
48  uint32_t num_bits = utility::bits_in_range(min, max);
49 
50  BS_ASSERT(num_bits <= sizeof(T) * 8);
51 
52  if constexpr (sizeof(T) > 4)
53  {
54  if (num_bits > 32)
55  {
56  // If the given range is bigger than a word (32 bits)
57  uint32_t unsigned_value = static_cast<uint32_t>(value - min);
58  BS_ASSERT(writer.serialize_bits(unsigned_value, 32));
59 
60  unsigned_value = static_cast<uint32_t>((value - min) >> 32);
61  BS_ASSERT(writer.serialize_bits(unsigned_value, num_bits - 32));
62 
63  return true;
64  }
65  }
66 
67  // If the given range is smaller than or equal to a word (32 bits)
68  uint32_t unsigned_value = static_cast<uint32_t>(value - min);
69  BS_ASSERT(writer.serialize_bits(unsigned_value, num_bits));
70 
71  return true;
72  }
73 
82  template<typename Stream>
84  static serialize(Stream& reader, T& value, T min = (std::numeric_limits<T>::min)(), T max = (std::numeric_limits<T>::max)()) noexcept
85  {
86  BS_ASSERT(min < max);
87 
88  uint32_t num_bits = utility::bits_in_range(min, max);
89 
90  BS_ASSERT(num_bits <= sizeof(T) * 8);
91 
92  if constexpr (sizeof(T) > 4)
93  {
94  if (num_bits > 32)
95  {
96  // If the given range is bigger than a word (32 bits)
97  value = 0;
98  uint32_t unsigned_value;
99 
100  BS_ASSERT(reader.serialize_bits(unsigned_value, 32));
101  value |= static_cast<T>(unsigned_value);
102 
103  BS_ASSERT(reader.serialize_bits(unsigned_value, num_bits - 32));
104  value |= static_cast<T>(unsigned_value) << 32;
105 
106  value += min;
107 
108  BS_ASSERT(value >= min && value <= max);
109 
110  return true;
111  }
112  }
113 
114  // If the given range is smaller than or equal to a word (32 bits)
115  uint32_t unsigned_value;
116  BS_ASSERT(reader.serialize_bits(unsigned_value, num_bits));
117 
118  value = static_cast<T>(unsigned_value) + min;
119 
120  BS_ASSERT(value >= min && value <= max);
121 
122  return true;
123  }
124  };
125 #pragma endregion
126 
127 #pragma region const integral types
134  template<typename T, T Min, T Max>
135  struct serialize_traits<bounded_int<T, Min, Max>, typename std::enable_if_t<std::is_integral_v<T> && !std::is_const_v<T>>>
136  {
137  static_assert(sizeof(T) <= 8, "Integers larger than 8 bytes are currently not supported. You will have to write this functionality yourself");
138 
145  template<typename Stream>
147  static serialize(Stream& writer, in<T> value) noexcept
148  {
149  static_assert(Min < Max);
150 
151  BS_ASSERT(value >= Min && value <= Max);
152 
153  constexpr uint32_t num_bits = utility::bits_in_range(Min, Max);
154 
155  static_assert(num_bits <= sizeof(T) * 8);
156 
157  if constexpr (sizeof(T) > 4 && num_bits > 32)
158  {
159  // If the given range is bigger than a word (32 bits)
160  uint32_t unsigned_value = static_cast<uint32_t>(value - Min);
161  BS_ASSERT(writer.serialize_bits(unsigned_value, 32));
162 
163  unsigned_value = static_cast<uint32_t>((value - Min) >> 32);
164  BS_ASSERT(writer.serialize_bits(unsigned_value, num_bits - 32));
165  }
166  else
167  {
168  // If the given range is smaller than or equal to a word (32 bits)
169  uint32_t unsigned_value = static_cast<uint32_t>(value - Min);
170  BS_ASSERT(writer.serialize_bits(unsigned_value, num_bits));
171  }
172 
173  return true;
174  }
175 
182  template<typename Stream>
184  static serialize(Stream& reader, T& value) noexcept
185  {
186  static_assert(Min < Max);
187 
188  constexpr uint32_t num_bits = utility::bits_in_range(Min, Max);
189 
190  static_assert(num_bits <= sizeof(T) * 8);
191 
192  if constexpr (sizeof(T) > 4 && num_bits > 32)
193  {
194  // If the given range is bigger than a word (32 bits)
195  value = 0;
196  uint32_t unsigned_value;
197 
198  BS_ASSERT(reader.serialize_bits(unsigned_value, 32));
199  value |= static_cast<T>(unsigned_value);
200 
201  BS_ASSERT(reader.serialize_bits(unsigned_value, num_bits - 32));
202  value |= static_cast<T>(unsigned_value) << 32;
203 
204  value += Min;
205  }
206  else
207  {
208  // If the given range is smaller than or equal to a word (32 bits)
209  uint32_t unsigned_value;
210  BS_ASSERT(reader.serialize_bits(unsigned_value, num_bits));
211 
212  value = static_cast<T>(unsigned_value) + Min;
213  }
214 
215  BS_ASSERT(value >= Min && value <= Max);
216 
217  return true;
218  }
219  };
220 #pragma endregion
221 }
#define BS_ASSERT(x)
Definition: assert.h:15
constexpr uint32_t bits_in_range(intmax_t min, intmax_t max)
Definition: bits.h:22
std::enable_if_t< T::writing, R > is_writing_t
Definition: meta.h:25
std::enable_if_t< T::reading, R > is_reading_t
Definition: meta.h:28
Definition: bounded_range.h:28
std::conditional_t<(sizeof(T)<=16 &&std::is_trivially_copy_constructible_v< T >), std::add_const_t< T >, std::add_lvalue_reference_t< std::add_const_t< T > >> in
Passes by const or const reference depending on size.
Definition: parameter.h:94
Wrapper type for compiletime known integer bounds.
Definition: integral_traits.h:20
static utility::is_reading_t< Stream > serialize(Stream &reader, T &value, T min=(std::numeric_limits< T >::min)(), T max=(std::numeric_limits< T >::max)()) noexcept
Reads an integer from the reader into value.
Definition: integral_traits.h:84
static utility::is_writing_t< Stream > serialize(Stream &writer, in< T > value, T min=(std::numeric_limits< T >::min)(), T max=(std::numeric_limits< T >::max)()) noexcept
Writes an integer into the writer.
Definition: integral_traits.h:42
static utility::is_reading_t< Stream > serialize(Stream &reader, T &value) noexcept
Reads an integer from the writer into value.
Definition: integral_traits.h:184
static utility::is_writing_t< Stream > serialize(Stream &writer, in< T > value) noexcept
Writes an integer into the writer.
Definition: integral_traits.h:147
A class for specializing trait serialization functions.
Definition: serialize_traits.h:11