[libcxx] r324596 - [libcxx] Avoid spurious construction of valarray elements

Mikhail Maltsev via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 8 03:33:48 PST 2018


Author: miyuki
Date: Thu Feb  8 03:33:48 2018
New Revision: 324596

URL: http://llvm.org/viewvc/llvm-project?rev=324596&view=rev
Log:
[libcxx] Avoid spurious construction of valarray elements

Summary:
Currently libc++ implements some operations on valarray by using the
resize method. This method has a parameter with a default value.
Because of this, valarray may spuriously construct and destruct
objects of valarray's element type.
    
This patch fixes this issue and adds corresponding test cases.


Reviewers: EricWF, mclow.lists

Reviewed By: mclow.lists

Subscribers: rogfer01, cfe-commits

Differential Revision: https://reviews.llvm.org/D41992

Modified:
    libcxx/trunk/include/valarray
    libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.assign/copy_assign.pass.cpp
    libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.assign/initializer_list_assign.pass.cpp
    libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.cons/default.pass.cpp
    libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.cons/size.pass.cpp

Modified: libcxx/trunk/include/valarray
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/valarray?rev=324596&r1=324595&r2=324596&view=diff
==============================================================================
--- libcxx/trunk/include/valarray (original)
+++ libcxx/trunk/include/valarray Thu Feb  8 03:33:48 2018
@@ -1053,6 +1053,9 @@ private:
     friend
     const _Up*
     end(const valarray<_Up>& __v);
+
+    void __clear();
+    valarray& __assign_range(const value_type* __f, const value_type* __l);
 };
 
 _LIBCPP_EXTERN_TEMPLATE(_LIBCPP_FUNC_VIS valarray<size_t>::valarray(size_t))
@@ -2750,7 +2753,24 @@ valarray<_Tp>::valarray(size_t __n)
     : __begin_(0),
       __end_(0)
 {
-    resize(__n);
+    if (__n)
+    {
+        __begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type)));
+#ifndef _LIBCPP_NO_EXCEPTIONS
+        try
+        {
+#endif  // _LIBCPP_NO_EXCEPTIONS
+            for (; __n; --__n, ++__end_)
+                ::new (__end_) value_type();
+#ifndef _LIBCPP_NO_EXCEPTIONS
+        }
+        catch (...)
+        {
+            __clear();
+            throw;
+        }
+#endif  // _LIBCPP_NO_EXCEPTIONS
+    }
 }
 
 template <class _Tp>
