[libc++] Implement std::experimental::observer_ptr

This patch adds std::experimental::observer_ptr (n4282) and also
fixes LWG2516.

Co-Authored-By: Louis Dionne <ldionne.2@gmail.com>
Differential Revision: https://reviews.llvm.org/D63230
This commit is contained in:
Zoe Carver 2023-11-05 17:56:23 -07:00 committed by Louis Dionne
parent cf7d4f543c
commit 7a62bee611
28 changed files with 1243 additions and 1 deletions

View File

@ -143,7 +143,7 @@
"`2441 <https://wg21.link/LWG2441>`__","Exact-width atomic typedefs should be provided","Oulu","|Complete|",""
"`2451 <https://wg21.link/LWG2451>`__","[fund.ts.v2] optional should 'forward' T's implicit conversions","Oulu","|Nothing To Do|",""
"`2509 <https://wg21.link/LWG2509>`__","[fund.ts.v2] any_cast doesn't work with rvalue reference targets and cannot move with a value target","Oulu","|Complete|",""
"`2516 <https://wg21.link/LWG2516>`__","[fund.ts.v2] Public ""exposition only"" members in observer_ptr","Oulu","",""
"`2516 <https://wg21.link/LWG2516>`__","[fund.ts.v2] Public ""exposition only"" members in observer_ptr","Oulu","|Complete|","18.0"
"`2542 <https://wg21.link/LWG2542>`__","Missing const requirements for associative containers","Oulu","",""
"`2549 <https://wg21.link/LWG2549>`__","Tuple EXPLICIT constructor templates that take tuple parameters end up taking references to temporaries and will create dangling references","Oulu","|Complete|",""
"`2550 <https://wg21.link/LWG2550>`__","Wording of unordered container's clear() method complexity","Oulu","|Complete|",""

1 Issue # Issue Name Meeting Status First released version
143 `2441 <https://wg21.link/LWG2441>`__ Exact-width atomic typedefs should be provided Oulu |Complete|
144 `2451 <https://wg21.link/LWG2451>`__ [fund.ts.v2] optional should 'forward' T's implicit conversions Oulu |Nothing To Do|
145 `2509 <https://wg21.link/LWG2509>`__ [fund.ts.v2] any_cast doesn't work with rvalue reference targets and cannot move with a value target Oulu |Complete|
146 `2516 <https://wg21.link/LWG2516>`__ [fund.ts.v2] Public "exposition only" members in observer_ptr Oulu |Complete| 18.0
147 `2542 <https://wg21.link/LWG2542>`__ Missing const requirements for associative containers Oulu
148 `2549 <https://wg21.link/LWG2549>`__ Tuple EXPLICIT constructor templates that take tuple parameters end up taking references to temporaries and will create dangling references Oulu |Complete|
149 `2550 <https://wg21.link/LWG2550>`__ Wording of unordered container's clear() method complexity Oulu |Complete|

View File

