From patchwork Fri Jul 6 14:16:07 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 940532 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-481130-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="YK3ODz+9"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41McGd37pGz9s4r for ; Sat, 7 Jul 2018 00:16:24 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=GY5oG8NHYGbaZqeM78XwQQsooj11/vAklzzFntuF/4AtbzbOXg/EU lpPdDMyLxhZ5DZ+oMAdusJB6ivolXlWz279t3nS6ztcVkQiVwXzRggRcBKBm8D35 K69WW+8VjUaHHgsZzhr5NCbtIaD5xa51mNndVnwnWXsePdRXv1bhzY= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=uORwpuvshPUfosK6h5UWzN5P74A=; b=YK3ODz+9bh6JnL6NEVzb TYpSTPrUFu2lB7zl1eofEaE0hnsC/x405SrVaxfBv+IKP/AoH1vT9bLWgqirKXZY n6KcM0/hXAdYq4+rEMcFEepTuCLc1x7AC0N6WRxvdJg9CWaP/c1mUnAa3Z5jjwrw +lHtqmIznyHeqTksnEuk0Sc= Received: (qmail 92798 invoked by alias); 6 Jul 2018 14:16:13 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 92772 invoked by uid 89); 6 Jul 2018 14:16:13 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-25.1 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, KAM_SHORT, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=altered, 1125, 2228 X-HELO: mx1.redhat.com Received: from mx3-rdu2.redhat.com (HELO mx1.redhat.com) (66.187.233.73) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 06 Jul 2018 14:16:09 +0000 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 5AE64401EF05; Fri, 6 Jul 2018 14:16:08 +0000 (UTC) Received: from localhost (unknown [10.33.36.63]) by smtp.corp.redhat.com (Postfix) with ESMTP id F223D2026D68; Fri, 6 Jul 2018 14:16:07 +0000 (UTC) Date: Fri, 6 Jul 2018 15:16:07 +0100 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH] PR libstdc++/84928 use std::move in algorithms Message-ID: <20180706141607.GA20403@redhat.com> MIME-Version: 1.0 Content-Disposition: inline X-Clacks-Overhead: GNU Terry Pratchett User-Agent: Mutt/1.9.2 (2017-12-15) P0616R0 altered the effects of the algorithms to use std::move on the accumulator values (resolving LWG 2055). This implements the change for C++2a, but retains the previous behaviour for older standards. * include/bits/stl_numeric.h (_GLIBCXX_MOVE_IF_20): Define macro to conditionally move, according to __cplusplus value. (accumulate, inner_product, partial_sum, adjacent_difference): Use _GLIBCXX_MOVE_IF_20. * testsuite/26_numerics/accumulate/lwg2055.cc: New test. * testsuite/26_numerics/adjacent_difference/lwg2055.cc: New test. * testsuite/26_numerics/inner_product/lwg2055.cc: New test. * testsuite/26_numerics/partial_sum/lwg2055.cc: New test. Tested powerpc64le-linux, committed to trunk. commit 1a98726ac77827d3978d694f33ef5183ff3c2def Author: Jonathan Wakely Date: Fri Jul 6 14:58:03 2018 +0100 PR libstdc++/84928 use std::move in algorithms P0616R0 altered the effects of the algorithms to use std::move on the accumulator values (resolving LWG 2055). This implements the change for C++2a, but retains the previous behaviour for older standards. * include/bits/stl_numeric.h (_GLIBCXX_MOVE_IF_20): Define macro to conditionally move, according to __cplusplus value. (accumulate, inner_product, partial_sum, adjacent_difference): Use _GLIBCXX_MOVE_IF_20. * testsuite/26_numerics/accumulate/lwg2055.cc: New test. * testsuite/26_numerics/adjacent_difference/lwg2055.cc: New test. * testsuite/26_numerics/inner_product/lwg2055.cc: New test. * testsuite/26_numerics/partial_sum/lwg2055.cc: New test. diff --git a/libstdc++-v3/include/bits/stl_numeric.h b/libstdc++-v3/include/bits/stl_numeric.h index dcc29fe065c..f4f6f9ef5ae 100644 --- a/libstdc++-v3/include/bits/stl_numeric.h +++ b/libstdc++-v3/include/bits/stl_numeric.h @@ -104,6 +104,14 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_ALGO +#if __cplusplus > 201703L +// _GLIBCXX_RESOLVE_LIB_DEFECTS +// DR 2055. std::move in std::accumulate and other algorithms +# define _GLIBCXX_MOVE_IF_20(_E) std::move(_E) +#else +# define _GLIBCXX_MOVE_IF_20(_E) _E +#endif + /** * @brief Accumulate values in a range. * @@ -124,7 +132,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO __glibcxx_requires_valid_range(__first, __last); for (; __first != __last; ++__first) - __init = __init + *__first; + __init = _GLIBCXX_MOVE_IF_20(__init) + *__first; return __init; } @@ -151,7 +159,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO __glibcxx_requires_valid_range(__first, __last); for (; __first != __last; ++__first) - __init = __binary_op(__init, *__first); + __init = __binary_op(_GLIBCXX_MOVE_IF_20(__init), *__first); return __init; } @@ -180,7 +188,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO __glibcxx_requires_valid_range(__first1, __last1); for (; __first1 != __last1; ++__first1, (void)++__first2) - __init = __init + (*__first1 * *__first2); + __init = _GLIBCXX_MOVE_IF_20(__init) + (*__first1 * *__first2); return __init; } @@ -214,7 +222,8 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO __glibcxx_requires_valid_range(__first1, __last1); for (; __first1 != __last1; ++__first1, (void)++__first2) - __init = __binary_op1(__init, __binary_op2(*__first1, *__first2)); + __init = __binary_op1(_GLIBCXX_MOVE_IF_20(__init), + __binary_op2(*__first1, *__first2)); return __init; } @@ -251,7 +260,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO *__result = __value; while (++__first != __last) { - __value = __value + *__first; + __value = _GLIBCXX_MOVE_IF_20(__value) + *__first; *++__result = __value; } return ++__result; @@ -292,7 +301,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO *__result = __value; while (++__first != __last) { - __value = __binary_op(__value, *__first); + __value = __binary_op(_GLIBCXX_MOVE_IF_20(__value), *__first); *++__result = __value; } return ++__result; @@ -332,7 +341,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO while (++__first != __last) { _ValueType __tmp = *__first; - *++__result = __tmp - __value; + *++__result = __tmp - _GLIBCXX_MOVE_IF_20(__value); __value = _GLIBCXX_MOVE(__tmp); } return ++__result; @@ -375,12 +384,14 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO while (++__first != __last) { _ValueType __tmp = *__first; - *++__result = __binary_op(__tmp, __value); + *++__result = __binary_op(__tmp, _GLIBCXX_MOVE_IF_20(__value)); __value = _GLIBCXX_MOVE(__tmp); } return ++__result; } +#undef _GLIBCXX_MOVE_IF_20 + _GLIBCXX_END_NAMESPACE_ALGO } // namespace std diff --git a/libstdc++-v3/testsuite/26_numerics/accumulate/lwg2055.cc b/libstdc++-v3/testsuite/26_numerics/accumulate/lwg2055.cc new file mode 100644 index 00000000000..1686f393e7e --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/accumulate/lwg2055.cc @@ -0,0 +1,93 @@ +// Copyright (C) 2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +struct Int +{ + Int(int v) : val(v) { } + + ~Int() = default; + + Int(const Int& x) : val(x.val), copies(x.copies), moved_from(x.moved_from) + { ++copies; } + + Int(Int&& x) : val(x.val), copies(x.copies), moved_from(x.moved_from) + { x.moved_from = true; } + + Int& operator=(const Int& x) + { + val = x.val; + copies = x.copies + 1; + moved_from = x.moved_from; + return *this; + } + + Int& operator=(Int&& x) + { + val = x.val; + copies = x.copies; + moved_from = x.moved_from; + x.moved_from = true; + return *this; + } + + int val = 0; + int copies = 0; + bool moved_from = false; +}; + +Int operator+(Int x, Int y) { x.val += y.val; return x; } + +struct Add +{ + Int operator()(Int x, Int y) const { x.val += y.val; return x; } +}; + +void +test01() +{ + Int i[] = { 0, 1, 2, 3, 4 }; + Int res = std::accumulate(std::begin(i), std::end(i), Int{0}); + VERIFY( res.copies == 0 ); + VERIFY( !res.moved_from ); + for (const auto& r : i) + VERIFY( !r.moved_from ); +} + +void +test02() +{ + Int i[] = { 0, 1, 2, 3, 4 }; + Int res = std::accumulate(std::begin(i), std::end(i), Int{0}, Add{}); + VERIFY( res.copies == 0 ); + VERIFY( !res.moved_from ); + for (const auto& r : i) + VERIFY( !r.moved_from ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/26_numerics/adjacent_difference/lwg2055.cc b/libstdc++-v3/testsuite/26_numerics/adjacent_difference/lwg2055.cc new file mode 100644 index 00000000000..766581a5d66 --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/adjacent_difference/lwg2055.cc @@ -0,0 +1,126 @@ +// Copyright (C) 2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +struct Int +{ + Int(int v) : val(v) { } + + ~Int() = default; + + Int(const Int& x) : val(x.val), copies(x.copies), moved_from(x.moved_from) + { ++copies; } + + Int(Int&& x) : val(x.val), copies(x.copies), moved_from(x.moved_from) + { x.moved_from = true; } + + Int& operator=(const Int& x) + { + val = x.val; + copies = x.copies + 1; + moved_from = x.moved_from; + return *this; + } + + Int& operator=(Int&& x) + { + val = x.val; + copies = x.copies; + moved_from = x.moved_from; + x.moved_from = true; + return *this; + } + + int val = 0; + int copies = 0; + bool moved_from = false; +}; + +Int operator-(Int x, Int y) { x.val -= y.val; return x; } + +struct Subtract +{ + Int operator()(Int x, Int y) const { x.val -= y.val; return x; } +}; + +void +test01() +{ + Int i[] = { 0, 1, 2, 3, 4 }; + std::adjacent_difference(std::begin(i), std::end(i), std::begin(i)); + for (const auto& r : i) + { + VERIFY( r.copies == 2 ); + VERIFY( !r.moved_from ); + } +} + +void +test02() +{ + Int i[] = { 0, 1, 2, 3, 4 }; + std::adjacent_difference(std::begin(i), std::end(i), std::begin(i), + Subtract{}); + for (const auto& r : i) + { + VERIFY( r.copies == 2 ); + VERIFY( !r.moved_from ); + } +} + +void +test03() +{ + Int i[] = { 0, 1, 2, 3, 4 }; + std::adjacent_difference(std::make_move_iterator(std::begin(i)), + std::make_move_iterator(std::end(i)), + std::begin(i)); + for (const auto& r : i) + { + VERIFY( r.copies == 1 ); + VERIFY( !r.moved_from ); + } +} + +void +test04() +{ + Int i[] = { 0, 1, 2, 3, 4 }; + std::adjacent_difference(std::make_move_iterator(std::begin(i)), + std::make_move_iterator(std::end(i)), + std::begin(i), Subtract{}); + for (const auto& r : i) + { + VERIFY( r.copies == 1 ); + VERIFY( !r.moved_from ); + } +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/26_numerics/inner_product/lwg2055.cc b/libstdc++-v3/testsuite/26_numerics/inner_product/lwg2055.cc new file mode 100644 index 00000000000..7fea5d09476 --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/inner_product/lwg2055.cc @@ -0,0 +1,107 @@ +// Copyright (C) 2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +struct Int +{ + Int(int v) : val(v) { } + + ~Int() = default; + + Int(const Int& x) : val(x.val), copies(x.copies), moved_from(x.moved_from) + { ++copies; } + + Int(Int&& x) : val(x.val), copies(x.copies), moved_from(x.moved_from) + { x.moved_from = true; } + + Int& operator=(const Int& x) + { + val = x.val; + copies = x.copies + 1; + moved_from = x.moved_from; + return *this; + } + + Int& operator=(Int&& x) + { + val = x.val; + copies = x.copies; + moved_from = x.moved_from; + x.moved_from = true; + return *this; + } + + int val = 0; + int copies = 0; + bool moved_from = false; +}; + +Int operator+(Int x, Int y) { x.val += y.val; return x; } +Int operator*(Int x, Int y) { x.val *= y.val; return x; } + +struct Add +{ + Int operator()(Int x, Int y) const { x.val += y.val; return x; } +}; + +struct Multiply +{ + Int operator()(Int x, Int y) const { x.val *= y.val; return x; } +}; + +void +test01() +{ + Int i[] = { 0, 1, 2, 3, 4 }; + Int j[] = { 5, 6, 7, 8, 9 }; + Int res = std::inner_product(std::begin(i), std::end(i), std::begin(j), + Int{0}); + VERIFY( res.copies == 0 ); + VERIFY( !res.moved_from ); + for (const auto& r : i) + VERIFY( !r.moved_from ); + for (const auto& r : j) + VERIFY( !r.moved_from ); +} + +void +test02() +{ + Int i[] = { 0, 1, 2, 3, 4 }; + Int j[] = { 5, 6, 7, 8, 9 }; + Int res = std::inner_product(std::begin(i), std::end(i), std::begin(j), + Int{0}, Add{}, Multiply{}); + VERIFY( res.copies == 0 ); + VERIFY( !res.moved_from ); + for (const auto& r : i) + VERIFY( !r.moved_from ); + for (const auto& r : j) + VERIFY( !r.moved_from ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/26_numerics/partial_sum/lwg2055.cc b/libstdc++-v3/testsuite/26_numerics/partial_sum/lwg2055.cc new file mode 100644 index 00000000000..871ddaf4c5e --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/partial_sum/lwg2055.cc @@ -0,0 +1,125 @@ +// Copyright (C) 2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +struct Int +{ + Int(int v) : val(v) { } + + ~Int() = default; + + Int(const Int& x) : val(x.val), copies(x.copies), moved_from(x.moved_from) + { ++copies; } + + Int(Int&& x) : val(x.val), copies(x.copies), moved_from(x.moved_from) + { x.moved_from = true; } + + Int& operator=(const Int& x) + { + val = x.val; + copies = x.copies + 1; + moved_from = x.moved_from; + return *this; + } + + Int& operator=(Int&& x) + { + val = x.val; + copies = x.copies; + moved_from = x.moved_from; + x.moved_from = true; + return *this; + } + + int val = 0; + int copies = 0; + bool moved_from = false; +}; + +Int operator+(Int x, Int y) { x.val += y.val; return x; } + +struct Add +{ + Int operator()(Int x, Int y) const { x.val += y.val; return x; } +}; + +void +test01() +{ + Int i[] = { 0, 1, 2, 3, 4 }; + std::partial_sum(std::begin(i), std::end(i), std::begin(i)); + for (const auto& r : i) + { + VERIFY( r.copies == 2 ); + VERIFY( !r.moved_from ); + } +} + +void +test02() +{ + Int i[] = { 0, 1, 2, 3, 4 }; + std::partial_sum(std::begin(i), std::end(i), std::begin(i), Add{}); + for (const auto& r : i) + { + VERIFY( r.copies == 2 ); + VERIFY( !r.moved_from ); + } +} + +void +test03() +{ + Int i[] = { 0, 1, 2, 3, 4 }; + std::partial_sum(std::make_move_iterator(std::begin(i)), + std::make_move_iterator(std::end(i)), + std::begin(i)); + for (const auto& r : i) + { + VERIFY( r.copies == 1 ); + VERIFY( !r.moved_from ); + } +} + +void +test04() +{ + Int i[] = { 0, 1, 2, 3, 4 }; + std::partial_sum(std::make_move_iterator(std::begin(i)), + std::make_move_iterator(std::end(i)), + std::begin(i), Add{}); + for (const auto& r : i) + { + VERIFY( r.copies == 1 ); + VERIFY( !r.moved_from ); + } +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +}