/src/libreoffice/include/o3tl/float_int_conversion.hxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | */ |
9 | | |
10 | | #pragma once |
11 | | |
12 | | #include <sal/config.h> |
13 | | |
14 | | #include <cmath> |
15 | | #include <limits> |
16 | | #include <type_traits> |
17 | | #include <o3tl/concepts.hxx> |
18 | | |
19 | | namespace o3tl |
20 | | { |
21 | | // Return true iff `value` of floating-point type `F` converts to a value of integral type `I` no |
22 | | // smaller than `min`: |
23 | | template <floating_point F, integral I> constexpr bool convertsToAtLeast(F value, I min) |
24 | 356k | { |
25 | | // If `F(min)`, `F(min) - F(1)` are too large in magnitude for `F`'s precision, then they either |
26 | | // fall into the same bucket, in which case we should return false if `value` represents that |
27 | | // bucket, or they are on the boundary of two adjacent buckets, in which case we should return |
28 | | // true if `value`represents the higher bucket containing `F(min)`: |
29 | 356k | return value > F(min) - F(1); |
30 | 356k | } _ZN4o3tl17convertsToAtLeastITkNSt3__114floating_pointEdTkNS1_8integralElEEbT_T0_ Line | Count | Source | 24 | 356k | { | 25 | | // If `F(min)`, `F(min) - F(1)` are too large in magnitude for `F`'s precision, then they either | 26 | | // fall into the same bucket, in which case we should return false if `value` represents that | 27 | | // bucket, or they are on the boundary of two adjacent buckets, in which case we should return | 28 | | // true if `value`represents the higher bucket containing `F(min)`: | 29 | 356k | return value > F(min) - F(1); | 30 | 356k | } |
Unexecuted instantiation: _ZN4o3tl17convertsToAtLeastITkNSt3__114floating_pointEdTkNS1_8integralEDsEEbT_T0_ Unexecuted instantiation: _ZN4o3tl17convertsToAtLeastITkNSt3__114floating_pointEdTkNS1_8integralEhEEbT_T0_ Unexecuted instantiation: _ZN4o3tl17convertsToAtLeastITkNSt3__114floating_pointEdTkNS1_8integralEsEEbT_T0_ Unexecuted instantiation: _ZN4o3tl17convertsToAtLeastITkNSt3__114floating_pointEdTkNS1_8integralEtEEbT_T0_ Unexecuted instantiation: _ZN4o3tl17convertsToAtLeastITkNSt3__114floating_pointEdTkNS1_8integralEiEEbT_T0_ Unexecuted instantiation: _ZN4o3tl17convertsToAtLeastITkNSt3__114floating_pointEdTkNS1_8integralEjEEbT_T0_ Unexecuted instantiation: _ZN4o3tl17convertsToAtLeastITkNSt3__114floating_pointEdTkNS1_8integralEmEEbT_T0_ |
31 | | |
32 | | // Return true iff `value` of floating-point type `F` converts to a value of integral type `I` no |
33 | | // larger than `max`: |
34 | | template <floating_point F, integral I> constexpr bool convertsToAtMost(F value, I max) |
35 | 356k | { |
36 | | // If `F(max)`, `F(max) + F(1)` are too large in magnitude for `F`'s precision, then they either |
37 | | // fall into the same bucket, in which case we should return false if `value` represents that |
38 | | // bucket, or they are on the boundary of two adjacent buckets, in which case we should return |
39 | | // true if `value`represents the lower bucket containing `F(max)`: |
40 | 356k | return value < F(max) + F(1); |
41 | 356k | } _ZN4o3tl16convertsToAtMostITkNSt3__114floating_pointEdTkNS1_8integralElEEbT_T0_ Line | Count | Source | 35 | 355k | { | 36 | | // If `F(max)`, `F(max) + F(1)` are too large in magnitude for `F`'s precision, then they either | 37 | | // fall into the same bucket, in which case we should return false if `value` represents that | 38 | | // bucket, or they are on the boundary of two adjacent buckets, in which case we should return | 39 | | // true if `value`represents the lower bucket containing `F(max)`: | 40 | 355k | return value < F(max) + F(1); | 41 | 355k | } |
Unexecuted instantiation: _ZN4o3tl16convertsToAtMostITkNSt3__114floating_pointEdTkNS1_8integralEiEEbT_T0_ _ZN4o3tl16convertsToAtMostITkNSt3__114floating_pointEdTkNS1_8integralEmEEbT_T0_ Line | Count | Source | 35 | 307 | { | 36 | | // If `F(max)`, `F(max) + F(1)` are too large in magnitude for `F`'s precision, then they either | 37 | | // fall into the same bucket, in which case we should return false if `value` represents that | 38 | | // bucket, or they are on the boundary of two adjacent buckets, in which case we should return | 39 | | // true if `value`represents the lower bucket containing `F(max)`: | 40 | 307 | return value < F(max) + F(1); | 41 | 307 | } |
Unexecuted instantiation: _ZN4o3tl16convertsToAtMostITkNSt3__114floating_pointEdTkNS1_8integralEDsEEbT_T0_ Unexecuted instantiation: _ZN4o3tl16convertsToAtMostITkNSt3__114floating_pointEdTkNS1_8integralEhEEbT_T0_ Unexecuted instantiation: _ZN4o3tl16convertsToAtMostITkNSt3__114floating_pointEdTkNS1_8integralEsEEbT_T0_ Unexecuted instantiation: _ZN4o3tl16convertsToAtMostITkNSt3__114floating_pointEdTkNS1_8integralEtEEbT_T0_ Unexecuted instantiation: _ZN4o3tl16convertsToAtMostITkNSt3__114floating_pointEdTkNS1_8integralEjEEbT_T0_ |
42 | | |
43 | | // Casts a floating-point to an integer, avoiding overflow. Used like: |
44 | | // sal_Int64 n = o3tl::saturating_cast<sal_Int64>(f); |
45 | | template <integral I, floating_point F> constexpr I saturating_cast(F f) |
46 | 43.4k | { |
47 | | if constexpr (std::is_signed_v<I>) |
48 | 43.4k | if (!convertsToAtLeast(f, std::numeric_limits<I>::min())) |
49 | 0 | return std::numeric_limits<I>::min(); |
50 | 43.4k | if (!convertsToAtMost(f, std::numeric_limits<I>::max())) |
51 | 0 | return std::numeric_limits<I>::max(); |
52 | 43.4k | return f; |
53 | 43.4k | } |
54 | | |
55 | | // Return `value` of floating-point type `F` rounded to the nearest integer away from zero (which |
56 | | // can be useful in calls to convertsToAtLeast/Most(roundAway(x), n), to reject x that are |
57 | | // smaller/larger than n because they have a fractional part): |
58 | | template <floating_point F> F roundAway(F value) |
59 | | { |
60 | | return value >= 0 ? std::ceil(value) : std::floor(value); |
61 | | } |
62 | | } |
63 | | |
64 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ |