[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:06:09 PDT 2024
https://github.com/PaulXiCao created https://github.com/llvm/llvm-project/pull/104633
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`.
>From 9839eb1fbefbfd3c7519f2db605bd1fc4169b629 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Thu, 15 Aug 2024 21:31:34 +0200
Subject: [PATCH 1/5] group std::div(), std::div_t tests into one test function
---
.../support.runtime/cstdlib.pass.cpp | 48 +++++++++++--------
1 file changed, 29 insertions(+), 19 deletions(-)
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..4f38fda86b2d3a 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,39 @@ 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
+ }
+}
+
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 +147,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 +159,5 @@ int main(int, char**)
#endif
test_abs();
-
- return 0;
+ test_div();
}
>From d231ef8b4835212063e44d27d8a8d4735cfdb1d7 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Thu, 15 Aug 2024 21:33:03 +0200
Subject: [PATCH 2/5] add test for simple input
---
.../support.runtime/cstdlib.pass.cpp | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
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 4f38fda86b2d3a..32410cba1fb285 100644
--- a/libcxx/test/std/language.support/support.runtime/cstdlib.pass.cpp
+++ b/libcxx/test/std/language.support/support.runtime/cstdlib.pass.cpp
@@ -102,6 +102,24 @@ void test_div() {
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 {
+ // fixme: change to static_assert() when constexpr-ready
+ const auto div = callable_div(42, 5);
+ assert(div.quot == 8);
+ assert(div.rem == 2);
+ };
+
+ // 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**)
>From 258e3dc862adaffe2758a441fd6eb3a2917977d5 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 16 Aug 2024 14:37:38 +0200
Subject: [PATCH 3/5] std::div(int,int) constexpr
---
libcxx/include/cstdlib | 26 ++++++++++++++++---
.../support.runtime/cstdlib.pass.cpp | 19 +++++++++-----
2 files changed, 35 insertions(+), 10 deletions(-)
diff --git a/libcxx/include/cstdlib b/libcxx/include/cstdlib
index c817fd8f4accda..24e36b3461d04c 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,29 @@ using ::quick_exit _LIBCPP_USING_IF_EXISTS;
using ::aligned_alloc _LIBCPP_USING_IF_EXISTS;
#endif
+using ::ldiv _LIBCPP_USING_IF_EXISTS;
+using ::lldiv _LIBCPP_USING_IF_EXISTS;
+
+#if _LIBCPP_STD_VER < 23
+// use non-constexpr versions from libc
+using ::div _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);
+}
+
+#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 32410cba1fb285..236002efe9f158 100644
--- a/libcxx/test/std/language.support/support.runtime/cstdlib.pass.cpp
+++ b/libcxx/test/std/language.support/support.runtime/cstdlib.pass.cpp
@@ -96,8 +96,8 @@ void test_div() {
{ // 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::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
@@ -106,18 +106,23 @@ void test_div() {
{ // check one basic input for correctness.
// (42 // 5 == 8) AND (42 % 5 == 2)
const auto check = [](const auto callable_div) -> void {
- // fixme: change to static_assert() when constexpr-ready
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); });
+ // 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
}
}
>From 1c11ce348553188f1215dfeda6fa03d9dca427b3 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 16 Aug 2024 14:42:09 +0200
Subject: [PATCH 4/5] std::div() for long, and long long as constexpr
---
libcxx/include/cstdlib | 9 +++++++++
.../language.support/support.runtime/cstdlib.pass.cpp | 8 ++++----
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/libcxx/include/cstdlib b/libcxx/include/cstdlib
index 24e36b3461d04c..b12c28894f0a86 100644
--- a/libcxx/include/cstdlib
+++ b/libcxx/include/cstdlib
@@ -167,6 +167,15 @@ 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);
+}
+
#endif // _LIBCPP_STD_VER
_LIBCPP_END_NAMESPACE_STD
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 236002efe9f158..a7ff6be1b240b8 100644
--- a/libcxx/test/std/language.support/support.runtime/cstdlib.pass.cpp
+++ b/libcxx/test/std/language.support/support.runtime/cstdlib.pass.cpp
@@ -96,8 +96,8 @@ void test_div() {
{ // 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::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
@@ -119,8 +119,8 @@ void test_div() {
// 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::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
>From 067b03ac48e4f787ab8ab34a95879e76483a72fb Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 16 Aug 2024 20:57:00 +0200
Subject: [PATCH 5/5] constexpr std::ldiv, std::lldiv
---
libcxx/include/cstdlib | 14 +++++++++++---
.../support.runtime/cstdlib.pass.cpp | 4 ++--
2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/libcxx/include/cstdlib b/libcxx/include/cstdlib
index b12c28894f0a86..8452cf164346ed 100644
--- a/libcxx/include/cstdlib
+++ b/libcxx/include/cstdlib
@@ -146,12 +146,11 @@ using ::quick_exit _LIBCPP_USING_IF_EXISTS;
using ::aligned_alloc _LIBCPP_USING_IF_EXISTS;
#endif
-using ::ldiv _LIBCPP_USING_IF_EXISTS;
-using ::lldiv _LIBCPP_USING_IF_EXISTS;
-
#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
@@ -176,6 +175,15 @@ inline _LIBCPP_HIDE_FROM_ABI constexpr lldiv_t div(long long __x,
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
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 a7ff6be1b240b8..cc2686d19a8f84 100644
--- a/libcxx/test/std/language.support/support.runtime/cstdlib.pass.cpp
+++ b/libcxx/test/std/language.support/support.runtime/cstdlib.pass.cpp
@@ -121,8 +121,8 @@ void test_div() {
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); });
+ 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
}
}
More information about the libcxx-commits
mailing list