1//========================================================================
2//
3// GooCheckedOps.h
4//
5// This file is licensed under the GPLv2 or later
6//
7// Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de>
8// Copyright (C) 2019 LE GARREC Vincent <legarrec.vincent@gmail.com>
9// Copyright (C) 2019-2021 Albert Astals Cid <aacid@kde.org>
10//
11//========================================================================
12
13#ifndef GOO_CHECKED_OPS_H
14#define GOO_CHECKED_OPS_H
15
16#include <limits>
17#include <type_traits>
18
19template<typename T>
20inline bool checkedAssign(long long lz, T *z)
21{
22 static_assert((std::numeric_limits<long long>::max)() > (std::numeric_limits<T>::max)(), "The max of long long type must be larger to perform overflow checks.");
23 static_assert((std::numeric_limits<long long>::min)() < (std::numeric_limits<T>::min)(), "The min of long long type must be smaller to perform overflow checks.");
24
25 if (lz > (std::numeric_limits<T>::max)() || lz < (std::numeric_limits<T>::min)()) {
26 return true;
27 }
28
29 *z = static_cast<T>(lz);
30 return false;
31}
32
33#ifndef __has_builtin
34# define __has_builtin(x) 0
35#endif
36
37template<typename T>
38inline bool checkedAdd(T x, T y, T *z)
39{
40// The __GNUC__ checks can not be removed until we depend on GCC >= 10.1
41// which is the first version that returns true for __has_builtin(__builtin_add_overflow)
42#if __GNUC__ >= 5 || __has_builtin(__builtin_add_overflow)
43 return __builtin_add_overflow(x, y, z);
44#else
45 const auto lz = static_cast<long long>(x) + static_cast<long long>(y);
46 return checkedAssign(lz, z);
47#endif
48}
49
50template<>
51inline bool checkedAdd<long long>(long long x, long long y, long long *z)
52{
53#if __GNUC__ >= 5 || __has_builtin(__builtin_add_overflow)
54 return __builtin_add_overflow(x, y, z);
55#else
56 if (x > 0 && y > 0) {
57 if (x > (std::numeric_limits<long long>::max)() - y) {
58 return true;
59 }
60 } else if (x < 0 && y < 0) {
61 if (x < (std::numeric_limits<long long>::min)() - y) {
62 return true;
63 }
64 }
65 *z = x + y;
66 return false;
67#endif
68}
69
70template<typename T>
71inline bool checkedSubtraction(T x, T y, T *z)
72{
73#if __GNUC__ >= 5 || __has_builtin(__builtin_sub_overflow)
74 return __builtin_sub_overflow(x, y, z);
75#else
76 const auto lz = static_cast<long long>(x) - static_cast<long long>(y);
77 return checkedAssign(lz, z);
78#endif
79}
80
81template<typename T>
82inline bool checkedMultiply(T x, T y, T *z)
83{
84#if __GNUC__ >= 5 || __has_builtin(__builtin_mul_overflow)
85 return __builtin_mul_overflow(x, y, z);
86#else
87 const auto lz = static_cast<long long>(x) * static_cast<long long>(y);
88 return checkedAssign(lz, z);
89#endif
90}
91
92template<>
93inline bool checkedMultiply<long long>(long long x, long long y, long long *z)
94{
95#if __GNUC__ >= 5 || __has_builtin(__builtin_mul_overflow)
96 return __builtin_mul_overflow(x, y, z);
97#else
98 if (x != 0 && (std::numeric_limits<long long>::max)() / x < y) {
99 return true;
100 }
101
102 *z = x * y;
103 return false;
104#endif
105}
106
107template<typename T>
108inline T safeAverage(T a, T b)
109{
110 static_assert((std::numeric_limits<long long>::max)() > (std::numeric_limits<T>::max)(), "The max of long long type must be larger to perform overflow checks.");
111 static_assert((std::numeric_limits<long long>::min)() < (std::numeric_limits<T>::min)(), "The min of long long type must be smaller to perform overflow checks.");
112
113 return static_cast<T>((static_cast<long long>(a) + static_cast<long long>(b)) / 2);
114}
115
116#endif // GOO_CHECKED_OPS_H
117

source code of poppler/goo/GooCheckedOps.h