From: Philippe Proulx Date: Fri, 15 Apr 2022 17:08:10 +0000 (-0400) Subject: src/cpp-common: add bt2_common::safeTo*() and bt2_common::safe*() X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=e2c3fe1ca07b187c76b5279d44613019b2efbe71 src/cpp-common: add bt2_common::safeTo*() and bt2_common::safe*() This patch adds the following function templates, under the `bt2_common` namespace, within the new `src/cpp-common/safe-ops.hpp` header: safeToMul(): Returns whether or not you can safely multiply two numbers without causing an overflow. safeToAdd(): Returns whether or not you can safely add two numbers without causing an overflow. safeToSub(): Returns whether or not you can safely subtract two numbers without causing an underflow. safeMul(): Multiplies some number by another, asserting that it's safe to do so, and returns the result. safeAdd(): Adds some number and another, asserting that it's safe to do so, and returns the result. safeSub(): Subtract some number from another, asserting that it's safe to do so, and returns the result. Those are similar to the existing bt_safe_*() C functions, except that: * They're function templates, so you can use any numeric type. * The safeTo*() function templates are `constexpr`. * They only work with unsigned types; signed types introduce some complexity (negative values) which I don't need to deal with right now. Signed-off-by: Philippe Proulx Change-Id: I29ed4b51d50ae2507f5580db20452ec6c188ef66 Reviewed-on: https://review.lttng.org/c/babeltrace/+/7916 Reviewed-on: https://review.lttng.org/c/babeltrace/+/10816 Tested-by: jenkins --- diff --git a/src/cpp-common/Makefile.am b/src/cpp-common/Makefile.am index 09b19a23..f67fcd06 100644 --- a/src/cpp-common/Makefile.am +++ b/src/cpp-common/Makefile.am @@ -13,4 +13,5 @@ EXTRA_DIST = bt2 \ string_view.hpp \ uuid-view.hpp \ endian.hpp \ - make-unique.hpp + make-unique.hpp \ + safe-ops.hpp diff --git a/src/cpp-common/safe-ops.hpp b/src/cpp-common/safe-ops.hpp new file mode 100644 index 00000000..90dae882 --- /dev/null +++ b/src/cpp-common/safe-ops.hpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022 Philippe Proulx + * + * SPDX-License-Identifier: MIT + */ + +#ifndef BABELTRACE_CPP_COMMON_SAFE_OPS_HPP +#define BABELTRACE_CPP_COMMON_SAFE_OPS_HPP + +#include +#include + +#include "common/assert.h" + +namespace bt2_common { + +template +constexpr bool safeToMul(const T a, const T b) +{ + static_assert(std::is_unsigned::value, "`T` is an unsigned type."); + + return a == 0 || b == 0 || a < std::numeric_limits::max() / b; +} + +template +T safeMul(const T a, const T b) noexcept +{ + static_assert(std::is_unsigned::value, "`T` is an unsigned type."); + + BT_ASSERT_DBG(safeToMul(a, b)); + return a * b; +} + +template +constexpr bool safeToAdd(const T a, const T b) +{ + static_assert(std::is_unsigned::value, "`T` is an unsigned type."); + + return a <= std::numeric_limits::max() - b; +} + +template +T safeAdd(const T a, const T b) noexcept +{ + static_assert(std::is_unsigned::value, "`T` is an unsigned type."); + + BT_ASSERT_DBG(safeToAdd(a, b)); + return a + b; +} + +template +constexpr bool safeToSub(const T a, const T b) +{ + static_assert(std::is_unsigned::value, "`T` is an unsigned type."); + + return a >= b; +} + +template +T safeSub(const T a, const T b) noexcept +{ + static_assert(std::is_unsigned::value, "`T` is an unsigned type."); + + BT_ASSERT_DBG(safeToSub(a, b)); + return a - b; +} + +} /* namespace bt2_common */ + +#endif /* BABELTRACE_CPP_COMMON_SAFE_OPS_HPP */