OSCR
Open Source Cartridge Reader
Loading...
Searching...
No Matches
Util.h
1/********************************************************************
2* Open Source Cartridge Reader *
3********************************************************************/
4#pragma once
5#ifndef OSCR_UTIL_H_
6#define OSCR_UTIL_H_
7
8# include "config.h"
9# include "syslibinc.h"
10# include "common/specializations.h"
11
12namespace OSCR
13{
17 namespace Util
18 {
22 constexpr size_t const flashBufferStrSize = 100;
23
24 template <__TEMPLATE_AUTO_UINT8 base, typename T,
25 if_is_integer_t<T> Enable = true,
26 enable_if_t<2 == base, bool> IsEnabled = true>
27 extern T power(T n);
28
29 template <__TEMPLATE_AUTO_UINT8 base, typename T,
30 if_is_integer_t<T> Enable = true,
31 enable_if_t<8 == base, bool> IsEnabled = true>
32 extern T power(T n);
33
34 template <__TEMPLATE_AUTO_UINT8 base, typename T,
35 if_is_integer_t<T> Enable = true,
36 enable_if_t<10 == base, bool> IsEnabled = true>
37 extern T power(T n);
38
39 template <__TEMPLATE_AUTO_UINT8 base, typename T,
40 if_is_integer_t<T> Enable = true,
41 enable_if_t<16 == base, bool> IsEnabled = true>
42 extern T power(T n);
43
44 template <typename T,
45 if_is_integer_t<T> Enable = true>
46 extern T power(T b, T n);
47
48 [[noreturn]] static inline void unreachable()
49 {
50 // Uses compiler specific extensions if possible.
51 // Even if no extension is used, undefined behavior is still raised by
52 // an empty function body and the noreturn attribute.
53#if defined(_MSC_VER) && !defined(__clang__) // MSVC
54 __assume(false);
55#else // GCC, Clang
56 __builtin_unreachable();
57#endif
58 }
59
72 bool strToInt(char const buffer[], int32_t & dest);
73
85 bool strToInt(char const buffer[], uint32_t & dest);
86
87 bool copyStr(char buffer[], size_t bufferSize, char const * str);
88
89 bool copyStrUpr(char buffer[], size_t bufferSize, char const * str);
90 bool copyStrLwr(char buffer[], size_t bufferSize, char const * str);
91
92 //template <bool prfx = true>
93 //int toHex(char * buff, size_t len, uint8_t number);
94
95 template <bool prfx = true,
96 typename T,
97 if_is_any_unsigned_t<T> Enable = true>
98 extern int toHex(char * buff, size_t len, T number);
99
109 bool copyStr_P(char buffer[], size_t bufferSize, char const * str);
110 bool copyStr_P(char buffer[], size_t bufferSize, __FlashStringHelper const * str);
111
112 bool copyStrUpr_P(char buffer[], size_t bufferSize, char const * str);
113 bool copyStrUpr_P(char buffer[], size_t bufferSize, __FlashStringHelper const * str);
114
115 bool copyStrLwr_P(char buffer[], size_t bufferSize, char const * str);
116 bool copyStrLwr_P(char buffer[], size_t bufferSize, __FlashStringHelper const * str);
117
128 bool applyTemplate_P(char buffer[], size_t bufferSize, char const * templateStr, int32_t num);
129 bool applyTemplate_P(char buffer[], size_t bufferSize, __FlashStringHelper const * templateStr, int32_t num);
130 bool applyTemplate_P(char buffer[], size_t bufferSize, char const * templateStr, uint32_t num);
131 bool applyTemplate_P(char buffer[], size_t bufferSize, __FlashStringHelper const * templateStr, uint32_t num);
132
145 bool applyTemplate_P(char buffer[], size_t bufferSize, char const * templateStr, char const * flashStr);
146 bool applyTemplate_P(char buffer[], size_t bufferSize, __FlashStringHelper const * templateStr, char const * flashStr);
147 bool applyTemplate_P(char buffer[], size_t bufferSize, char const * templateStr, __FlashStringHelper const * flashStr);
148 bool applyTemplate_P(char buffer[], size_t bufferSize, __FlashStringHelper const * templateStr, __FlashStringHelper const * flashStr);
149
160 bool applyTemplate(char buffer[], size_t bufferSize, char const * templateStr, char const * str);
161 bool applyTemplate(char buffer[], size_t bufferSize, __FlashStringHelper const * templateStr, char const * str);
162
163 extern bool isAlphaNumeric(uint8_t src);
164
173 template <typename T>
174 extern void swap(T &a, T &b);
175
191 template <typename Tout,
192 typename Tin,
193 if_is_any_number_t<Tout> outEnable = true,
194 if_is_any_number_t<Tin> inEnable = true>
195 inline Tout minOf(Tin a, Tin b)
196 {
197 if __if_constexpr ((is_unsigned_v<Tout>) && (is_signed_v<Tin>))
198 {
199 if (a < 0) a = 0;
200 if (b < 0) b = 0;
201 }
202
203 if (a > b) return b;
204 return a;
205 }
206
222 template <typename Tout,
223 typename Tin,
224 if_is_any_number_t<Tout> outEnable = true,
225 if_is_any_number_t<Tin> inEnable = true>
226 inline Tout maxOf(Tin a, Tin b)
227 {
228 if __if_constexpr ((is_unsigned_v<Tout>) && (is_signed_v<Tin>))
229 {
230 if (a < 0) a = 0;
231 if (b < 0) b = 0;
232 }
233
234 if (a < b) return b;
235 return a;
236 }
237
248 template <typename Tout,
249 typename Tin1,
250 typename Tin2,
251 if_is_any_number_t<Tout> outEnable = true,
252 if_is_any_number_t<Tin1> in1Enable = true,
253 if_is_any_number_t<Tin2> in2Enable = true>
254 inline Tout minOf(Tin1 a, Tin2 b)
255 {
256 // If output is unsigned
257 if __if_constexpr (is_unsigned_v<Tout>)
258 {
259 // If `a` is signed+negative, return 0
260 if __if_constexpr (is_signed_v<Tin1>)
261 {
262 if (a < 0) return 0;
263 }
264
265 // If `b` is signed+negative, return 0
266 if __if_constexpr (is_signed_v<Tin2>)
267 {
268 if (b < 0) return 0;
269 }
270 }
271
272 // signed `a`, unsigned `b`
273 if __if_constexpr ((is_signed_v<Tin1>) && (is_unsigned_v<Tin2>))
274 {
275 // since `b` is unsigned, it can't be lower than zero
276 if (a < 0) return a;
277
278 // `a` is not negative, so it is safe to cast to unsigned
279 if (((make_unsigned_t<Tin1>)a) > b) return b;
280 return a;
281 }
282 else if __if_constexpr ((is_unsigned_v<Tin1>) && (is_signed_v<Tin2>)) // unsigned `a`, signed `b`
283 {
284 // since `a` is unsigned, it can't be lower than zero
285 if (b < 0) return b;
286
287 // `b` is not negative, so it is safe to cast to unsigned
288 if (a > ((make_unsigned_t<Tin2>)b)) return b;
289
290 return a;
291 }
292 else // same signedness
293 {
294 if (a > b) return b;
295 return a;
296 }
297 }
298
309 template <typename Tout,
310 typename Tin1,
311 typename Tin2,
312 if_is_any_number_t<Tout> outEnable = true,
313 if_is_any_number_t<Tin1> in1Enable = true,
314 if_is_any_number_t<Tin2> in2Enable = true>
315 inline Tout maxOf(Tin1 a, Tin2 b)
316 {
317 // If `Tin1`(`a`) is signed and `Tin2` (`b`) is unsigned
318 if __if_constexpr ((is_signed_v<Tin1>) && (is_unsigned_v<Tin2>))
319 {
320 // since `b` is unsigned, it can't be lower than zero
321 if (a < 0) return b;
322
323 // Cast `a` to signed before comparing
324 if (((make_unsigned_t<Tin1>)a) > b) return b;
325
326 return a;
327 }
328 else if __if_constexpr ((is_unsigned_v<Tin1>) && (is_signed_v<Tin2>)) // If `Tin1`(`a`) is unsigned and `Tin2` (`b`) is signed
329 {
330 // since `a` is unsigned, it can't be lower than zero
331 if (b < 0) return a;
332
333 // Cast `b` to signed before comparing
334 if (a > (make_unsigned_t<Tin2>(b))) return b;
335
336 return a;
337 }
338 else
339 {
340 if (a < b) return b;
341 return a;
342 }
343 }
344
356 template <typename Tout,
357 typename Tin,
358 if_is_any_number_t<Tout> outEnable = true,
359 if_is_any_number_t<Tin> inEnable = true>
360 inline constexpr Tout minOf_CX(Tin a, Tin b)
361 {
362 if ((is_unsigned_v<Tout>) && (is_signed_v<Tin>))
363 {
364 if (a < 0) a = 0;
365 if (b < 0) b = 0;
366 }
367
368 if (a > b) return b;
369 return a;
370 }
371
383 template <typename Tout,
384 typename Tin,
385 if_is_any_number_t<Tout> outEnable = true,
386 if_is_any_number_t<Tin> inEnable = true>
387 inline constexpr Tout maxOf_CX(Tin a, Tin b)
388 {
389 if ((is_unsigned_v<Tout>) && (is_signed_v<Tin>))
390 {
391 if (a < 0) a = 0;
392 if (b < 0) b = 0;
393 }
394
395 if (a < b) return b;
396 return a;
397 }
398
417 template <typename Tin,
418 typename Tmin,
419 typename Tmax,
420 typename Tout = Tin,
421 if_is_any_number_t<Tin> inEnable = true,
422 if_is_any_number_t<Tmin> minEnable = true,
423 if_is_any_number_t<Tmax> maxEnable = true,
424 if_is_any_number_t<Tout> outEnable = true>
425 inline Tout clamp(Tin input, Tmin minimum, Tmax maximum)
426 {
427 return minOf<Tout, Tin, Tmax>(maxOf<Tin, Tin, Tmin>(input, minimum), maximum);
428 }
429
442 template <typename Tout,
443 typename Tin,
444 if_is_any_number_t<Tout> outEnable = true,
445 if_is_any_number_t<Tin> inEnable = true>
446 inline Tout clamp(Tin input, Tout minimum, Tout maximum)
447 {
448 if __if_constexpr ((is_unsigned_v<Tout>) && (is_signed_v<Tin>))
449 {
450 if (input < 0) return minimum;
451 }
452
453 if (input < minimum) return minimum;
454 if (input > maximum) return maximum;
455 return input;
456 }
457
470 template <typename Tout,
471 typename Tin,
472 if_is_any_number_t<Tout> outEnable = true,
473 if_is_any_number_t<Tin> inEnable = true>
474 inline constexpr Tout clamp_CX(Tin input, Tout minimum, Tout maximum)
475 {
476 if ((is_unsigned_v<Tout>) && (is_signed_v<Tin>))
477 {
478 if (input < 0) return minimum;
479 }
480
481 if (input < minimum) return minimum;
482 if (input > maximum) return maximum;
483
484 return input;
485 }
486
500 template <typename Value, Value LowerLimit, Value UpperLimit,
501 if_is_integer_t<Value> = true>
502 class clamped_value
503 {
504 public:
505 clamped_value(Value&& value) : value_{clamp(value, LowerLimit, UpperLimit)} {}
506 clamped_value(int&& value) : value_{clamp<int, Value, Value, Value>(value, LowerLimit, UpperLimit)} {}
507 clamped_value(unsigned int&& value) : value_{clamp<unsigned int, Value, Value, Value>(value, LowerLimit, UpperLimit)} {}
508
509 constexpr operator Value&() { return value_; }
510 constexpr operator Value() const { return value_; }
511
512 private:
513 Value value_;
514 };
515
516# if defined(NEEDS_UTIL_BITSET_TEMPLATE)
517 template <typename BitsetType = uint8_t,
518 if_is_integer_t<BitsetType> = true>
519# else /* !NEEDS_UTIL_BITSET_TEMPLATE */
520 typedef uint8_t BitsetType;
521
522 class bitset
523# endif /* NEEDS_UTIL_BITSET_TEMPLATE */
524 {
525 public:
526 class reference
527 {
528 friend class bitset;
529
530 bitset * __bitset;
531 size_t pos;
532
533 public:
534 constexpr reference(reference const &) = default;
535 constexpr reference(bitset & __b, size_t __pos): __bitset(&__b), pos(__pos)
536 {
537 // ...
538 }
539
540 __relaxed_constexpr
541 reference & operator=(bool value) noexcept // for b[i] = x;
542 {
543 __bitset->set(this->pos, value);
544 return *this;
545 }
546
547 __relaxed_constexpr
548 reference & operator=(reference const & ref) noexcept // for b[i] = b[j];
549 {
550 __bitset->set(this->pos, ref.__bitset->test(ref.pos));
551 return *this;
552 }
553
554 constexpr bool operator~() const noexcept // flips the bit
555 {
556 return !__bitset->test(this->pos);
557 }
558
559 constexpr operator bool() const noexcept // for x = b[i];
560 {
561 return __bitset->test(this->pos);
562 }
563
564 __relaxed_constexpr
565 reference & flip() noexcept // for b[i].flip();
566 {
567 __bitset->set(this->pos, !__bitset->test(this->pos));
568 return *this;
569 }
570 };
571
572 friend class reference;
573
574 protected:
575 uint8_t width = 0;
576 BitsetType bits = 0;
577
578 public:
579 // constructors
580 constexpr bitset(uint8_t size) noexcept: width(size)
581 {
582 // ...
583 }
584
585 constexpr bitset(uint8_t size, BitsetType val) noexcept: width(size), bits(val)
586 {
587 // ...
588 }
589
590 // bitset operations
591 __relaxed_constexpr
592 bitset & operator&=(bitset const & rhs) noexcept
593 {
594 this->bits &= rhs.bits;
595 return *this;
596 }
597
598 __relaxed_constexpr
599 bitset & operator|=(bitset const & rhs) noexcept
600 {
601 this->bits |= rhs.bits;
602 return *this;
603 }
604
605 __relaxed_constexpr
606 bitset & operator^=(bitset const & rhs) noexcept
607 {
608 this->bits ^= rhs.bits;
609 return *this;
610 }
611
612 __relaxed_constexpr
613 bitset & operator<<=(size_t shift) noexcept
614 {
615 this->bits <<= shift;
616 return *this;
617 }
618
619 __relaxed_constexpr
620 bitset & operator>>=(size_t shift) noexcept
621 {
622 this->bits >>= shift;
623 return *this;
624 }
625
626 __relaxed_constexpr
627 bitset operator<<(size_t shift) const noexcept
628 {
629 return bitset(*this) <<= shift;
630 }
631
632 __relaxed_constexpr
633 bitset operator>>(size_t shift) const noexcept
634 {
635 return bitset(*this) >>= shift;
636 }
637
638 __relaxed_constexpr
639 bitset & set() noexcept
640 {
641 for (size_t __position = 0; __position < this->width; __position++)
642 {
643 this->set(__position, true);
644 }
645
646 return *this;
647 }
648
649 __relaxed_constexpr
650 bitset & set(size_t __position, bool val = true)
651 {
652 if (__position > this->width) return *this;
653
654 if (val) bits |= (1 << __position);
655 else bits &= ~(1 << __position);
656
657 return *this;
658 }
659
660 __relaxed_constexpr
661 bitset & reset() noexcept
662 {
663 this->bits = 0;
664 return *this;
665 }
666
667 __relaxed_constexpr
668 bitset & reset(size_t __position)
669 {
670 this->set(__position, 0);
671 return *this;
672 }
673 constexpr bitset operator~() const noexcept;
674
675 __relaxed_constexpr
676 bitset & flip() noexcept
677 {
678 for (size_t __position = 0; __position < this->width; __position++)
679 {
680 this->flip(__position);
681 }
682
683 return *this;
684 }
685
686 __relaxed_constexpr
687 bitset & flip(size_t __position)
688 {
689 this->set(__position, !this->test(__position));
690 return *this;
691 }
692
693 // element access
694 constexpr bool operator[](size_t __position) const
695 {
696 return !!(bits & (1 << __position));
697 }
698
699 __relaxed_constexpr
700 reference operator[](size_t __position)
701 {
702 return reference(*this, __position);
703 }
704
705 // observers
706 __relaxed_constexpr
707 size_t count() const noexcept
708 {
709 size_t bitcount = 0;
710
711 for (size_t i = 0; i < this->width; i++)
712 {
713 bitcount += this->test(i);
714 }
715
716 return bitcount;
717 }
718
719 constexpr size_t size() const noexcept
720 {
721 return this->width;
722 }
723
724 constexpr bool operator==(bitset const & rhs) const noexcept
725 {
726 return ((this->width == rhs.width) && (this->bits == rhs.bits));
727 }
728
729 constexpr bool test(size_t __position) const
730 {
731 return !!(bits & (1 << __position));
732 }
733
734 __relaxed_constexpr
735 bool all() const noexcept
736 {
737 size_t const allbits = ~0U >> ((8 * sizeof(BitsetType)) - this->width);
738 return !!(bits & allbits);
739 }
740
741 constexpr bool any() const noexcept
742 {
743 return !!bits;
744 }
745
746 constexpr bool none() const noexcept
747 {
748 return !bits;
749 }
750 };
751 }
752
753# if defined(NEEDS_UTIL_BITSET_TEMPLATE)
755
756 template class bitset<uint8_t>;
757
758# if defined(NEEDS_UTIL_BITSET_TEMPLATE_16) || NEEDS_UTIL_BITSET_TEMPLATE >= 16
759 template class bitset<uint16_t>;
760# endif /* NEEDS_UTIL_BITSET_TEMPLATE_16 || NEEDS_UTIL_BITSET_TEMPLATE >= 16 */
761
762# if defined(NEEDS_UTIL_BITSET_TEMPLATE_32) || NEEDS_UTIL_BITSET_TEMPLATE >= 32
763 template class bitset<uint32_t>;
764# endif /* NEEDS_UTIL_BITSET_TEMPLATE_32 || NEEDS_UTIL_BITSET_TEMPLATE >= 32 */
765
766# if defined(NEEDS_UTIL_BITSET_TEMPLATE_64) || NEEDS_UTIL_BITSET_TEMPLATE >= 64
767 template class bitset<uint64_t>;
768# endif /* NEEDS_UTIL_BITSET_TEMPLATE_64 || NEEDS_UTIL_BITSET_TEMPLATE >= 64 */
769
771# endif
772}
773
774#endif /* !OSCR_UTIL_H_ */
Definition Util.h:527
Definition Util.h:524
Utility methods.
Definition Util.h:18
bool strToInt(char const buffer[], int32_t &dest)
Definition Util.cpp:143
constexpr Tout maxOf_CX(Tin a, Tin b)
Definition Util.h:387
bool copyStr_P(char buffer[], size_t bufferSize, char const *str)
Definition Util.cpp:354
Tout maxOf(Tin a, Tin b)
Definition Util.h:226
Tout minOf(Tin a, Tin b)
Definition Util.h:195
Tout clamp(Tin input, Tmin minimum, Tmax maximum)
Definition Util.h:425
constexpr Tout minOf_CX(Tin a, Tin b)
Definition Util.h:360
bool applyTemplate(char buffer[], size_t bufferSize, char const *templateStr, char const *str)
Definition Util.cpp:461
void swap(T &a, T &b)
Definition Util.cpp:58
bool applyTemplate_P(char buffer[], size_t bufferSize, char const *templateStr, int32_t num)
Definition Util.cpp:407
constexpr Tout clamp_CX(Tin input, Tout minimum, Tout maximum)
Definition Util.h:474
constexpr size_t const flashBufferStrSize
Definition Util.h:22
Main program.
Definition Storage.h:13