@ -925,6 +925,7 @@ set(files
experimental/iterator
experimental/list
experimental/map
experimental/memory
experimental/memory_resource
experimental/propagate_const
experimental/regex

View File

@ -91,6 +91,7 @@
#include <experimental/iterator>
#include <experimental/list>
#include <experimental/map>
#include <experimental/memory>
#include <experimental/memory_resource>
#include <experimental/propagate_const>
#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)

View File

@ -0,0 +1,194 @@
// -*- 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_EXPERIMENTAL_MEMORY
#define _LIBCPP_EXPERIMENTAL_MEMORY
/*
experimental/memory synopsis
namespace std::experimental::inline fundamentals_v2 {
template <class W> class observer_ptr {
public:
using element_type = W;
using pointer = add_pointer_t<W>; // exposition-only
using reference = add_lvalue_reference_t<W>; // exposition-only
// default ctor
constexpr observer_ptr() noexcept;
// pointer-accepting ctors
constexpr observer_ptr(nullptr_t) noexcept;
constexpr explicit observer_ptr(pointer) noexcept;
// copying ctors (in addition to compiler-generated copy ctor)
template <class W2> constexpr observer_ptr(observer_ptr<W2>) noexcept;
// observers
constexpr pointer get() const noexcept;
constexpr reference operator*() const;
constexpr pointer operator->() const noexcept;
constexpr explicit operator bool() const noexcept;
// conversions
constexpr explicit operator pointer() const noexcept;
// modifiers
constexpr pointer release() noexcept;
constexpr void reset(pointer = nullptr) noexcept;
constexpr void swap(observer_ptr&) noexcept;
};
}
*/
#include <__functional/hash.h>
#include <__functional/operations.h>
#include <__type_traits/add_lvalue_reference.h>
#include <__type_traits/add_pointer.h>
#include <__type_traits/common_type.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_convertible.h>
#include <cstddef>
#include <experimental/__config>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
#ifdef _LIBCPP_ENABLE_EXPERIMENTAL
_LIBCPP_BEGIN_NAMESPACE_LFTS_V2
# if _LIBCPP_STD_VER >= 17
template <class _Wp>
class observer_ptr {
public:
using element_type = _Wp;
// constructors
_LIBCPP_HIDE_FROM_ABI constexpr observer_ptr() noexcept : __ptr_(nullptr) {}
_LIBCPP_HIDE_FROM_ABI constexpr observer_ptr(nullptr_t) noexcept : __ptr_(nullptr) {}
_LIBCPP_HIDE_FROM_ABI constexpr explicit observer_ptr(element_type* __p) noexcept : __ptr_(__p) {}
template <class _W2, class = __enable_if_t<is_convertible<_W2*, _Wp*>::value>>
_LIBCPP_HIDE_FROM_ABI constexpr observer_ptr(observer_ptr<_W2> __other) noexcept : __ptr_(__other.get()) {}
// observers
_LIBCPP_HIDE_FROM_ABI constexpr element_type* get() const noexcept { return __ptr_; }
_LIBCPP_HIDE_FROM_ABI constexpr add_lvalue_reference_t<_Wp> operator*() const { return *__ptr_; }
_LIBCPP_HIDE_FROM_ABI constexpr element_type* operator->() const noexcept { return __ptr_; }
_LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __ptr_ != nullptr; }
// conversions
_LIBCPP_HIDE_FROM_ABI constexpr explicit operator element_type*() const noexcept { return __ptr_; }
// modifiers
_LIBCPP_HIDE_FROM_ABI constexpr void reset(element_type* __p = nullptr) noexcept { __ptr_ = __p; }
_LIBCPP_HIDE_FROM_ABI constexpr void swap(observer_ptr& __other) noexcept {
observer_ptr __tmp = __other;
__other = *this;
*this = __tmp;
}
_LIBCPP_HIDE_FROM_ABI constexpr element_type* release() noexcept {
observer_ptr __p;
__p.swap(*this);
return __p.get();
}
private:
element_type* __ptr_;
};
// specializations
template <class _Wp>
_LIBCPP_HIDE_FROM_ABI constexpr void swap(observer_ptr<_Wp>& __a, observer_ptr<_Wp>& __b) noexcept {
__a.swap(__b);
}
template <class _Wp>
_LIBCPP_HIDE_FROM_ABI observer_ptr<_Wp> make_observer(_Wp* __ptr) noexcept {
return observer_ptr<_Wp>{__ptr};
}
template <class _W1, class _W2>
_LIBCPP_HIDE_FROM_ABI bool operator==(observer_ptr<_W1> __a, observer_ptr<_W2> __b) {
return __a.get() == __b.get();
}
template <class _W1, class _W2>
_LIBCPP_HIDE_FROM_ABI bool operator!=(observer_ptr<_W1> __a, observer_ptr<_W2> __b) {
return !(__a == __b);
}
template <class _Wp>
_LIBCPP_HIDE_FROM_ABI bool operator==(observer_ptr<_Wp> __p, nullptr_t) {
return !__p;
}
template <class _Wp>
_LIBCPP_HIDE_FROM_ABI bool operator==(nullptr_t, observer_ptr<_Wp> __p) {
return !__p;
}
template <class _Wp>
_LIBCPP_HIDE_FROM_ABI bool operator!=(observer_ptr<_Wp> __p, nullptr_t) {
return (bool)__p;
}
template <class _Wp>
_LIBCPP_HIDE_FROM_ABI bool operator!=(nullptr_t, observer_ptr<_Wp> __p) {
return (bool)__p;
}
template <class _W1, class _W2>
_LIBCPP_HIDE_FROM_ABI bool operator<(observer_ptr<_W1> __a, observer_ptr<_W2> __b) {
return std::less<typename std::common_type<_W1*, _W2*>::type>()(__a.get(), __b.get());
}
template <class _W1, class _W2>
_LIBCPP_HIDE_FROM_ABI bool operator>(observer_ptr<_W1> __a, observer_ptr<_W2> __b) {
return __b < __a;
}
template <class _W1, class _W2>
_LIBCPP_HIDE_FROM_ABI bool operator<=(observer_ptr<_W1> __a, observer_ptr<_W2> __b) {
return !(__a > __b);
}
template <class _W1, class _W2>
_LIBCPP_HIDE_FROM_ABI bool operator>=(observer_ptr<_W1> __a, observer_ptr<_W2> __b) {
return !(__a < __b);
}
# endif // _LIBCPP_STD_VER >= 17
_LIBCPP_END_NAMESPACE_LFTS_V2
_LIBCPP_BEGIN_NAMESPACE_STD
// hash
# if _LIBCPP_STD_VER >= 17
template <class _Tp>
struct hash<experimental::observer_ptr<_Tp>> {
_LIBCPP_HIDE_FROM_ABI size_t operator()(const experimental::observer_ptr<_Tp>& __ptr) const noexcept {
return hash<_Tp*>()(__ptr.get());
}
};
# endif // _LIBCPP_STD_VER >= 17
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_ENABLE_EXPERIMENTAL
#endif /* _LIBCPP_EXPERIMENTAL_MEMORY */

