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