[libcxx-commits] [libcxx] [libc++][NFC] Simplify `gcd` a bit (PR #173570)
via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Dec 25 06:10:53 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: A. Jiang (frederick-vs-ja)
<details>
<summary>Changes</summary>
1. With `if constexpr` we can avoid partial specializations of `__ct_gcd`. This patch changes it to a function template and renames it to `__abs_in_type` to slightly improve readability.
2. `__gcd` was made non-recursive by 27a062e9ca7c92e89ed4084c3c3affb9fa39aabb, so this patch simply inlines it into `gcd`.
---
Full diff: https://github.com/llvm/llvm-project/pull/173570.diff
1 Files Affected:
- (modified) libcxx/include/__numeric/gcd_lcm.h (+24-35)
``````````diff
diff --git a/libcxx/include/__numeric/gcd_lcm.h b/libcxx/include/__numeric/gcd_lcm.h
index 95df54dc066df..fec8f25818c2a 100644
--- a/libcxx/include/__numeric/gcd_lcm.h
+++ b/libcxx/include/__numeric/gcd_lcm.h
@@ -33,28 +33,25 @@ _LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 17
-template <typename _Result, typename _Source, bool _IsSigned = is_signed<_Source>::value>
-struct __ct_abs;
-
-template <typename _Result, typename _Source>
-struct __ct_abs<_Result, _Source, true> {
- constexpr _LIBCPP_HIDE_FROM_ABI _Result operator()(_Source __t) const noexcept {
+template <class _Result, class _Source>
+constexpr _LIBCPP_HIDE_FROM_ABI _Result __abs_in_type(_Source __t) noexcept {
+ if constexpr (is_signed_v<_Source>) {
if (__t >= 0)
return __t;
if (__t == numeric_limits<_Source>::min())
return -static_cast<_Result>(__t);
return -__t;
- }
-};
-
-template <typename _Result, typename _Source>
-struct __ct_abs<_Result, _Source, false> {
- constexpr _LIBCPP_HIDE_FROM_ABI _Result operator()(_Source __t) const noexcept { return __t; }
-};
+ } else
+ return __t;
+}
-template <class _Tp>
-constexpr _LIBCPP_HIDDEN _Tp __gcd(_Tp __a, _Tp __b) {
- static_assert(!is_signed<_Tp>::value, "");
+template <class _Tp, class _Up>
+constexpr _LIBCPP_HIDE_FROM_ABI common_type_t<_Tp, _Up> gcd(_Tp __m, _Up __n) {
+ static_assert(is_integral<_Tp>::value && is_integral<_Up>::value, "Arguments to gcd must be integer types");
+ static_assert(!is_same<__remove_cv_t<_Tp>, bool>::value, "First argument to gcd cannot be bool");
+ static_assert(!is_same<__remove_cv_t<_Up>, bool>::value, "Second argument to gcd cannot be bool");
+ using _Rp = common_type_t<_Tp, _Up>;
+ using _Wp = make_unsigned_t<_Rp>;
// Using Binary GCD algorithm https://en.wikipedia.org/wiki/Binary_GCD_algorithm, based on an implementation
// from https://lemire.me/blog/2024/04/13/greatest-common-divisor-the-extended-euclidean-algorithm-and-speed/
@@ -67,22 +64,25 @@ constexpr _LIBCPP_HIDDEN _Tp __gcd(_Tp __a, _Tp __b) {
//
// And standard gcd algorithm where instead of modulo, minus is used.
+ auto __a = static_cast<_Wp>(std::__abs_in_type<_Rp>(__m));
+ auto __b = static_cast<_Wp>(std::__abs_in_type<_Rp>(__n));
+
if (__a < __b) {
- _Tp __tmp = __b;
+ _Wp __tmp = __b;
__b = __a;
__a = __tmp;
}
if (__b == 0)
- return __a;
+ return static_cast<_Rp>(__a);
__a %= __b; // Make both argument of the same size, and early result in the easy case.
if (__a == 0)
- return __b;
+ return static_cast<_Rp>(__b);
- _Tp __c = __a | __b;
+ _Wp __c = __a | __b;
int __shift = std::__countr_zero(__c);
__a >>= std::__countr_zero(__a);
do {
- _Tp __t = __b >> std::__countr_zero(__b);
+ _Wp __t = __b >> std::__countr_zero(__b);
if (__a > __t) {
__b = __a - __t;
__a = __t;
@@ -90,18 +90,7 @@ constexpr _LIBCPP_HIDDEN _Tp __gcd(_Tp __a, _Tp __b) {
__b = __t - __a;
}
} while (__b != 0);
- return __a << __shift;
-}
-
-template <class _Tp, class _Up>
-constexpr _LIBCPP_HIDE_FROM_ABI common_type_t<_Tp, _Up> gcd(_Tp __m, _Up __n) {
- static_assert(is_integral<_Tp>::value && is_integral<_Up>::value, "Arguments to gcd must be integer types");
- static_assert(!is_same<__remove_cv_t<_Tp>, bool>::value, "First argument to gcd cannot be bool");
- static_assert(!is_same<__remove_cv_t<_Up>, bool>::value, "Second argument to gcd cannot be bool");
- using _Rp = common_type_t<_Tp, _Up>;
- using _Wp = make_unsigned_t<_Rp>;
- return static_cast<_Rp>(
- std::__gcd(static_cast<_Wp>(__ct_abs<_Rp, _Tp>()(__m)), static_cast<_Wp>(__ct_abs<_Rp, _Up>()(__n))));
+ return static_cast<_Rp>(__a << __shift);
}
template <class _Tp, class _Up>
@@ -113,8 +102,8 @@ constexpr _LIBCPP_HIDE_FROM_ABI common_type_t<_Tp, _Up> lcm(_Tp __m, _Up __n) {
return 0;
using _Rp = common_type_t<_Tp, _Up>;
- _Rp __val1 = __ct_abs<_Rp, _Tp>()(__m) / std::gcd(__m, __n);
- _Rp __val2 = __ct_abs<_Rp, _Up>()(__n);
+ _Rp __val1 = std::__abs_in_type<_Rp>(__m) / std::gcd(__m, __n);
+ _Rp __val2 = std::__abs_in_type<_Rp>(__n);
_Rp __res;
[[maybe_unused]] bool __overflow = __builtin_mul_overflow(__val1, __val2, std::addressof(__res));
_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(!__overflow, "Overflow in lcm");
``````````
</details>
https://github.com/llvm/llvm-project/pull/173570
More information about the libcxx-commits
mailing list