src/cpp-common: add bt2_common::safeTo*() and bt2_common::safe*()
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 15 Apr 2022 17:08:10 +0000 (13:08 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Mon, 11 Sep 2023 15:24:02 +0000 (11:24 -0400)
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 <eeppeliteloop@gmail.com>
Change-Id: I29ed4b51d50ae2507f5580db20452ec6c188ef66
Reviewed-on: https://review.lttng.org/c/babeltrace/+/7916
Reviewed-on: https://review.lttng.org/c/babeltrace/+/10816
Tested-by: jenkins <jenkins@lttng.org>
src/cpp-common/Makefile.am
src/cpp-common/safe-ops.hpp [new file with mode: 0644]

index 09b19a230deacb7b17b7bd144be10d0aebaa4d0e..f67fcd06e06c57ce277b836f74aa27c0898135b4 100644 (file)
@@ -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 (file)
index 0000000..90dae88
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2022 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef BABELTRACE_CPP_COMMON_SAFE_OPS_HPP
+#define BABELTRACE_CPP_COMMON_SAFE_OPS_HPP
+
+#include <limits>
+#include <type_traits>
+
+#include "common/assert.h"
+
+namespace bt2_common {
+
+template <typename T>
+constexpr bool safeToMul(const T a, const T b)
+{
+    static_assert(std::is_unsigned<T>::value, "`T` is an unsigned type.");
+
+    return a == 0 || b == 0 || a < std::numeric_limits<T>::max() / b;
+}
+
+template <typename T>
+T safeMul(const T a, const T b) noexcept
+{
+    static_assert(std::is_unsigned<T>::value, "`T` is an unsigned type.");
+
+    BT_ASSERT_DBG(safeToMul(a, b));
+    return a * b;
+}
+
+template <typename T>
+constexpr bool safeToAdd(const T a, const T b)
+{
+    static_assert(std::is_unsigned<T>::value, "`T` is an unsigned type.");
+
+    return a <= std::numeric_limits<T>::max() - b;
+}
+
+template <typename T>
+T safeAdd(const T a, const T b) noexcept
+{
+    static_assert(std::is_unsigned<T>::value, "`T` is an unsigned type.");
+
+    BT_ASSERT_DBG(safeToAdd(a, b));
+    return a + b;
+}
+
+template <typename T>
+constexpr bool safeToSub(const T a, const T b)
+{
+    static_assert(std::is_unsigned<T>::value, "`T` is an unsigned type.");
+
+    return a >= b;
+}
+
+template <typename T>
+T safeSub(const T a, const T b) noexcept
+{
+    static_assert(std::is_unsigned<T>::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 */
This page took 0.025289 seconds and 4 git commands to generate.