libfxd 0.2.dev
A fixed-point library for C++.
Loading...
Searching...
No Matches
saturate.hpp
Go to the documentation of this file.
1/*
2 * libfxd - a fixed-point library for C++
3 *
4 * Copyright 2023 Daniel K. O.
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8#ifndef LIBFXD_SATURATE_HPP
9#define LIBFXD_SATURATE_HPP
10
11#include <concepts>
12#include <csignal>
13
14#include "concepts.hpp"
15#include "error.hpp"
16
17#include "detail/safe.hpp"
18#include "detail/safe-div.hpp"
19#include "detail/safe-mul.hpp"
20
21
23namespace fxd::saturate {
24
25
34 template<typename T>
35 [[nodiscard]]
36 constexpr
37 T
39 noexcept
40 {
41 switch (e) {
43 return std::numeric_limits<T>::lowest();
44 case error::overflow:
45 return std::numeric_limits<T>::max();
47 default:
48 std::raise(SIGFPE);
49 }
50 return 0;
51 }
52
53
54#define WRAP(expr) \
55 do { \
56 auto result = detail::safe::expr; \
57 using Ret = typename decltype(result)::value_type; \
58 if (!result) \
59 return saturate<Ret>(result.error()); \
60 return *result; \
61 } while (false)
62
63
70 template<fixed_point Fxd,
71 std::integral I>
72 [[nodiscard]]
73 constexpr
74 Fxd
75 from_raw(I val)
76 noexcept
77 {
78 WRAP(from_raw<Fxd>(val));
79 }
80
81
83 template<fixed_point Dst,
84 std::convertible_to<Dst> Src>
85 [[nodiscard]]
86 constexpr
87 Dst
88 make_fixed(Src src)
89 noexcept
90 {
91 WRAP(make_fixed<Dst>(src));
92 }
93
94
96 template<unsigned_fixed_point Dst,
97 std::convertible_to<Dst> Src>
98 [[nodiscard]]
99 constexpr
100 Dst
101 make_ufixed(Src src)
102 noexcept
103 {
104 WRAP(make_fixed<Dst>(src));
105 }
106
107
109 template<int Int, int Frac,
110 typename Raw = detail::select_int_t<Int + Frac>,
111 std::convertible_to<fixed<Int, Frac, Raw>> Src>
112 [[nodiscard]]
113 constexpr
115 make_fixed(Src src)
116 noexcept
117 {
118 using Dst = fixed<Int, Frac, Raw>;
119 return saturate::make_fixed<Dst>(src);
120 }
121
122
124 template<fixed_point Dst,
125 fixed_point Src>
126 [[nodiscard]]
127 constexpr
128 Dst
129 fixed_cast(Src src)
130 noexcept
131 {
132 WRAP(fixed_cast<Dst>(src));
133 }
134
135
137 template<int Int, int Frac,
138 typename Raw = detail::select_int_t<Int + Frac>,
139 fixed_point Src>
140 [[nodiscard]]
141 constexpr
143 fixed_cast(Src src)
144 noexcept
145 {
146 using Dst = fixed<Int, Frac, Raw>;
147 return saturate::fixed_cast<Dst>(src);
148 }
149
150
152 template<int Int, int Frac,
153 typename Raw = detail::select_uint_t<Int + Frac>,
154 fixed_point Src>
155 [[nodiscard]]
156 constexpr
158 ufixed_cast(Src src)
159 noexcept
160 {
161 using Dst = fixed<Int, Frac, Raw>;
162 return saturate::fixed_cast<Dst>(src);
163 }
164
165
167 template<std::integral I,
168 fixed_point Fxd>
169 [[nodiscard]]
170 constexpr
171 I
172 to_int(Fxd f)
173 noexcept
174 {
175 WRAP(to_int<I>(f));
176 }
177
178
180 template<fixed_point Fxd>
181 [[nodiscard]]
182 constexpr
183 detail::select_int_for<Fxd::int_bits, typename Fxd::raw_type>
184 to_int(Fxd f)
185 {
186 using I = detail::select_int_for<Fxd::int_bits, typename Fxd::raw_type>;
187 return saturate::to_int<I>(f);
188 }
189
190
192 template<fixed_point Dst,
193 std::convertible_to<Dst> Src>
194 constexpr
195 Dst&
196 assign(Dst& dst,
197 Src src)
198 noexcept
199 {
200 return dst = saturate::make_fixed<Dst>(src);
201 }
202
203
205 template<fixed_point Fxd>
206 constexpr
207 Fxd&
208 pre_inc(Fxd& f)
209 noexcept
210 {
211 auto result = detail::safe::incremented(f);
212 if (!result)
213 return f = saturate<Fxd>(result.error());
214 return f = *result;
215 }
216
217
219 template<fixed_point Fxd>
220 constexpr
221 Fxd
222 post_inc(Fxd& f)
223 noexcept
224 {
225 Fxd old_f = f;
227 return old_f;
228 }
229
230
232 template<fixed_point Fxd>
233 constexpr
234 Fxd&
235 pre_dec(Fxd& f)
236 noexcept
237 {
238 auto result = detail::safe::decremented(f);
239 if (!result)
240 return f = saturate<Fxd>(result.error());
241 return f = *result;
242 }
243
244
246 template<fixed_point Fxd>
247 constexpr
248 Fxd
249 post_dec(Fxd& f)
250 noexcept
251 {
252 Fxd old_f = f;
254 return old_f;
255 }
256
257
259 template<fixed_point Fxd>
260 [[nodiscard]]
261 constexpr
262 Fxd
263 negate(Fxd f)
264 noexcept
265 {
266 WRAP(negate(f));
267 }
268
269
271 template<fixed_point Fxd>
272 [[nodiscard]]
273 constexpr
274 Fxd
275 add(Fxd a,
276 Fxd b)
277 noexcept
278 {
279 WRAP(add(a, b));
280 }
281
282
284 template<fixed_point Fxd>
285 [[nodiscard]]
286 constexpr
287 Fxd
288 sub(Fxd a,
289 Fxd b)
290 noexcept
291 {
292 WRAP(sub(a, b));
293 }
294
295
297 namespace down {
298
300 template<fixed_point Fxd>
301 [[nodiscard]]
302 constexpr
303 Fxd
304 div(Fxd a,
305 Fxd b)
306 noexcept
307 {
308 WRAP(down::div(a, b));
309 }
310
311
313 template<fixed_point Fxd>
314 [[nodiscard]]
315 constexpr
316 Fxd
317 mul(Fxd a,
318 Fxd b)
319 noexcept
320 {
321 WRAP(down::mul(a, b));
322 }
323
324 } // namespace down
325
326
328 namespace up {
329
331 template<fixed_point Fxd>
332 [[nodiscard]]
333 constexpr
334 Fxd
335 div(Fxd a,
336 Fxd b)
337 noexcept
338 {
339 WRAP(up::div(a, b));
340 }
341
342
344 template<fixed_point Fxd>
345 [[nodiscard]]
346 constexpr
347 Fxd
348 mul(Fxd a,
349 Fxd b)
350 noexcept
351 {
352 WRAP(up::mul(a, b));
353 }
354
355 } // namespace up
356
357
359 inline
360 namespace zero {
361
363 template<fixed_point Fxd>
364 [[nodiscard]]
365 constexpr
366 Fxd
367 div(Fxd a,
368 Fxd b)
369 noexcept
370 {
371 WRAP(zero::div(a, b));
372 }
373
375 template<fixed_point Fxd>
376 [[nodiscard]]
377 constexpr
378 Fxd
379 mul(Fxd a,
380 Fxd b)
381 noexcept
382 {
383 WRAP(zero::mul(a, b));
384 }
385
386 } // namespace zero
387
388
390 template<fixed_point Fxd>
391 [[nodiscard]]
392 constexpr
393 Fxd
394 abs(Fxd f)
395 noexcept
396 {
397 WRAP(abs(f));
398 }
399
400
401#undef WRAP
402
403
404} // namespace fxd::saturate
405
406
407#endif
Concept to match any fxd::fixed
Definition: concepts.hpp:19
Concept to match only unsigned fxd::fixed
Definition: concepts.hpp:24
#define WRAP(expr)
Definition: except.hpp:54
constexpr Fxd mul(Fxd a, Fxd b) noexcept
Multiply rounding down, clamp on overflow.
Definition: saturate.hpp:317
constexpr Fxd div(Fxd a, Fxd b) noexcept
Divide rounding down, clamp on overflow.
Definition: saturate.hpp:304
constexpr Fxd mul(Fxd a, Fxd b) noexcept
Multiply rounding up, clamp on overflow.
Definition: saturate.hpp:348
constexpr Fxd div(Fxd a, Fxd b) noexcept
Divide rounding up, clamp on overflow.
Definition: saturate.hpp:335
constexpr Fxd mul(Fxd a, Fxd b) noexcept
Multiply rounding to zero, clamp on overflow.
Definition: saturate.hpp:379
constexpr Fxd div(Fxd a, Fxd b) noexcept
Divide rounding to zero, clamp on overflow.
Definition: saturate.hpp:367
Clamp on overflow.
Definition: saturate.hpp:23
constexpr Dst & assign(Dst &dst, Src src) noexcept
Assignment, clamp on overflow.
Definition: saturate.hpp:196
constexpr Fxd post_dec(Fxd &f) noexcept
Post-decrement (f--), clamp on overflow.
Definition: saturate.hpp:249
constexpr Fxd & pre_inc(Fxd &f) noexcept
Pre-increment (++f), clamp on overflow.
Definition: saturate.hpp:208
constexpr T saturate(error e) noexcept
Error handler that clamps the value on error.
Definition: saturate.hpp:38
constexpr Dst make_ufixed(Src src) noexcept
Construct from numerical value, clamp on overflow (unsigned version).
Definition: saturate.hpp:101
constexpr Fxd post_inc(Fxd &f) noexcept
Post-increment (f++), clamp on overflow.
Definition: saturate.hpp:222
constexpr Fxd & pre_dec(Fxd &f) noexcept
Pre-decrement (--f), clamp on overflow.
Definition: saturate.hpp:235
constexpr fixed< Int, Frac, Raw > ufixed_cast(Src src) noexcept
Convenience overload (unsigned version).
Definition: saturate.hpp:158
constexpr Dst fixed_cast(Src src) noexcept
Convert a fixed point to a different type of fixed point.
Definition: casting.hpp:28
constexpr I to_int(Fxd f) noexcept
Convert to integer.
Definition: conversions.hpp:45
error
Error values reported by fxd::expect function.
Definition: error.hpp:14
The fixed-point class template.
Definition: fixed.hpp:38