1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15
16 #include <optional>
17 #include <type_traits>
18
19 #include "pw_preprocessor/compiler.h"
20
21 namespace pw {
22
23 /// Adds two numbers, checking for overflow.
24 ///
25 /// @tparam T The type of the result, which is checked for overflow.
26 ///
27 /// @tparam A The type of the first addend, `a`.
28 ///
29 /// @tparam B The type of the second addend, `b`.
30 ///
31 /// @param[in] a The first addend.
32 ///
33 /// @param[in] b The second addend.
34 ///
35 /// @returns The sum (`a + b`) if addition was successful,
36 /// or `nullopt` if the addition would overflow.
37 ///
38 /// @note The template argument must be provided, e.g.
39 /// `pw::CheckedAdd<uint32_t>(...)`.
40 template <typename T, typename A, typename B>
CheckedAdd(A a,B b)41 constexpr std::optional<T> CheckedAdd(A a, B b) {
42 T result;
43
44 if (PW_ADD_OVERFLOW(a, b, &result)) {
45 return std::nullopt;
46 }
47
48 return result;
49 }
50
51 /// Increments a variable by some amount.
52 ///
53 /// @tparam T The type of the variable to be incremented.
54 ///
55 /// @tparam Inc The type of the variable to add.
56 ///
57 /// @param[in] base The variable to be incremented.
58 ///
59 /// @param[in] inc The number to add to `base`.
60 ///
61 /// @returns True if the addition was successful and `base` was incremented
62 /// (`base += inc`); False if the addition would overflow and ``base`` is
63 /// unmodified.
64 template <typename T, typename Inc>
CheckedIncrement(T & base,Inc inc)65 constexpr bool CheckedIncrement(T& base, Inc inc) {
66 std::optional<T> result =
67 CheckedAdd<std::remove_reference_t<decltype(base)>>(base, inc);
68 if (!result) {
69 return false;
70 }
71 base = *result;
72 return true;
73 }
74
75 /// Subtracts two numbers, checking for overflow.
76 ///
77 /// @tparam T The type of the result, which is checked for overflow.
78 ///
79 /// @tparam A The type of the minuend, `a`.
80 ///
81 /// @tparam B The type of the subtrahend, `b`.
82 ///
83 /// @param[in] a The minuend (the number from which `b` is subtracted).
84 ///
85 /// @param[in] b The subtrahend (the number subtracted from `a`).
86 ///
87 /// @returns The difference (`a - b`) if subtraction was successful,
88 /// or `nullopt` if the subtraction would overflow.
89 ///
90 /// @note The template argument must be provided, e.g.
91 /// `pw::CheckedSub<uint32_t>(...)`.
92 template <typename T, typename A, typename B>
CheckedSub(A a,B b)93 constexpr std::optional<T> CheckedSub(A a, B b) {
94 T result;
95
96 if (PW_SUB_OVERFLOW(a, b, &result)) {
97 return std::nullopt;
98 }
99
100 return result;
101 }
102
103 /// Decrements a variable by some amount.
104 ///
105 /// @tparam T The type of the variable to be decremented.
106 ///
107 /// @tparam Dec The type of the variable to subtract.
108 ///
109 /// @param[in] base The variable to be decremented.
110 ///
111 /// @param[in] inc The number to subtract from `base`.
112 ///
113 /// @returns True if the subtraction was successful and `base` was decremented
114 /// (`base -= inc`); False if the subtraction would overflow and ``base`` is
115 /// unmodified.
116 template <typename T, typename Dec>
CheckedDecrement(T & base,Dec dec)117 constexpr bool CheckedDecrement(T& base, Dec dec) {
118 std::optional<T> result =
119 CheckedSub<std::remove_reference_t<decltype(base)>>(base, dec);
120 if (!result) {
121 return false;
122 }
123 base = *result;
124 return true;
125 }
126
127 /// Multiplies two numbers, checking for overflow.
128 ///
129 /// @tparam T The type of the result, which is checked for overflow.
130 ///
131 /// @tparam A The type of the first factor, `a`.
132 ///
133 /// @tparam B The type of the second factor, `b`.
134 ///
135 /// @param[in] a The first factor.
136 ///
137 /// @param[in] b The second factor.
138 ///
139 /// @returns The product (`a * b`) if multiplication was successful,
140 /// or `nullopt` if the multiplication would overflow.
141 ///
142 /// @note The template argument must be provided, e.g.
143 /// `pw::CheckedMul<uint32_t>(...)`.
144 template <typename T, typename A, typename B>
CheckedMul(A a,B b)145 constexpr std::optional<T> CheckedMul(A a, B b) {
146 T result;
147
148 if (PW_MUL_OVERFLOW(a, b, &result)) {
149 return std::nullopt;
150 }
151
152 return result;
153 }
154
155 } // namespace pw
156