forked from OSchip/llvm-project
[libc++] Add helper type non-propagating-cache
Differential Revision: https://reviews.llvm.org/D102121
This commit is contained in:
parent
6f5064cd0c
commit
3959c95deb
|
@ -193,6 +193,7 @@ set(files
|
|||
__ranges/empty.h
|
||||
__ranges/enable_borrowed_range.h
|
||||
__ranges/enable_view.h
|
||||
__ranges/non_propagating_cache.h
|
||||
__ranges/ref_view.h
|
||||
__ranges/size.h
|
||||
__ranges/subrange.h
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
#include <__ranges/all.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__ranges/enable_borrowed_range.h>
|
||||
#include <__ranges/non_propagating_cache.h>
|
||||
#include <__ranges/size.h>
|
||||
#include <__ranges/view_interface.h>
|
||||
#include <optional>
|
||||
#include <__utility/move.h>
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
|
@ -36,21 +38,16 @@ _LIBCPP_BEGIN_NAMESPACE_STD
|
|||
namespace ranges {
|
||||
template<view _View>
|
||||
class drop_view
|
||||
: public view_interface<drop_view<_View>> {
|
||||
|
||||
: public view_interface<drop_view<_View>>
|
||||
{
|
||||
// We cache begin() whenever ranges::next is not guaranteed O(1) to provide an
|
||||
// amortized O(1) begin() method. If this is an input_range, then we cannot cache
|
||||
// begin because begin is not equality preserving.
|
||||
// Note: drop_view<input-range>::begin() is still trivially amortized O(1) because
|
||||
// one can't call begin() on it more than once.
|
||||
static constexpr bool _UseCache = forward_range<_View> && !(random_access_range<_View> && sized_range<_View>);
|
||||
using _Cache = optional<iterator_t<_View>>;
|
||||
struct _Empty { };
|
||||
|
||||
// For forward ranges use std::optional to cache the begin iterator.
|
||||
// No unique address + _Empty means we don't use any extra space when this
|
||||
// is not a forward iterator.
|
||||
[[no_unique_address]] conditional_t<_UseCache, _Cache, _Empty> __cached_begin_;
|
||||
using _Cache = _If<_UseCache, __non_propagating_cache<iterator_t<_View>>, __empty_cache>;
|
||||
[[no_unique_address]] _Cache __cached_begin_ = _Cache();
|
||||
range_difference_t<_View> __count_ = 0;
|
||||
_View __base_ = _View();
|
||||
|
||||
|
@ -59,48 +56,12 @@ public:
|
|||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr drop_view(_View __base, range_difference_t<_View> __count)
|
||||
: __cached_begin_()
|
||||
, __count_(__count)
|
||||
: __count_(__count)
|
||||
, __base_(_VSTD::move(__base))
|
||||
{
|
||||
_LIBCPP_ASSERT(__count_ >= 0, "count must be greater than or equal to zero.");
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr drop_view(drop_view const& __other)
|
||||
: __cached_begin_() // Intentionally not propagating the cached begin iterator.
|
||||
, __count_(__other.__count_)
|
||||
, __base_(__other.__base_)
|
||||
{ }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr drop_view(drop_view&& __other)
|
||||
: __cached_begin_() // Intentionally not propagating the cached begin iterator.
|
||||
, __count_(_VSTD::move(__other.__count_))
|
||||
, __base_(_VSTD::move(__other.__base_))
|
||||
{ }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr drop_view& operator=(drop_view const& __other) {
|
||||
if constexpr (_UseCache) {
|
||||
__cached_begin_.reset();
|
||||
}
|
||||
__base_ = __other.__base_;
|
||||
__count_ = __other.__count_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr drop_view& operator=(drop_view&& __other) {
|
||||
if constexpr (_UseCache) {
|
||||
__cached_begin_.reset();
|
||||
__other.__cached_begin_.reset();
|
||||
}
|
||||
__base_ = _VSTD::move(__other.__base_);
|
||||
__count_ = _VSTD::move(__other.__count_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _View base() const& requires copy_constructible<_View> { return __base_; }
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return _VSTD::move(__base_); }
|
||||
|
||||
|
@ -110,12 +71,12 @@ public:
|
|||
random_access_range<const _View> && sized_range<const _View>))
|
||||
{
|
||||
if constexpr (_UseCache)
|
||||
if (__cached_begin_)
|
||||
if (__cached_begin_.__has_value())
|
||||
return *__cached_begin_;
|
||||
|
||||
auto __tmp = ranges::next(ranges::begin(__base_), __count_, ranges::end(__base_));
|
||||
if constexpr (_UseCache)
|
||||
__cached_begin_ = __tmp;
|
||||
__cached_begin_.__set(__tmp);
|
||||
return __tmp;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 <__memory/addressof.h>
|
||||
#include <concepts> // constructible_from
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
#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 {
|
||||
// __non_propagating_cache is a helper type that allows storing an optional value in it,
|
||||
// but which does not copy the source's value when it is copy constructed/assigned to,
|
||||
// and which resets the source's value when it is moved-from.
|
||||
//
|
||||
// This type is used as an implementation detail of some views that need to cache the
|
||||
// result of `begin()` in order to provide an amortized O(1) begin() method. Typically,
|
||||
// we don't want to propagate the value of the cache upon copy because the cached iterator
|
||||
// may refer to internal details of the source view.
|
||||
template<class _Tp>
|
||||
requires is_object_v<_Tp>
|
||||
class _LIBCPP_TEMPLATE_VIS __non_propagating_cache {
|
||||
optional<_Tp> __value_ = nullopt;
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI __non_propagating_cache() = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr __non_propagating_cache(__non_propagating_cache const&) noexcept
|
||||
: __value_(nullopt)
|
||||
{ }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr __non_propagating_cache(__non_propagating_cache&& __other) noexcept
|
||||
: __value_(nullopt)
|
||||
{
|
||||
__other.__value_.reset();
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr __non_propagating_cache& operator=(__non_propagating_cache const& __other) noexcept {
|
||||
if (this != _VSTD::addressof(__other)) {
|
||||
__value_.reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr __non_propagating_cache& operator=(__non_propagating_cache&& __other) noexcept {
|
||||
__value_.reset();
|
||||
__other.__value_.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr _Tp& operator*() { return *__value_; }
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr _Tp const& operator*() const { return *__value_; }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr bool __has_value() const { return __value_.has_value(); }
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr void __set(_Tp const& __value) { __value_.emplace(__value); }
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr void __set(_Tp&& __value) { __value_.emplace(_VSTD::move(__value)); }
|
||||
};
|
||||
|
||||
struct __empty_cache { };
|
||||
} // 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
|
|
@ -613,6 +613,7 @@ module std [system] {
|
|||
module empty_view { private header "__ranges/empty_view.h" }
|
||||
module enable_borrowed_range { private header "__ranges/enable_borrowed_range.h" }
|
||||
module enable_view { private header "__ranges/enable_view.h" }
|
||||
module non_propagating_cache { private header "__ranges/non_propagating_cache.h" }
|
||||
module ref_view { private header "__ranges/ref_view.h" }
|
||||
module size { private header "__ranges/size.h" }
|
||||
module subrange { private header "__ranges/subrange.h" }
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// REQUIRES: modules-build
|
||||
|
||||
// WARNING: This test was generated by 'generate_private_header_tests.py'
|
||||
// and should not be edited manually.
|
||||
|
||||
// expected-error@*:* {{use of private header from outside its module: '__ranges/non_propagating_cache.h'}}
|
||||
#include <__ranges/non_propagating_cache.h>
|
|
@ -0,0 +1,104 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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& operator=(__non_propagating_cache const&);
|
||||
|
||||
// ADDITIONAL_COMPILE_FLAGS: -Wno-self-assign
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
template<bool NoexceptCopy>
|
||||
struct CopyAssignable {
|
||||
int x;
|
||||
constexpr explicit CopyAssignable(int i) : x(i) { }
|
||||
CopyAssignable(CopyAssignable const&) = default;
|
||||
constexpr CopyAssignable& operator=(CopyAssignable const& other) noexcept(NoexceptCopy) {
|
||||
x = other.x;
|
||||
return *this;
|
||||
}
|
||||
constexpr bool operator==(CopyAssignable const& other) const { return x == other.x; }
|
||||
};
|
||||
|
||||
struct NotCopyAssignable {
|
||||
int x;
|
||||
constexpr explicit NotCopyAssignable(int i) : x(i) { }
|
||||
NotCopyAssignable(NotCopyAssignable const&) = default;
|
||||
NotCopyAssignable& operator=(NotCopyAssignable const&) = delete;
|
||||
constexpr bool operator==(NotCopyAssignable const& other) const { return x == other.x; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
constexpr void test() {
|
||||
using Cache = std::ranges::__non_propagating_cache<T>;
|
||||
static_assert(std::is_nothrow_copy_assignable_v<Cache>);
|
||||
|
||||
// Assign to an empty cache
|
||||
{
|
||||
Cache a; a.__set(T{3});
|
||||
Cache b;
|
||||
|
||||
Cache& result = (b = a);
|
||||
assert(&result == &b);
|
||||
assert(!b.__has_value()); // make sure we don't propagate
|
||||
|
||||
assert(a.__has_value()); // make sure we don't "steal" from the source
|
||||
assert(*a == T{3}); //
|
||||
}
|
||||
|
||||
// Assign to a non-empty cache
|
||||
{
|
||||
Cache a; a.__set(T{3});
|
||||
Cache b; b.__set(T{5});
|
||||
|
||||
Cache& result = (b = a);
|
||||
assert(&result == &b);
|
||||
assert(!b.__has_value()); // make sure we don't propagate
|
||||
|
||||
assert(a.__has_value()); // make sure we don't "steal" from the source
|
||||
assert(*a == T{3}); //
|
||||
}
|
||||
|
||||
// Self-assignment should not do anything (case with empty cache)
|
||||
{
|
||||
Cache b;
|
||||
Cache& result = (b = b);
|
||||
assert(&result == &b);
|
||||
assert(!b.__has_value());
|
||||
}
|
||||
|
||||
// Self-assignment should not do anything (case with non-empty cache)
|
||||
{
|
||||
Cache b; b.__set(T{5});
|
||||
Cache& result = (b = b);
|
||||
assert(&result == &b);
|
||||
assert(b.__has_value());
|
||||
assert(*b == T{5});
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<CopyAssignable<true>>();
|
||||
test<CopyAssignable<false>>();
|
||||
test<NotCopyAssignable>();
|
||||
test<int>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(tests());
|
||||
tests();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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& operator=(__non_propagating_cache&&);
|
||||
|
||||
// ADDITIONAL_COMPILE_FLAGS: -Wno-self-assign
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
template<bool NoexceptMove>
|
||||
struct MoveAssignable {
|
||||
int x;
|
||||
constexpr explicit MoveAssignable(int i) : x(i) { }
|
||||
MoveAssignable(MoveAssignable&&) = default;
|
||||
constexpr MoveAssignable& operator=(MoveAssignable&& other) noexcept(NoexceptMove) {
|
||||
x = other.x;
|
||||
other.x = -1;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct NotMoveAssignable {
|
||||
int x;
|
||||
constexpr explicit NotMoveAssignable(int i) : x(i) { }
|
||||
NotMoveAssignable(NotMoveAssignable&&) = default;
|
||||
NotMoveAssignable& operator=(NotMoveAssignable&&) = delete;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
constexpr void test() {
|
||||
using Cache = std::ranges::__non_propagating_cache<T>;
|
||||
static_assert(std::is_nothrow_move_assignable_v<Cache>);
|
||||
|
||||
// Assign to an empty cache
|
||||
{
|
||||
Cache a; a.__set(T{3});
|
||||
Cache b;
|
||||
|
||||
Cache& result = (b = std::move(a));
|
||||
assert(&result == &b);
|
||||
assert(!b.__has_value()); // make sure we don't propagate
|
||||
assert(!a.__has_value()); // make sure we disengage the source
|
||||
}
|
||||
|
||||
// Assign to a non-empty cache
|
||||
{
|
||||
Cache a; a.__set(T{3});
|
||||
Cache b; b.__set(T{5});
|
||||
|
||||
Cache& result = (b = std::move(a));
|
||||
assert(&result == &b);
|
||||
assert(!b.__has_value()); // make sure we don't propagate
|
||||
assert(!a.__has_value()); // make sure we disengage the source
|
||||
}
|
||||
|
||||
// Self-assignment should clear the cache (case with empty cache)
|
||||
{
|
||||
Cache b;
|
||||
|
||||
Cache& result = (b = std::move(b));
|
||||
assert(&result == &b);
|
||||
assert(!b.__has_value());
|
||||
}
|
||||
|
||||
// Self-assignment should clear the cache (case with non-empty cache)
|
||||
{
|
||||
Cache b; b.__set(T{5});
|
||||
|
||||
Cache& result = (b = std::move(b));
|
||||
assert(&result == &b);
|
||||
assert(!b.__has_value());
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<MoveAssignable<true>>();
|
||||
test<MoveAssignable<false>>();
|
||||
test<NotMoveAssignable>();
|
||||
test<int>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(tests());
|
||||
tests();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
|
||||
// template<class T>
|
||||
// requires is_object_v<T>
|
||||
// class non-propagating-cache;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
template<template<class...> class T, class ...Args>
|
||||
concept well_formed = requires {
|
||||
typename T<Args...>;
|
||||
};
|
||||
|
||||
struct T { };
|
||||
static_assert( well_formed<std::ranges::__non_propagating_cache, int>);
|
||||
static_assert( well_formed<std::ranges::__non_propagating_cache, T>);
|
||||
static_assert( well_formed<std::ranges::__non_propagating_cache, void (*)()>);
|
||||
static_assert(!well_formed<std::ranges::__non_propagating_cache, void>);
|
||||
static_assert(!well_formed<std::ranges::__non_propagating_cache, T&>);
|
||||
static_assert(!well_formed<std::ranges::__non_propagating_cache, void()>);
|
|
@ -0,0 +1,75 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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>
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
template<bool NoexceptCopy>
|
||||
struct CopyConstructible {
|
||||
int x;
|
||||
constexpr explicit CopyConstructible(int i) : x(i) { }
|
||||
constexpr CopyConstructible(CopyConstructible const& other) noexcept(NoexceptCopy) : x(other.x) { }
|
||||
CopyConstructible& operator=(CopyConstructible const&) = default;
|
||||
constexpr bool operator==(CopyConstructible const& other) const { return x == other.x; }
|
||||
};
|
||||
|
||||
struct NotCopyConstructible {
|
||||
int x;
|
||||
constexpr explicit NotCopyConstructible(int i) : x(i) { }
|
||||
NotCopyConstructible(NotCopyConstructible const&) = delete;
|
||||
NotCopyConstructible(NotCopyConstructible&&) = default;
|
||||
constexpr bool operator==(NotCopyConstructible const& other) const { return x == other.x; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
constexpr void test() {
|
||||
using Cache = std::ranges::__non_propagating_cache<T>;
|
||||
static_assert(std::is_nothrow_copy_constructible_v<Cache>);
|
||||
Cache a;
|
||||
a.__set(T{3});
|
||||
|
||||
// Test with direct initialization
|
||||
{
|
||||
Cache b(a);
|
||||
assert(!b.__has_value()); // make sure we don't propagate
|
||||
|
||||
assert(a.__has_value()); // make sure we don't "steal" from the source
|
||||
assert(*a == T{3}); //
|
||||
}
|
||||
|
||||
// Test with copy initialization
|
||||
{
|
||||
Cache b = a;
|
||||
assert(!b.__has_value()); // make sure we don't propagate
|
||||
|
||||
assert(a.__has_value()); // make sure we don't "steal" from the source
|
||||
assert(*a == T{3}); //
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<CopyConstructible<true>>();
|
||||
test<CopyConstructible<false>>();
|
||||
test<NotCopyConstructible>();
|
||||
test<int>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(tests());
|
||||
tests();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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();
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
struct HasDefault { HasDefault() = default; };
|
||||
struct NoDefault { NoDefault() = delete; };
|
||||
|
||||
template <class T>
|
||||
constexpr void test() {
|
||||
using Cache = std::ranges::__non_propagating_cache<T>;
|
||||
static_assert(std::is_nothrow_default_constructible_v<Cache>);
|
||||
Cache cache;
|
||||
assert(!cache.__has_value());
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<HasDefault>();
|
||||
test<NoDefault>();
|
||||
test<int>();
|
||||
test<char*>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(tests());
|
||||
tests();
|
||||
return 0;
|
||||
}
|
|
@ -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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
// UNSUPPORTED: gcc-10
|
||||
|
||||
// __non_propagating_cache(__non_propagating_cache&&);
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
template<bool NoexceptMove>
|
||||
struct MoveConstructible {
|
||||
int x;
|
||||
constexpr explicit MoveConstructible(int i) : x(i) { }
|
||||
constexpr MoveConstructible(MoveConstructible&& other) noexcept(NoexceptMove) : x(other.x) { other.x = -1; }
|
||||
MoveConstructible& operator=(MoveConstructible&&) = default;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
constexpr void test() {
|
||||
using Cache = std::ranges::__non_propagating_cache<T>;
|
||||
static_assert(std::is_nothrow_move_constructible_v<Cache>);
|
||||
|
||||
// Test with direct initialization
|
||||
{
|
||||
Cache a;
|
||||
a.__set(T{3});
|
||||
|
||||
Cache b(std::move(a));
|
||||
assert(!b.__has_value()); // make sure we don't propagate
|
||||
assert(!a.__has_value()); // make sure we disengage the source
|
||||
}
|
||||
|
||||
// Test with copy initialization
|
||||
{
|
||||
Cache a;
|
||||
a.__set(T{3});
|
||||
|
||||
Cache b = std::move(a);
|
||||
assert(!b.__has_value()); // make sure we don't propagate
|
||||
assert(!a.__has_value()); // make sure we disengage the source
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<MoveConstructible<true>>();
|
||||
test<MoveConstructible<false>>();
|
||||
test<int>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(tests());
|
||||
tests();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
|
||||
// constexpr T const& operator*() const;
|
||||
// constexpr T& operator*();
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
template <class T>
|
||||
constexpr void test() {
|
||||
using Cache = std::ranges::__non_propagating_cache<T>;
|
||||
|
||||
// non-const version
|
||||
{
|
||||
Cache cache; cache.__set(T{3});
|
||||
T& result = *cache;
|
||||
assert(result == T{3});
|
||||
}
|
||||
|
||||
// const version
|
||||
{
|
||||
Cache cache; cache.__set(T{3});
|
||||
T const& result = *static_cast<Cache const&>(cache);
|
||||
assert(result == T{3});
|
||||
}
|
||||
}
|
||||
|
||||
struct T {
|
||||
int x;
|
||||
constexpr explicit T(int i) : x(i) { }
|
||||
constexpr bool operator==(T const& other) const { return x == other.x; }
|
||||
};
|
||||
|
||||
constexpr bool tests() {
|
||||
test<T>();
|
||||
test<int>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(tests());
|
||||
tests();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
|
||||
// constexpr bool __has_value() const;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
template <class T>
|
||||
constexpr void test() {
|
||||
using Cache = std::ranges::__non_propagating_cache<T>;
|
||||
|
||||
// __has_value on an empty cache
|
||||
{
|
||||
Cache const cache;
|
||||
assert(!cache.__has_value());
|
||||
}
|
||||
|
||||
// __has_value on a non-empty cache
|
||||
{
|
||||
Cache cache; cache.__set(T{});
|
||||
assert(cache.__has_value());
|
||||
}
|
||||
}
|
||||
|
||||
struct T { };
|
||||
|
||||
constexpr bool tests() {
|
||||
test<T>();
|
||||
test<int>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(tests());
|
||||
tests();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue