| // Copyright 2026 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef QUICHE_COMMON_QUICHE_CHECKED_MATH_H_ |
| #define QUICHE_COMMON_QUICHE_CHECKED_MATH_H_ |
| |
| #include <concepts> |
| #include <optional> |
| |
| #include "absl/base/config.h" |
| #include "absl/types/span.h" |
| |
| namespace quiche { |
| |
| // Adds two unsigned integers, `a` and `b`. Returns the sum if the resulting |
| // sum fits into the specified integer type, or nullopt if it does not. |
| template <typename T> |
| requires(std::unsigned_integral<T>) |
| std::optional<T> SafeAdd(T a, T b) { |
| T out; |
| #if ABSL_HAVE_BUILTIN(__builtin_add_overflow) |
| if (__builtin_add_overflow(a, b, &out)) { |
| return std::nullopt; |
| } |
| #else |
| out = a + b; |
| if (out < a) { |
| return std::nullopt; |
| } |
| #endif |
| return out; |
| } |
| |
| // Adds two unsigned integers, `a` and `b`. If the resulting sum fits into the |
| // specified integer type, sets `a` to that sum value, and returns true; |
| // otherwise, returns false. |
| template <typename T> |
| requires(std::unsigned_integral<T>) |
| [[nodiscard]] bool SafeIncrementBy(T& a, T b) { |
| std::optional<T> out = SafeAdd(a, b); |
| if (!out.has_value()) { |
| return false; |
| } |
| a = *out; |
| return true; |
| } |
| |
| // Sums all of the provided arguments, and returns the sum if it fits into the |
| // resulting integer, or nullopt if it overflows. |
| template <typename T> |
| requires(std::unsigned_integral<T>) |
| std::optional<T> SafeSum(absl::Span<const T> summands) { |
| T out = 0; |
| for (const T num : summands) { |
| if (!SafeIncrementBy(out, num)) { |
| return std::nullopt; |
| } |
| } |
| return out; |
| } |
| |
| } // namespace quiche |
| |
| #endif // QUICHE_COMMON_QUICHE_CHECKED_MATH_H_ |