[libcxx-commits] [libcxx] [RFC][libc++] Fixes valarray proxy type operations. (PR #76528)
Mark de Wever via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Dec 28 11:34:05 PST 2023
https://github.com/mordante created https://github.com/llvm/llvm-project/pull/76528
The valarray<>::operator[](...) const functions return proxy objects. The valarray<>::operator[](...) functions return valarray objects.
However the standard allows functions return valarray object to return custom proxy objects. Libc++ returns __val_expr proxies. Functions taking a valarray object should work with the custom proxies. Therefore several operations have a custom proxy overload instead of valarray overloads.
Libc++ doesn't specify a valarray overload. This is an issue with the standard proxy types; these can implicitly be converted to a valarray.
The solution seems to be adding valarray overloads for all functions that take a custom proxy.
Fixes: https://github.com/llvm/llvm-project/issues/21320
>From 26676bc2144ebcdbe53e4bf5a2f714e1f22e1aa3 Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Thu, 28 Dec 2023 20:23:00 +0100
Subject: [PATCH] [RFC][libc++] Fixes valarray proxy type operations.
The valarray<>::operator[](...) const functions return proxy objects.
The valarray<>::operator[](...) functions return valarray objects.
However the standard allows functions return valarray object to return
custom proxy objects. Libc++ returns __val_expr proxies. Functions taking
a valarray object should work with the custom proxies. Therefore several
operations have a custom proxy overload instead of valarray overloads.
Libc++ doesn't specify a valarray overload. This is an issue with the
standard proxy types; these can implicitly be converted to a valarray.
The solution seems to be adding valarray overloads for all functions that
take a custom proxy.
Fixes: https://github.com/llvm/llvm-project/issues/21320
---
libcxx/include/valarray | 13 ++++
.../valarray.cassign/and_valarray.pass.cpp | 76 ++++++++++++++-----
2 files changed, 72 insertions(+), 17 deletions(-)
diff --git a/libcxx/include/valarray b/libcxx/include/valarray
index fb618684952128..221b7cc2eff691 100644
--- a/libcxx/include/valarray
+++ b/libcxx/include/valarray
@@ -819,6 +819,19 @@ public:
_LIBCPP_HIDE_FROM_ABI valarray& operator<<=(const value_type& __x);
_LIBCPP_HIDE_FROM_ABI valarray& operator>>=(const value_type& __x);
+ // The valarray overloads are needed for the types with an implicit
+ // conversion to valarray. For example slice_array.
+ _LIBCPP_HIDE_FROM_ABI valarray& operator*=(const valarray& __v) { return operator*= <valarray>(__v); }
+ _LIBCPP_HIDE_FROM_ABI valarray& operator/=(const valarray& __v) { return operator/= <valarray>(__v); }
+ _LIBCPP_HIDE_FROM_ABI valarray& operator%=(const valarray& __v) { return operator%= <valarray>(__v); }
+ _LIBCPP_HIDE_FROM_ABI valarray& operator+=(const valarray& __v) { return operator+= <valarray>(__v); }
+ _LIBCPP_HIDE_FROM_ABI valarray& operator-=(const valarray& __v) { return operator-= <valarray>(__v); }
+ _LIBCPP_HIDE_FROM_ABI valarray& operator^=(const valarray& __v) { return operator^= <valarray>(__v); }
+ _LIBCPP_HIDE_FROM_ABI valarray& operator&=(const valarray& __v) { return operator&= <valarray>(__v); }
+ _LIBCPP_HIDE_FROM_ABI valarray& operator|=(const valarray& __v) { return operator|= <valarray>(__v); }
+ _LIBCPP_HIDE_FROM_ABI valarray& operator<<=(const valarray& __v) { return operator<<= <valarray>(__v); }
+ _LIBCPP_HIDE_FROM_ABI valarray& operator>>=(const valarray& __v) { return operator>>= <valarray>(__v); }
+
template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI valarray& operator*=(const _Expr& __v);
diff --git a/libcxx/test/std/numerics/numarray/template.valarray/valarray.cassign/and_valarray.pass.cpp b/libcxx/test/std/numerics/numarray/template.valarray/valarray.cassign/and_valarray.pass.cpp
index 5824d5344bfd8d..e5514f361c41a3 100644
--- a/libcxx/test/std/numerics/numarray/template.valarray/valarray.cassign/and_valarray.pass.cpp
+++ b/libcxx/test/std/numerics/numarray/template.valarray/valarray.cassign/and_valarray.pass.cpp
@@ -12,29 +12,71 @@
// valarray& operator&=(const valarray& v);
+// [valarray.syn]/3
+// Any function returning a valarray<T> is permitted to return an object of
+// another type, provided all the const member functions of valarray<T> are
+// also applicable to this type.
+//
+// Libc++ uses this and returns __val_expr<_Expr> for several operations.
+//
+// The const overloads of
+// valarray::operator[](...) const
+// return propxy objects. These proxies are implicitly convertable to
+// std::valarray.
+//
+// Validate the function works for valarray, the proxies, and __val_expr.
+
#include <valarray>
#include <cassert>
#include <cstddef>
#include "test_macros.h"
-int main(int, char**)
-{
- {
- typedef int T;
- T a1[] = {1, 2, 3, 4, 5};
- T a2[] = {6, 7, 8, 9, 10};
- T a3[] = {0, 2, 0, 0, 0};
- const unsigned N = sizeof(a1)/sizeof(a1[0]);
- std::valarray<T> v1(a1, N);
- std::valarray<T> v2(a2, N);
- std::valarray<T> v3(a3, N);
- v1 &= v2;
- assert(v1.size() == v2.size());
- assert(v1.size() == v3.size());
- for (std::size_t i = 0; i < v1.size(); ++i)
- assert(v1[i] == v3[i]);
- }
+template <class A>
+void test(const A& rhs) {
+ int input[] = {1, 2, 3, 4, 5};
+ int expected[] = {0, 2, 0, 0, 0};
+ const unsigned N = sizeof(input) / sizeof(input[0]);
+ std::valarray<int> value(input, N);
+
+ value &= rhs;
+
+ assert(value.size() == N);
+ for (std::size_t i = 0; i < value.size(); ++i)
+ assert(value[i] == expected[i]);
+}
+
+int main(int, char**) {
+ int input[] = {6, 7, 8, 9, 10};
+ const unsigned N = sizeof(input) / sizeof(input[0]);
+
+ std::valarray<bool> mask(true, N);
+ std::size_t indices[] = {0, 1, 2, 3, 4};
+ std::valarray<std::size_t> indirect(indices, N);
+
+ std::valarray<int> zero(0, N);
+
+ {
+ std::valarray<int> value(input, N);
+
+ test(value);
+ test(value[std::slice(0, N, 1)]);
+ test(value[std::gslice(0, std::valarray<std::size_t>(N, 1), std::valarray<std::size_t>(1, 1))]);
+ test(value[mask]);
+ test(value[indirect]);
+ test(value + zero);
+ }
+
+ {
+ const std::valarray<int> value(input, N);
+
+ test(value);
+ test(value[std::slice(0, N, 1)]);
+ test(value[std::gslice(0, std::valarray<std::size_t>(N, 1), std::valarray<std::size_t>(1, 1))]);
+ test(value[mask]);
+ test(value[indirect]);
+ test(value + zero);
+ }
return 0;
}
More information about the libcxx-commits
mailing list