blob: 871906d62da851152c935ac30d9edeb5771ba719 [file] [log] [blame]
kumarashishg826308d2023-06-23 13:21:22 +00001// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
6#define THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
7
8#include <stddef.h>
9#include <stdint.h>
10
11#include <cassert>
12#include <climits>
13#include <cmath>
14#include <cstdlib>
15#include <limits>
16#include <type_traits>
17
18#include "build/build_config.h"
19#include "third_party/base/numerics/safe_conversions.h"
20
21#if BUILDFLAG(IS_ASMJS)
22// Optimized safe math instructions are incompatible with asmjs.
23#define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
24// Where available use builtin math overflow support on Clang and GCC.
25#elif !defined(__native_client__) && \
26 ((defined(__clang__) && \
27 ((__clang_major__ > 3) || \
28 (__clang_major__ == 3 && __clang_minor__ >= 4))) || \
29 (defined(__GNUC__) && __GNUC__ >= 5))
30#include "third_party/base/numerics/safe_math_clang_gcc_impl.h"
31#define BASE_HAS_OPTIMIZED_SAFE_MATH (1)
32#else
33#define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
34#endif
35
36namespace pdfium {
37namespace base {
38namespace internal {
39
40// These are the non-functioning boilerplate implementations of the optimized
41// safe math routines.
42#if !BASE_HAS_OPTIMIZED_SAFE_MATH
43template <typename T, typename U>
44struct CheckedAddFastOp {
45 static const bool is_supported = false;
46 template <typename V>
47 static constexpr bool Do(T, U, V*) {
48 // Force a compile failure if instantiated.
49 return CheckOnFailure::template HandleFailure<bool>();
50 }
51};
52
53template <typename T, typename U>
54struct CheckedSubFastOp {
55 static const bool is_supported = false;
56 template <typename V>
57 static constexpr bool Do(T, U, V*) {
58 // Force a compile failure if instantiated.
59 return CheckOnFailure::template HandleFailure<bool>();
60 }
61};
62
63template <typename T, typename U>
64struct CheckedMulFastOp {
65 static const bool is_supported = false;
66 template <typename V>
67 static constexpr bool Do(T, U, V*) {
68 // Force a compile failure if instantiated.
69 return CheckOnFailure::template HandleFailure<bool>();
70 }
71};
72
73template <typename T, typename U>
74struct ClampedAddFastOp {
75 static const bool is_supported = false;
76 template <typename V>
77 static constexpr V Do(T, U) {
78 // Force a compile failure if instantiated.
79 return CheckOnFailure::template HandleFailure<V>();
80 }
81};
82
83template <typename T, typename U>
84struct ClampedSubFastOp {
85 static const bool is_supported = false;
86 template <typename V>
87 static constexpr V Do(T, U) {
88 // Force a compile failure if instantiated.
89 return CheckOnFailure::template HandleFailure<V>();
90 }
91};
92
93template <typename T, typename U>
94struct ClampedMulFastOp {
95 static const bool is_supported = false;
96 template <typename V>
97 static constexpr V Do(T, U) {
98 // Force a compile failure if instantiated.
99 return CheckOnFailure::template HandleFailure<V>();
100 }
101};
102
103template <typename T>
104struct ClampedNegFastOp {
105 static const bool is_supported = false;
106 static constexpr T Do(T) {
107 // Force a compile failure if instantiated.
108 return CheckOnFailure::template HandleFailure<T>();
109 }
110};
111#endif // BASE_HAS_OPTIMIZED_SAFE_MATH
112#undef BASE_HAS_OPTIMIZED_SAFE_MATH
113
114// This is used for UnsignedAbs, where we need to support floating-point
115// template instantiations even though we don't actually support the operations.
116// However, there is no corresponding implementation of e.g. SafeUnsignedAbs,
117// so the float versions will not compile.
118template <typename Numeric,
119 bool IsInteger = std::is_integral<Numeric>::value,
120 bool IsFloat = std::is_floating_point<Numeric>::value>
121struct UnsignedOrFloatForSize;
122
123template <typename Numeric>
124struct UnsignedOrFloatForSize<Numeric, true, false> {
125 using type = typename std::make_unsigned<Numeric>::type;
126};
127
128template <typename Numeric>
129struct UnsignedOrFloatForSize<Numeric, false, true> {
130 using type = Numeric;
131};
132
133// Wrap the unary operations to allow SFINAE when instantiating integrals versus
134// floating points. These don't perform any overflow checking. Rather, they
135// exhibit well-defined overflow semantics and rely on the caller to detect
136// if an overflow occurred.
137
138template <typename T,
139 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
140constexpr T NegateWrapper(T value) {
141 using UnsignedT = typename std::make_unsigned<T>::type;
142 // This will compile to a NEG on Intel, and is normal negation on ARM.
143 return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value));
144}
145
146template <
147 typename T,
148 typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
149constexpr T NegateWrapper(T value) {
150 return -value;
151}
152
153template <typename T,
154 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
155constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {
156 return ~value;
157}
158
159template <typename T,
160 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
161constexpr T AbsWrapper(T value) {
162 return static_cast<T>(SafeUnsignedAbs(value));
163}
164
165template <
166 typename T,
167 typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
168constexpr T AbsWrapper(T value) {
169 return value < 0 ? -value : value;
170}
171
172template <template <typename, typename, typename> class M,
173 typename L,
174 typename R>
175struct MathWrapper {
176 using math = M<typename UnderlyingType<L>::type,
177 typename UnderlyingType<R>::type,
178 void>;
179 using type = typename math::result_type;
180};
181
182// The following macros are just boilerplate for the standard arithmetic
183// operator overloads and variadic function templates. A macro isn't the nicest
184// solution, but it beats rewriting these over and over again.
185#define BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME) \
186 template <typename L, typename R, typename... Args> \
187 constexpr auto CL_ABBR##OP_NAME(const L lhs, const R rhs, \
188 const Args... args) { \
189 return CL_ABBR##MathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs, \
190 args...); \
191 }
192
193#define BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP, CMP_OP) \
194 /* Binary arithmetic operator for all CLASS##Numeric operations. */ \
195 template <typename L, typename R, \
196 typename std::enable_if<Is##CLASS##Op<L, R>::value>::type* = \
197 nullptr> \
198 constexpr CLASS##Numeric< \
199 typename MathWrapper<CLASS##OP_NAME##Op, L, R>::type> \
200 operator OP(const L lhs, const R rhs) { \
201 return decltype(lhs OP rhs)::template MathOp<CLASS##OP_NAME##Op>(lhs, \
202 rhs); \
203 } \
204 /* Assignment arithmetic operator implementation from CLASS##Numeric. */ \
205 template <typename L> \
206 template <typename R> \
207 constexpr CLASS##Numeric<L>& CLASS##Numeric<L>::operator CMP_OP( \
208 const R rhs) { \
209 return MathOp<CLASS##OP_NAME##Op>(rhs); \
210 } \
211 /* Variadic arithmetic functions that return CLASS##Numeric. */ \
212 BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)
213
214} // namespace internal
215} // namespace base
216} // namespace pdfium
217
218#endif // THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_