View File

@ -533,6 +533,10 @@ module std_experimental [system] {
header "experimental/map"
export *
}
module memory {
header "experimental/memory"
export *
}
module memory_resource {
header "experimental/memory_resource"
export *

View File

@ -241,6 +241,10 @@ experimental/list experimental/memory_resource
experimental/list list
experimental/map experimental/memory_resource
experimental/map map
experimental/memory cstddef
experimental/memory cstdint
experimental/memory cstring
experimental/memory limits
experimental/memory_resource atomic
experimental/memory_resource climits
experimental/memory_resource concepts

1 algorithm atomic
241 experimental/list list
242 experimental/map experimental/memory_resource
243 experimental/map map
244 experimental/memory cstddef
245 experimental/memory cstdint
246 experimental/memory cstring
247 experimental/memory limits
248 experimental/memory_resource atomic
249 experimental/memory_resource climits
250 experimental/memory_resource concepts

View File

@ -242,6 +242,10 @@ experimental/list experimental/memory_resource
experimental/list list
experimental/map experimental/memory_resource
experimental/map map
experimental/memory cstddef
experimental/memory cstdint
experimental/memory cstring
experimental/memory limits
experimental/memory_resource atomic
experimental/memory_resource climits
experimental/memory_resource concepts

1 algorithm atomic
242 experimental/list list
243 experimental/map experimental/memory_resource
244 experimental/map map
245 experimental/memory cstddef
246 experimental/memory cstdint
247 experimental/memory cstring
248 experimental/memory limits
249 experimental/memory_resource atomic
250 experimental/memory_resource climits
251 experimental/memory_resource concepts

View File

@ -242,6 +242,10 @@ experimental/list experimental/memory_resource
experimental/list list
experimental/map experimental/memory_resource
experimental/map map
experimental/memory cstddef
experimental/memory cstdint
experimental/memory cstring
experimental/memory limits
experimental/memory_resource atomic
experimental/memory_resource climits
experimental/memory_resource concepts

1 algorithm atomic
242 experimental/list list
243 experimental/map experimental/memory_resource
244 experimental/map map
245 experimental/memory cstddef
246 experimental/memory cstdint
247 experimental/memory cstring
248 experimental/memory limits
249 experimental/memory_resource atomic
250 experimental/memory_resource climits
251 experimental/memory_resource concepts

View File

@ -242,6 +242,10 @@ experimental/list experimental/memory_resource
experimental/list list
experimental/map experimental/memory_resource
experimental/map map
experimental/memory cstddef
experimental/memory cstdint
experimental/memory cstring
experimental/memory limits
experimental/memory_resource atomic
experimental/memory_resource climits
experimental/memory_resource concepts

1 algorithm atomic
242 experimental/list list
243 experimental/map experimental/memory_resource
244 experimental/map map
245 experimental/memory cstddef
246 experimental/memory cstdint
247 experimental/memory cstring
248 experimental/memory limits
249 experimental/memory_resource atomic
250 experimental/memory_resource climits
251 experimental/memory_resource concepts

View File

@ -248,6 +248,10 @@ experimental/list experimental/memory_resource
experimental/list list
experimental/map experimental/memory_resource
experimental/map map
experimental/memory cstddef
experimental/memory cstdint
experimental/memory cstring
experimental/memory limits
experimental/memory_resource atomic
experimental/memory_resource climits
experimental/memory_resource concepts

1 algorithm atomic
248 experimental/list list
249 experimental/map experimental/memory_resource
250 experimental/map map
251 experimental/memory cstddef
252 experimental/memory cstdint
253 experimental/memory cstring
254 experimental/memory limits
255 experimental/memory_resource atomic
256 experimental/memory_resource climits
257 experimental/memory_resource concepts

View File

@ -170,6 +170,10 @@ experimental/list experimental/memory_resource
experimental/list list
experimental/map experimental/memory_resource
experimental/map map
experimental/memory cstddef
experimental/memory cstdint
experimental/memory cstring
experimental/memory limits
experimental/memory_resource cstddef
experimental/memory_resource experimental/utility
experimental/memory_resource limits

1 algorithm climits
170 experimental/list list
171 experimental/map experimental/memory_resource
172 experimental/map map
173 experimental/memory cstddef
174 experimental/memory cstdint
175 experimental/memory cstring
176 experimental/memory limits
177 experimental/memory_resource cstddef
178 experimental/memory_resource experimental/utility
179 experimental/memory_resource limits

View File

@ -170,6 +170,10 @@ experimental/list experimental/memory_resource
experimental/list list
experimental/map experimental/memory_resource
experimental/map map
experimental/memory cstddef
experimental/memory cstdint
experimental/memory cstring
experimental/memory limits
experimental/memory_resource cstddef
experimental/memory_resource experimental/utility
experimental/memory_resource limits

1 algorithm climits
170 experimental/list list
171 experimental/map experimental/memory_resource
172 experimental/map map
173 experimental/memory cstddef
174 experimental/memory cstdint
175 experimental/memory cstring
176 experimental/memory limits
177 experimental/memory_resource cstddef
178 experimental/memory_resource experimental/utility
179 experimental/memory_resource limits

View File

@ -0,0 +1,179 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// REQUIRES: c++experimental
// <experimental/memory>
// observer_ptr
//
// template <class W1, class W2>
// bool operator==(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2);
//
// template <class W1, class W2>
// bool operator!=(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2);
//
// template <class W>
// bool operator==(const observer_ptr<W>& p, std::nullptr_t) noexcept;
//
// template <class W>
// bool operator==(std::nullptr_t, const observer_ptr<W>& p) noexcept;
//
// template <class W>
// bool operator!=(const observer_ptr<W>& p, std::nullptr_t) noexcept;
//
// template <class W>
// bool operator!=(std::nullptr_t, const observer_ptr<W>& p) noexcept;
//
// template <class W1, class W2>
// bool operator<(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2);
//
// template <class W1, class W2>
// bool operator>(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2);
//
// template <class W1, class W2>
// bool operator<=(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2);
//
// template <class W1, class W2>
// bool operator>=(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2);
#include <experimental/memory>
#include <cassert>
void test() {
using T = int;
using Ptr = std::experimental::observer_ptr<T>;
using VoidPtr = std::experimental::observer_ptr<void>;
// operator==(observer_ptr, observer_ptr)
{
T obj1, obj2;
Ptr ptr1(&obj1), ptr1_x(&obj1);
Ptr ptr2(&obj2);
VoidPtr ptr3(&obj1);
assert(!(ptr1 == ptr2));
assert(ptr1 == ptr1_x);
assert(ptr1 == ptr3);
}
// operator!=(observer_ptr, observer_ptr)
{
T obj1, obj2;
Ptr ptr1(&obj1), ptr1_x(&obj1);
Ptr ptr2(&obj2);
VoidPtr ptr3(&obj1);
assert(ptr1 != ptr2);
assert(!(ptr1 != ptr1_x));
assert(ptr2 != ptr3);
}
// operator==(observer_ptr, nullptr_t)
{
T obj1;
Ptr ptr1(&obj1);
Ptr ptr2(nullptr);
assert(!(ptr1 == nullptr));
assert(ptr2 == nullptr);
}
// operator==(nullptr_t, observer_ptr)
{
T obj1;
Ptr ptr1(&obj1);
Ptr ptr2(nullptr);
assert(!(nullptr == ptr1));
assert(nullptr == ptr2);
}
// operator!=(observer_ptr, nullptr_t)
{
T obj1;
Ptr ptr1(&obj1);
Ptr ptr2(nullptr);
assert(ptr1 != nullptr);
assert(!(ptr2 != nullptr));
}
// operator!=(nullptr_t, observer_ptr)
{
T obj1;
Ptr ptr1(&obj1);
Ptr ptr2(nullptr);
assert(nullptr != ptr1);
assert(!(nullptr != ptr2));
}
// operator<(observer_ptr, observer_ptr)
{
T obj1, obj2;
Ptr ptr1(&obj1);
Ptr ptr2(&obj2);
VoidPtr ptr3(&obj1);
assert(!(ptr1 < ptr1));
assert((ptr1 < ptr2) == (&obj1 < &obj2));
assert(!(ptr1 < ptr3));
}
// operator>(observer_ptr, observer_ptr)
{
T obj1, obj2;
Ptr ptr1(&obj1);
Ptr ptr2(&obj2);
VoidPtr ptr3(&obj1);
assert(!(ptr1 > ptr1));
assert((ptr1 > ptr2) == (&obj1 > &obj2));
assert(!(ptr1 > ptr3));
}
// operator<=(observer_ptr, observer_ptr)
{
T obj1, obj2;
Ptr ptr1(&obj1);
Ptr ptr2(&obj2);
VoidPtr ptr3(&obj1);
assert(ptr1 <= ptr1);
assert((ptr1 <= ptr2) == (&obj1 <= &obj2));
assert(ptr1 <= ptr3);
}
// operator>=(observer_ptr, observer_ptr)
{
T obj1, obj2;
Ptr ptr1(&obj1);
Ptr ptr2(&obj2);
VoidPtr ptr3(&obj1);
assert(ptr1 >= ptr1);
assert((ptr1 >= ptr2) == (&obj1 >= &obj2));
assert(ptr1 >= ptr3);
}
}
int main(int, char**) {
// Note: this is not constexpr in the spec
test();
return 0;
}

View File

@ -0,0 +1,75 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// REQUIRES: c++experimental
// <experimental/memory>
// observer_ptr
//
// template <class W2>
// constexpr observer_ptr(observer_ptr<W2> other) noexcept;
#include <experimental/memory>
#include <type_traits>
#include <cassert>
#include "test_macros.h"
template <class To, class From>
constexpr void test_converting_ctor() {
using ToPtr = std::experimental::observer_ptr<To>;
using FromPtr = std::experimental::observer_ptr<From>;
From obj;
FromPtr from(&obj);
ToPtr to = from;
assert(from.get() == &obj);
assert(to.get() == &obj);
#if TEST_STD_VER >= 20
static_assert(std::is_nothrow_convertible<FromPtr, ToPtr>::value);
#endif
}
template <class To, class From>
constexpr void check_non_constructible() {
using ToPtr = std::experimental::observer_ptr<To>;
using FromPtr = std::experimental::observer_ptr<From>;
static_assert(!std::is_constructible<ToPtr, FromPtr>::value);
}
struct Bar {};
struct Base {};
struct Derived : Base {};
constexpr bool test() {
test_converting_ctor<void, Bar>();
test_converting_ctor<void, int>();
test_converting_ctor<Base, Derived>();
check_non_constructible<Derived, Base>();
check_non_constructible<int, void>();
check_non_constructible<Bar, void>();
check_non_constructible<int, long>();
check_non_constructible<long, int>();
// Check const-ness
check_non_constructible<Bar, Bar const>();
test_converting_ctor<Bar const, Bar>();
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,60 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// REQUIRES: c++experimental
// <experimental/memory>
// observer_ptr
//
// observer_ptr(const observer_ptr& other) = default;
// observer_ptr(observer_ptr&& other) = default;
#include <experimental/memory>
#include <cassert>
#include <type_traits>
#include <utility>
template <class T, class Object = T>
constexpr void test_copy_move() {
using Ptr = std::experimental::observer_ptr<T>;
Object obj;
{
Ptr ptr(&obj);
Ptr copy = ptr;
assert(ptr.get() == &obj);
assert(copy.get() == &obj);
static_assert(std::is_nothrow_copy_constructible<Ptr>::value);
}
{
Ptr ptr(&obj);
Ptr copy = std::move(ptr);
assert(ptr.get() == &obj);
assert(copy.get() == &obj);
static_assert(std::is_nothrow_move_constructible<Ptr>::value);
}
}
struct Bar {};
constexpr bool test() {
test_copy_move<int>();
test_copy_move<Bar>();
test_copy_move<void, int>();
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,50 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// REQUIRES: c++experimental
// <experimental/memory>
// observer_ptr
//
// constexpr observer_ptr() noexcept;
#include <experimental/memory>
#include <type_traits>
#include <cassert>
template <class T>
constexpr void test_default_ctor() {
using Ptr = std::experimental::observer_ptr<T>;
Ptr ptr;
assert(ptr.get() == nullptr);
static_assert(std::is_nothrow_default_constructible<Ptr>::value);
}
struct Foo;
struct Bar {
Bar(int) {}
};
constexpr bool test() {
test_default_ctor<Foo>();
test_default_ctor<Bar>();
test_default_ctor<int>();
test_default_ctor<void>();
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,49 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// REQUIRES: c++experimental
// <experimental/memory>
// observer_ptr
//
// constexpr explicit observer_ptr(element_type* p) noexcept;
#include <experimental/memory>
#include <type_traits>
#include <cassert>
template <class T, class ObjectT = T>
constexpr void test_element_type_ctor() {
using Ptr = std::experimental::observer_ptr<T>;
ObjectT obj;
T* raw = &obj;
Ptr ptr(raw);
assert(ptr.get() == raw);
static_assert(!std::is_convertible<T*, Ptr>::value);
static_assert(std::is_nothrow_constructible<Ptr, T*>::value);
}
struct Bar {};
constexpr bool test() {
test_element_type_ctor<Bar>();
test_element_type_ctor<int>();
test_element_type_ctor<void, int>();
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,51 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// REQUIRES: c++experimental
// <experimental/memory>
// observer_ptr
//
// constexpr observer_ptr(nullptr_t) noexcept;
#include <experimental/memory>
#include <cassert>
#include <cstddef>
#include <type_traits>
template <class T>
constexpr void test_nullptr_ctor() {
using Ptr = std::experimental::observer_ptr<T>;
Ptr ptr = nullptr;
assert(ptr.get() == nullptr);
static_assert(std::is_nothrow_constructible<Ptr, std::nullptr_t>::value);
}
struct Foo;
struct Bar {
Bar(int) {}
};
constexpr bool test() {
test_nullptr_ctor<Foo>();
test_nullptr_ctor<Bar>();
test_nullptr_ctor<int>();
test_nullptr_ctor<void>();
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,65 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// REQUIRES: c++experimental
// <experimental/memory>
// observer_ptr
//
// constexpr std::add_lvalue_reference_t<element_type> operator*() const;
// constexpr element_type* operator->() const noexcept;
#include <experimental/memory>
#include <type_traits>
#include <cassert>
template <class T, class Object = T>
constexpr void test_deref() {
using Ptr = std::experimental::observer_ptr<T>;
Object obj;
{
Ptr const ptr(&obj);
T& r = *ptr;
assert(&r == &obj);
}
{
Ptr const ptr(&obj);
T* r = ptr.operator->();
assert(r == &obj);
static_assert(noexcept(ptr.operator->()));
}
}
struct Bar {};
struct Foo {
int member = 42;
};
constexpr bool test() {
test_deref<Bar>();
test_deref<int>();
{
Foo foo;
std::experimental::observer_ptr<Foo> ptr(&foo);
assert(&ptr->member == &foo.member);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,50 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// REQUIRES: c++experimental
// <experimental/memory>
// observer_ptr
//
// constexpr element_type* get() const noexcept;
#include <experimental/memory>
#include <type_traits>
#include <cassert>
template <class T, class Object = T>
constexpr void test_get() {
using Ptr = std::experimental::observer_ptr<T>;
Object obj;
Ptr const ptr(&obj);
assert(ptr.get() == &obj);
static_assert(noexcept(ptr.get()));
static_assert(std::is_same<decltype(ptr.get()), T*>::value);
}
struct Bar {};
constexpr bool test() {
test_get<Bar>();
test_get<int>();
test_get<void, int>();
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,52 @@
//===----------------------------------------------------------------------===//
//
// 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
// REQUIRES: c++experimental
// <experimental/memory>
// observer_ptr
//
// template <class T> struct hash<std::experimental::observer_ptr<T>>;
#include <experimental/memory>
#include <cassert>
#include "poisoned_hash_helper.h"
template <class T, class Object = T>
void test_hash() {
{
using Ptr = std::experimental::observer_ptr<T>;
Object obj;
Ptr ptr(&obj);
std::hash<std::experimental::observer_ptr<T>> f;
std::size_t h = f(ptr);
assert(h == std::hash<T*>()(&obj));
}
test_hash_enabled_for_type<std::experimental::observer_ptr<T>>();
}
struct Bar {};
void test() {
test_hash<void, int>();
test_hash<int>();
test_hash<Bar>();
}
int main(int, char**) {
// Note: This isn't constexpr friendly in the spec!
test();
return 0;
}

View File

@ -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
// REQUIRES: c++experimental
// <experimental/memory>
// observer_ptr
//
// template <class W>
// std::experimental::observer_ptr<W> make_observer(W* p) noexcept;
#include <experimental/memory>
#include <cassert>
#include <type_traits>
template <class T, class Object = T>
void test_make_observer() {
using Ptr = std::experimental::observer_ptr<T>;
Object obj;
T* raw = &obj;
Ptr ptr = std::experimental::make_observer(raw);
assert(ptr.get() == raw);
static_assert(noexcept(std::experimental::make_observer(raw)));
static_assert(std::is_same<decltype(std::experimental::make_observer(raw)), Ptr>::value);
}
struct Bar {};
void test() {
test_make_observer<void, int>();
test_make_observer<int>();
test_make_observer<Bar>();
}
int main(int, char**) {
// Note: this is not constexpr in the spec
test();
return 0;
}

View File

@ -0,0 +1,61 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// REQUIRES: c++experimental
// <experimental/memory>
// observer_ptr
//
// constexpr explicit operator bool() const noexcept;
#include <experimental/memory>
#include <type_traits>
#include <cassert>
template <class T, class Object = T>
constexpr void test_operator_bool() {
using Ptr = std::experimental::observer_ptr<T>;
Object obj;
{
Ptr const ptr(&obj);
bool b = static_cast<bool>(ptr);
assert(b);
static_assert(noexcept(static_cast<bool>(ptr)));
}
{
Ptr const ptr(nullptr);
bool b = static_cast<bool>(ptr);
assert(!b);
}
static_assert(!std::is_convertible<Ptr const, bool>::value);
static_assert(std::is_constructible<bool, Ptr const>::value);
}
struct Bar {};
constexpr bool test() {
test_operator_bool<Bar>();
test_operator_bool<int>();
test_operator_bool<void, int>();
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,58 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// REQUIRES: c++experimental
// <experimental/memory>
// observer_ptr
//
// constexpr explicit operator element_type*() const noexcept;
#include <experimental/memory>
#include <type_traits>
#include <cassert>
template <class T, class Object = T>
constexpr void test_convertibility() {
Object obj;
std::experimental::observer_ptr<T> ptr(&obj);
T* raw = static_cast<T*>(ptr);
assert(raw == &obj);
static_assert(!std::is_convertible<std::experimental::observer_ptr<T>, T*>::value, "");
static_assert(std::is_constructible<T*, std::experimental::observer_ptr<T>>::value, "");
}
struct Incomplete;
struct Bar {};
constexpr bool test() {
test_convertibility<void, int>();
test_convertibility<bool>();
test_convertibility<int>();
test_convertibility<Bar>();
{
std::experimental::observer_ptr<Incomplete> ptr = nullptr;
Incomplete* raw = static_cast<Incomplete*>(ptr);
assert(raw == nullptr);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,53 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// REQUIRES: c++experimental
// <experimental/memory>
// observer_ptr
//
// constexpr element_type* release() noexcept;
#include <experimental/memory>
#include <type_traits>
#include <cassert>
template <class T, class Object = T>
constexpr void test_release() {
Object obj;
using Ptr = std::experimental::observer_ptr<T>;
Ptr ptr(&obj);
assert(ptr.get() == &obj);
decltype(auto) r = ptr.release();
assert(r == &obj);
assert(ptr.get() == nullptr);
static_assert(std::is_same<decltype(r), typename Ptr::element_type*>::value);
static_assert(noexcept(ptr.release()));
}
struct Bar {};
constexpr bool test() {
test_release<Bar>();
test_release<int>();
test_release<void, int>();
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,61 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// REQUIRES: c++experimental
// <experimental/memory>
// observer_ptr
//
// constexpr void reset(element_type* p = nullptr) noexcept;
#include <experimental/memory>
#include <type_traits>
#include <cassert>
template <class T, class Object = T>
constexpr void test_reset() {
using Ptr = std::experimental::observer_ptr<T>;
Object obj1, obj2;
{
Ptr ptr(&obj1);
assert(ptr.get() == &obj1);
ptr.reset(&obj2);
assert(ptr.get() == &obj2);
static_assert(noexcept(ptr.reset(&obj2)));
static_assert(std::is_same<decltype(ptr.reset(&obj2)), void>::value);
}
{
Ptr ptr(&obj1);
assert(ptr.get() == &obj1);
ptr.reset();
assert(ptr.get() == nullptr);
static_assert(noexcept(ptr.reset()));
static_assert(std::is_same<decltype(ptr.reset()), void>::value);
}
}
struct Bar {};
constexpr bool test() {
test_reset<Bar>();
test_reset<int>();
test_reset<void, int>();
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,79 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// REQUIRES: c++experimental
// <experimental/memory>
// observer_ptr
//
// constexpr void swap(observer_ptr& other) noexcept;
//
// template <class W>
// void swap(observer_ptr<W>& lhs, observer_ptr<W>& rhs) noexcept;
#include <experimental/memory>
#include <type_traits>
#include <cassert>
template <class T, class Object = T>
constexpr void test_swap() {
using Ptr = std::experimental::observer_ptr<T>;
Object obj1, obj2;
{
Ptr ptr1(&obj1);
Ptr ptr2(&obj2);
assert(ptr1.get() == &obj1);
assert(ptr2.get() == &obj2);
ptr1.swap(ptr2);
assert(ptr1.get() == &obj2);
assert(ptr2.get() == &obj1);
static_assert(noexcept(ptr1.swap(ptr2)));
static_assert(std::is_same<decltype(ptr1.swap(ptr2)), void>::value);
}
{
Ptr ptr1(&obj1);
Ptr ptr2(&obj2);
assert(ptr1.get() == &obj1);
assert(ptr2.get() == &obj2);
std::experimental::swap(ptr1, ptr2);
assert(ptr1.get() == &obj2);
assert(ptr2.get() == &obj1);
static_assert(noexcept(std::experimental::swap(ptr1, ptr2)));
static_assert(std::is_same<decltype(std::experimental::swap(ptr1, ptr2)), void>::value);
}
}
struct Bar {};
constexpr bool test() {
test_swap<Bar>();
test_swap<int>();
test_swap<void, int>();
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,23 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// REQUIRES: c++experimental
// <experimental/memory>
// observer_ptr
//
// using element_type = W;
#include <experimental/memory>
#include <type_traits>
using T = std::experimental::observer_ptr<int>::element_type;
static_assert(std::is_same<T, int>::value);