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
+ // TODO not sure if modm_assert_continue_fail_debug or modm_assert_continue_fail is needed
44
+
45
+ // FIXME with AVR-GCC we get:
46
+ // error: '__c' declared 'static' in 'constexpr' function
47
+ // modm_assert_continue_fail(value <= max, "ProportionalUnsigned", "value out of range");
48
+ this ->value = value;
49
+ }
50
+
51
+ // Construct from bigger or equal ProportionalUnsigned
52
+ template <int E, std::enable_if_t <(D <= E), void *> = nullptr >
53
+ constexpr ProportionalUnsigned (const ProportionalUnsigned<E>& other)
54
+ : value(other.value >> (E - D)) {}
55
+
56
+ template <int E, std::enable_if_t <(D <= E), void *> = nullptr >
57
+ constexpr ProportionalUnsigned (ProportionalUnsigned<E> &&other)
58
+ : value(other.value >> (E - D)) {}
59
+
60
+ // Construct from smaller ProportionalUnsigned
61
+ template <int E, std::enable_if_t <(D > E), void *> = nullptr >
62
+ constexpr ProportionalUnsigned (const ProportionalUnsigned<E>& other)
63
+ : value(other.value * max / other.max)
64
+ {}
65
+
66
+ template <int E, std::enable_if_t <(D > E), void *> = nullptr >
67
+ constexpr ProportionalUnsigned (ProportionalUnsigned<E> &&other)
68
+ : value(other.value * max / other.max)
69
+ {}
70
+
71
+ /* // Faster construction for D == 1
72
+ constexpr ProportionalUnsigned(const ProportionalUnsigned<1> &other) : value(other.value ? bitmask<D>() : 0){}
73
+
74
+ // constexpr ProportionalUnsigned(ProportionalUnsigned<1> &&other) : value(other.value ? bitmask<D>() : 0){}
75
+ constexpr ProportionalUnsigned& operator=(const ProportionalUnsigned<1> &other) {
76
+ value = other.value ? bitmask<D>() : 0;
77
+ return *this;
78
+ } */
79
+
80
+ T getValue () const
81
+ { return value; }
82
+
83
+ // Cast to underlying type. No more comparison operators required.
84
+ // @see https://en.cppreference.com/w/cpp/language/cast_operator
85
+ operator T () const
86
+ { return value; }
87
+
88
+ void operator =(T value) {
89
+ // TODO not sure if modm_assert_continue_fail_debug or modm_assert_continue_fail is needed
90
+ modm_assert_continue_fail_debug (value <= max, " ProportionalUnsigned" , " value out of range" );
91
+ this ->value = value;
92
+ }
93
+
94
+ // Assign ProportionalUnsigned with more or equal Digits
95
+ template <int E, std::enable_if_t <(D <= E), void *> = nullptr >
96
+ constexpr void operator =(const ProportionalUnsigned<E>& other) {
97
+ value = other.value >> (E - D);
98
+ }
99
+
100
+ // Assign ProportionalUnsigned with less Digits
101
+ template <int E, std::enable_if_t <(D > E), void *> = nullptr >
102
+ constexpr void operator =(const ProportionalUnsigned<E>& other) {
103
+ value = other.value * max / other.max ;
104
+ }
105
+ protected:
106
+ T value{0 };
107
+
108
+ private:
109
+ template <int >
110
+ friend class ProportionalUnsigned ;
111
+ };
112
+
113
+ }
0 commit comments