Index: include/CMakeLists.txt =================================================================== --- include/CMakeLists.txt +++ include/CMakeLists.txt @@ -73,6 +73,7 @@ experimental/iterator experimental/list experimental/map + experimental/memory experimental/memory_resource experimental/propagate_const experimental/regex Index: include/experimental/memory =================================================================== --- /dev/null +++ include/experimental/memory @@ -0,0 +1,212 @@ +// -*- 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 + +#include <__debug> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + + +_LIBCPP_BEGIN_NAMESPACE_LFTS + +#if _LIBCPP_STD_VER > 14 + +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 explicit 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 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) noexcept +{ + __a.swap(__b); +} + +template +observer_ptr<_Wp> make_observer(_Wp* __ptr) noexcept +{ + 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 __b < __a; +} + +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); +} + +#endif // _LIBCPP_STD_VER > 14 + +_LIBCPP_END_NAMESPACE_LFTS + +_LIBCPP_BEGIN_NAMESPACE_STD + +// hash + +#if _LIBCPP_STD_VER > 14 +template +struct hash> +{ + typedef experimental::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()); + } +}; +#endif // _LIBCPP_STD_VER > 14 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif /* _LIBCPP_EXPERIMENTAL_MEMORY */ Index: include/module.modulemap =================================================================== --- include/module.modulemap +++ include/module.modulemap @@ -551,6 +551,10 @@ header "experimental/map" export * } + module memory_resource { + header "experimental/memory" + export * + } module memory_resource { header "experimental/memory_resource" export * Index: test/libcxx/double_include.sh.cpp =================================================================== --- test/libcxx/double_include.sh.cpp +++ test/libcxx/double_include.sh.cpp @@ -151,6 +151,7 @@ #include #include #include +#include #include #include #include Index: test/libcxx/experimental/memory/memory.observer.ptr/version.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/experimental/memory/memory.observer.ptr/version.pass.cpp @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +#include + +#include "test_macros.h" + +#ifndef _LIBCPP_VERSION +#error _LIBCPP_VERSION not defined +#endif + +int main(int, char**) +{ + + return 0; +} 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::experimental::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::experimental::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::experimental::observer_ptr ptr; + assert(ptr.get() == nullptr); + } + { + std::experimental::observer_ptr ptr(nullptr); + assert(ptr.get() == nullptr); + } +} + +template +void constrct_ptr(T* raw_ptr) +{ + std::experimental::observer_ptr ptr(raw_ptr); + assert(ptr.get() == raw_ptr); + custom_delete(raw_ptr); +} + +template +void constrct_other(U* raw_ptr) +{ + std::experimental::observer_ptr uptr(raw_ptr); + std::experimental::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::experimental::observer_ptr ptr_a(raw_ptr); + std::experimental::observer_ptr ptr_b(ptr_a); + std::experimental::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::experimental::observer_ptr OP1; + typedef std::experimental::observer_ptr OP2; + typedef std::experimental::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::experimental::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::experimental::observer_ptr ptr; + assert(ptr.release() == nullptr); + assert(ptr.get() == nullptr); + } + { + int* raw_ptr = new int; + std::experimental::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::experimental::observer_ptr ptr; + ptr.reset(raw_ptr1); + assert(ptr.get() == raw_ptr1); + } + { + std::experimental::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::experimental::observer_ptr ptr1; + std::experimental::observer_ptr ptr2; + ptr1.swap(ptr2); + assert(ptr1.get() == nullptr); + assert(ptr2.get() == nullptr); + } + { + std::experimental::observer_ptr ptr1(raw_ptr1); + std::experimental::observer_ptr ptr2; + ptr1.swap(ptr2); + assert(ptr1.get() == nullptr); + assert(ptr2.get() == raw_ptr1); + } + { + std::experimental::observer_ptr ptr1; + std::experimental::observer_ptr ptr2(raw_ptr2); + ptr1.swap(ptr2); + assert(ptr1.get() == raw_ptr2); + assert(ptr2.get() == nullptr); + } + { + std::experimental::observer_ptr ptr1(raw_ptr1); + std::experimental::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,54 @@ +// -*- 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 { + const int x; + constexpr Foo(const int x) : x(x) {} +}; + +int main(int, char**) +{ + static constexpr int x = 42; + constexpr const int* raw_ptr = &x; + { + constexpr std::experimental::observer_ptr ptr(raw_ptr); + static_assert(ptr.get() == raw_ptr); + } + { + constexpr std::experimental::observer_ptr ptr1; + const bool check1 = ptr1; + static_assert(check1 == false); + + constexpr std::experimental::observer_ptr ptr2(raw_ptr); + const bool check2 = ptr2; + static_assert(check2 == true); + } + { + static constexpr Foo f = Foo(42); + constexpr const Foo* foo_ptr = &f; + constexpr std::experimental::observer_ptr ptr(foo_ptr); + static_assert(ptr->x == 42); + static_assert((*ptr).x == 42); + + } + + 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::experimental::observer_ptr ptr1(new int(42)); + std::experimental::observer_ptr ptr2(new int(101)); + std::experimental::swap(ptr1, ptr2); + + assert(*ptr1 == 101); + assert(*ptr2 == 42); + + delete ptr1.get(); + delete ptr2.get(); + } + { + int* raw = new int; + std::experimental::observer_ptr ptr = std::experimental::make_observer(raw); + assert(ptr.get() == raw); + delete raw; + } + + std::experimental::observer_ptr ptr1(new int); + std::experimental::observer_ptr ptr2(new int); + std::experimental::observer_ptr ptr3; + std::experimental::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())); + } + { + 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())); + } + { + 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; +}