[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

llvm-svn: 324596
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: 2b20304def44a0e3c4ab4ae90f50d4c4449ce03d
diff --git a/include/valarray b/include/valarray
index ee61238..b495ccf 100644
--- a/include/valarray
+++ b/include/valarray
@@ -1053,6 +1053,9 @@
     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 @@
     : __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 @@
         }
         catch (...)
         {
-            resize(0);
+            __clear();
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2805,7 +2825,7 @@
         }
         catch (...)
         {
-            resize(0);
+            __clear();
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2842,7 +2862,7 @@
         }
         catch (...)
         {
-            resize(0);
+            __clear();
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2870,7 +2890,7 @@
         }
         catch (...)
         {
-            resize(0);
+            __clear();
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2899,7 +2919,7 @@
         }
         catch (...)
         {
-            resize(0);
+            __clear();
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2928,7 +2948,7 @@
         }
         catch (...)
         {
-            resize(0);
+            __clear();
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2957,7 +2977,7 @@
         }
         catch (...)
         {
-            resize(0);
+            __clear();
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2968,7 +2988,24 @@
 inline
 valarray<_Tp>::~valarray()
 {
-    resize(0);
+    __clear();
+}
+
+template <class _Tp>
+valarray<_Tp>&
+valarray<_Tp>::__assign_range(const value_type* __f, const value_type* __l)
+{
+    size_t __n = __l - __f;
+    if (size() != __n)
+    {
+        __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>
@@ -2976,11 +3013,7 @@
 valarray<_Tp>::operator=(const valarray& __v)
 {
     if (this != &__v)
-    {
-        if (size() != __v.size())
-            resize(__v.size());
-        _VSTD::copy(__v.__begin_, __v.__end_, __begin_);
-    }
+        return __assign_range(__v.__begin_, __v.__end_);
     return *this;
 }
 
@@ -2991,7 +3024,7 @@
 valarray<_Tp>&
 valarray<_Tp>::operator=(valarray&& __v) _NOEXCEPT
 {
-    resize(0);
+    __clear();
     __begin_ = __v.__begin_;
     __end_ = __v.__end_;
     __v.__begin_ = nullptr;
@@ -3004,10 +3037,7 @@
 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 @@
 
 template <class _Tp>
 void
-valarray<_Tp>::resize(size_t __n, value_type __x)
+valarray<_Tp>::__clear()
 {
     if (__begin_ != nullptr)
     {
@@ -3689,6 +3719,13 @@
         _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 @@
         }
         catch (...)
         {
-            resize(0);
+            __clear();
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS