C++ Library Extensions 2022.12.09
To help learn modern C++ programming
tpf_safe_type.hpp
Go to the documentation of this file.
1
11#ifndef _TPF_SAFE_TYPE_HPP
12#define _TPF_SAFE_TYPE_HPP
13
14#ifndef NOMINMAX
15#define NOMINMAX
16#endif
17
18#ifdef _MSVC_LANG
19 #if _MSVC_LANG < 201703L
20 #error This libary requires C++17 Standard (Visual Studio 2017).
21 #endif
22#else
23
24 #if __cplusplus < 201703
25 #error This library requires C++17 Standard (GNU g++ version 8.0 or clang++ version 8.0 above)
26 #endif // end of __cplusplus
27
28#endif // end of _MSVC_LANG
29
30#include <iostream>
31#include <type_traits>
32#include <limits>
33#include <string>
34#include <sstream>
35#include <iomanip>
36#include <cstdlib>
37
38#include <tpf_types.hpp>
39
40namespace tpf
41{
46 namespace safe_type
47 {
53 template<typename Type> constexpr Type limits_max =
54 std::numeric_limits<Type>::max();
55
61 template<typename Type> constexpr Type limits_min =
62 std::numeric_limits<Type>::min();
63
64 // count bits in the mask
65 // mask ( 7) : 0000 0111, should return 3
66 // mask (-1) : 1111 1111, should return 8
67 // mask (0x80) : 1000 0000, should return 1
68 // mask (0) : 0000 0000, should return 0
69 // mask (1) : 0000 0001, should return 1
70
71 namespace hidden
72 {
73 template<typename T, typename = types::enable_if_integral_t<T>>
75
76 template<typename T, typename = types::enable_if_integral_t<T>>
78
79 template<typename S, typename T>
81
82 template<typename S, typename T,
86
87 template<typename S, typename T,
91
92 } // end of namespace hidden
93
99 template<typename T>
100 constexpr int sizeof_bits = sizeof(T) * 8;
101
107 template<typename T>
108 constexpr auto high_bit_mask =
109 hidden::unsigned_integral_t<T>(1) << (sizeof_bits<T>-1);
110
118 template<typename Type>
120 count_set_bits(Type bits)
121 {
123
124 int count = 0;
125
126 for (; mask; mask >>= 1)
127 count += (int)(mask & 1);
128
129 return count;
130 }
131
139 template<typename Type>
141 to_bits(Type bits)
142 {
144
145 int count = 0; std::string str;
146
147 for (int pos = sizeof_bits<Type>; pos; mask <<= 1, --pos)
148 {
149 if (!str.empty() && (pos % 4 == 0))
150 str.push_back(' ');
151
152 str.push_back((mask & high_bit_mask<Type>) ? '1' : '0');
153 }
154
155 return str;
156 }
157
165 template<typename Type>
167 to_hex(Type v)
168 {
169 std::string str;
170
171 if constexpr (types::is_char_v<Type>)
172 {
173 std::ostringstream os;
174
175 os << std::setfill('0') << std::setw(sizeof(Type) * 2)
176 << std::uppercase << std::hex << (short)v;
177
178 str = os.str();
179
180 if (str.size()==4)
181 {
182 if (v > 0)
183 {
184 str.pop_back();
185 str.pop_back();
186 }
187 else
188 {
189 std::string ss;
190
191 ss.push_back(str[2]);
192 ss.push_back(str[3]);
193
194 str = ss;
195 }
196 }
197 }
198 else
199 {
200 std::ostringstream os;
201
202 os << std::setfill('0') << std::setw(sizeof(Type) * 2)
203 << std::uppercase << std::hex <<v;
204
205 str = os.str();
206 }
207
208 return str;
209 }
210
218 template<typename Type>
220 to_dec(Type v)
221 {
222 std::ostringstream os;
223
224 if constexpr (types::is_char_v<Type>)
225 os << (short)v;
226 else
227 os << v;
228
229 return os.str();
230 }
231
239 template<typename Type>
242 {
243 std::ostringstream os;
244
245 if constexpr (types::is_char_v<Type>)
246 os << (short)v;
247 else
248 os << v;
249
250 return (int) os.str().size();
251 }
252
259 template<typename Type>
262 {
263 int a = field_width(std::numeric_limits<Type>::max());
264 int b = field_width(std::numeric_limits<Type>::min());
265
266 return a > b ? a : b;
267 }
268
276 template<typename Type>
279 {
280 std::ostringstream os;
281
282 int max_field = numeric_width<Type>();
283
284 if constexpr (types::is_char_v<Type>)
285 os << std::setw(max_field)<<(short)v;
286 else
287 os << std::setw(max_field)<<v;
288
289 return os.str();
290 }
291
299 template<typename Type>
302 {
303 std::ostringstream os;
304
305 os << to_dec_width(v) << " (" << to_hex<Type>(v) << "): " << to_bits<Type>(v);
306
307 return os.str();
308 }
309
316 template<typename Type>
319 {
320 std::ostringstream os;
321
322 constexpr auto minimum = std::numeric_limits<Type>::min();
323 constexpr auto maximum = std::numeric_limits<Type>::max();
324
325 os << "Type name: " << Tpf_GetTypeName(Type)
326 << ",\tByte size: " << sizeof(Type) << ",\tBit count: " << sizeof_bits<Type>
327 << "\nMinimum: "<< numeric_base(minimum)
328 << "\nMaximum: "<< numeric_base(maximum);
329
330 return os.str();
331 }
332
337 template<typename = void>
339 {
340 auto nl = "\n\n";
341
342 std::cout << numeric_type_info((char)0) << nl;
343 std::cout << numeric_type_info((unsigned char)0) << nl;
344 std::cout << numeric_type_info((short)0) << nl;
345 std::cout << numeric_type_info((unsigned short)0) << nl;
346 std::cout << numeric_type_info((int)0) << nl;
347 std::cout << numeric_type_info((unsigned)0) << nl;
348 std::cout << numeric_type_info((long)0) << nl;
349 std::cout << numeric_type_info((unsigned long)0) << nl;
350 std::cout << numeric_type_info((long long)0) << nl;
351 std::cout << numeric_type_info((unsigned long long)0) << std::endl;
352 }
353
361 template<typename Type>
364 {
365 std::cout << numeric_type_info<Type>((Type)0) << "\n";
366
367 Type c1 = ~c; // 1's complement of s1
368 Type c2 = ~c + 1; // 2's complement of s1
369 Type c3 = c + c2; // c + (~c+1)
370 std::cout << "original value : c = " << numeric_base(c) << "\n";
371 std::cout << "1's complement : ~c = " << numeric_base(c1) << "\n";
372 std::cout << "2's complement : ~c + 1 = " << numeric_base(c2) << "\n";
373 std::cout << "complement check: c + (~c+1) = " << numeric_base(c3) << std::endl;
374 }
375
376 // signed: a + b
385 template<typename Type>
387 safe_add(Type a, Type b)
388 {
389 if(a < 0 && b < 0)
390 {
391 // when both a and b are negative
392 // limits_min<Type> <= a + b ... (1a)
393 // limits_min<Type> - b <= a ... (2a)
394
395 if(limits_min<Type> - b <= a)
396 return a + b;
397 else
398 {
399 std::ostringstream os;
400 os << "overflow: a = " << a
401 << ", b = " << b;
402
403 Tpf_ThrowDebugException(os.str());
404 }
405 }
406 else if(a > 0 && b > 0)
407 {
408 /*
409 when both a and b are positive
410 limits_max<Type> >= a + b ... (1b)
411 limits_max<Type> - b >= a ... (2b)
412 */
413 if( limits_max<Type> - b >= a)
414 return a + b;
415 else
416 {
417 std::ostringstream os;
418 os << "overflow: a = " << a
419 << ", b = " << b;
420
421 Tpf_ThrowDebugException(os.str());
422 }
423 }
424 else
425 return a + b;
426 }
427
428 // signed: a - b
437 template<typename Type>
439 safe_sub(Type a, Type b)
440 {
441 return safe_add(a, -b);
442 }
443
444 // unsigned: a + b
453 template<typename Type>
455 safe_add(Type a, Type b)
456 {
457 /*
458 0<= a + b <= limits_max<Type>
459 a <= limits_max<Type> - b
460 */
461 if(a <= limits_max<Type> - b)
462 return a + b;
463 else
464 {
465 std::ostringstream os;
466 os << "overflow: a = " << a
467 << ", b = " << b;
468
469 Tpf_ThrowDebugException(os.str());
470 }
471 }
472
473 // unsigned: a - b
482 template<typename Type>
484 safe_sub(Type a, Type b)
485 {
486 /*
487 0 <= a - b
488 b <= a ...
489 */
490 if(b <= a)
491 return a - b;
492 else
493 {
494 std::ostringstream os;
495 os << "overflow: a = " << a
496 << ", b = " << b;
497
498 Tpf_ThrowDebugException(os.str());
499 }
500 }
501
510 template<typename Type>
512 safe_mul(Type a, Type b)
513 {
514 auto rlt = a * b;
515
516 if( (b == 0) || (rlt / b == a))
517 return rlt;
518 else
519 {
520 std::ostringstream os;
521 os << "overflow: a = " << a
522 << ", b = " << b;
523
524 Tpf_ThrowDebugException(os.str());
525 }
526 }
527
536 template<typename Type>
538 safe_div(Type a, Type b)
539 {
540 if( b != 0)
541 return a / b;
542 else
543 {
544 std::ostringstream os;
545 os << "division by zero - a = " << a
546 << ", b = " << b;
547
548 Tpf_ThrowDebugException(os.str());
549 }
550 }
551
552 template<typename Type>
554 safe_add(Type a, Type b)
555 {
556 auto rlt = a + b;
557 if(rlt != rlt)
558 {
559 std::ostringstream os;
560 os << "floating-point operation failed - a = "
561 << a <<", b = " << b;
562
563 Tpf_ThrowDebugException(os.str());
564 }
565
566 return rlt;
567 }
568
569 template<typename Type>
571 safe_sub(Type a, Type b)
572 {
573 auto rlt = a - b;
574 if(rlt != rlt)
575 {
576 std::ostringstream os;
577 os << "floating-point operation failed - a = "
578 << a <<", b = " << b;
579
580 Tpf_ThrowDebugException(os.str());
581 }
582
583 return rlt;
584 }
585
586 template<typename Type>
588 safe_mul(Type a, Type b)
589 {
590 auto rlt = a * b;
591 if(rlt != rlt)
592 {
593 std::ostringstream os;
594 os << "floating-point operation failed - a = "
595 << a <<", b = " << b;
596
597 Tpf_ThrowDebugException(os.str());
598 }
599
600 return rlt;
601 }
602
603 template<typename Type>
605 safe_div(Type a, Type b)
606 {
607 auto rlt = a / b;
608 if(rlt != rlt)
609 {
610 std::ostringstream os;
611
612 os << "floating-point operation failed - a = "
613 << a <<", b = " << b;
614
615 Tpf_ThrowDebugException(os.str());
616 }
617
618 return rlt;
619 }
620
621 } // end of namespace bitwise
622
623} // end of namespace tpf
624
625#endif // end of file
std::atomic< int > count
Definition: 022-mutex.cpp:10
auto & cout
auto & endl
signed_integral_t< common_t< S, T > > signed_common_t
types::make_signed_integral_t< T > signed_integral_t
unsigned_integral_t< common_t< S, T > > unsigned_common_t
types::make_unsigned_integral_t< T > unsigned_integral_t
types::common_type_t< S, T > common_t
types::enable_if_signed_integral_t< Type > safe_add(Type a, Type b)
Safe addition of the signed integral types.
types::enable_if_integral_t< Type, int > numeric_width()
Return's maximum numeric field width.
constexpr Type limits_max
Upperbound number the Type can represent.
types::enable_if_integral_t< Type > safe_mul(Type a, Type b)
Safe multiplication of integral types.
types::enable_if_integral_t< Type, std::string > to_bits(Type bits)
Returns binary bit pattern.
types::enable_if_integral_t< Type, void > twos_complement(Type c)
Displays Twos complement.
types::enable_if_integral_t< Type, std::string > numeric_base(Type v)
Displays how integral types are represented.
types::enable_if_integral_t< Type > safe_div(Type a, Type b)
Safe division of integral types.
void integral_type_info()
Displays all integral types' representation.
types::enable_if_integral_t< Type, std::string > to_hex(Type v)
Returns hexidecimal representation.
constexpr auto high_bit_mask
Return's bit mask for the highest bit.
types::enable_if_integral_t< Type, int > field_width(Type v)
Returns' field width.
types::enable_if_integral_t< Type, int > count_set_bits(Type bits)
Counts set bits.
types::enable_if_integral_t< Type, std::string > to_dec(Type v)
Returns decimal representation.
types::enable_if_integral_t< Type, std::string > to_dec_width(Type v)
Returns decimal field width.
types::enable_if_integral_t< Type, std::string > numeric_type_info(Type)
Displays integral type's numerical information.
constexpr Type limits_min
Lowerbound number the Type can represent.
constexpr int sizeof_bits
Returns bit count of type T.
types::enable_if_signed_integral_t< Type > safe_sub(Type a, Type b)
Safe subtraction of signed integral types.
hidden::make_signed_integral_t< Type > make_signed_integral_t
Definition: tpf_types.hpp:5116
hidden::enable_if_integral_t< Type, ReturnType > enable_if_integral_t
Definition: tpf_types.hpp:5080
hidden::enable_if_signed_integral_t< Type, ReturnType > enable_if_signed_integral_t
Definition: tpf_types.hpp:5083
hidden::common_type_t< Types... > common_type_t
Definition: tpf_types.hpp:5122
hidden::enable_if_unsigned_integral_t< Type, ReturnType > enable_if_unsigned_integral_t
Definition: tpf_types.hpp:5086
hidden::enable_if_real_number_t< Type, ReturnType > enable_if_real_number_t
Definition: tpf_types.hpp:5101
hidden::make_unsigned_integral_t< Type > make_unsigned_integral_t
Definition: tpf_types.hpp:5113
Includes subnamespace conversion.
Definition: 31-visit.cpp:7
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
constexpr auto nl
Definition: tpf_output.hpp:971
Type functions are implemented.
#define Tpf_ThrowDebugException(debug_message)
Throw a debug_exception with message as argument.
Definition: tpf_types.hpp:1416
#define Tpf_GetTypeName(type_arg)
A macro that returns type_arg's string name.
Definition: tpf_types.hpp:1422