Index: include/experimental/memory =================================================================== --- /dev/null +++ include/experimental/memory @@ -0,0 +1,201 @@ +// -*- C++ -*- +//===-------------------------- algorithm ---------------------------------===// +// +// 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 + +/* +namespace std { +template class observer_ptr { +public: + // publish our template parameter and variations thereof + using element_type = W; + using pointer = add_pointer_t; // exposition-only + using reference = add_lvalue_reference_t; // exposition-only + + // default c’tor + constexpr observer_ptr() noexcept; + + // pointer-accepting c’tors + constexpr observer_ptr(nullptr_t) noexcept; + constexpr explicit observer_ptr(pointer) noexcept; + + // copying c’tors (in addition to compiler-generated copy c’tor) + template constexpr observer_ptr(observer_ptr) 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 +#include + +#include <__debug> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + + +_LIBCPP_BEGIN_NAMESPACE_STD // TODO: use _LIBCPP_BEGIN_NAMESPACE_LFTS? + +template +class observer_ptr +{ + typedef add_pointer_t<_Wp> pointer; + typedef add_lvalue_reference_t<_Wp> reference; + + pointer __ptr; + +public: + typedef _Wp element_type; + + // constructors + constexpr observer_ptr() noexcept : __ptr(nullptr) { } + constexpr observer_ptr(nullptr_t) noexcept : __ptr(nullptr) { } + constexpr observer_ptr(pointer __p) noexcept : __ptr(__p) { } + + template::value>> + constexpr observer_ptr(observer_ptr<_W2> __other) noexcept + : __ptr(__other.get()) { } + + observer_ptr(observer_ptr const&) = default; + observer_ptr(observer_ptr&&) = default; + + // observers + constexpr pointer get() const noexcept { return __ptr; } + constexpr reference operator*() const { return *__ptr; } + constexpr pointer operator->() const noexcept { return __ptr; } + constexpr explicit operator bool() const noexcept { return __ptr != nullptr; } + + // conversions + constexpr /*explicit*/ operator pointer() const noexcept { return __ptr; } + + // modifiers + constexpr void swap(observer_ptr& __other) noexcept { _VSTD::swap(__ptr, __other.__ptr); } + constexpr void reset(pointer __p = nullptr) { __ptr = __p; } + constexpr pointer release() noexcept + { + observer_ptr __p; + __p.swap(*this); + return __p.get(); + } +}; + +// specializations + +template +void swap(observer_ptr<_Wp>& __a, observer_ptr<_Wp>& __b) +{ + __a.swap(__b); +} + +template +observer_ptr<_Wp> make_observer(_Wp* __ptr) +{ + return observer_ptr<_Wp>{__ptr}; +} + +template +bool operator==(observer_ptr<_W1> __a, observer_ptr<_W2> __b) +{ + return __a.get() == __b.get(); +} + +template +bool operator!=(observer_ptr<_W1> __a, observer_ptr<_W2> __b) +{ + return !(__a == __b); +} + +template +bool operator==(observer_ptr<_Wp> __p, nullptr_t) +{ + return !__p; +} + +template +bool operator==(nullptr_t, observer_ptr<_Wp> __p) +{ + return !__p; +} + +template +bool operator!=(observer_ptr<_Wp> __p, nullptr_t) +{ + return (bool)__p; +} + +template +bool operator!=(nullptr_t, observer_ptr<_Wp> __p) +{ + return (bool)__p; +} + +template +bool operator<(observer_ptr<_W1> __a, observer_ptr<_W2> __b) +{ + return _VSTD::less::type>()(__a.get(), __b.get()); +} + +template +bool operator>(observer_ptr<_W1> __a, observer_ptr<_W2> __b) +{ + return __a < __b; // TODO: is this really correct? +} + +template +bool operator<=(observer_ptr<_W1> __a, observer_ptr<_W2> __b) +{ + return !(__a > __b); +} + +template +bool operator>=(observer_ptr<_W1> __a, observer_ptr<_W2> __b) +{ + return !(__a < __b); +} + +// hash + +template +struct hash> +{ + typedef observer_ptr<_Tp> argument_type; + typedef size_t result_type; + + _LIBCPP_INLINE_VISIBILITY + result_type operator()(const argument_type& __ptr) const noexcept + { + return hash<_Tp*>()(__ptr.get()); + } +}; + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif /* _LIBCPP_EXPERIMENTAL_MEMORY */ Index: test/std/experimental/memory/memory.observer.ptr/conv.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.observer.ptr/conv.pass.cpp @@ -0,0 +1,42 @@ +// -*- 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++98, c++03, c++11, c++14 + +// + +// observer_ptr + +#include +#include +#include + +#include "test_macros.h" + +template +void test_convertibility() +{ + typedef std::observer_ptr OP; + static_assert(std::is_convertible::value, ""); +} + +struct Foo; + +struct Bar {}; + +int main(int, char**) +{ + test_convertibility(); + test_convertibility(); + test_convertibility(); + test_convertibility(); + test_convertibility(); + + return 0; +} \ No newline at end of file Index: test/std/experimental/memory/memory.observer.ptr/ctor.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.observer.ptr/ctor.pass.cpp @@ -0,0 +1,129 @@ +// -*- 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++98, c++03, c++11, c++14 + +// + +// observer_ptr + +#include +#include +#include + +#include "test_macros.h" + +template +void custom_delete(T* ptr) { delete ptr; } +void custom_delete(void* ptr) { delete (int*)ptr; } + +template +void assert_constructability() +{ + typedef std::observer_ptr OP; + static_assert(std::is_nothrow_constructible::value, ""); + static_assert(std::is_nothrow_constructible::value, ""); + static_assert(std::is_nothrow_constructible::value, ""); + static_assert(std::is_nothrow_constructible::value, ""); + static_assert(std::is_nothrow_constructible::value, ""); + static_assert(std::is_nothrow_constructible>::value == + std::is_convertible::value, ""); +} + +template +void constrct_nullptr() +{ + { + std::observer_ptr ptr; + assert(ptr.get() == nullptr); + } + { + std::observer_ptr ptr(nullptr); + assert(ptr.get() == nullptr); + } +} + +template +void constrct_ptr(T* raw_ptr) +{ + std::observer_ptr ptr(raw_ptr); + assert(ptr.get() == raw_ptr); + custom_delete(raw_ptr); +} + +template +void constrct_other(U* raw_ptr) +{ + std::observer_ptr uptr(raw_ptr); + std::observer_ptr tptr(uptr); + assert(uptr.get() == raw_ptr); + assert(tptr.get() == raw_ptr); + custom_delete(raw_ptr); +} + +template +void test_copy_move(T* raw_ptr) +{ + std::observer_ptr ptr_a(raw_ptr); + std::observer_ptr ptr_b(ptr_a); + std::observer_ptr ptr_c(std::move(ptr_a)); + assert(ptr_b.get() == raw_ptr); + assert(ptr_c.get() == raw_ptr); + custom_delete(raw_ptr); +} + +struct Foo; +struct Bar +{ + Bar(int) {} +}; + +int main(int, char**) +{ + { + assert_constructability(); + assert_constructability(); + assert_constructability(); + assert_constructability(); + assert_constructability(); + assert_constructability(); + assert_constructability(); + assert_constructability(); + assert_constructability(); + } + { + constrct_nullptr(); + constrct_nullptr(); + constrct_nullptr(); + constrct_nullptr(); + } + { + constrct_ptr(new int); + constrct_ptr(new Bar(42)); + constrct_ptr((void*)new int); + } + { + constrct_other(new int); + constrct_other(new Bar(42)); + + // overload resolution + typedef std::observer_ptr OP1; + typedef std::observer_ptr OP2; + typedef std::observer_ptr OP3; + static_assert(!std::is_nothrow_constructible::value, ""); + static_assert(!std::is_nothrow_constructible::value, ""); + } + { + test_copy_move(new int); + test_copy_move((void*)new int); + test_copy_move(new Bar(42)); + } + + return 0; +} \ No newline at end of file Index: test/std/experimental/memory/memory.observer.ptr/hash.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.observer.ptr/hash.pass.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// 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++98, c++03, c++11, c++14 + +// + +// observer_ptr + +#include +#include + +#include "poisoned_hash_helper.hpp" +#include "test_macros.h" + +struct A {}; + +int main(int, char**) +{ + { + int* ptr = new int; + std::observer_ptr p(ptr); + std::hash> f; + std::size_t h = f(p); + assert(h == std::hash()(ptr)); + } + { + test_hash_enabled_for_type>(); + test_hash_enabled_for_type>(); + } + + return 0; +} Index: test/std/experimental/memory/memory.observer.ptr/mod/release.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.observer.ptr/mod/release.pass.cpp @@ -0,0 +1,38 @@ +// -*- 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++98, c++03, c++11, c++14 + +// + +// observer_ptr + +#include +#include +#include + +#include "test_macros.h" + +int main(int, char**) +{ + { + std::observer_ptr ptr; + assert(ptr.release() == nullptr); + assert(ptr.get() == nullptr); + } + { + int* raw_ptr = new int; + std::observer_ptr ptr(raw_ptr); + assert(ptr.release() == raw_ptr); + assert(ptr.get() == nullptr); + delete raw_ptr; + } + + return 0; +} \ No newline at end of file Index: test/std/experimental/memory/memory.observer.ptr/mod/reset.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.observer.ptr/mod/reset.pass.cpp @@ -0,0 +1,42 @@ +// -*- 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++98, c++03, c++11, c++14 + +// + +// observer_ptr + +#include +#include +#include + +#include "test_macros.h" + +int main(int, char**) +{ + int* raw_ptr1 = new int; + int* raw_ptr2 = new int; + + { + std::observer_ptr ptr; + ptr.reset(raw_ptr1); + assert(ptr.get() == raw_ptr1); + } + { + std::observer_ptr ptr(raw_ptr1); + ptr.reset(raw_ptr2); + assert(ptr.get() == raw_ptr2); + } + + delete raw_ptr1; + delete raw_ptr2; + + return 0; +} \ No newline at end of file Index: test/std/experimental/memory/memory.observer.ptr/mod/swap.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.observer.ptr/mod/swap.pass.cpp @@ -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++98, c++03, c++11, c++14 + +// + +// observer_ptr + +#include +#include +#include + +#include "test_macros.h" + +int main(int, char**) +{ + int* raw_ptr1 = new int; + int* raw_ptr2 = new int; + + { + std::observer_ptr ptr1; + std::observer_ptr ptr2; + ptr1.swap(ptr2); + assert(ptr1.get() == nullptr); + assert(ptr2.get() == nullptr); + } + { + std::observer_ptr ptr1(raw_ptr1); + std::observer_ptr ptr2; + ptr1.swap(ptr2); + assert(ptr1.get() == nullptr); + assert(ptr2.get() == raw_ptr1); + } + { + std::observer_ptr ptr1; + std::observer_ptr ptr2(raw_ptr2); + ptr1.swap(ptr2); + assert(ptr1.get() == raw_ptr2); + assert(ptr2.get() == nullptr); + } + { + std::observer_ptr ptr1(raw_ptr1); + std::observer_ptr ptr2(raw_ptr2); + ptr1.swap(ptr2); + assert(ptr1.get() == raw_ptr2); + assert(ptr2.get() == raw_ptr1); + } + + delete raw_ptr1; + delete raw_ptr2; + + return 0; +} \ No newline at end of file Index: test/std/experimental/memory/memory.observer.ptr/obs.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.observer.ptr/obs.pass.cpp @@ -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++98, c++03, c++11, c++14 + +// + +// observer_ptr + +#include +#include +#include + +#include "test_macros.h" + +struct Foo { + int x; + Foo(int x) : x(x) {} +}; + +int main(int, char**) +{ + int* raw_ptr = new int; + { + std::observer_ptr ptr(raw_ptr); + assert(ptr.get() == raw_ptr); + } + { + std::observer_ptr ptr1; + bool check = ptr1; + assert(check == false); + + std::observer_ptr ptr2(raw_ptr); + check = ptr2; + assert(check == true); + } + { + Foo* foo_ptr = new Foo(42); + std::observer_ptr ptr(foo_ptr); + assert(ptr->x == 42); + assert((*ptr).x == 42); + + } + delete raw_ptr; + + return 0; +} \ No newline at end of file Index: test/std/experimental/memory/memory.observer.ptr/spec.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.observer.ptr/spec.pass.cpp @@ -0,0 +1,87 @@ +// -*- 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++98, c++03, c++11, c++14 + +// + +// observer_ptr + +#include +#include +#include + +#include "test_macros.h" + +int main(int, char**) +{ + { + std::observer_ptr ptr1(new int(42)); + std::observer_ptr ptr2(new int(101)); + std::swap(ptr1, ptr2); + + assert(*ptr1 == 101); + assert(*ptr2 == 42); + + delete ptr1.get(); + delete ptr2.get(); + } + { + int* raw = new int; + std::observer_ptr ptr = std::make_observer(raw); + assert(ptr.get() == raw); + delete raw; + } + + std::observer_ptr ptr1(new int); + std::observer_ptr ptr2(new int); + std::observer_ptr ptr3; + std::observer_ptr vptr((void*)new int); + { + assert(ptr1 == ptr1); + assert(!(ptr1 == ptr2)); + } + { + assert(ptr1 != ptr2); + } + { + assert(ptr3 == nullptr); + assert(nullptr == ptr3); + assert(!(ptr1 == nullptr)); + assert(!(nullptr == ptr1)); + } + { + assert(!(ptr3 != nullptr)); + assert(!(nullptr != ptr3)); + assert(ptr1 != nullptr); + assert(nullptr != ptr1); + } + { + assert((ptr1 < ptr1) == (ptr1.get() < ptr1.get())); + assert((ptr1 < vptr) == (ptr1.get() < vptr.get())); + } + { // TODO: is this correct? + assert((ptr1 > ptr1) == (ptr1.get() < ptr1.get())); + assert((ptr1 > vptr) == (ptr1.get() < vptr.get())); + } + { // TODO: same as above + assert((ptr1 <= ptr1) != (ptr1.get() < ptr1.get())); + assert((ptr1 <= vptr) != (ptr1.get() < vptr.get())); + } + { + assert((ptr1 >= ptr1) != (ptr1.get() < ptr1.get())); + assert((ptr1 >= vptr) != (ptr1.get() < vptr.get())); + } + + delete ptr1.get(); + delete ptr2.get(); + delete (int*)vptr.get(); + + return 0; +}