@@ -2780,7 +2800,7 @@ valarray<_Tp>::valarray(const value_type
         }
         catch (...)
         {
-            resize(0);
+            __clear();
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2805,7 +2825,7 @@ valarray<_Tp>::valarray(const valarray&
         }
         catch (...)
         {
-            resize(0);
+            __clear();
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2842,7 +2862,7 @@ valarray<_Tp>::valarray(initializer_list
         }
         catch (...)
         {
-            resize(0);
+            __clear();
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2870,7 +2890,7 @@ valarray<_Tp>::valarray(const slice_arra
         }
         catch (...)
         {
-            resize(0);
+            __clear();
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2899,7 +2919,7 @@ valarray<_Tp>::valarray(const gslice_arr
         }
         catch (...)
         {
-            resize(0);
+            __clear();
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2928,7 +2948,7 @@ valarray<_Tp>::valarray(const mask_array
         }
         catch (...)
         {
-            resize(0);
+            __clear();
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2957,7 +2977,7 @@ valarray<_Tp>::valarray(const indirect_a
         }
         catch (...)
         {
-            resize(0);
+            __clear();
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2968,22 +2988,35 @@ template <class _Tp>
 inline
 valarray<_Tp>::~valarray()
 {
-    resize(0);
+    __clear();
 }
 
 template <class _Tp>
 valarray<_Tp>&
-valarray<_Tp>::operator=(const valarray& __v)
+valarray<_Tp>::__assign_range(const value_type* __f, const value_type* __l)
 {
-    if (this != &__v)
+    size_t __n = __l - __f;
+    if (size() != __n)
     {
-        if (size() != __v.size())
-            resize(__v.size());
-        _VSTD::copy(__v.__begin_, __v.__end_, __begin_);
+        __clear();
+        __begin_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type)));
+        __end_ = __begin_ + __n;
+        _VSTD::uninitialized_copy(__f, __l, __begin_);
+    } else {
+        _VSTD::copy(__f, __l, __begin_);
     }
     return *this;
 }
 
+template <class _Tp>
+valarray<_Tp>&
+valarray<_Tp>::operator=(const valarray& __v)
+{
+    if (this != &__v)
+        return __assign_range(__v.__begin_, __v.__end_);
+    return *this;
+}
+
 #ifndef _LIBCPP_CXX03_LANG
 
 template <class _Tp>
@@ -2991,7 +3024,7 @@ inline
 valarray<_Tp>&
 valarray<_Tp>::operator=(valarray&& __v) _NOEXCEPT
 {
-    resize(0);
+    __clear();
     __begin_ = __v.__begin_;
     __end_ = __v.__end_;
     __v.__begin_ = nullptr;
@@ -3004,10 +3037,7 @@ inline
 valarray<_Tp>&
 valarray<_Tp>::operator=(initializer_list<value_type> __il)
 {
-    if (size() != __il.size())
-        resize(__il.size());
-    _VSTD::copy(__il.begin(), __il.end(), __begin_);
-    return *this;
+    return __assign_range(__il.begin(), __il.end());
 }
 
 #endif  // _LIBCPP_CXX03_LANG
@@ -3680,7 +3710,7 @@ valarray<_Tp>::apply(value_type __f(cons
 
 template <class _Tp>
 void
-valarray<_Tp>::resize(size_t __n, value_type __x)
+valarray<_Tp>::__clear()
 {
     if (__begin_ != nullptr)
     {
@@ -3689,6 +3719,13 @@ valarray<_Tp>::resize(size_t __n, value_
         _VSTD::__libcpp_deallocate(__begin_);
         __begin_ = __end_ = nullptr;
     }
+}
+
+template <class _Tp>
+void
+valarray<_Tp>::resize(size_t __n, value_type __x)
+{
+    __clear();
     if (__n)
     {
         __begin_ = __end_ = static_cast<value_type*>(_VSTD::__allocate(__n * sizeof(value_type)));
@@ -3702,7 +3739,7 @@ valarray<_Tp>::resize(size_t __n, value_
         }
         catch (...)
         {
-            resize(0);
+            __clear();
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS

Modified: libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.assign/copy_assign.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.assign/copy_assign.pass.cpp?rev=324596&r1=324595&r2=324596&view=diff
==============================================================================
--- libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.assign/copy_assign.pass.cpp (original)
+++ libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.assign/copy_assign.pass.cpp Thu Feb  8 03:33:48 2018
@@ -17,6 +17,21 @@
 #include <cassert>
 #include <cstddef>
 
+struct S
+{
+    S() : x_(0) { default_ctor_called = true; }
+    S(int x) : x_(x) {}
+    int x_;
+    static bool default_ctor_called;
+};
+
+bool S::default_ctor_called = false;
+
+bool operator==(const S& lhs, const S& rhs)
+{
+    return lhs.x_ == rhs.x_;
+}
+
 int main()
 {
     {
@@ -56,4 +71,16 @@ int main()
                 assert(v2[i][j] == v[i][j]);
         }
     }
+    {
+        typedef S T;
+        T a[] = {T(1), T(2), T(3), T(4), T(5)};
+        const unsigned N = sizeof(a)/sizeof(a[0]);
+        std::valarray<T> v(a, N);
+        std::valarray<T> v2;
+        v2 = v;
+        assert(v2.size() == v.size());
+        for (std::size_t i = 0; i < v2.size(); ++i)
+            assert(v2[i] == v[i]);
+        assert(!S::default_ctor_called);
+    }
 }

Modified: libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.assign/initializer_list_assign.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.assign/initializer_list_assign.pass.cpp?rev=324596&r1=324595&r2=324596&view=diff
==============================================================================
--- libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.assign/initializer_list_assign.pass.cpp (original)
+++ libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.assign/initializer_list_assign.pass.cpp Thu Feb  8 03:33:48 2018
@@ -19,6 +19,21 @@
 #include <cassert>
 #include <cstddef>
 
+struct S
+{
+    S() : x_(0) { default_ctor_called = true; }
+    S(int x) : x_(x) {}
+    int x_;
+    static bool default_ctor_called;
+};
+
+bool S::default_ctor_called = false;
+
+bool operator==(const S& lhs, const S& rhs)
+{
+    return lhs.x_ == rhs.x_;
+}
+
 int main()
 {
     {
@@ -55,4 +70,15 @@ int main()
                 assert(v2[i][j] == a[i][j]);
         }
     }
+    {
+        typedef S T;
+        T a[] = {T(1), T(2), T(3), T(4), T(5)};
+        const unsigned N = sizeof(a)/sizeof(a[0]);
+        std::valarray<T> v2;
+        v2 = {T(1), T(2), T(3), T(4), T(5)};
+        assert(v2.size() == N);
+        for (std::size_t i = 0; i < v2.size(); ++i)
+            assert(v2[i] == a[i]);
+        assert(!S::default_ctor_called);
+    }
 }

Modified: libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.cons/default.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.cons/default.pass.cpp?rev=324596&r1=324595&r2=324596&view=diff
==============================================================================
--- libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.cons/default.pass.cpp (original)
+++ libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.cons/default.pass.cpp Thu Feb  8 03:33:48 2018
@@ -16,6 +16,13 @@
 #include <valarray>
 #include <cassert>
 
+struct S {
+    S() { ctor_called = true; }
+    static bool ctor_called;
+};
+
+bool S::ctor_called = false;
+
 int main()
 {
     {
@@ -34,4 +41,9 @@ int main()
         std::valarray<std::valarray<double> > v;
         assert(v.size() == 0);
     }
+    {
+        std::valarray<S> v;
+        assert(v.size() == 0);
+        assert(!S::ctor_called);
+    }
 }

Modified: libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.cons/size.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.cons/size.pass.cpp?rev=324596&r1=324595&r2=324596&view=diff
==============================================================================
--- libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.cons/size.pass.cpp (original)
+++ libcxx/trunk/test/std/numerics/numarray/template.valarray/valarray.cons/size.pass.cpp Thu Feb  8 03:33:48 2018
@@ -16,6 +16,15 @@
 #include <valarray>
 #include <cassert>
 
+struct S {
+    S() : x(1) {}
+    ~S() { ++cnt_dtor; }
+    int x;
+    static size_t cnt_dtor;
+};
+
+size_t S::cnt_dtor = 0;
+
 int main()
 {
     {
@@ -36,4 +45,11 @@ int main()
         for (int i = 0; i < 100; ++i)
             assert(v[i].size() == 0);
     }
+    {
+        std::valarray<S> v(100);
+        assert(v.size() == 100);
+        for (int i = 0; i < 100; ++i)
+            assert(v[i].x == 1);
+    }
+    assert(S::cnt_dtor == 100);
 }




More information about the cfe-commits mailing list