| // Copyright 2025 The Fuchsia 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 SRC_DEVELOPER_DEBUG_ZXDB_COMMON_CHECKED_MATH_H_ |
| #define SRC_DEVELOPER_DEBUG_ZXDB_COMMON_CHECKED_MATH_H_ |
| |
| #include <optional> |
| |
| namespace zxdb { |
| |
| // Returns the result of adding |lhs| and |rhs|. If the result overflows, then std::nullopt is |
| // returned. The sizes of the types for |lhs| and |rhs| may differ. The returned value will be |
| // stored in the larger of the two and is the type that must overflow for this function to return |
| // std::nullopt. |
| // |
| // Use it like: |
| // |
| // uint64_t some_number = 0; |
| // if (auto checked_sum = CheckedAdd(1, 2)) { |
| // some_number = *checked_sum; |
| // } else { |
| // return Err("Overflow!"); |
| // } |
| template <typename T, typename U, typename R = std::conditional_t<sizeof(T) >= sizeof(U), T, U>> |
| constexpr std::optional<R> CheckedAdd(T lhs, U rhs) { |
| #if __has_builtin(__builtin_add_overflow) |
| T res = 0; |
| if (__builtin_add_overflow(lhs, rhs, &res)) { |
| return std::nullopt; |
| } |
| |
| return std::optional<T>(res); |
| #else |
| #error "No overflow intrinsic available!" |
| #endif |
| } |
| |
| } // namespace zxdb |
| |
| #endif // SRC_DEVELOPER_DEBUG_ZXDB_COMMON_CHECKED_MATH_H_ |