diff --git a/libcxx/include/tuple b/libcxx/include/tuple --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -193,6 +193,14 @@ swap(__x.get(), __y.get()); } +#if _LIBCPP_STD_VER > 20 +template +inline _LIBCPP_HIDE_FROM_ABI constexpr +void swap(const __tuple_leaf<_Ip, _Hp, _Ep>& __lhs, const __tuple_leaf<_Ip, _Hp, _Ep>& __rhs) { + swap(__lhs.get(), __rhs.get()); +} +#endif + template class __tuple_leaf { @@ -281,6 +289,14 @@ return 0; } +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI constexpr + int swap(const __tuple_leaf& __rhs) const noexcept(is_nothrow_swappable_v<__tuple_leaf>) { + _VSTD::swap(*this, __rhs); + return 0; + } +#endif + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 _Hp& get() _NOEXCEPT {return __value_;} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const _Hp& get() const _NOEXCEPT {return __value_;} }; @@ -347,6 +363,13 @@ return 0; } +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI constexpr + void swap(const __tuple_leaf& __rhs) const noexcept(is_nothrow_swappable_v<__tuple_leaf>) { + _VSTD::swap(*this, __rhs); + } +#endif + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 _Hp& get() _NOEXCEPT {return static_cast<_Hp&>(*this);} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const _Hp& get() const _NOEXCEPT {return static_cast(*this);} }; @@ -437,6 +460,13 @@ { _VSTD::__swallow(__tuple_leaf<_Indx, _Tp>::swap(static_cast<__tuple_leaf<_Indx, _Tp>&>(__t))...); } + +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI constexpr + void swap(const __tuple_impl& __rhs) const noexcept(__all...>::value) { + _VSTD::__swallow(__tuple_leaf<_Indx, _Tp>::swap(static_cast&>(__rhs))...); + } +#endif }; template @@ -1079,6 +1109,13 @@ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 void swap(tuple& __t) _NOEXCEPT_(__all<__is_nothrow_swappable<_Tp>::value...>::value) {__base_.swap(__t.__base_);} + +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI constexpr + void swap(const tuple& __rhs) const noexcept(__all...>::value) { + __base_.swap(__rhs.__base_); + } +#endif }; template <> @@ -1101,6 +1138,9 @@ tuple(allocator_arg_t, const _Alloc&, array<_Up, 0>) _NOEXCEPT {} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 void swap(tuple&) _NOEXCEPT {} +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI constexpr void swap(const tuple&) const noexcept {} +#endif }; #if _LIBCPP_STD_VER >= 17 @@ -1127,6 +1167,15 @@ _NOEXCEPT_(__all<__is_nothrow_swappable<_Tp>::value...>::value) {__t.swap(__u);} +#if _LIBCPP_STD_VER > 20 +template +_LIBCPP_HIDE_FROM_ABI constexpr +enable_if_t<__all...>::value, void> +swap(const tuple<_Tp...>& __lhs, const tuple<_Tp...>& __rhs) { + __lhs.swap(__rhs); +} +#endif + // get template diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.special/non_member_swap_const.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.special/non_member_swap_const.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.special/non_member_swap_const.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template class tuple; + +// template +// void swap(const tuple& x, const tuple& y); + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include + +struct ConstSwappable { + mutable int i; +}; + +constexpr void swap(const ConstSwappable& lhs, const ConstSwappable& rhs) { std::swap(lhs.i, rhs.i); } + +int main(int, char**) { + { + typedef std::tuple<> T; + const T t0; + T t1; + swap(t0, t1); + } + { + typedef std::tuple T; + T t0({0}); + const T t1({1}); + swap(t0, t1); + assert(std::get<0>(t0).i == 1); + assert(std::get<0>(t1).i == 0); + } + { + typedef std::tuple T; + const T t0({0}, {1}); + const T t1({2}, {3}); + swap(t0, t1); + assert(std::get<0>(t0).i == 2); + assert(std::get<1>(t0).i == 3); + assert(std::get<0>(t1).i == 0); + assert(std::get<1>(t1).i == 1); + } + { + typedef std::tuple T; + const T t0({0}, {1}, {2}); + const T t1({3}, {4}, {5}); + swap(t0, t1); + assert(std::get<0>(t0).i == 3); + assert(std::get<1>(t0).i == 4); + assert(std::get<2>(t0).i == 5); + assert(std::get<0>(t1).i == 0); + assert(std::get<1>(t1).i == 1); + assert(std::get<2>(t1).i == 2); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.swap/member_swap_const.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.swap/member_swap_const.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.swap/member_swap_const.pass.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// void swap(const tuple& rhs); + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include + +struct ConstSwappable { + mutable int i; +}; + +constexpr void swap(const ConstSwappable& lhs, const ConstSwappable& rhs) { std::swap(lhs.i, rhs.i); } + +constexpr bool test() { + { + typedef std::tuple T; + const T t0({0}); + T t1({1}); + t0.swap(t1); + assert(std::get<0>(t0).i == 1); + assert(std::get<0>(t1).i == 0); + } + { + typedef std::tuple T; + const T t0({0}, {1}); + const T t1({2}, {3}); + t0.swap(t1); + assert(std::get<0>(t0).i == 2); + assert(std::get<1>(t0).i == 3); + assert(std::get<0>(t1).i == 0); + assert(std::get<1>(t1).i == 1); + } + { + typedef std::tuple T; + const T t0({0}, {1}, {2}); + const T t1({3}, {4}, {5}); + t0.swap(t1); + assert(std::get<0>(t0).i == 3); + assert(std::get<1>(t0).i == 4); + assert(std::get<2>(t0).i == 5); + assert(std::get<0>(t1).i == 0); + assert(std::get<1>(t1).i == 1); + assert(std::get<2>(t1).i == 2); + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +}