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