Coverage Report

Created: 2026-01-10 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qpdf/include/qpdf/QIntC.hh
Line
Count
Source
1
// Copyright (c) 2005-2021 Jay Berkenbilt
2
// Copyright (c) 2022-2026 Jay Berkenbilt and Manfred Holger
3
//
4
// This file is part of qpdf.
5
//
6
// Licensed under the Apache License, Version 2.0 (the "License");
7
// you may not use this file except in compliance with the License.
8
// You may obtain a copy of the License at
9
//
10
//   http://www.apache.org/licenses/LICENSE-2.0
11
//
12
// Unless required by applicable law or agreed to in writing, software
13
// distributed under the License is distributed on an "AS IS" BASIS,
14
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
// See the License for the specific language governing permissions and
16
// limitations under the License.
17
//
18
// Versions of qpdf prior to version 7 were released under the terms
19
// of version 2.0 of the Artistic License. At your option, you may
20
// continue to consider qpdf to be licensed under those terms. Please
21
// see the manual for additional information.
22
23
#ifndef QINTC_HH
24
#define QINTC_HH
25
26
#include <qpdf/DLL.h>
27
#include <qpdf/Types.h>
28
#include <iostream>
29
#include <limits>
30
#include <locale>
31
#include <sstream>
32
#include <stdexcept>
33
#include <type_traits>
34
35
// This namespace provides safe integer conversion that detects
36
// overflows. It uses short, cryptic names for brevity.
37
38
namespace QIntC // QIntC = qpdf Integer Conversion
39
{
40
    // to_u is here for backward-compatibility from before we required
41
    // C++-11.
42
    template <typename T>
43
    class to_u
44
    {
45
      public:
46
        typedef typename std::make_unsigned<T>::type type;
47
    };
48
49
    // Basic IntConverter class, which converts an integer from the
50
    // From class to one of the To class if it can be done safely and
51
    // throws a range_error otherwise. This class is specialized for
52
    // each permutation of signed/unsigned for the From and To
53
    // classes.
54
    template <
55
        typename From,
56
        typename To,
57
        bool From_signed = std::numeric_limits<From>::is_signed,
58
        bool To_signed = std::numeric_limits<To>::is_signed>
59
    class IntConverter
60
    {
61
    };
62
63
    template <typename From, typename To>
64
    class IntConverter<From, To, false, false>
65
    {
66
      public:
67
        inline static To
68
        convert(From const& i)
69
18.7M
        {
70
            // From and To are both unsigned.
71
18.7M
            if (i > std::numeric_limits<To>::max()) {
72
0
                error(i);
73
0
            }
74
18.7M
            return static_cast<To>(i);
75
18.7M
        }
QIntC::IntConverter<unsigned int, unsigned long, false, false>::convert(unsigned int const&)
Line
Count
Source
69
66.9k
        {
70
            // From and To are both unsigned.
71
66.9k
            if (i > std::numeric_limits<To>::max()) {
72
0
                error(i);
73
0
            }
74
66.9k
            return static_cast<To>(i);
75
66.9k
        }
QIntC::IntConverter<unsigned long, unsigned int, false, false>::convert(unsigned long const&)
Line
Count
Source
69
9.77M
        {
70
            // From and To are both unsigned.
71
9.77M
            if (i > std::numeric_limits<To>::max()) {
72
0
                error(i);
73
0
            }
74
9.77M
            return static_cast<To>(i);
75
9.77M
        }
QIntC::IntConverter<unsigned long, unsigned long, false, false>::convert(unsigned long const&)
Line
Count
Source
69
8.74M
        {
70
            // From and To are both unsigned.
71
8.74M
            if (i > std::numeric_limits<To>::max()) {
72
0
                error(i);
73
0
            }
74
8.74M
            return static_cast<To>(i);
75
8.74M
        }
QIntC::IntConverter<unsigned long long, unsigned long, false, false>::convert(unsigned long long const&)
Line
Count
Source
69
27.7k
        {
70
            // From and To are both unsigned.
71
27.7k
            if (i > std::numeric_limits<To>::max()) {
72
0
                error(i);
73
0
            }
74
27.7k
            return static_cast<To>(i);
75
27.7k
        }
Unexecuted instantiation: QIntC::IntConverter<unsigned long long, unsigned int, false, false>::convert(unsigned long long const&)
Unexecuted instantiation: QIntC::IntConverter<unsigned char, unsigned long, false, false>::convert(unsigned char const&)
QIntC::IntConverter<unsigned long, unsigned char, false, false>::convert(unsigned long const&)
Line
Count
Source
69
87.1k
        {
70
            // From and To are both unsigned.
71
87.1k
            if (i > std::numeric_limits<To>::max()) {
72
0
                error(i);
73
0
            }
74
87.1k
            return static_cast<To>(i);
75
87.1k
        }
76
77
        static void
78
        error(From i)
79
0
        {
80
0
            std::ostringstream msg;
81
0
            msg.imbue(std::locale::classic());
82
0
            msg << "integer out of range converting " << i << " from a " << sizeof(From)
83
0
                << "-byte unsigned type to a " << sizeof(To) << "-byte unsigned type";
84
0
            throw std::range_error(msg.str());
85
0
        }
Unexecuted instantiation: QIntC::IntConverter<unsigned int, unsigned long, false, false>::error(unsigned int)
Unexecuted instantiation: QIntC::IntConverter<unsigned long, unsigned int, false, false>::error(unsigned long)
Unexecuted instantiation: QIntC::IntConverter<unsigned long, unsigned long, false, false>::error(unsigned long)
Unexecuted instantiation: QIntC::IntConverter<unsigned long long, unsigned long, false, false>::error(unsigned long long)
Unexecuted instantiation: QIntC::IntConverter<unsigned long long, unsigned int, false, false>::error(unsigned long long)
Unexecuted instantiation: QIntC::IntConverter<unsigned char, unsigned long, false, false>::error(unsigned char)
Unexecuted instantiation: QIntC::IntConverter<unsigned long, unsigned char, false, false>::error(unsigned long)
86
    };
87
88
    template <typename From, typename To>
89
    class IntConverter<From, To, true, true>
90
    {
91
      public:
92
        inline static To
93
        convert(From const& i)
94
4.97M
        {
95
            // From and To are both signed.
96
4.97M
            if ((i < std::numeric_limits<To>::min()) || (i > std::numeric_limits<To>::max())) {
97
1.01k
                error(i);
98
1.01k
            }
99
4.97M
            return static_cast<To>(i);
100
4.97M
        }
QIntC::IntConverter<long long, int, true, true>::convert(long long const&)
Line
Count
Source
94
4.96M
        {
95
            // From and To are both signed.
96
4.96M
            if ((i < std::numeric_limits<To>::min()) || (i > std::numeric_limits<To>::max())) {
97
1.01k
                error(i);
98
1.01k
            }
99
4.96M
            return static_cast<To>(i);
100
4.96M
        }
Unexecuted instantiation: QIntC::IntConverter<double, int, true, true>::convert(double const&)
QIntC::IntConverter<long, int, true, true>::convert(long const&)
Line
Count
Source
94
6.97k
        {
95
            // From and To are both signed.
96
6.97k
            if ((i < std::numeric_limits<To>::min()) || (i > std::numeric_limits<To>::max())) {
97
0
                error(i);
98
0
            }
99
6.97k
            return static_cast<To>(i);
100
6.97k
        }
Unexecuted instantiation: QIntC::IntConverter<long long, long, true, true>::convert(long long const&)
Unexecuted instantiation: QIntC::IntConverter<long, long long, true, true>::convert(long const&)
101
102
        static void
103
        error(From i)
104
1.01k
        {
105
1.01k
            std::ostringstream msg;
106
1.01k
            msg.imbue(std::locale::classic());
107
1.01k
            msg << "integer out of range converting " << i << " from a " << sizeof(From)
108
1.01k
                << "-byte signed type to a " << sizeof(To) << "-byte signed type";
109
1.01k
            throw std::range_error(msg.str());
110
1.01k
        }
QIntC::IntConverter<long long, int, true, true>::error(long long)
Line
Count
Source
104
1.01k
        {
105
1.01k
            std::ostringstream msg;
106
1.01k
            msg.imbue(std::locale::classic());
107
1.01k
            msg << "integer out of range converting " << i << " from a " << sizeof(From)
108
1.01k
                << "-byte signed type to a " << sizeof(To) << "-byte signed type";
109
1.01k
            throw std::range_error(msg.str());
110
1.01k
        }
Unexecuted instantiation: QIntC::IntConverter<double, int, true, true>::error(double)
Unexecuted instantiation: QIntC::IntConverter<long, int, true, true>::error(long)
Unexecuted instantiation: QIntC::IntConverter<long long, long, true, true>::error(long long)
Unexecuted instantiation: QIntC::IntConverter<long, long long, true, true>::error(long)
111
    };
112
113
    template <typename From, typename To>
114
    class IntConverter<From, To, true, false>
115
    {
116
      public:
117
        inline static To
118
        convert(From const& i)
119
7.30M
        {
120
            // From is signed, and To is unsigned. If i > 0, it's safe to
121
            // convert it to the corresponding unsigned type and to
122
            // compare with To's max.
123
7.30M
            auto ii = static_cast<typename to_u<From>::type>(i);
124
7.30M
            if ((i < 0) || (ii > std::numeric_limits<To>::max())) {
125
0
                error(i);
126
0
            }
127
7.30M
            return static_cast<To>(i);
128
7.30M
        }
QIntC::IntConverter<long long, unsigned long, true, false>::convert(long long const&)
Line
Count
Source
119
2.65M
        {
120
            // From is signed, and To is unsigned. If i > 0, it's safe to
121
            // convert it to the corresponding unsigned type and to
122
            // compare with To's max.
123
2.65M
            auto ii = static_cast<typename to_u<From>::type>(i);
124
2.65M
            if ((i < 0) || (ii > std::numeric_limits<To>::max())) {
125
0
                error(i);
126
0
            }
127
2.65M
            return static_cast<To>(i);
128
2.65M
        }
QIntC::IntConverter<long, unsigned long, true, false>::convert(long const&)
Line
Count
Source
119
2.32M
        {
120
            // From is signed, and To is unsigned. If i > 0, it's safe to
121
            // convert it to the corresponding unsigned type and to
122
            // compare with To's max.
123
2.32M
            auto ii = static_cast<typename to_u<From>::type>(i);
124
2.32M
            if ((i < 0) || (ii > std::numeric_limits<To>::max())) {
125
0
                error(i);
126
0
            }
127
2.32M
            return static_cast<To>(i);
128
2.32M
        }
QIntC::IntConverter<int, unsigned int, true, false>::convert(int const&)
Line
Count
Source
119
306k
        {
120
            // From is signed, and To is unsigned. If i > 0, it's safe to
121
            // convert it to the corresponding unsigned type and to
122
            // compare with To's max.
123
306k
            auto ii = static_cast<typename to_u<From>::type>(i);
124
306k
            if ((i < 0) || (ii > std::numeric_limits<To>::max())) {
125
0
                error(i);
126
0
            }
127
306k
            return static_cast<To>(i);
128
306k
        }
QIntC::IntConverter<int, unsigned long, true, false>::convert(int const&)
Line
Count
Source
119
1.47M
        {
120
            // From is signed, and To is unsigned. If i > 0, it's safe to
121
            // convert it to the corresponding unsigned type and to
122
            // compare with To's max.
123
1.47M
            auto ii = static_cast<typename to_u<From>::type>(i);
124
1.47M
            if ((i < 0) || (ii > std::numeric_limits<To>::max())) {
125
0
                error(i);
126
0
            }
127
1.47M
            return static_cast<To>(i);
128
1.47M
        }
QIntC::IntConverter<long long, unsigned long long, true, false>::convert(long long const&)
Line
Count
Source
119
79.8k
        {
120
            // From is signed, and To is unsigned. If i > 0, it's safe to
121
            // convert it to the corresponding unsigned type and to
122
            // compare with To's max.
123
79.8k
            auto ii = static_cast<typename to_u<From>::type>(i);
124
79.8k
            if ((i < 0) || (ii > std::numeric_limits<To>::max())) {
125
0
                error(i);
126
0
            }
127
79.8k
            return static_cast<To>(i);
128
79.8k
        }
QIntC::IntConverter<int, unsigned long long, true, false>::convert(int const&)
Line
Count
Source
119
461k
        {
120
            // From is signed, and To is unsigned. If i > 0, it's safe to
121
            // convert it to the corresponding unsigned type and to
122
            // compare with To's max.
123
461k
            auto ii = static_cast<typename to_u<From>::type>(i);
124
461k
            if ((i < 0) || (ii > std::numeric_limits<To>::max())) {
125
0
                error(i);
126
0
            }
127
461k
            return static_cast<To>(i);
128
461k
        }
Unexecuted instantiation: QIntC::IntConverter<char, unsigned long, true, false>::convert(char const&)
Unexecuted instantiation: QIntC::IntConverter<int, unsigned char, true, false>::convert(int const&)
Unexecuted instantiation: QIntC::IntConverter<int, unsigned short, true, false>::convert(int const&)
129
130
        static void
131
        error(From i)
132
0
        {
133
0
            std::ostringstream msg;
134
0
            msg.imbue(std::locale::classic());
135
0
            msg << "integer out of range converting " << i << " from a " << sizeof(From)
136
0
                << "-byte signed type to a " << sizeof(To) << "-byte unsigned type";
137
0
            throw std::range_error(msg.str());
138
0
        }
Unexecuted instantiation: QIntC::IntConverter<long long, unsigned long, true, false>::error(long long)
Unexecuted instantiation: QIntC::IntConverter<long, unsigned long, true, false>::error(long)
Unexecuted instantiation: QIntC::IntConverter<int, unsigned int, true, false>::error(int)
Unexecuted instantiation: QIntC::IntConverter<int, unsigned long, true, false>::error(int)
Unexecuted instantiation: QIntC::IntConverter<long long, unsigned long long, true, false>::error(long long)
Unexecuted instantiation: QIntC::IntConverter<int, unsigned long long, true, false>::error(int)
Unexecuted instantiation: QIntC::IntConverter<char, unsigned long, true, false>::error(char)
Unexecuted instantiation: QIntC::IntConverter<int, unsigned char, true, false>::error(int)
Unexecuted instantiation: QIntC::IntConverter<int, unsigned short, true, false>::error(int)
139
    };
140
141
    template <typename From, typename To>
142
    class IntConverter<From, To, false, true>
143
    {
144
      public:
145
        inline static To
146
        convert(From const& i)
147
6.42M
        {
148
            // From is unsigned, and to is signed. Convert To's max to the
149
            // unsigned version of To and compare i against that.
150
6.42M
            auto maxval = static_cast<typename to_u<To>::type>(std::numeric_limits<To>::max());
151
6.42M
            if (i > maxval) {
152
29
                error(i);
153
29
            }
154
6.42M
            return static_cast<To>(i);
155
6.42M
        }
QIntC::IntConverter<unsigned long, long long, false, true>::convert(unsigned long const&)
Line
Count
Source
147
5.91M
        {
148
            // From is unsigned, and to is signed. Convert To's max to the
149
            // unsigned version of To and compare i against that.
150
5.91M
            auto maxval = static_cast<typename to_u<To>::type>(std::numeric_limits<To>::max());
151
5.91M
            if (i > maxval) {
152
0
                error(i);
153
0
            }
154
5.91M
            return static_cast<To>(i);
155
5.91M
        }
QIntC::IntConverter<unsigned long, int, false, true>::convert(unsigned long const&)
Line
Count
Source
147
510k
        {
148
            // From is unsigned, and to is signed. Convert To's max to the
149
            // unsigned version of To and compare i against that.
150
510k
            auto maxval = static_cast<typename to_u<To>::type>(std::numeric_limits<To>::max());
151
510k
            if (i > maxval) {
152
29
                error(i);
153
29
            }
154
510k
            return static_cast<To>(i);
155
510k
        }
156
157
        static void
158
        error(From i)
159
29
        {
160
29
            std::ostringstream msg;
161
29
            msg.imbue(std::locale::classic());
162
29
            msg << "integer out of range converting " << i << " from a " << sizeof(From)
163
29
                << "-byte unsigned type to a " << sizeof(To) << "-byte signed type";
164
29
            throw std::range_error(msg.str());
165
29
        }
Unexecuted instantiation: QIntC::IntConverter<unsigned long, long long, false, true>::error(unsigned long)
QIntC::IntConverter<unsigned long, int, false, true>::error(unsigned long)
Line
Count
Source
159
29
        {
160
29
            std::ostringstream msg;
161
29
            msg.imbue(std::locale::classic());
162
29
            msg << "integer out of range converting " << i << " from a " << sizeof(From)
163
29
                << "-byte unsigned type to a " << sizeof(To) << "-byte signed type";
164
29
            throw std::range_error(msg.str());
165
29
        }
166
    };
167
168
    // Specific converters. The return type of each function must match
169
    // the second template parameter to IntConverter.
170
    template <typename T>
171
    inline char
172
    to_char(T const& i)
173
    {
174
        return IntConverter<T, char>::convert(i);
175
    }
176
177
    template <typename T>
178
    inline unsigned char
179
    to_uchar(T const& i)
180
87.1k
    {
181
87.1k
        return IntConverter<T, unsigned char>::convert(i);
182
87.1k
    }
Unexecuted instantiation: unsigned char QIntC::to_uchar<int>(int const&)
unsigned char QIntC::to_uchar<unsigned long>(unsigned long const&)
Line
Count
Source
180
87.1k
    {
181
87.1k
        return IntConverter<T, unsigned char>::convert(i);
182
87.1k
    }
183
184
    template <typename T>
185
    inline short
186
    to_short(T const& i)
187
    {
188
        return IntConverter<T, short>::convert(i);
189
    }
190
191
    template <typename T>
192
    inline unsigned short
193
    to_ushort(T const& i)
194
0
    {
195
0
        return IntConverter<T, unsigned short>::convert(i);
196
0
    }
197
198
    template <typename T>
199
    inline int
200
    to_int(T const& i)
201
5.48M
    {
202
5.48M
        return IntConverter<T, int>::convert(i);
203
5.48M
    }
int QIntC::to_int<unsigned long>(unsigned long const&)
Line
Count
Source
201
510k
    {
202
510k
        return IntConverter<T, int>::convert(i);
203
510k
    }
int QIntC::to_int<long long>(long long const&)
Line
Count
Source
201
4.96M
    {
202
4.96M
        return IntConverter<T, int>::convert(i);
203
4.96M
    }
Unexecuted instantiation: int QIntC::to_int<double>(double const&)
int QIntC::to_int<long>(long const&)
Line
Count
Source
201
6.97k
    {
202
6.97k
        return IntConverter<T, int>::convert(i);
203
6.97k
    }
204
205
    template <typename T>
206
    inline unsigned int
207
    to_uint(T const& i)
208
10.0M
    {
209
10.0M
        return IntConverter<T, unsigned int>::convert(i);
210
10.0M
    }
unsigned int QIntC::to_uint<int>(int const&)
Line
Count
Source
208
306k
    {
209
306k
        return IntConverter<T, unsigned int>::convert(i);
210
306k
    }
unsigned int QIntC::to_uint<unsigned long>(unsigned long const&)
Line
Count
Source
208
9.77M
    {
209
9.77M
        return IntConverter<T, unsigned int>::convert(i);
210
9.77M
    }
Unexecuted instantiation: unsigned int QIntC::to_uint<unsigned long long>(unsigned long long const&)
211
212
    template <typename T>
213
    inline size_t
214
    to_size(T const& i)
215
6.54M
    {
216
6.54M
        return IntConverter<T, size_t>::convert(i);
217
6.54M
    }
unsigned long QIntC::to_size<long long>(long long const&)
Line
Count
Source
215
2.65M
    {
216
2.65M
        return IntConverter<T, size_t>::convert(i);
217
2.65M
    }
unsigned long QIntC::to_size<long>(long const&)
Line
Count
Source
215
2.32M
    {
216
2.32M
        return IntConverter<T, size_t>::convert(i);
217
2.32M
    }
unsigned long QIntC::to_size<unsigned int>(unsigned int const&)
Line
Count
Source
215
66.9k
    {
216
66.9k
        return IntConverter<T, size_t>::convert(i);
217
66.9k
    }
unsigned long QIntC::to_size<int>(int const&)
Line
Count
Source
215
1.47M
    {
216
1.47M
        return IntConverter<T, size_t>::convert(i);
217
1.47M
    }
unsigned long QIntC::to_size<unsigned long>(unsigned long const&)
Line
Count
Source
215
486
    {
216
486
        return IntConverter<T, size_t>::convert(i);
217
486
    }
unsigned long QIntC::to_size<unsigned long long>(unsigned long long const&)
Line
Count
Source
215
27.7k
    {
216
27.7k
        return IntConverter<T, size_t>::convert(i);
217
27.7k
    }
218
219
    template <typename T>
220
    inline qpdf_offset_t
221
    to_offset(T const& i)
222
5.91M
    {
223
5.91M
        return IntConverter<T, qpdf_offset_t>::convert(i);
224
5.91M
    }
long long QIntC::to_offset<unsigned long>(unsigned long const&)
Line
Count
Source
222
5.91M
    {
223
5.91M
        return IntConverter<T, qpdf_offset_t>::convert(i);
224
5.91M
    }
Unexecuted instantiation: long long QIntC::to_offset<long>(long const&)
225
226
    template <typename T>
227
    inline long
228
    to_long(T const& i)
229
    {
230
        return IntConverter<T, long>::convert(i);
231
    }
232
233
    template <typename T>
234
    inline unsigned long
235
    to_ulong(T const& i)
236
8.74M
    {
237
8.74M
        return IntConverter<T, unsigned long>::convert(i);
238
8.74M
    }
unsigned long QIntC::to_ulong<unsigned long>(unsigned long const&)
Line
Count
Source
236
8.74M
    {
237
8.74M
        return IntConverter<T, unsigned long>::convert(i);
238
8.74M
    }
Unexecuted instantiation: unsigned long QIntC::to_ulong<char>(char const&)
Unexecuted instantiation: unsigned long QIntC::to_ulong<unsigned char>(unsigned char const&)
Unexecuted instantiation: unsigned long QIntC::to_ulong<int>(int const&)
239
240
    template <typename T>
241
    inline long long
242
    to_longlong(T const& i)
243
1.75k
    {
244
1.75k
        return IntConverter<T, long long>::convert(i);
245
1.75k
    }
246
247
    template <typename T>
248
    inline unsigned long long
249
    to_ulonglong(T const& i)
250
541k
    {
251
541k
        return IntConverter<T, unsigned long long>::convert(i);
252
541k
    }
unsigned long long QIntC::to_ulonglong<long long>(long long const&)
Line
Count
Source
250
79.8k
    {
251
79.8k
        return IntConverter<T, unsigned long long>::convert(i);
252
79.8k
    }
unsigned long long QIntC::to_ulonglong<int>(int const&)
Line
Count
Source
250
461k
    {
251
461k
        return IntConverter<T, unsigned long long>::convert(i);
252
461k
    }
253
254
    template <typename T>
255
    void
256
    range_check_error(T const& cur, T const& delta)
257
26.1k
    {
258
26.1k
        if ((delta > 0) && ((std::numeric_limits<T>::max() - cur) < delta)) {
259
48
            std::ostringstream msg;
260
48
            msg.imbue(std::locale::classic());
261
48
            msg << "adding " << delta << " to " << cur << " would cause an integer overflow";
262
48
            throw std::range_error(msg.str());
263
26.0k
        } else if ((delta < 0) && ((std::numeric_limits<T>::min() - cur) > delta)) {
264
0
            std::ostringstream msg;
265
0
            msg.imbue(std::locale::classic());
266
0
            msg << "adding " << delta << " to " << cur << " would cause an integer underflow";
267
0
            throw std::range_error(msg.str());
268
0
        }
269
26.1k
    }
270
271
    template <typename T>
272
    inline void
273
    range_check(T const& cur, T const& delta)
274
182k
    {
275
182k
        if ((delta > 0) != (cur > 0)) {
276
156k
            return;
277
156k
        }
278
26.1k
        QIntC::range_check_error<T>(cur, delta);
279
26.1k
    }
280
281
    template <typename T>
282
    void
283
    range_check_subtract_error(T const& cur, T const& delta)
284
    {
285
        if ((delta > 0) && ((std::numeric_limits<T>::min() + delta) > cur)) {
286
            std::ostringstream msg;
287
            msg.imbue(std::locale::classic());
288
            msg << "subtracting " << delta << " from " << cur
289
                << " would cause an integer underflow";
290
            throw std::range_error(msg.str());
291
        } else if ((delta < 0) && ((std::numeric_limits<T>::max() + delta) < cur)) {
292
            std::ostringstream msg;
293
            msg.imbue(std::locale::classic());
294
            msg << "subtracting " << delta << " from " << cur << " would cause an integer overflow";
295
            throw std::range_error(msg.str());
296
        }
297
    }
298
299
    template <typename T>
300
    inline void
301
    range_check_subtract(T const& cur, T const& delta)
302
    {
303
        if ((delta >= 0) == (cur >= 0)) {
304
            return;
305
        }
306
        QIntC::range_check_subtract_error<T>(cur, delta);
307
    }
308
}; // namespace QIntC
309
310
#endif // QINTC_HH