diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/libwebrtc/rtc_base/numerics/safe_compare.h | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/rtc_base/numerics/safe_compare.h')
-rw-r--r-- | third_party/libwebrtc/rtc_base/numerics/safe_compare.h | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/numerics/safe_compare.h b/third_party/libwebrtc/rtc_base/numerics/safe_compare.h new file mode 100644 index 0000000000..85f0a30e83 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/safe_compare.h @@ -0,0 +1,176 @@ +/* + * Copyright 2016 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This file defines six constexpr functions: +// +// rtc::SafeEq // == +// rtc::SafeNe // != +// rtc::SafeLt // < +// rtc::SafeLe // <= +// rtc::SafeGt // > +// rtc::SafeGe // >= +// +// They each accept two arguments of arbitrary types, and in almost all cases, +// they simply call the appropriate comparison operator. However, if both +// arguments are integers, they don't compare them using C++'s quirky rules, +// but instead adhere to the true mathematical definitions. It is as if the +// arguments were first converted to infinite-range signed integers, and then +// compared, although of course nothing expensive like that actually takes +// place. In practice, for signed/signed and unsigned/unsigned comparisons and +// some mixed-signed comparisons with a compile-time constant, the overhead is +// zero; in the remaining cases, it is just a few machine instructions (no +// branches). + +#ifndef RTC_BASE_NUMERICS_SAFE_COMPARE_H_ +#define RTC_BASE_NUMERICS_SAFE_COMPARE_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <type_traits> +#include <utility> + +#include "rtc_base/type_traits.h" + +namespace rtc { + +namespace safe_cmp_impl { + +template <size_t N> +struct LargerIntImpl : std::false_type {}; +template <> +struct LargerIntImpl<sizeof(int8_t)> : std::true_type { + using type = int16_t; +}; +template <> +struct LargerIntImpl<sizeof(int16_t)> : std::true_type { + using type = int32_t; +}; +template <> +struct LargerIntImpl<sizeof(int32_t)> : std::true_type { + using type = int64_t; +}; + +// LargerInt<T1, T2>::value is true iff there's a signed type that's larger +// than T1 (and no larger than the larger of T2 and int*, for performance +// reasons); and if there is such a type, LargerInt<T1, T2>::type is an alias +// for it. +template <typename T1, typename T2> +struct LargerInt + : LargerIntImpl<sizeof(T1) < sizeof(T2) || sizeof(T1) < sizeof(int*) + ? sizeof(T1) + : 0> {}; + +template <typename T> +constexpr typename std::make_unsigned<T>::type MakeUnsigned(T a) { + return static_cast<typename std::make_unsigned<T>::type>(a); +} + +// Overload for when both T1 and T2 have the same signedness. +template <typename Op, + typename T1, + typename T2, + typename std::enable_if<std::is_signed<T1>::value == + std::is_signed<T2>::value>::type* = nullptr> +constexpr bool Cmp(T1 a, T2 b) { + return Op::Op(a, b); +} + +// Overload for signed - unsigned comparison that can be promoted to a bigger +// signed type. +template <typename Op, + typename T1, + typename T2, + typename std::enable_if<std::is_signed<T1>::value && + std::is_unsigned<T2>::value && + LargerInt<T2, T1>::value>::type* = nullptr> +constexpr bool Cmp(T1 a, T2 b) { + return Op::Op(a, static_cast<typename LargerInt<T2, T1>::type>(b)); +} + +// Overload for unsigned - signed comparison that can be promoted to a bigger +// signed type. +template <typename Op, + typename T1, + typename T2, + typename std::enable_if<std::is_unsigned<T1>::value && + std::is_signed<T2>::value && + LargerInt<T1, T2>::value>::type* = nullptr> +constexpr bool Cmp(T1 a, T2 b) { + return Op::Op(static_cast<typename LargerInt<T1, T2>::type>(a), b); +} + +// Overload for signed - unsigned comparison that can't be promoted to a bigger +// signed type. +template <typename Op, + typename T1, + typename T2, + typename std::enable_if<std::is_signed<T1>::value && + std::is_unsigned<T2>::value && + !LargerInt<T2, T1>::value>::type* = nullptr> +constexpr bool Cmp(T1 a, T2 b) { + return a < 0 ? Op::Op(-1, 0) : Op::Op(safe_cmp_impl::MakeUnsigned(a), b); +} + +// Overload for unsigned - signed comparison that can't be promoted to a bigger +// signed type. +template <typename Op, + typename T1, + typename T2, + typename std::enable_if<std::is_unsigned<T1>::value && + std::is_signed<T2>::value && + !LargerInt<T1, T2>::value>::type* = nullptr> +constexpr bool Cmp(T1 a, T2 b) { + return b < 0 ? Op::Op(0, -1) : Op::Op(a, safe_cmp_impl::MakeUnsigned(b)); +} + +#define RTC_SAFECMP_MAKE_OP(name, op) \ + struct name { \ + template <typename T1, typename T2> \ + static constexpr bool Op(T1 a, T2 b) { \ + return a op b; \ + } \ + }; +RTC_SAFECMP_MAKE_OP(EqOp, ==) +RTC_SAFECMP_MAKE_OP(NeOp, !=) +RTC_SAFECMP_MAKE_OP(LtOp, <) +RTC_SAFECMP_MAKE_OP(LeOp, <=) +RTC_SAFECMP_MAKE_OP(GtOp, >) +RTC_SAFECMP_MAKE_OP(GeOp, >=) +#undef RTC_SAFECMP_MAKE_OP + +} // namespace safe_cmp_impl + +#define RTC_SAFECMP_MAKE_FUN(name) \ + template <typename T1, typename T2> \ + constexpr \ + typename std::enable_if<IsIntlike<T1>::value && IsIntlike<T2>::value, \ + bool>::type Safe##name(T1 a, T2 b) { \ + /* Unary plus here turns enums into real integral types. */ \ + return safe_cmp_impl::Cmp<safe_cmp_impl::name##Op>(+a, +b); \ + } \ + template <typename T1, typename T2> \ + constexpr \ + typename std::enable_if<!IsIntlike<T1>::value || !IsIntlike<T2>::value, \ + bool>::type Safe##name(const T1& a, \ + const T2& b) { \ + return safe_cmp_impl::name##Op::Op(a, b); \ + } +RTC_SAFECMP_MAKE_FUN(Eq) +RTC_SAFECMP_MAKE_FUN(Ne) +RTC_SAFECMP_MAKE_FUN(Lt) +RTC_SAFECMP_MAKE_FUN(Le) +RTC_SAFECMP_MAKE_FUN(Gt) +RTC_SAFECMP_MAKE_FUN(Ge) +#undef RTC_SAFECMP_MAKE_FUN + +} // namespace rtc + +#endif // RTC_BASE_NUMERICS_SAFE_COMPARE_H_ |