diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -51,6 +51,7 @@ __ranges/empty_view.h __ranges/enable_borrowed_range.h __ranges/enable_view.h + __ranges/non_propagating_cache.h __ranges/view_interface.h __ranges/ref_view.h __ranges/size.h diff --git a/libcxx/include/__ranges/non_propagating_cache.h b/libcxx/include/__ranges/non_propagating_cache.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/non_propagating_cache.h @@ -0,0 +1,74 @@ +// -*- C++ -*- +//===--------------------- __ranges/concepts.h ----------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +#ifndef _LIBCPP___RANGES_NON_PROPAGATING_CACHE_H +#define _LIBCPP___RANGES_NON_PROPAGATING_CACHE_H + +#include <__config> +#include <__iterator/concepts.h> // indirectly_readable +#include <__iterator/iterator_traits.h> // iter_reference_t +#include // constructible_from +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +// clang-format off + +#if !defined(_LIBCPP_HAS_NO_RANGES) + +namespace ranges { + template + requires is_object_v<_Tp> + struct __non_propagating_cache : optional<_Tp> { + using optional<_Tp>::optional; + inline static constexpr bool cache_enabled = true; + + constexpr __non_propagating_cache(const __non_propagating_cache&) noexcept {} + + constexpr __non_propagating_cache(__non_propagating_cache&& __other) noexcept { + __other.reset(); + } + + constexpr __non_propagating_cache& operator=(const __non_propagating_cache& __other) noexcept { + if (_VSTD::addressof(__other) != this) { + optional<_Tp>::reset(); + } + + return *this; + } + + constexpr __non_propagating_cache& operator=(__non_propagating_cache&& __other) noexcept { + optional<_Tp>::reset(); + __other.reset(); + return *this; + } + }; + + template + requires is_object_v<_Tp> + struct __non_propagating_cache<_Tp, false> { + inline static constexpr bool cache_enabled = false; + }; +} // namespace ranges + +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___RANGES_NON_PROPAGATING_CACHE_H diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -459,6 +459,7 @@ module empty_view { header "__ranges/empty_view.h" } module enable_borrowed_range { header "__ranges/enable_borrowed_range.h" } module enable_view { header "__ranges/enable_view.h" } + module non_propagating_cache { header "__ranges/non_propagating_cache.h" export optional } module ref_view { header "__ranges/ref_view.h" } module size { header "__ranges/size.h" } module subrange { header "__ranges/subrange.h" } diff --git a/libcxx/test/libcxx/ranges/range.nonprop.cache/cache_disabled.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.nonprop.cache/cache_disabled.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.nonprop.cache/cache_disabled.compile.pass.cpp @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: gcc-10 + +// std::ranges::__non_propagating_cache + +#include <__ranges/non_propagating_cache.h> + +#include +#include + +static_assert(std::is_empty_v, false> >); +static_assert(std::is_empty_v::iterator, false> >); diff --git a/libcxx/test/libcxx/ranges/range.nonprop.cache/copy_assign.pass.cpp b/libcxx/test/libcxx/ranges/range.nonprop.cache/copy_assign.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.nonprop.cache/copy_assign.pass.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: gcc-10 + +// __non_propagating_cache& __non_propagating_cache::operator=(__non_propagating_cache const&); + +#include <__ranges/non_propagating_cache.h> + +#include +#include + +#include "test_macros.h" + +constexpr bool check_copy_assign() { + auto x = std::ranges::__non_propagating_cache, true>({0, 1, 2, 3, 4}); + auto y = std::ranges::__non_propagating_cache, true>({5, 6, 7, 8, 9}); + x = y; + assert(!x.has_value()); + assert(y.has_value()); + assert((y.value() == std::array{5, 6, 7, 8, 9})); + return true; +} + +int main(int, char**) { + static_assert(std::is_nothrow_copy_assignable_v, true> >); + static_assert(check_copy_assign()); + check_copy_assign(); + return 0; +} diff --git a/libcxx/test/libcxx/ranges/range.nonprop.cache/copy_ctor.pass.cpp b/libcxx/test/libcxx/ranges/range.nonprop.cache/copy_ctor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.nonprop.cache/copy_ctor.pass.cpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: gcc-10 + +// __non_propagating_cache(__non_propagating_cache const&); + +#include <__ranges/non_propagating_cache.h> + +#include +#include + +#include "test_macros.h" + +constexpr bool check_copy_ctor() { + auto x = std::ranges::__non_propagating_cache, true>({0, 1, 2, 3, 4}); + auto y = x; + assert(x.has_value()); + assert((x.value() == std::array{0, 1, 2, 3, 4})); + assert(!y.has_value()); + return true; +} + +int main(int, char**) { + static_assert(std::is_nothrow_copy_constructible_v, true> >); + static_assert(check_copy_ctor()); + check_copy_ctor(); + return 0; +} diff --git a/libcxx/test/libcxx/ranges/range.nonprop.cache/move_assign.pass.cpp b/libcxx/test/libcxx/ranges/range.nonprop.cache/move_assign.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.nonprop.cache/move_assign.pass.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: gcc-10 + +// __non_propagating_cache& __non_propagating_cache::operator=(__non_propagating_cache&&); + +#include <__ranges/non_propagating_cache.h> + +#include +#include +#include + +#include "test_macros.h" + +constexpr bool check_move_assign() { + auto x = std::ranges::__non_propagating_cache, true>({0, 1, 2, 3, 4}); + auto y = std::ranges::__non_propagating_cache, true>({5, 6, 7, 8, 9}); + x = std::move(y); + return !x && !y; +} + +int main(int, char**) { + static_assert(std::is_nothrow_move_assignable_v, true> >); + static_assert(check_move_assign()); + assert(check_move_assign()); + return 0; +} diff --git a/libcxx/test/libcxx/ranges/range.nonprop.cache/move_ctor.pass.cpp b/libcxx/test/libcxx/ranges/range.nonprop.cache/move_ctor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.nonprop.cache/move_ctor.pass.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: gcc-10 + +// __non_propagating_cache(__non_propagating_cache&&); + +#include <__ranges/non_propagating_cache.h> + +#include +#include +#include + +#include "test_macros.h" + +constexpr bool check_move_ctor() { + auto x = std::ranges::__non_propagating_cache, true>({0, 1, 2, 3, 4}); + auto y = std::move(x); + return !x && !y; +} + +int main(int, char**) { + static_assert(std::is_nothrow_move_constructible_v, true> >); + static_assert(check_move_ctor()); + assert(check_move_ctor()); + return 0; +}