Coverage Report

Created: 2025-12-08 09:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */