C++ Library Extensions 2022.12.09
To help learn modern C++ programming
cpg_bitwise.hpp
Go to the documentation of this file.
1#ifndef _CPG_BITWISE_HPP
2#define _CPG_BITWISE_HPP
3
4#ifndef NOMINMAX
5#define NOMINMAX
6#endif
7
8#include <iostream>
9#include <type_traits>
10#include <limits>
11#include <string>
12#include <sstream>
13#include <iomanip>
14#include <cstddef> // for std::byte
15#include <bitset>
16#include <cmath>
17#include <concepts>
18#include <bit>
19
20/*
21 105 - C++ Casting 3 - C++20 새로운 비트 연산 라이브러리, bit, concepts, algorithm
22 https://www.youtube.com/watch?v=AXSGZDVDtdc&list=PLsIvhalfft1EtaiJJRmWKUGG0W1hyUKiw&index=104
23
24*/
25
26namespace cpg::bitwise
27{
28 namespace hidden
29 {
30 template<typename T> struct st_is_character
31 {
32 static const bool value = false;
33 };
34
35 template<> struct st_is_character<char>
36 {
37 static const bool value = true;
38 };
39
40 template<> struct st_is_character<unsigned char>
41 {
42 static const bool value = true;
43 };
44
45 template<> struct st_is_character<signed char>
46 {
47 static const bool value = true;
48 };
49
50 template<> struct st_is_character<wchar_t>
51 {
52 static const bool value = true;
53 };
54 }
55
56 template<typename T>
58
59 template<typename T> constexpr T limits_max = std::numeric_limits<T>::max();
60 template<typename T> constexpr T limits_min = std::numeric_limits<T>::min();
61
62 // count bits in the mask
63 // mask ( 7) : 0000 0111, should return 3
64 // mask (-1) : 1111 1111, should return 8
65 // mask (0x80) : 1000 0000, should return 1
66 // mask (0) : 0000 0000, should return 0
67 // mask (1) : 0000 0001, should return 1
68
69 template<typename T>
70 using enable_if_integral = std::enable_if_t<std::is_integral<T>::value>;
71
72 template<typename T, typename = enable_if_integral<T>>
73 using unsigned_t = std::make_unsigned_t<T>;
74
75 template<typename T, typename = enable_if_integral<T>>
76 using signed_t = std::make_signed_t<T>;
77
78 template<typename S, typename T>
79 using common_t = std::common_type_t<S, T>;
80
81 template<typename S, typename T,
82 typename = enable_if_integral<S>,
83 typename = enable_if_integral<T>>
85
86 template<typename S, typename T,
87 typename = enable_if_integral<S>,
88 typename = enable_if_integral<T>>
90
91 template<typename T>
92 constexpr int sizeof_bits = sizeof(T) * 8;
93
94 template<typename T>
96 = unsigned_t<T>(1) << (sizeof_bits<T>-1);
97
98 template<std::integral T>
99 int count_set_bits(T bits)
100 {
101 unsigned_t<T> mask = bits;
102
103 int count = 0;
104
105 for (; mask; mask >>= 1)
106 count += (int)(mask & 1);
107
108 return count;
109 }
110
111 template<std::integral T>
112 std::string to_bits(T bits)
113 {
114 unsigned_t<T> mask = bits;
115 int count = 0;
116
117 std::ostringstream os;
118
119 for (int pos = sizeof_bits<T>; pos; mask <<= 1, --pos)
120 {
121 if (!os.str().empty() && (pos % 4 == 0))
122 os << ' ';
123
124 os << ((mask & high_bit_mask<T>) ? '1' : '0');
125 }
126
127 return os.str();
128 }
129
130 template<std::integral T, std::size_t N>
131 std::string to_bits_reverse(T(&bits)[N])
132 {
133 std::ostringstream os;
134
135 for(int n = (int)N-1; n > 0 ; --n)
136 {
137 os << to_bits(bits[n]) <<" | ";
138 }
139
140 os << to_bits(bits[0]);
141
142 return os.str();
143 }
144
145 template<std::integral T, std::size_t N>
146 std::string to_bits(T(&bits)[N])
147 {
148 std::ostringstream os;
149
150 for(int n = 0; n < (int)N - 1; ++n)
151 {
152 os << to_bits(bits[n]) <<" | ";
153 }
154
155 os << to_bits(bits[N-1]);
156
157 return os.str();
158 }
159
160 template<std::integral T>
161 std::string to_hex(T v)
162 {
163 std::string str;
164
165 if (is_char_v<T>)
166 {
167 std::ostringstream os;
168
169 os << std::setfill('0') << std::setw(sizeof(T) * 2)
170 << std::uppercase << std::hex << (short)v;
171
172 str = os.str();
173
174 if (str.size()==4)
175 {
176 if (v > 0)
177 {
178 str.pop_back();
179 str.pop_back();
180 }
181 else
182 {
183 std::string ss;
184
185 ss.push_back(str[2]);
186 ss.push_back(str[3]);
187
188 str = ss;
189 }
190 }
191 }
192 else
193 {
194 std::ostringstream os;
195
196 os << std::setfill('0') << std::setw(sizeof(T) * 2)
197 << std::uppercase << std::hex <<v;
198
199 str = os.str();
200 }
201
202 return str;
203 }
204
205 template<std::integral T, std::size_t N>
206 std::string to_hex_reverse(T(&v)[N])
207 {
208 std::ostringstream os;
209
210 for(int n = (int)N-1; n > 0 ; --n)
211 {
212 os << to_hex(v[n]) <<" | ";
213 }
214
215 os << to_hex(v[0]);
216
217 return os.str();
218 }
219
220 template<std::integral T, std::size_t N>
221 std::string to_hex(T(&v)[N])
222 {
223 std::ostringstream os;
224
225 for(int n = 0; n < (int)N - 1 ; ++n)
226 {
227 os << to_hex(v[n]) <<" | ";
228 }
229
230 os << to_hex(v[N-1]);
231
232 return os.str();
233 }
234
235 template<std::integral T>
236 std::string to_dec(T v)
237 {
238 std::ostringstream os;
239
240 if (is_char_v<T>)
241 os << (short)v;
242 else
243 os << v;
244
245 return os.str();
246 }
247
248 template<std::integral T, std::size_t N>
249 std::string to_dec_reverse(T(&v)[N])
250 {
251 std::ostringstream os;
252
253 for(int n = (int)N-1; n > 0; --n)
254 {
255 os << to_dec(v[n]) <<" | ";
256 }
257
258 os << to_dec(v[0]);
259
260 return os.str();
261 }
262
263 template<std::integral T, std::size_t N>
264 std::string to_dec(T(&v)[N])
265 {
266 std::ostringstream os;
267
268 for(int n = 0; n < (int)N - 1; ++n)
269 {
270 os << to_dec(v[n]) <<" | ";
271 }
272
273 os << to_dec(v[N-1]);
274
275 return os.str();
276 }
277
278 template<std::integral T>
279 int field_with(T v)
280 {
281 std::ostringstream os;
282
283 if (is_char_v<T>)
284 os << (short)v;
285 else
286 os << v;
287
288 return (int) os.str().size();
289 }
290
291 template<std::integral T>
293 {
294 int a = field_with(std::numeric_limits<T>::max());
295 int b = field_with(std::numeric_limits<T>::min());
296
297 return a > b ? a : b;
298 }
299
300 template<std::integral T>
301 std::string to_dec_width(T v)
302 {
303 std::ostringstream os;
304
305 int max_field = numeric_width<T>();
306
307 if (is_char_v<T>)
308 os << std::setw(max_field)<<(short)v;
309 else
310 os << std::setw(max_field)<<v;
311
312 return os.str();
313 }
314
315 template<std::integral T>
316 std::string numeric_base(T v)
317 {
318 std::ostringstream os;
319
320 os << to_dec_width(v) << " (" << to_hex<T>(v) << "): " << to_bits<T>(v);
321
322 return os.str();
323 }
324
325 template<std::integral T>
326 std::string numeric_type_info()
327 {
328 std::ostringstream os;
329
330 auto minimum = std::numeric_limits<T>::min();
331 auto maximum = std::numeric_limits<T>::max();
332
333 os << "Type name: " << Cpg_GetTypeName(T)
334 << ",\tByte size: " << sizeof(T) << ",\tBit count: " << sizeof_bits<T>
335 << "\nMinimum: "<< numeric_base(minimum)
336 << "\nMaximum: "<< numeric_base(maximum);
337
338 return os.str();
339 }
340
341 template<typename = void>
342 std::string integral_type_info()
343 {
344 std::ostringstream os;
345
346 os << numeric_type_info<char>() << "\n\n";
347 os << numeric_type_info<unsigned char>() << "\n\n";
348 os << numeric_type_info<short>() << "\n\n";
349 os << numeric_type_info<unsigned short>() << "\n\n";
350 os << numeric_type_info<int>() << "\n\n";
351 os << numeric_type_info<unsigned int>() << "\n\n";
352 os << numeric_type_info<long>() << "\n\n";
353 os << numeric_type_info<unsigned long>() << "\n\n";
354 os << numeric_type_info<long long>() << "\n\n";
355 os << numeric_type_info<unsigned long long>() << "\n";
356
357 return os.str();
358 }
359
360 template<std::integral T>
361 std::string twos_complement(T c)
362 {
363 std::ostringstream os;
364 os << numeric_type_info<T>() << "\n";
365
366 T c1 = ~c; // 1's complement of s1
367 T c2 = ~c + 1; // 2's complement of s1
368 T c3 = c + c2; // c + (~c+1)
369 os << "original value : c = " << numeric_base(c) << "\n";
370 os << "1's complement : ~c = " << numeric_base(c1) << "\n";
371 os << "2's complement : ~c + 1 = " << numeric_base(c2) << "\n";
372 os << "complement check: c + (~c+1) = " << numeric_base(c3) << "\n";
373
374 return os.str();
375 }
376
377 template<std::unsigned_integral T>
379 {
380 constexpr static size_t byte_size = sizeof(T);
381 constexpr static T min_limit = std::numeric_limits<T>::min();
382 constexpr static T max_limit = std::numeric_limits<T>::max();
383
384 // on some machine, bit count of a byte is not 8 bits, but 16 bits
385 // but I will ignore it, and assume 1 byte represents 8 bits
386 constexpr static size_t bit_size = sizeof(T) * 8;
387
388 union
389 {
390 // n for number or numerical interpretation
391 T n{};
392
393 // b for binary digits - b is array of type std::byte
394 std::byte b[byte_size];
395 };
396
397 // most significant byte
398 const std::byte& msb() const noexcept
399 {
400 return b[byte_size - 1];
401 }
402
403 // most significant byte
404 std::byte& msb() noexcept
405 {
406 return b[byte_size - 1];
407 }
408
409 // least significant byte
410 const std::byte& lsb() const noexcept
411 {
412 return b[0];
413 }
414
415 // least significant byte
416 std::byte& lsb() noexcept
417 {
418 return b[0];
419 }
420
421 template<typename S>
422 requires std::floating_point<S> || std::integral<S>
423 bit_pattern& operator=(S s) noexcept
424 {
425 if constexpr(std::floating_point<S>)
426 {
427 // s is a floating point type
428 this->n = (T) std::round(s); // 1. round(), then 2. typecast S to T
429 }
430 else
431 {
432 // s is an integral type
433 this->n = (T)s; // typecast S to T
434 }
435
436 return *this;
437 }
438
439 // we allow both integral and real numbers to be assigned by this class
440 template<typename S>
441 requires std::floating_point<S> || std::integral<S>
442 operator S() const noexcept
443 {
444 return (S)this->n;
445 }
446
447 }; // end of class bit_pattern
448}
449
450#define Tpf_SignedCommonType(a, b) tpf::bitwise::signed_common_t<decltype(a), decltype(b)>
451#define Tpf_UnignedCommonType(a, b) tpf::bitwise::unsigned_common_t<decltype(a), decltype(b)>
452
453#endif // end of file _CPG_BITWISE_HPP
std::atomic< int > count
Definition: 022-mutex.cpp:10
#define Cpg_GetTypeName(type_arg,...)
Definition: cpg_types.hpp:740
std::enable_if_t< std::is_integral< T >::value > enable_if_integral
Definition: cpg_bitwise.hpp:70
constexpr int sizeof_bits
Definition: cpg_bitwise.hpp:92
signed_t< common_t< S, T > > signed_common_t
Definition: cpg_bitwise.hpp:84
std::string to_hex_reverse(T(&v)[N])
std::string twos_complement(T c)
int numeric_width()
std::string to_bits_reverse(T(&bits)[N])
constexpr T limits_max
Definition: cpg_bitwise.hpp:59
int count_set_bits(T bits)
Definition: cpg_bitwise.hpp:99
std::string to_dec_width(T v)
unsigned_t< common_t< S, T > > unsigned_common_t
Definition: cpg_bitwise.hpp:89
std::common_type_t< S, T > common_t
Definition: cpg_bitwise.hpp:79
std::string to_hex(T v)
std::make_signed_t< T > signed_t
Definition: cpg_bitwise.hpp:76
std::string numeric_type_info()
std::string integral_type_info()
constexpr unsigned_t< T > high_bit_mask
Definition: cpg_bitwise.hpp:96
int field_with(T v)
std::string to_dec_reverse(T(&v)[N])
std::string numeric_base(T v)
std::make_unsigned_t< T > unsigned_t
Definition: cpg_bitwise.hpp:73
constexpr T limits_min
Definition: cpg_bitwise.hpp:60
std::string to_dec(T v)
std::string to_bits(T bits)
constexpr bool is_char_v
Definition: cpg_bitwise.hpp:57
auto minimum(Type_1 a, Type_2 b)
Definition: tpf_types.hpp:196
auto maximum(Type_1 a, Type_2 b)
Definition: tpf_types.hpp:181
static constexpr size_t bit_size
std::byte & msb() noexcept
static constexpr size_t byte_size
static constexpr T max_limit
const std::byte & msb() const noexcept
const std::byte & lsb() const noexcept
std::byte & lsb() noexcept
static constexpr T min_limit
bit_pattern & operator=(S s) noexcept
std::byte b[byte_size]