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+ */
29+ template <int D>
30+ class ScalingUnsigned {
31+ public:
32+ static constexpr int Digits = D;
33+
34+ using T = uint_t <D>::least;
35+ static constexpr T min = 0 ;
36+ static constexpr T max = bitmask<D>();
37+
38+ constexpr ScalingUnsigned () = default;
39+
40+ // FIXME want both:
41+ // COMPTIME: static_assert(value <= max, "value out of range")
42+ // RUNTIME: std::min(value, max) or modm_assert(value <= max, ...)
43+ constexpr ScalingUnsigned (T value)
44+ : value(std::min(value, max)) {
45+ // TODO disable via lbuild option
46+ // modm_assert_continue_fail_debug(value <= max, "ScalingUnsigned", "constructor", "value out of range");
47+ }
48+
49+ // Construct from bigger or equal ScalingUnsigned
50+ template <int E, std::enable_if_t <(D <= E), void *> = nullptr >
51+ constexpr ScalingUnsigned (const ScalingUnsigned<E>& other)
52+ : value(other.value >> (E - D)) {}
53+
54+ template <int E, std::enable_if_t <(D <= E), void *> = nullptr >
55+ constexpr ScalingUnsigned (ScalingUnsigned<E> &&other)
56+ : value(other.value >> (E - D)) {}
57+
58+ // Construct from smaller ScalingUnsigned
59+ template <int E, std::enable_if_t <(D > E), void *> = nullptr >
60+ constexpr ScalingUnsigned (const ScalingUnsigned<E>& other)
61+ : value(other.value * max / other.max)
62+ {}
63+
64+ template <int E, std::enable_if_t <(D > E), void *> = nullptr >
65+ constexpr ScalingUnsigned (ScalingUnsigned<E> &&other)
66+ : value(other.value * max / other.max)
67+ {}
68+
69+ /* // Faster construction from from single digit
70+ constexpr ScalingUnsigned(const ScalingUnsigned<1> &other) : value(other.value ? bitmask<D>() : 0){}
71+
72+ // constexpr ScalingUnsigned(ScalingUnsigned<1> &&other) : value(other.value ? bitmask<D>() : 0){}
73+ constexpr ScalingUnsigned& operator=(const ScalingUnsigned<1> &other) {
74+ value = other.value ? bitmask<D>() : 0;
75+ return *this;
76+ } */
77+
78+ // Assign ScalingUnsigned with more or equal Digits
79+ template <int E, std::enable_if_t <(D <= E), void *> = nullptr >
80+ void operator =(const ScalingUnsigned<E>& other) {
81+ value = other.value >> (E - D);
82+ }
83+
84+ // Assign ScalingUnsigned with less Digits
85+ template <int E, std::enable_if_t <(D > E), void *> = nullptr >
86+ void operator =(const ScalingUnsigned<E>& other) {
87+ value = other.value * max / other.max ;
88+ }
89+
90+ // FIXME want both:
91+ // COMPTIME: static_assert(value <= max, "value out of range")
92+ // RUNTIME: std::min(value, max) or modm_assert(value <= max, ...)
93+ void setValue (T value) {
94+ this ->value = std::min (value, max);
95+ // TODO disable via lbuild option
96+ // modm_assert_continue_fail_debug(value <= max, "modm::ScalingUnsigned", "setValue()", "value out of range");
97+ }
98+
99+ T getValue () const
100+ { return value; }
101+
102+ // operator T&() { return value; }
103+ // operator T() const { return value; }
104+
105+ constexpr auto operator <=>(const ScalingUnsigned<D> &) const = default ;
106+
107+ protected:
108+ T value{0 };
109+ private:
110+ template <int >
111+ friend class ScalingUnsigned ;
112+ };
113+
114+ }
0 commit comments