• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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