[libcxx-commits] [libcxx] [libc++][math] Implement C++23 (parts of) P0533: constexpr `std::div()` (PR #104633)

via libcxx-commits libcxx-commits at lists.llvm.org
Fri Aug 16 12:08:27 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: None (PaulXiCao)

<details>
<summary>Changes</summary>

This implements `std::div()`, `std::ldiv()`, `std::lldiv()` as `constexpr`. It is part of the C++23 [P0533](wg21.link/p0533).
The previous implementation dispatched down to the libc versions which are not `constexpr`.

---
Full diff: https://github.com/llvm/llvm-project/pull/104633.diff


2 Files Affected:

- (modified) libcxx/include/cstdlib (+40-3) 
- (modified) libcxx/test/std/language.support/support.runtime/cstdlib.pass.cpp (+52-19) 


``````````diff
diff --git a/libcxx/include/cstdlib b/libcxx/include/cstdlib
index c817fd8f4accda..8452cf164346ed 100644
--- a/libcxx/include/cstdlib
+++ b/libcxx/include/cstdlib
@@ -131,9 +131,6 @@ using ::qsort _LIBCPP_USING_IF_EXISTS;
 using ::abs _LIBCPP_USING_IF_EXISTS;
 using ::labs _LIBCPP_USING_IF_EXISTS;
 using ::llabs _LIBCPP_USING_IF_EXISTS;
-using ::div _LIBCPP_USING_IF_EXISTS;
-using ::ldiv _LIBCPP_USING_IF_EXISTS;
-using ::lldiv _LIBCPP_USING_IF_EXISTS;
 using ::mblen _LIBCPP_USING_IF_EXISTS;
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 using ::mbtowc _LIBCPP_USING_IF_EXISTS;
@@ -149,6 +146,46 @@ using ::quick_exit _LIBCPP_USING_IF_EXISTS;
 using ::aligned_alloc _LIBCPP_USING_IF_EXISTS;
 #endif
 
+#if _LIBCPP_STD_VER < 23
+// use non-constexpr versions from libc
+using ::div _LIBCPP_USING_IF_EXISTS;
+using ::ldiv _LIBCPP_USING_IF_EXISTS;
+using ::lldiv _LIBCPP_USING_IF_EXISTS;
+
+#else  // _LIBCPP_STD_VER >= 23
+
+template <class _Div_t, class _Int>
+_LIBCPP_HIDE_FROM_ABI constexpr _Div_t __div(_Int __x, _Int __y) {
+  _Div_t __d;
+  __d.quot = __x / __y;
+  __d.rem = __x % __y;
+  return __d;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI constexpr div_t div(int __x, int __y) {
+  return std::__div<std::div_t>(__x, __y);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI constexpr ldiv_t div(long __x, long __y) {
+  return std::__div<std::ldiv_t>(__x, __y);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI constexpr lldiv_t div(long long __x,
+                                                   long long __y) {
+  return std::__div<std::lldiv_t>(__x, __y);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI constexpr ldiv_t ldiv(long __x, long __y) {
+  return std::div(__x, __y);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI constexpr lldiv_t lldiv(long long __x,
+                                                     long long __y) {
+  return std::div(__x, __y);
+}
+
+#endif  // _LIBCPP_STD_VER
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP_CSTDLIB
diff --git a/libcxx/test/std/language.support/support.runtime/cstdlib.pass.cpp b/libcxx/test/std/language.support/support.runtime/cstdlib.pass.cpp
index 823417f8a418eb..cc2686d19a8f84 100644
--- a/libcxx/test/std/language.support/support.runtime/cstdlib.pass.cpp
+++ b/libcxx/test/std/language.support/support.runtime/cstdlib.pass.cpp
@@ -34,15 +34,6 @@
 #error RAND_MAX not defined
 #endif
 
-template <class TestType, class IntType>
-void test_div_struct() {
-    TestType obj;
-    static_assert(sizeof(obj) >= sizeof(IntType) * 2, ""); // >= to account for alignment.
-    static_assert((std::is_same<decltype(obj.quot), IntType>::value), "");
-    static_assert((std::is_same<decltype(obj.rem), IntType>::value), "");
-    ((void) obj);
-};
-
 template <class T, class = decltype(std::abs(std::declval<T>()))>
 std::true_type has_abs_imp(int);
 template <class T>
@@ -85,14 +76,62 @@ void test_abs() {
     assert(std::abs(-1.) == 1);
 }
 
+template <class TestType, class IntType>
+void test_div_struct() {
+  TestType obj;
+  static_assert(sizeof(obj) >= sizeof(IntType) * 2,
+                "");  // >= to account for alignment.
+  static_assert((std::is_same<decltype(obj.quot), IntType>::value), "");
+  static_assert((std::is_same<decltype(obj.rem), IntType>::value), "");
+  ((void)obj);
+}
+
+void test_div() {
+  {  // tests member types of std::div_t, etc.
+    test_div_struct<std::div_t, int>();
+    test_div_struct<std::ldiv_t, long>();
+    test_div_struct<std::lldiv_t, long long>();
+  }
+
+  {  // tests return type of std::div
+    // clang-format off
+    static_assert((std::is_same<decltype(std::div(  0,   0  )), std::div_t  >::value), "");
+    static_assert((std::is_same<decltype(std::div(  0L,  0L )), std::ldiv_t >::value), "");
+    static_assert((std::is_same<decltype(std::div(  0LL, 0LL)), std::lldiv_t>::value), "");
+    static_assert((std::is_same<decltype(std::ldiv( 0L,  0L )), std::ldiv_t >::value), "");
+    static_assert((std::is_same<decltype(std::lldiv(0LL, 0LL)), std::lldiv_t>::value), "");
+    // clang-format on
+  }
+
+  {  // check one basic input for correctness.
+    // (42 // 5 == 8) AND (42 % 5 == 2)
+    const auto check = [](const auto callable_div) -> void {
+      const auto div = callable_div(42, 5);
+      assert(div.quot == 8);
+      assert(div.rem == 2);
+
+#if _LIBCPP_STD_VER >= 23
+      constexpr auto div2 = callable_div(42, 5);
+      static_assert(div2.quot == 8);
+      static_assert(div2.rem == 2);
+#endif
+    };
+
+    // clang-format off
+    check([](int       n, int       k) { return std::div(  n, k); });
+    check([](long      n, long      k) { return std::div(  n, k); });
+    check([](long long n, long long k) { return std::div(  n, k); });
+    check([](long      n, long      k) { return std::ldiv( n, k); });
+    check([](long long n, long long k) { return std::lldiv(n, k); });
+    // clang-format on
+  }
+}
+
 int main(int, char**)
 {
     std::size_t s = 0;
     ((void)s);
     static_assert((std::is_same<std::size_t, decltype(sizeof(int))>::value), "");
-    test_div_struct<std::div_t, int>();
-    test_div_struct<std::ldiv_t, long>();
-    test_div_struct<std::lldiv_t, long long>();
     char** endptr = 0;
     static_assert((std::is_same<decltype(std::atof("")), double>::value), "");
     static_assert((std::is_same<decltype(std::atoi("")), int>::value), "");
@@ -131,11 +170,6 @@ int main(int, char**)
     static_assert((std::is_same<decltype(std::abs((long long)0)), long long>::value), "");
     static_assert((std::is_same<decltype(std::labs((long)0)), long>::value), "");
     static_assert((std::is_same<decltype(std::llabs((long long)0)), long long>::value), "");
-    static_assert((std::is_same<decltype(std::div(0,0)), std::div_t>::value), "");
-    static_assert((std::is_same<decltype(std::div(0L,0L)), std::ldiv_t>::value), "");
-    static_assert((std::is_same<decltype(std::div(0LL,0LL)), std::lldiv_t>::value), "");
-    static_assert((std::is_same<decltype(std::ldiv(0L,0L)), std::ldiv_t>::value), "");
-    static_assert((std::is_same<decltype(std::lldiv(0LL,0LL)), std::lldiv_t>::value), "");
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
     wchar_t* pw = 0;
     const wchar_t* pwc = 0;
@@ -148,6 +182,5 @@ int main(int, char**)
 #endif
 
     test_abs();
-
-    return 0;
+    test_div();
 }

``````````

</details>


https://github.com/llvm/llvm-project/pull/104633


More information about the libcxx-commits mailing list