1
+ /*
2
+ * Copyright (c) 2021, Thomas Sommer
3
+ *
4
+ * This file is part of the modm project.
5
+ *
6
+ * This Source Code Form is subject to the terms of the Mozilla Public
7
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
8
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9
+ */
10
+ // ----------------------------------------------------------------------------
11
+
12
+ #pragma once
13
+
14
+ #include < algorithm>
15
+
16
+ #include < modm/math/utils/integer_traits.hpp>
17
+ #include < modm/architecture/interface/assert.hpp>
18
+
19
+ namespace modm {
20
+
21
+ /* *
22
+ * @brief Unsigned integer with arbitrary digits and scaling value on conversion
23
+ * between instances with different digits.
24
+ *
25
+ * @tparam D Number of Digits
26
+ *
27
+ * @author Thomas Sommer
28
+ * @ingroup modm_math
29
+ */
30
+ template <int D>
31
+ requires (D > 0 )
32
+ class ProportionalUnsigned {
33
+ public:
34
+ static constexpr int Digits = D;
35
+
36
+ using T = uint_t <D>::least;
37
+ static constexpr T min = 0 ;
38
+ static constexpr T max = bitmask<D>();
39
+
40
+ constexpr ProportionalUnsigned () = default;
41
+
42
+ constexpr ProportionalUnsigned (T value) {
43
+ if (std::is_constant_evaluated ())
44
+ this ->value = std::min (value, max);
45
+ else {
46
+ modm_assert_continue_fail_debug (value <= max, " ProportionalUnsigned" , " value out of range" );
47
+ // Constructing runtime should a.f.a.p.
48
+ this ->value = value;
49
+ }
50
+ }
51
+
52
+ // Construct from bigger or equal ProportionalUnsigned
53
+ template <int E, std::enable_if_t <(D <= E), void *> = nullptr >
54
+ constexpr ProportionalUnsigned (const ProportionalUnsigned<E>& other)
55
+ : value(other.value >> (E - D)) {}
56
+
57
+ template <int E, std::enable_if_t <(D <= E), void *> = nullptr >
58
+ constexpr ProportionalUnsigned (ProportionalUnsigned<E> &&other)
59
+ : value(other.value >> (E - D)) {}
60
+
61
+ // Construct from smaller ProportionalUnsigned
62
+ template <int E, std::enable_if_t <(D > E), void *> = nullptr >
63
+ constexpr ProportionalUnsigned (const ProportionalUnsigned<E>& other)
64
+ : value(other.value * max / other.max)
65
+ {}
66
+
67
+ template <int E, std::enable_if_t <(D > E), void *> = nullptr >
68
+ constexpr ProportionalUnsigned (ProportionalUnsigned<E> &&other)
69
+ : value(other.value * max / other.max)
70
+ {}
71
+
72
+ /* // Faster construction for D == 1
73
+ constexpr ProportionalUnsigned(const ProportionalUnsigned<1> &other) : value(other.value ? bitmask<D>() : 0){}
74
+
75
+ // constexpr ProportionalUnsigned(ProportionalUnsigned<1> &&other) : value(other.value ? bitmask<D>() : 0){}
76
+ constexpr ProportionalUnsigned& operator=(const ProportionalUnsigned<1> &other) {
77
+ value = other.value ? bitmask<D>() : 0;
78
+ return *this;
79
+ } */
80
+
81
+ // Cast to underlying type. No need to define getters and comparison operators.
82
+ // @see https://en.cppreference.com/w/cpp/language/cast_operator
83
+ operator T () const
84
+ { return value; }
85
+
86
+ // Assign ProportionalUnsigned with more or equal Digits
87
+ template <int E, std::enable_if_t <(D <= E), void *> = nullptr >
88
+ constexpr void operator =(const ProportionalUnsigned<E>& other) {
89
+ value = other.value >> (E - D);
90
+ }
91
+
92
+ // Assign ProportionalUnsigned with less Digits
93
+ template <int E, std::enable_if_t <(D > E), void *> = nullptr >
94
+ constexpr void operator =(const ProportionalUnsigned<E>& other) {
95
+ value = other.value * max / other.max ;
96
+ }
97
+
98
+ constexpr void setValue (T value) {
99
+ if (std::is_constant_evaluated ())
100
+ this ->value = std::min (value, max);
101
+ else {
102
+ modm_assert_continue_fail_debug (value <= max, " ProportionalUnsigned" , " value out of range" );
103
+ // Calling setValue() runtime should a.f.a.p.
104
+ this ->value = value;
105
+ }
106
+ }
107
+
108
+ protected:
109
+ T value{0 };
110
+
111
+ private:
112
+ template <int >
113
+ friend class ProportionalUnsigned ;
114
+ };
115
+
116
+ }
0 commit comments