Coverage Report

Created: 2026-02-16 07:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/AK/Checked.h
Line
Count
Source
1
/*
2
 * Copyright (C) 2011-2019 Apple Inc. All rights reserved.
3
 * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions are met:
8
 *
9
 * 1. Redistributions of source code must retain the above copyright notice, this
10
 *    list of conditions and the following disclaimer.
11
 *
12
 * 2. Redistributions in binary form must reproduce the above copyright notice,
13
 *    this list of conditions and the following disclaimer in the documentation
14
 *    and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 */
27
28
#pragma once
29
30
#include <AK/Assertions.h>
31
#include <AK/Concepts.h>
32
#include <AK/NumericLimits.h>
33
#include <AK/StdLibExtras.h>
34
35
namespace AK {
36
37
template<typename Destination, typename Source, bool destination_is_wider = (sizeof(Destination) >= sizeof(Source)), bool destination_is_signed = NumericLimits<Destination>::is_signed(), bool source_is_signed = NumericLimits<Source>::is_signed()>
38
struct TypeBoundsChecker;
39
40
template<typename Destination, typename Source>
41
struct TypeBoundsChecker<Destination, Source, false, false, false> {
42
    static constexpr bool is_within_range(Source value)
43
77
    {
44
77
        return value <= NumericLimits<Destination>::max();
45
77
    }
AK::TypeBoundsChecker<unsigned int, unsigned long, false, false, false>::is_within_range(unsigned long)
Line
Count
Source
43
77
    {
44
77
        return value <= NumericLimits<Destination>::max();
45
77
    }
Unexecuted instantiation: AK::TypeBoundsChecker<unsigned char, unsigned long, false, false, false>::is_within_range(unsigned long)
Unexecuted instantiation: AK::TypeBoundsChecker<unsigned short, unsigned long, false, false, false>::is_within_range(unsigned long)
46
};
47
48
template<typename Destination, typename Source>
49
struct TypeBoundsChecker<Destination, Source, false, true, true> {
50
    static constexpr bool is_within_range(Source value)
51
0
    {
52
0
        return value <= NumericLimits<Destination>::max()
53
0
            && NumericLimits<Destination>::min() <= value;
54
0
    }
Unexecuted instantiation: AK::TypeBoundsChecker<int, long, false, true, true>::is_within_range(long)
Unexecuted instantiation: AK::TypeBoundsChecker<signed char, long, false, true, true>::is_within_range(long)
Unexecuted instantiation: AK::TypeBoundsChecker<short, long, false, true, true>::is_within_range(long)
Unexecuted instantiation: AK::TypeBoundsChecker<int, double, false, true, true>::is_within_range(double)
55
};
56
57
template<typename Destination, typename Source>
58
struct TypeBoundsChecker<Destination, Source, false, false, true> {
59
    static constexpr bool is_within_range(Source value)
60
0
    {
61
0
        return value >= 0 && value <= NumericLimits<Destination>::max();
62
0
    }
Unexecuted instantiation: AK::TypeBoundsChecker<unsigned int, long, false, false, true>::is_within_range(long)
Unexecuted instantiation: AK::TypeBoundsChecker<unsigned char, long, false, false, true>::is_within_range(long)
Unexecuted instantiation: AK::TypeBoundsChecker<unsigned short, long, false, false, true>::is_within_range(long)
Unexecuted instantiation: AK::TypeBoundsChecker<unsigned int, double, false, false, true>::is_within_range(double)
Unexecuted instantiation: AK::TypeBoundsChecker<unsigned char, double, false, false, true>::is_within_range(double)
Unexecuted instantiation: AK::TypeBoundsChecker<unsigned short, double, false, false, true>::is_within_range(double)
63
};
64
65
template<typename Destination, typename Source>
66
struct TypeBoundsChecker<Destination, Source, false, true, false> {
67
    static constexpr bool is_within_range(Source value)
68
0
    {
69
0
        return value <= static_cast<Source>(NumericLimits<Destination>::max());
70
0
    }
Unexecuted instantiation: AK::TypeBoundsChecker<int, unsigned long, false, true, false>::is_within_range(unsigned long)
Unexecuted instantiation: AK::TypeBoundsChecker<signed char, unsigned long, false, true, false>::is_within_range(unsigned long)
Unexecuted instantiation: AK::TypeBoundsChecker<short, unsigned long, false, true, false>::is_within_range(unsigned long)
71
};
72
73
template<typename Destination, typename Source>
74
struct TypeBoundsChecker<Destination, Source, true, false, false> {
75
    static constexpr bool is_within_range(Source)
76
8.04G
    {
77
8.04G
        return true;
78
8.04G
    }
AK::TypeBoundsChecker<unsigned long, unsigned long, true, false, false>::is_within_range(unsigned long)
Line
Count
Source
76
8.03G
    {
77
8.03G
        return true;
78
8.03G
    }
AK::TypeBoundsChecker<unsigned long, unsigned int, true, false, false>::is_within_range(unsigned int)
Line
Count
Source
76
63
    {
77
63
        return true;
78
63
    }
AK::TypeBoundsChecker<unsigned int, unsigned int, true, false, false>::is_within_range(unsigned int)
Line
Count
Source
76
75
    {
77
75
        return true;
78
75
    }
AK::TypeBoundsChecker<unsigned int, unsigned char, true, false, false>::is_within_range(unsigned char)
Line
Count
Source
76
4.66M
    {
77
4.66M
        return true;
78
4.66M
    }
AK::TypeBoundsChecker<unsigned long, unsigned short, true, false, false>::is_within_range(unsigned short)
Line
Count
Source
76
4.13k
    {
77
4.13k
        return true;
78
4.13k
    }
79
};
80
81
template<typename Destination, typename Source>
82
struct TypeBoundsChecker<Destination, Source, true, true, true> {
83
    static constexpr bool is_within_range(Source)
84
23.0M
    {
85
23.0M
        return true;
86
23.0M
    }
AK::TypeBoundsChecker<int, int, true, true, true>::is_within_range(int)
Line
Count
Source
84
20.6M
    {
85
20.6M
        return true;
86
20.6M
    }
Unexecuted instantiation: AK::TypeBoundsChecker<long, long, true, true, true>::is_within_range(long)
AK::TypeBoundsChecker<long, int, true, true, true>::is_within_range(int)
Line
Count
Source
84
2.42M
    {
85
2.42M
        return true;
86
2.42M
    }
Unexecuted instantiation: AK::TypeBoundsChecker<int, float, true, true, true>::is_within_range(float)
Unexecuted instantiation: AK::TypeBoundsChecker<long, float, true, true, true>::is_within_range(float)
Unexecuted instantiation: AK::TypeBoundsChecker<long, double, true, true, true>::is_within_range(double)
87
};
88
89
template<typename Destination, typename Source>
90
struct TypeBoundsChecker<Destination, Source, true, false, true> {
91
    static constexpr bool is_within_range(Source value)
92
13
    {
93
13
        return value >= 0;
94
13
    }
AK::TypeBoundsChecker<unsigned int, int, true, false, true>::is_within_range(int)
Line
Count
Source
92
13
    {
93
13
        return value >= 0;
94
13
    }
Unexecuted instantiation: AK::TypeBoundsChecker<unsigned long, long, true, false, true>::is_within_range(long)
Unexecuted instantiation: AK::TypeBoundsChecker<unsigned long, int, true, false, true>::is_within_range(int)
Unexecuted instantiation: AK::TypeBoundsChecker<unsigned int, float, true, false, true>::is_within_range(float)
Unexecuted instantiation: AK::TypeBoundsChecker<unsigned long, float, true, false, true>::is_within_range(float)
Unexecuted instantiation: AK::TypeBoundsChecker<unsigned long, double, true, false, true>::is_within_range(double)
95
};
96
97
template<typename Destination, typename Source>
98
struct TypeBoundsChecker<Destination, Source, true, true, false> {
99
    static constexpr bool is_within_range(Source value)
100
0
    {
101
0
        if (sizeof(Destination) > sizeof(Source))
102
0
            return true;
103
0
        return value <= static_cast<Source>(NumericLimits<Destination>::max());
104
0
    }
105
};
106
107
template<typename Destination, typename Source>
108
[[nodiscard]] constexpr bool is_within_range(Source value)
109
8.06G
{
110
8.06G
    return TypeBoundsChecker<Destination, Source>::is_within_range(value);
111
8.06G
}
bool AK::is_within_range<unsigned long, unsigned long>(unsigned long)
Line
Count
Source
109
8.03G
{
110
8.03G
    return TypeBoundsChecker<Destination, Source>::is_within_range(value);
111
8.03G
}
bool AK::is_within_range<unsigned long, unsigned int>(unsigned int)
Line
Count
Source
109
63
{
110
63
    return TypeBoundsChecker<Destination, Source>::is_within_range(value);
111
63
}
bool AK::is_within_range<unsigned int, int>(int)
Line
Count
Source
109
13
{
110
13
    return TypeBoundsChecker<Destination, Source>::is_within_range(value);
111
13
}
bool AK::is_within_range<unsigned int, unsigned long>(unsigned long)
Line
Count
Source
109
77
{
110
77
    return TypeBoundsChecker<Destination, Source>::is_within_range(value);
111
77
}
bool AK::is_within_range<unsigned int, unsigned int>(unsigned int)
Line
Count
Source
109
75
{
110
75
    return TypeBoundsChecker<Destination, Source>::is_within_range(value);
111
75
}
bool AK::is_within_range<int, int>(int)
Line
Count
Source
109
20.6M
{
110
20.6M
    return TypeBoundsChecker<Destination, Source>::is_within_range(value);
111
20.6M
}
bool AK::is_within_range<unsigned int, unsigned char>(unsigned char)
Line
Count
Source
109
4.66M
{
110
4.66M
    return TypeBoundsChecker<Destination, Source>::is_within_range(value);
111
4.66M
}
Unexecuted instantiation: bool AK::is_within_range<int, unsigned long>(unsigned long)
Unexecuted instantiation: bool AK::is_within_range<int, long>(long)
Unexecuted instantiation: bool AK::is_within_range<long, unsigned long>(unsigned long)
Unexecuted instantiation: bool AK::is_within_range<long, long>(long)
Unexecuted instantiation: bool AK::is_within_range<unsigned int, long>(long)
Unexecuted instantiation: bool AK::is_within_range<unsigned long, long>(long)
Unexecuted instantiation: bool AK::is_within_range<signed char, long>(long)
Unexecuted instantiation: bool AK::is_within_range<signed char, unsigned long>(unsigned long)
Unexecuted instantiation: bool AK::is_within_range<unsigned char, long>(long)
Unexecuted instantiation: bool AK::is_within_range<unsigned char, unsigned long>(unsigned long)
Unexecuted instantiation: bool AK::is_within_range<short, long>(long)
Unexecuted instantiation: bool AK::is_within_range<short, unsigned long>(unsigned long)
Unexecuted instantiation: bool AK::is_within_range<unsigned short, long>(long)
Unexecuted instantiation: bool AK::is_within_range<unsigned short, unsigned long>(unsigned long)
Unexecuted instantiation: bool AK::is_within_range<unsigned long, int>(int)
Unexecuted instantiation: bool AK::is_within_range<unsigned int, double>(double)
Unexecuted instantiation: bool AK::is_within_range<int, double>(double)
Unexecuted instantiation: bool AK::is_within_range<unsigned char, double>(double)
Unexecuted instantiation: bool AK::is_within_range<unsigned short, double>(double)
bool AK::is_within_range<long, int>(int)
Line
Count
Source
109
2.42M
{
110
2.42M
    return TypeBoundsChecker<Destination, Source>::is_within_range(value);
111
2.42M
}
bool AK::is_within_range<unsigned long, unsigned short>(unsigned short)
Line
Count
Source
109
4.13k
{
110
4.13k
    return TypeBoundsChecker<Destination, Source>::is_within_range(value);
111
4.13k
}
Unexecuted instantiation: bool AK::is_within_range<int, float>(float)
Unexecuted instantiation: bool AK::is_within_range<unsigned int, float>(float)
Unexecuted instantiation: bool AK::is_within_range<long, float>(float)
Unexecuted instantiation: bool AK::is_within_range<unsigned long, float>(float)
Unexecuted instantiation: bool AK::is_within_range<long, double>(double)
Unexecuted instantiation: bool AK::is_within_range<unsigned long, double>(double)
112
113
template<Integral T>
114
class Checked {
115
public:
116
0
    constexpr Checked() = default;
Unexecuted instantiation: AK::Checked<unsigned int>::Checked()
Unexecuted instantiation: AK::Checked<int>::Checked()
117
118
    explicit constexpr Checked(T value)
119
76.8M
        : m_value(value)
120
76.8M
    {
121
76.8M
    }
AK::Checked<int>::Checked(int)
Line
Count
Source
119
55.6M
        : m_value(value)
120
55.6M
    {
121
55.6M
    }
AK::Checked<long>::Checked(long)
Line
Count
Source
119
21.1M
        : m_value(value)
120
21.1M
    {
121
21.1M
    }
Unexecuted instantiation: AK::Checked<unsigned int>::Checked(unsigned int)
AK::Checked<unsigned long>::Checked(unsigned long)
Line
Count
Source
119
2.31k
        : m_value(value)
120
2.31k
    {
121
2.31k
    }
122
123
    template<Integral U>
124
    constexpr Checked(U value)
125
8.06G
    {
126
8.06G
        m_overflow = !is_within_range<T>(value);
127
8.06G
        m_value = value;
128
8.06G
    }
_ZN2AK7CheckedImEC2ITkNS_8Concepts8IntegralEmEET_
Line
Count
Source
125
8.03G
    {
126
8.03G
        m_overflow = !is_within_range<T>(value);
127
8.03G
        m_value = value;
128
8.03G
    }
_ZN2AK7CheckedImEC2ITkNS_8Concepts8IntegralEjEET_
Line
Count
Source
125
63
    {
126
63
        m_overflow = !is_within_range<T>(value);
127
63
        m_value = value;
128
63
    }
_ZN2AK7CheckedIjEC2ITkNS_8Concepts8IntegralEiEET_
Line
Count
Source
125
13
    {
126
13
        m_overflow = !is_within_range<T>(value);
127
13
        m_value = value;
128
13
    }
_ZN2AK7CheckedIjEC2ITkNS_8Concepts8IntegralEmEET_
Line
Count
Source
125
77
    {
126
77
        m_overflow = !is_within_range<T>(value);
127
77
        m_value = value;
128
77
    }
_ZN2AK7CheckedIjEC2ITkNS_8Concepts8IntegralEjEET_
Line
Count
Source
125
75
    {
126
75
        m_overflow = !is_within_range<T>(value);
127
75
        m_value = value;
128
75
    }
_ZN2AK7CheckedIiEC2ITkNS_8Concepts8IntegralEiEET_
Line
Count
Source
125
20.6M
    {
126
20.6M
        m_overflow = !is_within_range<T>(value);
127
20.6M
        m_value = value;
128
20.6M
    }
_ZN2AK7CheckedIjEC2ITkNS_8Concepts8IntegralEhEET_
Line
Count
Source
125
4.66M
    {
126
4.66M
        m_overflow = !is_within_range<T>(value);
127
4.66M
        m_value = value;
128
4.66M
    }
Unexecuted instantiation: _ZN2AK7CheckedImEC2ITkNS_8Concepts8IntegralEiEET_
Unexecuted instantiation: _ZN2AK7CheckedIlEC2ITkNS_8Concepts8IntegralElEET_
_ZN2AK7CheckedIlEC2ITkNS_8Concepts8IntegralEiEET_
Line
Count
Source
125
2.42M
    {
126
2.42M
        m_overflow = !is_within_range<T>(value);
127
2.42M
        m_value = value;
128
2.42M
    }
_ZN2AK7CheckedImEC2ITkNS_8Concepts8IntegralEtEET_
Line
Count
Source
125
4.13k
    {
126
4.13k
        m_overflow = !is_within_range<T>(value);
127
4.13k
        m_value = value;
128
4.13k
    }
129
130
    constexpr Checked(Checked const&) = default;
131
132
    constexpr Checked(Checked&& other)
133
0
        : m_value(exchange(other.m_value, 0))
134
0
        , m_overflow(exchange(other.m_overflow, false))
135
0
    {
136
0
    }
137
138
    template<typename U>
139
    constexpr Checked& operator=(U value)
140
0
    {
141
0
        *this = Checked(value);
142
0
        return *this;
143
0
    }
Unexecuted instantiation: AK::Checked<unsigned long>& AK::Checked<unsigned long>::operator=<unsigned int>(unsigned int)
Unexecuted instantiation: AK::Checked<unsigned long>& AK::Checked<unsigned long>::operator=<int>(int)
Unexecuted instantiation: AK::Checked<unsigned int>& AK::Checked<unsigned int>::operator=<unsigned long>(unsigned long)
Unexecuted instantiation: AK::Checked<int>& AK::Checked<int>::operator=<int>(int)
144
145
    constexpr Checked& operator=(Checked const& other) = default;
146
147
    constexpr Checked& operator=(Checked&& other)
148
0
    {
149
0
        m_value = exchange(other.m_value, 0);
150
0
        m_overflow = exchange(other.m_overflow, false);
151
0
        return *this;
152
0
    }
Unexecuted instantiation: AK::Checked<unsigned int>::operator=(AK::Checked<unsigned int>&&)
Unexecuted instantiation: AK::Checked<unsigned long>::operator=(AK::Checked<unsigned long>&&)
Unexecuted instantiation: AK::Checked<int>::operator=(AK::Checked<int>&&)
153
154
    [[nodiscard]] constexpr bool has_overflow() const
155
5.00G
    {
156
5.00G
        return m_overflow;
157
5.00G
    }
AK::Checked<unsigned long>::has_overflow() const
Line
Count
Source
155
4.98G
    {
156
4.98G
        return m_overflow;
157
4.98G
    }
AK::Checked<long>::has_overflow() const
Line
Count
Source
155
2.57k
    {
156
2.57k
        return m_overflow;
157
2.57k
    }
AK::Checked<int>::has_overflow() const
Line
Count
Source
155
13.5M
    {
156
13.5M
        return m_overflow;
157
13.5M
    }
AK::Checked<unsigned int>::has_overflow() const
Line
Count
Source
155
4.66M
    {
156
4.66M
        return m_overflow;
157
4.66M
    }
158
159
    ALWAYS_INLINE constexpr bool operator!() const
160
0
    {
161
0
        VERIFY(!m_overflow);
162
0
        return !m_value;
163
0
    }
164
165
    ALWAYS_INLINE constexpr T value() const
166
8.14G
    {
167
8.14G
        VERIFY(!m_overflow);
168
8.14G
        return m_value;
169
8.14G
    }
AK::Checked<unsigned long>::value() const
Line
Count
Source
166
8.03G
    {
167
8.03G
        VERIFY(!m_overflow);
168
8.03G
        return m_value;
169
8.03G
    }
AK::Checked<long>::value() const
Line
Count
Source
166
23.6M
    {
167
23.6M
        VERIFY(!m_overflow);
168
23.6M
        return m_value;
169
23.6M
    }
AK::Checked<int>::value() const
Line
Count
Source
166
76.3M
    {
167
76.3M
        VERIFY(!m_overflow);
168
76.3M
        return m_value;
169
76.3M
    }
AK::Checked<unsigned int>::value() const
Line
Count
Source
166
4.32M
    {
167
4.32M
        VERIFY(!m_overflow);
168
4.32M
        return m_value;
169
4.32M
    }
170
171
    ALWAYS_INLINE constexpr T value_unchecked() const
172
0
    {
173
0
        return m_value;
174
0
    }
Unexecuted instantiation: AK::Checked<long>::value_unchecked() const
Unexecuted instantiation: AK::Checked<unsigned long>::value_unchecked() const
175
176
    constexpr void add(T other)
177
2.02G
    {
178
2.02G
        m_overflow |= __builtin_add_overflow(m_value, other, &m_value);
179
2.02G
    }
AK::Checked<long>::add(long)
Line
Count
Source
177
21.1M
    {
178
21.1M
        m_overflow |= __builtin_add_overflow(m_value, other, &m_value);
179
21.1M
    }
AK::Checked<unsigned long>::add(unsigned long)
Line
Count
Source
177
1.93G
    {
178
1.93G
        m_overflow |= __builtin_add_overflow(m_value, other, &m_value);
179
1.93G
    }
AK::Checked<unsigned int>::add(unsigned int)
Line
Count
Source
177
410
    {
178
410
        m_overflow |= __builtin_add_overflow(m_value, other, &m_value);
179
410
    }
AK::Checked<int>::add(int)
Line
Count
Source
177
62.4M
    {
178
62.4M
        m_overflow |= __builtin_add_overflow(m_value, other, &m_value);
179
62.4M
    }
180
181
    constexpr void sub(T other)
182
0
    {
183
0
        m_overflow |= __builtin_sub_overflow(m_value, other, &m_value);
184
0
    }
Unexecuted instantiation: AK::Checked<long>::sub(long)
Unexecuted instantiation: AK::Checked<unsigned int>::sub(unsigned int)
Unexecuted instantiation: AK::Checked<unsigned long>::sub(unsigned long)
Unexecuted instantiation: AK::Checked<int>::sub(int)
185
186
    constexpr void mul(T other)
187
3.14G
    {
188
3.14G
        m_overflow |= __builtin_mul_overflow(m_value, other, &m_value);
189
3.14G
    }
AK::Checked<unsigned long>::mul(unsigned long)
Line
Count
Source
187
3.04G
    {
188
3.04G
        m_overflow |= __builtin_mul_overflow(m_value, other, &m_value);
189
3.04G
    }
AK::Checked<long>::mul(long)
Line
Count
Source
187
21.1M
    {
188
21.1M
        m_overflow |= __builtin_mul_overflow(m_value, other, &m_value);
189
21.1M
    }
AK::Checked<int>::mul(int)
Line
Count
Source
187
69.1M
    {
188
69.1M
        m_overflow |= __builtin_mul_overflow(m_value, other, &m_value);
189
69.1M
    }
AK::Checked<unsigned int>::mul(unsigned int)
Line
Count
Source
187
4.66M
    {
188
4.66M
        m_overflow |= __builtin_mul_overflow(m_value, other, &m_value);
189
4.66M
    }
190
191
    constexpr void div(T other)
192
6.75M
    {
193
6.75M
        if constexpr (IsSigned<T>) {
194
            // Ensure that the resulting value won't be out of range, this can only happen when dividing by -1.
195
6.75M
            if (other == -1 && m_value == NumericLimits<T>::min()) {
196
0
                m_overflow = true;
197
0
                return;
198
0
            }
199
6.75M
        }
200
6.75M
        if (other == 0) {
201
0
            m_overflow = true;
202
0
            return;
203
0
        }
204
6.75M
        m_value /= other;
205
6.75M
    }
AK::Checked<int>::div(int)
Line
Count
Source
192
6.75M
    {
193
6.75M
        if constexpr (IsSigned<T>) {
194
            // Ensure that the resulting value won't be out of range, this can only happen when dividing by -1.
195
6.75M
            if (other == -1 && m_value == NumericLimits<T>::min()) {
196
0
                m_overflow = true;
197
0
                return;
198
0
            }
199
6.75M
        }
200
6.75M
        if (other == 0) {
201
0
            m_overflow = true;
202
0
            return;
203
0
        }
204
6.75M
        m_value /= other;
205
6.75M
    }
Unexecuted instantiation: AK::Checked<unsigned int>::div(unsigned int)
Unexecuted instantiation: AK::Checked<long>::div(long)
Unexecuted instantiation: AK::Checked<unsigned long>::div(unsigned long)
206
207
    constexpr void mod(T other)
208
0
    {
209
0
        auto initial = m_value;
210
0
        div(other);
211
0
        m_value *= other;
212
0
        m_value = initial - m_value;
213
0
    }
Unexecuted instantiation: AK::Checked<unsigned int>::mod(unsigned int)
Unexecuted instantiation: AK::Checked<long>::mod(long)
Unexecuted instantiation: AK::Checked<unsigned long>::mod(unsigned long)
214
215
    constexpr void saturating_sub(T other)
216
0
    {
217
0
        sub(other);
218
        // Depending on whether other was positive or negative, we have to saturate to min or max.
219
0
        if (m_overflow && other <= 0)
220
0
            m_value = NumericLimits<T>::max();
221
0
        else if (m_overflow)
222
0
            m_value = NumericLimits<T>::min();
223
0
        m_overflow = false;
224
0
    }
Unexecuted instantiation: AK::Checked<long>::saturating_sub(long)
Unexecuted instantiation: AK::Checked<int>::saturating_sub(int)
225
226
    constexpr void saturating_add(T other)
227
76.8M
    {
228
76.8M
        add(other);
229
        // Depending on whether other was positive or negative, we have to saturate to max or min.
230
76.8M
        if (m_overflow && other >= 0)
231
2.60M
            m_value = NumericLimits<T>::max();
232
74.2M
        else if (m_overflow)
233
6.61M
            m_value = NumericLimits<T>::min();
234
76.8M
        m_overflow = false;
235
76.8M
    }
AK::Checked<long>::saturating_add(long)
Line
Count
Source
227
21.1M
    {
228
21.1M
        add(other);
229
        // Depending on whether other was positive or negative, we have to saturate to max or min.
230
21.1M
        if (m_overflow && other >= 0)
231
82.2k
            m_value = NumericLimits<T>::max();
232
21.1M
        else if (m_overflow)
233
89.3k
            m_value = NumericLimits<T>::min();
234
21.1M
        m_overflow = false;
235
21.1M
    }
AK::Checked<int>::saturating_add(int)
Line
Count
Source
227
55.6M
    {
228
55.6M
        add(other);
229
        // Depending on whether other was positive or negative, we have to saturate to max or min.
230
55.6M
        if (m_overflow && other >= 0)
231
2.52M
            m_value = NumericLimits<T>::max();
232
53.1M
        else if (m_overflow)
233
6.52M
            m_value = NumericLimits<T>::min();
234
55.6M
        m_overflow = false;
235
55.6M
    }
Unexecuted instantiation: AK::Checked<unsigned long>::saturating_add(unsigned long)
236
237
    constexpr void saturating_mul(T other)
238
76.8M
    {
239
        // Figure out if the result is positive, negative or zero beforehand.
240
76.8M
        auto either_is_zero = this->m_value == 0 || other == 0;
241
76.8M
        auto result_is_positive = (this->m_value > 0) == (other > 0);
242
243
76.8M
        mul(other);
244
76.8M
        if (m_overflow) {
245
8.40M
            if (either_is_zero)
246
0
                m_value = 0;
247
8.40M
            else if (result_is_positive)
248
2.34M
                m_value = NumericLimits<T>::max();
249
6.05M
            else
250
6.05M
                m_value = NumericLimits<T>::min();
251
8.40M
        }
252
76.8M
        m_overflow = false;
253
76.8M
    }
AK::Checked<long>::saturating_mul(long)
Line
Count
Source
238
21.1M
    {
239
        // Figure out if the result is positive, negative or zero beforehand.
240
21.1M
        auto either_is_zero = this->m_value == 0 || other == 0;
241
21.1M
        auto result_is_positive = (this->m_value > 0) == (other > 0);
242
243
21.1M
        mul(other);
244
21.1M
        if (m_overflow) {
245
166k
            if (either_is_zero)
246
0
                m_value = 0;
247
166k
            else if (result_is_positive)
248
165k
                m_value = NumericLimits<T>::max();
249
1.49k
            else
250
1.49k
                m_value = NumericLimits<T>::min();
251
166k
        }
252
21.1M
        m_overflow = false;
253
21.1M
    }
AK::Checked<int>::saturating_mul(int)
Line
Count
Source
238
55.6M
    {
239
        // Figure out if the result is positive, negative or zero beforehand.
240
55.6M
        auto either_is_zero = this->m_value == 0 || other == 0;
241
55.6M
        auto result_is_positive = (this->m_value > 0) == (other > 0);
242
243
55.6M
        mul(other);
244
55.6M
        if (m_overflow) {
245
8.23M
            if (either_is_zero)
246
0
                m_value = 0;
247
8.23M
            else if (result_is_positive)
248
2.18M
                m_value = NumericLimits<T>::max();
249
6.05M
            else
250
6.05M
                m_value = NumericLimits<T>::min();
251
8.23M
        }
252
55.6M
        m_overflow = false;
253
55.6M
    }
254
255
    constexpr Checked& operator+=(Checked const& other)
256
4.82k
    {
257
4.82k
        m_overflow |= other.m_overflow;
258
4.82k
        add(other.value());
259
4.82k
        return *this;
260
4.82k
    }
AK::Checked<unsigned int>::operator+=(AK::Checked<unsigned int> const&)
Line
Count
Source
256
75
    {
257
75
        m_overflow |= other.m_overflow;
258
75
        add(other.value());
259
75
        return *this;
260
75
    }
AK::Checked<unsigned long>::operator+=(AK::Checked<unsigned long> const&)
Line
Count
Source
256
4.75k
    {
257
4.75k
        m_overflow |= other.m_overflow;
258
4.75k
        add(other.value());
259
4.75k
        return *this;
260
4.75k
    }
261
262
    constexpr Checked& operator+=(T other)
263
1.94G
    {
264
1.94G
        add(other);
265
1.94G
        return *this;
266
1.94G
    }
AK::Checked<long>::operator+=(long)
Line
Count
Source
263
2.57k
    {
264
2.57k
        add(other);
265
2.57k
        return *this;
266
2.57k
    }
AK::Checked<unsigned long>::operator+=(unsigned long)
Line
Count
Source
263
1.93G
    {
264
1.93G
        add(other);
265
1.93G
        return *this;
266
1.93G
    }
AK::Checked<unsigned int>::operator+=(unsigned int)
Line
Count
Source
263
335
    {
264
335
        add(other);
265
335
        return *this;
266
335
    }
AK::Checked<int>::operator+=(int)
Line
Count
Source
263
6.75M
    {
264
6.75M
        add(other);
265
6.75M
        return *this;
266
6.75M
    }
267
268
    constexpr Checked& operator-=(Checked const& other)
269
    {
270
        m_overflow |= other.m_overflow;
271
        sub(other.value());
272
        return *this;
273
    }
274
275
    constexpr Checked& operator-=(T other)
276
0
    {
277
0
        sub(other);
278
0
        return *this;
279
0
    }
Unexecuted instantiation: AK::Checked<long>::operator-=(long)
Unexecuted instantiation: AK::Checked<unsigned int>::operator-=(unsigned int)
Unexecuted instantiation: AK::Checked<unsigned long>::operator-=(unsigned long)
280
281
    constexpr Checked& operator*=(Checked const& other)
282
    {
283
        m_overflow |= other.m_overflow;
284
        mul(other.value());
285
        return *this;
286
    }
287
288
    constexpr Checked& operator*=(T other)
289
18.4M
    {
290
18.4M
        mul(other);
291
18.4M
        return *this;
292
18.4M
    }
Unexecuted instantiation: AK::Checked<long>::operator*=(long)
AK::Checked<unsigned long>::operator*=(unsigned long)
Line
Count
Source
289
231k
    {
290
231k
        mul(other);
291
231k
        return *this;
292
231k
    }
AK::Checked<unsigned int>::operator*=(unsigned int)
Line
Count
Source
289
4.66M
    {
290
4.66M
        mul(other);
291
4.66M
        return *this;
292
4.66M
    }
AK::Checked<int>::operator*=(int)
Line
Count
Source
289
13.5M
    {
290
13.5M
        mul(other);
291
13.5M
        return *this;
292
13.5M
    }
293
294
    constexpr Checked& operator/=(Checked const& other)
295
    {
296
        m_overflow |= other.m_overflow;
297
        div(other.value());
298
        return *this;
299
    }
300
301
    constexpr Checked& operator/=(T other)
302
6.75M
    {
303
6.75M
        div(other);
304
6.75M
        return *this;
305
6.75M
    }
AK::Checked<int>::operator/=(int)
Line
Count
Source
302
6.75M
    {
303
6.75M
        div(other);
304
6.75M
        return *this;
305
6.75M
    }
Unexecuted instantiation: AK::Checked<unsigned int>::operator/=(unsigned int)
Unexecuted instantiation: AK::Checked<long>::operator/=(long)
Unexecuted instantiation: AK::Checked<unsigned long>::operator/=(unsigned long)
306
307
    constexpr Checked& operator%=(Checked const& other)
308
    {
309
        m_overflow |= other.m_overflow;
310
        mod(other.value());
311
        return *this;
312
    }
313
314
    constexpr Checked& operator%=(T other)
315
    {
316
        mod(other);
317
        return *this;
318
    }
319
320
    constexpr Checked& operator++()
321
0
    {
322
0
        add(1);
323
0
        return *this;
324
0
    }
325
326
    constexpr Checked operator++(int)
327
0
    {
328
0
        Checked old { *this };
329
0
        add(1);
330
0
        return old;
331
0
    }
Unexecuted instantiation: AK::Checked<long>::operator++(int)
Unexecuted instantiation: AK::Checked<unsigned int>::operator++(int)
Unexecuted instantiation: AK::Checked<unsigned long>::operator++(int)
332
333
    constexpr Checked& operator--()
334
    {
335
        sub(1);
336
        return *this;
337
    }
338
339
    constexpr Checked operator--(int)
340
    {
341
        Checked old { *this };
342
        sub(1);
343
        return old;
344
    }
345
346
    template<typename U, typename V>
347
    [[nodiscard]] static constexpr bool addition_would_overflow(U u, V v)
348
7.77G
    {
349
#if __has_builtin(__builtin_add_overflow_p)
350
        return __builtin_add_overflow_p(u, v, (T)0);
351
#elif __has_builtin(__builtin_add_overflow)
352
        T result;
353
7.77G
        return __builtin_add_overflow(u, v, &result);
354
#else
355
        Checked checked;
356
        checked = u;
357
        checked += v;
358
        return checked.has_overflow();
359
#endif
360
7.77G
    }
bool AK::Checked<unsigned long>::addition_would_overflow<unsigned long, unsigned long>(unsigned long, unsigned long)
Line
Count
Source
348
3.20G
    {
349
#if __has_builtin(__builtin_add_overflow_p)
350
        return __builtin_add_overflow_p(u, v, (T)0);
351
#elif __has_builtin(__builtin_add_overflow)
352
        T result;
353
3.20G
        return __builtin_add_overflow(u, v, &result);
354
#else
355
        Checked checked;
356
        checked = u;
357
        checked += v;
358
        return checked.has_overflow();
359
#endif
360
3.20G
    }
bool AK::Checked<unsigned int>::addition_would_overflow<unsigned int, int>(unsigned int, int)
Line
Count
Source
348
4.55G
    {
349
#if __has_builtin(__builtin_add_overflow_p)
350
        return __builtin_add_overflow_p(u, v, (T)0);
351
#elif __has_builtin(__builtin_add_overflow)
352
        T result;
353
4.55G
        return __builtin_add_overflow(u, v, &result);
354
#else
355
        Checked checked;
356
        checked = u;
357
        checked += v;
358
        return checked.has_overflow();
359
#endif
360
4.55G
    }
bool AK::Checked<unsigned int>::addition_would_overflow<unsigned int, unsigned int>(unsigned int, unsigned int)
Line
Count
Source
348
158k
    {
349
#if __has_builtin(__builtin_add_overflow_p)
350
        return __builtin_add_overflow_p(u, v, (T)0);
351
#elif __has_builtin(__builtin_add_overflow)
352
        T result;
353
158k
        return __builtin_add_overflow(u, v, &result);
354
#else
355
        Checked checked;
356
        checked = u;
357
        checked += v;
358
        return checked.has_overflow();
359
#endif
360
158k
    }
Unexecuted instantiation: bool AK::Checked<long>::addition_would_overflow<long, long>(long, long)
Unexecuted instantiation: bool AK::Checked<int>::addition_would_overflow<int, int>(int, int)
bool AK::Checked<short>::addition_would_overflow<int, unsigned short>(int, unsigned short)
Line
Count
Source
348
4.97M
    {
349
#if __has_builtin(__builtin_add_overflow_p)
350
        return __builtin_add_overflow_p(u, v, (T)0);
351
#elif __has_builtin(__builtin_add_overflow)
352
        T result;
353
4.97M
        return __builtin_add_overflow(u, v, &result);
354
#else
355
        Checked checked;
356
        checked = u;
357
        checked += v;
358
        return checked.has_overflow();
359
#endif
360
4.97M
    }
bool AK::Checked<short>::addition_would_overflow<short, int>(short, int)
Line
Count
Source
348
7.37M
    {
349
#if __has_builtin(__builtin_add_overflow_p)
350
        return __builtin_add_overflow_p(u, v, (T)0);
351
#elif __has_builtin(__builtin_add_overflow)
352
        T result;
353
7.37M
        return __builtin_add_overflow(u, v, &result);
354
#else
355
        Checked checked;
356
        checked = u;
357
        checked += v;
358
        return checked.has_overflow();
359
#endif
360
7.37M
    }
361
362
    template<typename U, typename V>
363
    [[nodiscard]] static constexpr bool subtraction_would_overflow(U u, V v)
364
0
    {
365
#if __has_builtin(__builtin_sub_overflow_p)
366
        return __builtin_sub_overflow_p(u, v, (T)0);
367
#elif __has_builtin(__builtin_sub_overflow)
368
        T result;
369
0
        return __builtin_sub_overflow(u, v, &result);
370
#else
371
        Checked checked;
372
        checked = u;
373
        checked -= v;
374
        return checked.has_overflow();
375
#endif
376
0
    }
377
378
    template<typename U, typename V>
379
    static constexpr T saturating_add(U a, V b)
380
0
    {
381
0
        Checked checked { a };
382
0
        checked.saturating_add(b);
383
0
        return checked.value();
384
0
    }
Unexecuted instantiation: long AK::Checked<long>::saturating_add<long, int>(long, int)
Unexecuted instantiation: int AK::Checked<int>::saturating_add<int, int>(int, int)
385
386
    template<typename U, typename V>
387
    static constexpr T saturating_sub(U a, V b)
388
0
    {
389
0
        Checked checked { a };
390
0
        checked.saturating_sub(b);
391
0
        return checked.value();
392
0
    }
393
394
    template<typename U, typename V>
395
    static constexpr T saturating_mul(U a, V b)
396
76.8M
    {
397
76.8M
        Checked checked { a };
398
76.8M
        checked.saturating_mul(b);
399
76.8M
        return checked.value();
400
76.8M
    }
long AK::Checked<long>::saturating_mul<long, long>(long, long)
Line
Count
Source
396
21.1M
    {
397
21.1M
        Checked checked { a };
398
21.1M
        checked.saturating_mul(b);
399
21.1M
        return checked.value();
400
21.1M
    }
int AK::Checked<int>::saturating_mul<int, int>(int, int)
Line
Count
Source
396
55.6M
    {
397
55.6M
        Checked checked { a };
398
55.6M
        checked.saturating_mul(b);
399
55.6M
        return checked.value();
400
55.6M
    }
401
402
    template<typename U, typename V>
403
    [[nodiscard]] static constexpr bool multiplication_would_overflow(U u, V v)
404
449k
    {
405
#if __has_builtin(__builtin_mul_overflow_p)
406
        return __builtin_mul_overflow_p(u, v, (T)0);
407
#elif __has_builtin(__builtin_mul_overflow)
408
        T result;
409
449k
        return __builtin_mul_overflow(u, v, &result);
410
#else
411
        Checked checked;
412
        checked = u;
413
        checked *= v;
414
        return checked.has_overflow();
415
#endif
416
449k
    }
bool AK::Checked<unsigned long>::multiplication_would_overflow<unsigned long, int>(unsigned long, int)
Line
Count
Source
404
449k
    {
405
#if __has_builtin(__builtin_mul_overflow_p)
406
        return __builtin_mul_overflow_p(u, v, (T)0);
407
#elif __has_builtin(__builtin_mul_overflow)
408
        T result;
409
449k
        return __builtin_mul_overflow(u, v, &result);
410
#else
411
        Checked checked;
412
        checked = u;
413
        checked *= v;
414
        return checked.has_overflow();
415
#endif
416
449k
    }
Unexecuted instantiation: bool AK::Checked<unsigned int>::multiplication_would_overflow<unsigned long, unsigned long>(unsigned long, unsigned long)
Unexecuted instantiation: bool AK::Checked<int>::multiplication_would_overflow<int, int>(int, int)
Unexecuted instantiation: bool AK::Checked<unsigned int>::multiplication_would_overflow<unsigned int, unsigned long>(unsigned int, unsigned long)
Unexecuted instantiation: bool AK::Checked<unsigned long>::multiplication_would_overflow<unsigned int, unsigned long>(unsigned int, unsigned long)
417
418
    template<typename U, typename V, typename X>
419
    [[nodiscard]] static constexpr bool multiplication_would_overflow(U u, V v, X x)
420
    {
421
        Checked checked;
422
        checked = u;
423
        checked *= v;
424
        checked *= x;
425
        return checked.has_overflow();
426
    }
427
428
private:
429
    T m_value {};
430
    bool m_overflow { false };
431
};
432
433
template<typename T>
434
constexpr Checked<T> operator+(Checked<T> const& a, Checked<T> const& b)
435
1.54k
{
436
1.54k
    Checked<T> c { a };
437
1.54k
    c.add(b.value());
438
1.54k
    return c;
439
1.54k
}
AK::Checked<int> AK::operator+<int>(AK::Checked<int> const&, AK::Checked<int> const&)
Line
Count
Source
435
1.54k
{
436
1.54k
    Checked<T> c { a };
437
1.54k
    c.add(b.value());
438
1.54k
    return c;
439
1.54k
}
Unexecuted instantiation: AK::Checked<unsigned int> AK::operator+<unsigned int>(AK::Checked<unsigned int> const&, AK::Checked<unsigned int> const&)
Unexecuted instantiation: AK::Checked<unsigned long> AK::operator+<unsigned long>(AK::Checked<unsigned long> const&, AK::Checked<unsigned long> const&)
440
441
template<typename T>
442
constexpr Checked<T> operator-(Checked<T> const& a, Checked<T> const& b)
443
0
{
444
0
    Checked<T> c { a };
445
0
    c.sub(b.value());
446
0
    return c;
447
0
}
Unexecuted instantiation: AK::Checked<unsigned int> AK::operator-<unsigned int>(AK::Checked<unsigned int> const&, AK::Checked<unsigned int> const&)
Unexecuted instantiation: AK::Checked<unsigned long> AK::operator-<unsigned long>(AK::Checked<unsigned long> const&, AK::Checked<unsigned long> const&)
448
449
template<typename T>
450
constexpr Checked<T> operator*(Checked<T> const& a, Checked<T> const& b)
451
3.04G
{
452
3.04G
    Checked<T> c { a };
453
3.04G
    c.mul(b.value());
454
3.04G
    return c;
455
3.04G
}
AK::Checked<unsigned long> AK::operator*<unsigned long>(AK::Checked<unsigned long> const&, AK::Checked<unsigned long> const&)
Line
Count
Source
451
3.04G
{
452
3.04G
    Checked<T> c { a };
453
3.04G
    c.mul(b.value());
454
3.04G
    return c;
455
3.04G
}
Unexecuted instantiation: AK::Checked<unsigned int> AK::operator*<unsigned int>(AK::Checked<unsigned int> const&, AK::Checked<unsigned int> const&)
456
457
template<typename T>
458
constexpr Checked<T> operator/(Checked<T> const& a, Checked<T> const& b)
459
{
460
    Checked<T> c { a };
461
    c.div(b.value());
462
    return c;
463
}
464
465
template<typename T>
466
constexpr Checked<T> operator%(Checked<T> const& a, Checked<T> const& b)
467
0
{
468
0
    Checked<T> c { a };
469
0
    c.mod(b.value());
470
0
    return c;
471
0
}
472
473
template<typename T>
474
constexpr bool operator<(Checked<T> const& a, T b)
475
1.36k
{
476
1.36k
    return a.value() < b;
477
1.36k
}
478
479
template<typename T>
480
constexpr bool operator>(Checked<T> const& a, T b)
481
5.27k
{
482
5.27k
    return a.value() > b;
483
5.27k
}
bool AK::operator><int>(AK::Checked<int> const&, int)
Line
Count
Source
481
1.13k
{
482
1.13k
    return a.value() > b;
483
1.13k
}
bool AK::operator><unsigned long>(AK::Checked<unsigned long> const&, unsigned long)
Line
Count
Source
481
4.13k
{
482
4.13k
    return a.value() > b;
483
4.13k
}
484
485
template<typename T>
486
constexpr bool operator>=(Checked<T> const& a, T b)
487
0
{
488
0
    return a.value() >= b;
489
0
}
490
491
template<typename T>
492
constexpr bool operator<=(Checked<T> const& a, T b)
493
1.93G
{
494
1.93G
    return a.value() <= b;
495
1.93G
}
bool AK::operator<=<int>(AK::Checked<int> const&, int)
Line
Count
Source
493
1.23k
{
494
1.23k
    return a.value() <= b;
495
1.23k
}
bool AK::operator<=<unsigned long>(AK::Checked<unsigned long> const&, unsigned long)
Line
Count
Source
493
1.93G
{
494
1.93G
    return a.value() <= b;
495
1.93G
}
Unexecuted instantiation: bool AK::operator<=<unsigned int>(AK::Checked<unsigned int> const&, unsigned int)
496
497
template<typename T>
498
constexpr bool operator==(Checked<T> const& a, T b)
499
{
500
    return a.value() == b;
501
}
502
503
template<typename T>
504
constexpr bool operator!=(Checked<T> const& a, T b)
505
{
506
    return a.value() != b;
507
}
508
509
template<typename T>
510
constexpr bool operator<(T a, Checked<T> const& b)
511
620
{
512
620
    return a < b.value();
513
620
}
bool AK::operator< <unsigned long>(unsigned long, AK::Checked<unsigned long> const&)
Line
Count
Source
511
620
{
512
620
    return a < b.value();
513
620
}
Unexecuted instantiation: bool AK::operator< <int>(int, AK::Checked<int> const&)
Unexecuted instantiation: bool AK::operator< <unsigned int>(unsigned int, AK::Checked<unsigned int> const&)
514
515
template<typename T>
516
constexpr bool operator>(T a, Checked<T> const& b)
517
{
518
    return a > b.value();
519
}
520
521
template<typename T>
522
constexpr bool operator>=(T a, Checked<T> const& b)
523
{
524
    return a >= b.value();
525
}
526
527
template<typename T>
528
constexpr bool operator<=(T a, Checked<T> const& b)
529
{
530
    return a <= b.value();
531
}
532
533
template<typename T>
534
constexpr bool operator==(T a, Checked<T> const& b)
535
{
536
    return a == b.value();
537
}
538
539
template<typename T>
540
constexpr bool operator!=(T a, Checked<T> const& b)
541
{
542
    return a != b.value();
543
}
544
545
template<typename T>
546
constexpr Checked<T> make_checked(T value)
547
0
{
548
0
    return Checked<T>(value);
549
0
}
550
551
}
552
553
#if USING_AK_GLOBALLY
554
using AK::Checked;
555
using AK::make_checked;
556
#endif