[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