diff --git a/include/backward/auto_ptr.h b/include/backward/auto_ptr.h new file mode 100644 index 0000000..8511636 --- /dev/null +++ b/include/backward/auto_ptr.h @@ -0,0 +1,337 @@ +// auto_ptr implementation -*- C++ -*- + +// Copyright (C) 2007-2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file backward/auto_ptr.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{memory} + */ + +#ifndef _BACKWARD_AUTO_PTR_H +#define _BACKWARD_AUTO_PTR_H 1 + +#include +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * A wrapper class to provide auto_ptr with reference semantics. + * For example, an auto_ptr can be assigned (or constructed from) + * the result of a function which returns an auto_ptr by value. + * + * All the auto_ptr_ref stuff should happen behind the scenes. + */ + template + struct auto_ptr_ref + { + _Tp1* _M_ptr; + + explicit + auto_ptr_ref(_Tp1* __p): _M_ptr(__p) { } + } _GLIBCXX_DEPRECATED; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + + /** + * @brief A simple smart pointer providing strict ownership semantics. + * + * The Standard says: + *
+   *  An @c auto_ptr owns the object it holds a pointer to.  Copying
+   *  an @c auto_ptr copies the pointer and transfers ownership to the
+   *  destination.  If more than one @c auto_ptr owns the same object
+   *  at the same time the behavior of the program is undefined.
+   *
+   *  The uses of @c auto_ptr include providing temporary
+   *  exception-safety for dynamically allocated memory, passing
+   *  ownership of dynamically allocated memory to a function, and
+   *  returning dynamically allocated memory from a function.  @c
+   *  auto_ptr does not meet the CopyConstructible and Assignable
+   *  requirements for Standard Library container elements and thus
+   *  instantiating a Standard Library container with an @c auto_ptr
+   *  results in undefined behavior.
+   *  
+ * Quoted from [20.4.5]/3. + * + * Good examples of what can and cannot be done with auto_ptr can + * be found in the libstdc++ testsuite. + * + * _GLIBCXX_RESOLVE_LIB_DEFECTS + * 127. auto_ptr<> conversion issues + * These resolutions have all been incorporated. + */ + template + class auto_ptr + { + private: + _Tp* _M_ptr; + + public: + /// The pointed-to type. + typedef _Tp element_type; + + /** + * @brief An %auto_ptr is usually constructed from a raw pointer. + * @param __p A pointer (defaults to NULL). + * + * This object now @e owns the object pointed to by @a __p. + */ + explicit + auto_ptr(element_type* __p = 0) throw() : _M_ptr(__p) { } + + /** + * @brief An %auto_ptr can be constructed from another %auto_ptr. + * @param __a Another %auto_ptr of the same type. + * + * This object now @e owns the object previously owned by @a __a, + * which has given up ownership. + */ + auto_ptr(auto_ptr& __a) throw() : _M_ptr(__a.release()) { } + + /** + * @brief An %auto_ptr can be constructed from another %auto_ptr. + * @param __a Another %auto_ptr of a different but related type. + * + * A pointer-to-Tp1 must be convertible to a + * pointer-to-Tp/element_type. + * + * This object now @e owns the object previously owned by @a __a, + * which has given up ownership. + */ + template + auto_ptr(auto_ptr<_Tp1>& __a) throw() : _M_ptr(__a.release()) { } + + /** + * @brief %auto_ptr assignment operator. + * @param __a Another %auto_ptr of the same type. + * + * This object now @e owns the object previously owned by @a __a, + * which has given up ownership. The object that this one @e + * used to own and track has been deleted. + */ + auto_ptr& + operator=(auto_ptr& __a) throw() + { + reset(__a.release()); + return *this; + } + + /** + * @brief %auto_ptr assignment operator. + * @param __a Another %auto_ptr of a different but related type. + * + * A pointer-to-Tp1 must be convertible to a pointer-to-Tp/element_type. + * + * This object now @e owns the object previously owned by @a __a, + * which has given up ownership. The object that this one @e + * used to own and track has been deleted. + */ + template + auto_ptr& + operator=(auto_ptr<_Tp1>& __a) throw() + { + reset(__a.release()); + return *this; + } + + /** + * When the %auto_ptr goes out of scope, the object it owns is + * deleted. If it no longer owns anything (i.e., @c get() is + * @c NULL), then this has no effect. + * + * The C++ standard says there is supposed to be an empty throw + * specification here, but omitting it is standard conforming. Its + * presence can be detected only if _Tp::~_Tp() throws, but this is + * prohibited. [17.4.3.6]/2 + */ + ~auto_ptr() { delete _M_ptr; } + + /** + * @brief Smart pointer dereferencing. + * + * If this %auto_ptr no longer owns anything, then this + * operation will crash. (For a smart pointer, no longer owns + * anything is the same as being a null pointer, and you know + * what happens when you dereference one of those...) + */ + element_type& + operator*() const throw() + { + __glibcxx_assert(_M_ptr != 0); + return *_M_ptr; + } + + /** + * @brief Smart pointer dereferencing. + * + * This returns the pointer itself, which the language then will + * automatically cause to be dereferenced. + */ + element_type* + operator->() const throw() + { + __glibcxx_assert(_M_ptr != 0); + return _M_ptr; + } + + /** + * @brief Bypassing the smart pointer. + * @return The raw pointer being managed. + * + * You can get a copy of the pointer that this object owns, for + * situations such as passing to a function which only accepts + * a raw pointer. + * + * @note This %auto_ptr still owns the memory. + */ + element_type* + get() const throw() { return _M_ptr; } + + /** + * @brief Bypassing the smart pointer. + * @return The raw pointer being managed. + * + * You can get a copy of the pointer that this object owns, for + * situations such as passing to a function which only accepts + * a raw pointer. + * + * @note This %auto_ptr no longer owns the memory. When this object + * goes out of scope, nothing will happen. + */ + element_type* + release() throw() + { + element_type* __tmp = _M_ptr; + _M_ptr = 0; + return __tmp; + } + + /** + * @brief Forcibly deletes the managed object. + * @param __p A pointer (defaults to NULL). + * + * This object now @e owns the object pointed to by @a __p. The + * previous object has been deleted. + */ + void + reset(element_type* __p = 0) throw() + { + if (__p != _M_ptr) + { + delete _M_ptr; + _M_ptr = __p; + } + } + + /** + * @brief Automatic conversions + * + * These operations are supposed to convert an %auto_ptr into and from + * an auto_ptr_ref automatically as needed. This would allow + * constructs such as + * @code + * auto_ptr func_returning_auto_ptr(.....); + * ... + * auto_ptr ptr = func_returning_auto_ptr(.....); + * @endcode + * + * But it doesn't work, and won't be fixed. For further details see + * http://cplusplus.github.io/LWG/lwg-closed.html#463 + */ + auto_ptr(auto_ptr_ref __ref) throw() + : _M_ptr(__ref._M_ptr) { } + + auto_ptr& + operator=(auto_ptr_ref __ref) throw() + { + if (__ref._M_ptr != this->get()) + { + delete _M_ptr; + _M_ptr = __ref._M_ptr; + } + return *this; + } + + template + operator auto_ptr_ref<_Tp1>() throw() + { return auto_ptr_ref<_Tp1>(this->release()); } + + template + operator auto_ptr<_Tp1>() throw() + { return auto_ptr<_Tp1>(this->release()); } + } _GLIBCXX_DEPRECATED; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 541. shared_ptr template assignment and void + template<> + class auto_ptr + { + public: + typedef void element_type; + } _GLIBCXX_DEPRECATED; + +#if __cplusplus >= 201103L + template<_Lock_policy _Lp> + template + inline + __shared_count<_Lp>::__shared_count(std::auto_ptr<_Tp>&& __r) + : _M_pi(new _Sp_counted_ptr<_Tp*, _Lp>(__r.get())) + { __r.release(); } + + template + template + inline + __shared_ptr<_Tp, _Lp>::__shared_ptr(std::auto_ptr<_Tp1>&& __r) + : _M_ptr(__r.get()), _M_refcount() + { + __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>) + static_assert( sizeof(_Tp1) > 0, "incomplete type" ); + _Tp1* __tmp = __r.get(); + _M_refcount = __shared_count<_Lp>(std::move(__r)); + _M_enable_shared_from_this_with(__tmp); + } + + template + template + inline + shared_ptr<_Tp>::shared_ptr(std::auto_ptr<_Tp1>&& __r) + : __shared_ptr<_Tp>(std::move(__r)) { } + + template + template + inline + unique_ptr<_Tp, _Dp>::unique_ptr(auto_ptr<_Up>&& __u) noexcept + : _M_t(__u.release(), deleter_type()) { } +#endif + +#pragma GCC diagnostic pop + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif /* _BACKWARD_AUTO_PTR_H */ diff --git a/include/bits/shared_ptr.h b/include/bits/shared_ptr.h new file mode 100644 index 0000000..0c393e2 --- /dev/null +++ b/include/bits/shared_ptr.h @@ -0,0 +1,918 @@ +// shared_ptr and weak_ptr implementation -*- C++ -*- + +// Copyright (C) 2007-2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +// GCC Note: Based on files from version 1.32.0 of the Boost library. + +// shared_count.hpp +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. + +// shared_ptr.hpp +// Copyright (C) 1998, 1999 Greg Colvin and Beman Dawes. +// Copyright (C) 2001, 2002, 2003 Peter Dimov + +// weak_ptr.hpp +// Copyright (C) 2001, 2002, 2003 Peter Dimov + +// enable_shared_from_this.hpp +// Copyright (C) 2002 Peter Dimov + +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +/** @file + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{memory} + */ + +#ifndef _SHARED_PTR_H +#define _SHARED_PTR_H 1 + +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @addtogroup pointer_abstractions + * @{ + */ + + // 20.7.2.2.11 shared_ptr I/O + + /// Write the stored pointer to an ostream. + /// @relates shared_ptr + template + inline std::basic_ostream<_Ch, _Tr>& + operator<<(std::basic_ostream<_Ch, _Tr>& __os, + const __shared_ptr<_Tp, _Lp>& __p) + { + __os << __p.get(); + return __os; + } + + template + inline _Del* + get_deleter(const __shared_ptr<_Tp, _Lp>& __p) noexcept + { +#if __cpp_rtti + return static_cast<_Del*>(__p._M_get_deleter(typeid(_Del))); +#else + return 0; +#endif + } + + /// 20.7.2.2.10 shared_ptr get_deleter + + /// If `__p` has a deleter of type `_Del`, return a pointer to it. + /// @relates shared_ptr + template + inline _Del* + get_deleter(const shared_ptr<_Tp>& __p) noexcept + { +#if __cpp_rtti + return static_cast<_Del*>(__p._M_get_deleter(typeid(_Del))); +#else + return 0; +#endif + } + + /** + * @brief A smart pointer with reference-counted copy semantics. + * + * A `shared_ptr` object is either empty or _owns_ a pointer passed + * to the constructor. Copies of a `shared_ptr` share ownership of + * the same pointer. When the last `shared_ptr` that owns the pointer + * is destroyed or reset, the owned pointer is freed (either by `delete` + * or by invoking a custom deleter that was passed to the constructor). + * + * A `shared_ptr` also stores another pointer, which is usually + * (but not always) the same pointer as it owns. The stored pointer + * can be retrieved by calling the `get()` member function. + * + * The equality and relational operators for `shared_ptr` only compare + * the stored pointer returned by `get()`, not the owned pointer. + * To test whether two `shared_ptr` objects share ownership of the same + * pointer see `std::shared_ptr::owner_before` and `std::owner_less`. + */ + template + class shared_ptr : public __shared_ptr<_Tp> + { + template + using _Constructible = typename enable_if< + is_constructible<__shared_ptr<_Tp>, _Args...>::value + >::type; + + template + using _Assignable = typename enable_if< + is_assignable<__shared_ptr<_Tp>&, _Arg>::value, shared_ptr& + >::type; + + public: + + /// The type pointed to by the stored pointer, remove_extent_t<_Tp> + using element_type = typename __shared_ptr<_Tp>::element_type; + +#if __cplusplus >= 201703L +# define __cpp_lib_shared_ptr_weak_type 201606 + /// The corresponding weak_ptr type for this shared_ptr + using weak_type = weak_ptr<_Tp>; +#endif + /** + * @brief Construct an empty %shared_ptr. + * @post use_count()==0 && get()==0 + */ + constexpr shared_ptr() noexcept : __shared_ptr<_Tp>() { } + + shared_ptr(const shared_ptr&) noexcept = default; ///< Copy constructor + + /** + * @brief Construct a %shared_ptr that owns the pointer @a __p. + * @param __p A pointer that is convertible to element_type*. + * @post use_count() == 1 && get() == __p + * @throw std::bad_alloc, in which case @c delete @a __p is called. + */ + template> + explicit + shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { } + + /** + * @brief Construct a %shared_ptr that owns the pointer @a __p + * and the deleter @a __d. + * @param __p A pointer. + * @param __d A deleter. + * @post use_count() == 1 && get() == __p + * @throw std::bad_alloc, in which case @a __d(__p) is called. + * + * Requirements: _Deleter's copy constructor and destructor must + * not throw + * + * __shared_ptr will release __p by calling __d(__p) + */ + template> + shared_ptr(_Yp* __p, _Deleter __d) + : __shared_ptr<_Tp>(__p, std::move(__d)) { } + + /** + * @brief Construct a %shared_ptr that owns a null pointer + * and the deleter @a __d. + * @param __p A null pointer constant. + * @param __d A deleter. + * @post use_count() == 1 && get() == __p + * @throw std::bad_alloc, in which case @a __d(__p) is called. + * + * Requirements: _Deleter's copy constructor and destructor must + * not throw + * + * The last owner will call __d(__p) + */ + template + shared_ptr(nullptr_t __p, _Deleter __d) + : __shared_ptr<_Tp>(__p, std::move(__d)) { } + + /** + * @brief Construct a %shared_ptr that owns the pointer @a __p + * and the deleter @a __d. + * @param __p A pointer. + * @param __d A deleter. + * @param __a An allocator. + * @post use_count() == 1 && get() == __p + * @throw std::bad_alloc, in which case @a __d(__p) is called. + * + * Requirements: _Deleter's copy constructor and destructor must + * not throw _Alloc's copy constructor and destructor must not + * throw. + * + * __shared_ptr will release __p by calling __d(__p) + */ + template> + shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a) + : __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { } + + /** + * @brief Construct a %shared_ptr that owns a null pointer + * and the deleter @a __d. + * @param __p A null pointer constant. + * @param __d A deleter. + * @param __a An allocator. + * @post use_count() == 1 && get() == __p + * @throw std::bad_alloc, in which case @a __d(__p) is called. + * + * Requirements: _Deleter's copy constructor and destructor must + * not throw _Alloc's copy constructor and destructor must not + * throw. + * + * The last owner will call __d(__p) + */ + template + shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a) + : __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { } + + // Aliasing constructor + + /** + * @brief Constructs a `shared_ptr` instance that stores `__p` + * and shares ownership with `__r`. + * @param __r A `shared_ptr`. + * @param __p A pointer that will remain valid while `*__r` is valid. + * @post `get() == __p && use_count() == __r.use_count()` + * + * This can be used to construct a `shared_ptr` to a sub-object + * of an object managed by an existing `shared_ptr`. The complete + * object will remain valid while any `shared_ptr` owns it, even + * if they don't store a pointer to the complete object. + * + * @code + * shared_ptr> pii(new pair()); + * shared_ptr pi(pii, &pii->first); + * assert(pii.use_count() == 2); + * @endcode + */ + template + shared_ptr(const shared_ptr<_Yp>& __r, element_type* __p) noexcept + : __shared_ptr<_Tp>(__r, __p) { } + +#if __cplusplus > 201703L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2996. Missing rvalue overloads for shared_ptr operations + /** + * @brief Constructs a `shared_ptr` instance that stores `__p` + * and shares ownership with `__r`. + * @param __r A `shared_ptr`. + * @param __p A pointer that will remain valid while `*__r` is valid. + * @post `get() == __p && !__r.use_count() && !__r.get()` + * + * This can be used to construct a `shared_ptr` to a sub-object + * of an object managed by an existing `shared_ptr`. The complete + * object will remain valid while any `shared_ptr` owns it, even + * if they don't store a pointer to the complete object. + * + * @code + * shared_ptr> pii(new pair()); + * shared_ptr pi1(pii, &pii->first); + * assert(pii.use_count() == 2); + * shared_ptr pi2(std::move(pii), &pii->second); + * assert(pii.use_count() == 0); + * @endcode + */ + template + shared_ptr(shared_ptr<_Yp>&& __r, element_type* __p) noexcept + : __shared_ptr<_Tp>(std::move(__r), __p) { } +#endif + /** + * @brief If @a __r is empty, constructs an empty %shared_ptr; + * otherwise construct a %shared_ptr that shares ownership + * with @a __r. + * @param __r A %shared_ptr. + * @post get() == __r.get() && use_count() == __r.use_count() + */ + template&>> + shared_ptr(const shared_ptr<_Yp>& __r) noexcept + : __shared_ptr<_Tp>(__r) { } + + /** + * @brief Move-constructs a %shared_ptr instance from @a __r. + * @param __r A %shared_ptr rvalue. + * @post *this contains the old value of @a __r, @a __r is empty. + */ + shared_ptr(shared_ptr&& __r) noexcept + : __shared_ptr<_Tp>(std::move(__r)) { } + + /** + * @brief Move-constructs a %shared_ptr instance from @a __r. + * @param __r A %shared_ptr rvalue. + * @post *this contains the old value of @a __r, @a __r is empty. + */ + template>> + shared_ptr(shared_ptr<_Yp>&& __r) noexcept + : __shared_ptr<_Tp>(std::move(__r)) { } + + /** + * @brief Constructs a %shared_ptr that shares ownership with @a __r + * and stores a copy of the pointer stored in @a __r. + * @param __r A weak_ptr. + * @post use_count() == __r.use_count() + * @throw bad_weak_ptr when __r.expired(), + * in which case the constructor has no effect. + */ + template&>> + explicit shared_ptr(const weak_ptr<_Yp>& __r) + : __shared_ptr<_Tp>(__r) { } + +#if _GLIBCXX_USE_DEPRECATED +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + template>> + shared_ptr(auto_ptr<_Yp>&& __r); +#pragma GCC diagnostic pop +#endif + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2399. shared_ptr's constructor from unique_ptr should be constrained + template>> + shared_ptr(unique_ptr<_Yp, _Del>&& __r) + : __shared_ptr<_Tp>(std::move(__r)) { } + +#if __cplusplus <= 201402L && _GLIBCXX_USE_DEPRECATED + // This non-standard constructor exists to support conversions that + // were possible in C++11 and C++14 but are ill-formed in C++17. + // If an exception is thrown this constructor has no effect. + template, __sp_array_delete>* = 0> + shared_ptr(unique_ptr<_Yp, _Del>&& __r) + : __shared_ptr<_Tp>(std::move(__r), __sp_array_delete()) { } +#endif + + /** + * @brief Construct an empty %shared_ptr. + * @post use_count() == 0 && get() == nullptr + */ + constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { } + + shared_ptr& operator=(const shared_ptr&) noexcept = default; + + template + _Assignable&> + operator=(const shared_ptr<_Yp>& __r) noexcept + { + this->__shared_ptr<_Tp>::operator=(__r); + return *this; + } + +#if _GLIBCXX_USE_DEPRECATED +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + template + _Assignable> + operator=(auto_ptr<_Yp>&& __r) + { + this->__shared_ptr<_Tp>::operator=(std::move(__r)); + return *this; + } +#pragma GCC diagnostic pop +#endif + + shared_ptr& + operator=(shared_ptr&& __r) noexcept + { + this->__shared_ptr<_Tp>::operator=(std::move(__r)); + return *this; + } + + template + _Assignable> + operator=(shared_ptr<_Yp>&& __r) noexcept + { + this->__shared_ptr<_Tp>::operator=(std::move(__r)); + return *this; + } + + template + _Assignable> + operator=(unique_ptr<_Yp, _Del>&& __r) + { + this->__shared_ptr<_Tp>::operator=(std::move(__r)); + return *this; + } + + private: + // This constructor is non-standard, it is used by allocate_shared. + template + shared_ptr(_Sp_alloc_shared_tag<_Alloc> __tag, _Args&&... __args) + : __shared_ptr<_Tp>(__tag, std::forward<_Args>(__args)...) + { } + + template + friend shared_ptr<_Yp> + allocate_shared(const _Alloc& __a, _Args&&... __args); + + // This constructor is non-standard, it is used by weak_ptr::lock(). + shared_ptr(const weak_ptr<_Tp>& __r, std::nothrow_t) + : __shared_ptr<_Tp>(__r, std::nothrow) { } + + friend class weak_ptr<_Tp>; + }; + +#if __cpp_deduction_guides >= 201606 + template + shared_ptr(weak_ptr<_Tp>) -> shared_ptr<_Tp>; + template + shared_ptr(unique_ptr<_Tp, _Del>) -> shared_ptr<_Tp>; +#endif + + // 20.7.2.2.7 shared_ptr comparisons + + /// @relates shared_ptr @{ + + /// Equality operator for shared_ptr objects, compares the stored pointers + template + _GLIBCXX_NODISCARD inline bool + operator==(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept + { return __a.get() == __b.get(); } + + /// shared_ptr comparison with nullptr + template + _GLIBCXX_NODISCARD inline bool + operator==(const shared_ptr<_Tp>& __a, nullptr_t) noexcept + { return !__a; } + +#ifdef __cpp_lib_three_way_comparison + template + inline strong_ordering + operator<=>(const shared_ptr<_Tp>& __a, + const shared_ptr<_Up>& __b) noexcept + { return compare_three_way()(__a.get(), __b.get()); } + + template + inline strong_ordering + operator<=>(const shared_ptr<_Tp>& __a, nullptr_t) noexcept + { + using pointer = typename shared_ptr<_Tp>::element_type*; + return compare_three_way()(__a.get(), static_cast(nullptr)); + } +#else + /// shared_ptr comparison with nullptr + template + _GLIBCXX_NODISCARD inline bool + operator==(nullptr_t, const shared_ptr<_Tp>& __a) noexcept + { return !__a; } + + /// Inequality operator for shared_ptr objects, compares the stored pointers + template + _GLIBCXX_NODISCARD inline bool + operator!=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept + { return __a.get() != __b.get(); } + + /// shared_ptr comparison with nullptr + template + _GLIBCXX_NODISCARD inline bool + operator!=(const shared_ptr<_Tp>& __a, nullptr_t) noexcept + { return (bool)__a; } + + /// shared_ptr comparison with nullptr + template + _GLIBCXX_NODISCARD inline bool + operator!=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept + { return (bool)__a; } + + /// Relational operator for shared_ptr objects, compares the stored pointers + template + _GLIBCXX_NODISCARD inline bool + operator<(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept + { + using _Tp_elt = typename shared_ptr<_Tp>::element_type; + using _Up_elt = typename shared_ptr<_Up>::element_type; + using _Vp = typename common_type<_Tp_elt*, _Up_elt*>::type; + return less<_Vp>()(__a.get(), __b.get()); + } + + /// shared_ptr comparison with nullptr + template + _GLIBCXX_NODISCARD inline bool + operator<(const shared_ptr<_Tp>& __a, nullptr_t) noexcept + { + using _Tp_elt = typename shared_ptr<_Tp>::element_type; + return less<_Tp_elt*>()(__a.get(), nullptr); + } + + /// shared_ptr comparison with nullptr + template + _GLIBCXX_NODISCARD inline bool + operator<(nullptr_t, const shared_ptr<_Tp>& __a) noexcept + { + using _Tp_elt = typename shared_ptr<_Tp>::element_type; + return less<_Tp_elt*>()(nullptr, __a.get()); + } + + /// Relational operator for shared_ptr objects, compares the stored pointers + template + _GLIBCXX_NODISCARD inline bool + operator<=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept + { return !(__b < __a); } + + /// shared_ptr comparison with nullptr + template + _GLIBCXX_NODISCARD inline bool + operator<=(const shared_ptr<_Tp>& __a, nullptr_t) noexcept + { return !(nullptr < __a); } + + /// shared_ptr comparison with nullptr + template + _GLIBCXX_NODISCARD inline bool + operator<=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept + { return !(__a < nullptr); } + + /// Relational operator for shared_ptr objects, compares the stored pointers + template + _GLIBCXX_NODISCARD inline bool + operator>(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept + { return (__b < __a); } + + /// shared_ptr comparison with nullptr + template + _GLIBCXX_NODISCARD inline bool + operator>(const shared_ptr<_Tp>& __a, nullptr_t) noexcept + { return nullptr < __a; } + + /// shared_ptr comparison with nullptr + template + _GLIBCXX_NODISCARD inline bool + operator>(nullptr_t, const shared_ptr<_Tp>& __a) noexcept + { return __a < nullptr; } + + /// Relational operator for shared_ptr objects, compares the stored pointers + template + _GLIBCXX_NODISCARD inline bool + operator>=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept + { return !(__a < __b); } + + /// shared_ptr comparison with nullptr + template + _GLIBCXX_NODISCARD inline bool + operator>=(const shared_ptr<_Tp>& __a, nullptr_t) noexcept + { return !(__a < nullptr); } + + /// shared_ptr comparison with nullptr + template + _GLIBCXX_NODISCARD inline bool + operator>=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept + { return !(nullptr < __a); } +#endif + + // 20.7.2.2.8 shared_ptr specialized algorithms. + + /// Swap overload for shared_ptr + template + inline void + swap(shared_ptr<_Tp>& __a, shared_ptr<_Tp>& __b) noexcept + { __a.swap(__b); } + + // 20.7.2.2.9 shared_ptr casts. + + /// Convert type of `shared_ptr`, via `static_cast` + template + inline shared_ptr<_Tp> + static_pointer_cast(const shared_ptr<_Up>& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + return _Sp(__r, static_cast(__r.get())); + } + + /// Convert type of `shared_ptr`, via `const_cast` + template + inline shared_ptr<_Tp> + const_pointer_cast(const shared_ptr<_Up>& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + return _Sp(__r, const_cast(__r.get())); + } + + /// Convert type of `shared_ptr`, via `dynamic_cast` + template + inline shared_ptr<_Tp> + dynamic_pointer_cast(const shared_ptr<_Up>& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + if (auto* __p = dynamic_cast(__r.get())) + return _Sp(__r, __p); + return _Sp(); + } + +#if __cplusplus >= 201703L + /// Convert type of `shared_ptr`, via `reinterpret_cast` + template + inline shared_ptr<_Tp> + reinterpret_pointer_cast(const shared_ptr<_Up>& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + return _Sp(__r, reinterpret_cast(__r.get())); + } + +#if __cplusplus > 201703L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2996. Missing rvalue overloads for shared_ptr operations + + /// Convert type of `shared_ptr` rvalue, via `static_cast` + template + inline shared_ptr<_Tp> + static_pointer_cast(shared_ptr<_Up>&& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + return _Sp(std::move(__r), + static_cast(__r.get())); + } + + /// Convert type of `shared_ptr` rvalue, via `const_cast` + template + inline shared_ptr<_Tp> + const_pointer_cast(shared_ptr<_Up>&& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + return _Sp(std::move(__r), + const_cast(__r.get())); + } + + /// Convert type of `shared_ptr` rvalue, via `dynamic_cast` + template + inline shared_ptr<_Tp> + dynamic_pointer_cast(shared_ptr<_Up>&& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + if (auto* __p = dynamic_cast(__r.get())) + return _Sp(std::move(__r), __p); + return _Sp(); + } + + /// Convert type of `shared_ptr` rvalue, via `reinterpret_cast` + template + inline shared_ptr<_Tp> + reinterpret_pointer_cast(shared_ptr<_Up>&& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + return _Sp(std::move(__r), + reinterpret_cast(__r.get())); + } +#endif // C++20 +#endif // C++17 + + // @} + + /** + * @brief A non-owning observer for a pointer owned by a shared_ptr + * + * A weak_ptr provides a safe alternative to a raw pointer when you want + * a non-owning reference to an object that is managed by a shared_ptr. + * + * Unlike a raw pointer, a weak_ptr can be converted to a new shared_ptr + * that shares ownership with every other shared_ptr that already owns + * the pointer. In other words you can upgrade from a non-owning "weak" + * reference to an owning shared_ptr, without having access to any of + * the existing shared_ptr objects. + * + * Also unlike a raw pointer, a weak_ptr does not become "dangling" after + * the object it points to has been destroyed. Instead, a weak_ptr + * becomes _expired_ and can no longer be converted to a shared_ptr that + * owns the freed pointer, so you cannot accidentally access the pointed-to + * object after it has been destroyed. + */ + template + class weak_ptr : public __weak_ptr<_Tp> + { + template + using _Constructible = typename enable_if< + is_constructible<__weak_ptr<_Tp>, _Arg>::value + >::type; + + template + using _Assignable = typename enable_if< + is_assignable<__weak_ptr<_Tp>&, _Arg>::value, weak_ptr& + >::type; + + public: + constexpr weak_ptr() noexcept = default; + + template&>> + weak_ptr(const shared_ptr<_Yp>& __r) noexcept + : __weak_ptr<_Tp>(__r) { } + + weak_ptr(const weak_ptr&) noexcept = default; + + template&>> + weak_ptr(const weak_ptr<_Yp>& __r) noexcept + : __weak_ptr<_Tp>(__r) { } + + weak_ptr(weak_ptr&&) noexcept = default; + + template>> + weak_ptr(weak_ptr<_Yp>&& __r) noexcept + : __weak_ptr<_Tp>(std::move(__r)) { } + + weak_ptr& + operator=(const weak_ptr& __r) noexcept = default; + + template + _Assignable&> + operator=(const weak_ptr<_Yp>& __r) noexcept + { + this->__weak_ptr<_Tp>::operator=(__r); + return *this; + } + + template + _Assignable&> + operator=(const shared_ptr<_Yp>& __r) noexcept + { + this->__weak_ptr<_Tp>::operator=(__r); + return *this; + } + + weak_ptr& + operator=(weak_ptr&& __r) noexcept = default; + + template + _Assignable> + operator=(weak_ptr<_Yp>&& __r) noexcept + { + this->__weak_ptr<_Tp>::operator=(std::move(__r)); + return *this; + } + + shared_ptr<_Tp> + lock() const noexcept + { return shared_ptr<_Tp>(*this, std::nothrow); } + }; + +#if __cpp_deduction_guides >= 201606 + template + weak_ptr(shared_ptr<_Tp>) -> weak_ptr<_Tp>; +#endif + + // 20.7.2.3.6 weak_ptr specialized algorithms. + /// Swap overload for weak_ptr + /// @relates weak_ptr + template + inline void + swap(weak_ptr<_Tp>& __a, weak_ptr<_Tp>& __b) noexcept + { __a.swap(__b); } + + + /// Primary template owner_less + template + struct owner_less; + + /// Void specialization of owner_less compares either shared_ptr or weak_ptr + template<> + struct owner_less : _Sp_owner_less + { }; + + /// Partial specialization of owner_less for shared_ptr. + template + struct owner_less> + : public _Sp_owner_less, weak_ptr<_Tp>> + { }; + + /// Partial specialization of owner_less for weak_ptr. + template + struct owner_less> + : public _Sp_owner_less, shared_ptr<_Tp>> + { }; + + /** + * @brief Base class allowing use of member function shared_from_this. + */ + template + class enable_shared_from_this + { + protected: + constexpr enable_shared_from_this() noexcept { } + + enable_shared_from_this(const enable_shared_from_this&) noexcept { } + + enable_shared_from_this& + operator=(const enable_shared_from_this&) noexcept + { return *this; } + + ~enable_shared_from_this() { } + + public: + shared_ptr<_Tp> + shared_from_this() + { return shared_ptr<_Tp>(this->_M_weak_this); } + + shared_ptr + shared_from_this() const + { return shared_ptr(this->_M_weak_this); } + +#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 +#define __cpp_lib_enable_shared_from_this 201603 + weak_ptr<_Tp> + weak_from_this() noexcept + { return this->_M_weak_this; } + + weak_ptr + weak_from_this() const noexcept + { return this->_M_weak_this; } +#endif + + private: + template + void + _M_weak_assign(_Tp1* __p, const __shared_count<>& __n) const noexcept + { _M_weak_this._M_assign(__p, __n); } + + // Found by ADL when this is an associated class. + friend const enable_shared_from_this* + __enable_shared_from_this_base(const __shared_count<>&, + const enable_shared_from_this* __p) + { return __p; } + + template + friend class __shared_ptr; + + mutable weak_ptr<_Tp> _M_weak_this; + }; + + /// @relates shared_ptr @{ + + /** + * @brief Create an object that is owned by a shared_ptr. + * @param __a An allocator. + * @param __args Arguments for the @a _Tp object's constructor. + * @return A shared_ptr that owns the newly created object. + * @throw An exception thrown from @a _Alloc::allocate or from the + * constructor of @a _Tp. + * + * A copy of @a __a will be used to allocate memory for the shared_ptr + * and the new object. + */ + template + inline shared_ptr<_Tp> + allocate_shared(const _Alloc& __a, _Args&&... __args) + { + return shared_ptr<_Tp>(_Sp_alloc_shared_tag<_Alloc>{__a}, + std::forward<_Args>(__args)...); + } + + /** + * @brief Create an object that is owned by a shared_ptr. + * @param __args Arguments for the @a _Tp object's constructor. + * @return A shared_ptr that owns the newly created object. + * @throw std::bad_alloc, or an exception thrown from the + * constructor of @a _Tp. + */ + template + inline shared_ptr<_Tp> + make_shared(_Args&&... __args) + { + typedef typename std::remove_cv<_Tp>::type _Tp_nc; + return std::allocate_shared<_Tp>(std::allocator<_Tp_nc>(), + std::forward<_Args>(__args)...); + } + + /// std::hash specialization for shared_ptr. + template + struct hash> + : public __hash_base> + { + size_t + operator()(const shared_ptr<_Tp>& __s) const noexcept + { + return std::hash::element_type*>()(__s.get()); + } + }; + + // @} relates shared_ptr + // @} group pointer_abstractions + +#if __cplusplus >= 201703L + namespace __detail::__variant + { + template struct _Never_valueless_alt; // see + + // Provide the strong exception-safety guarantee when emplacing a + // shared_ptr into a variant. + template + struct _Never_valueless_alt> + : std::true_type + { }; + + // Provide the strong exception-safety guarantee when emplacing a + // weak_ptr into a variant. + template + struct _Never_valueless_alt> + : std::true_type + { }; + } // namespace __detail::__variant +#endif // C++17 + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif // _SHARED_PTR_H diff --git a/include/bits/shared_ptr_atomic.h b/include/bits/shared_ptr_atomic.h new file mode 100644 index 0000000..13eb7f4 --- /dev/null +++ b/include/bits/shared_ptr_atomic.h @@ -0,0 +1,336 @@ +// shared_ptr atomic access -*- C++ -*- + +// Copyright (C) 2014-2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/shared_ptr_atomic.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{memory} + */ + +#ifndef _SHARED_PTR_ATOMIC_H +#define _SHARED_PTR_ATOMIC_H 1 + +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @addtogroup pointer_abstractions + * @{ + */ + /// @relates shared_ptr @{ + + /// @cond undocumented + + struct _Sp_locker + { + _Sp_locker(const _Sp_locker&) = delete; + _Sp_locker& operator=(const _Sp_locker&) = delete; + +#ifdef __GTHREADS + explicit + _Sp_locker(const void*) noexcept; + _Sp_locker(const void*, const void*) noexcept; + ~_Sp_locker(); + + private: + unsigned char _M_key1; + unsigned char _M_key2; +#else + explicit _Sp_locker(const void*, const void* = nullptr) { } +#endif + }; + + /// @endcond + + /** + * @brief Report whether shared_ptr atomic operations are lock-free. + * @param __p A non-null pointer to a shared_ptr object. + * @return True if atomic access to @c *__p is lock-free, false otherwise. + * @{ + */ + template + inline bool + atomic_is_lock_free(const __shared_ptr<_Tp, _Lp>* __p) + { +#ifdef __GTHREADS + return __gthread_active_p() == 0; +#else + return true; +#endif + } + + template + inline bool + atomic_is_lock_free(const shared_ptr<_Tp>* __p) + { return std::atomic_is_lock_free<_Tp, __default_lock_policy>(__p); } + + // @} + + /** + * @brief Atomic load for shared_ptr objects. + * @param __p A non-null pointer to a shared_ptr object. + * @return @c *__p + * + * The memory order shall not be @c memory_order_release or + * @c memory_order_acq_rel. + * @{ + */ + template + inline shared_ptr<_Tp> + atomic_load_explicit(const shared_ptr<_Tp>* __p, memory_order) + { + _Sp_locker __lock{__p}; + return *__p; + } + + template + inline shared_ptr<_Tp> + atomic_load(const shared_ptr<_Tp>* __p) + { return std::atomic_load_explicit(__p, memory_order_seq_cst); } + + template + inline __shared_ptr<_Tp, _Lp> + atomic_load_explicit(const __shared_ptr<_Tp, _Lp>* __p, memory_order) + { + _Sp_locker __lock{__p}; + return *__p; + } + + template + inline __shared_ptr<_Tp, _Lp> + atomic_load(const __shared_ptr<_Tp, _Lp>* __p) + { return std::atomic_load_explicit(__p, memory_order_seq_cst); } + // @} + + /** + * @brief Atomic store for shared_ptr objects. + * @param __p A non-null pointer to a shared_ptr object. + * @param __r The value to store. + * + * The memory order shall not be @c memory_order_acquire or + * @c memory_order_acq_rel. + * @{ + */ + template + inline void + atomic_store_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r, + memory_order) + { + _Sp_locker __lock{__p}; + __p->swap(__r); // use swap so that **__p not destroyed while lock held + } + + template + inline void + atomic_store(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r) + { std::atomic_store_explicit(__p, std::move(__r), memory_order_seq_cst); } + + template + inline void + atomic_store_explicit(__shared_ptr<_Tp, _Lp>* __p, + __shared_ptr<_Tp, _Lp> __r, + memory_order) + { + _Sp_locker __lock{__p}; + __p->swap(__r); // use swap so that **__p not destroyed while lock held + } + + template + inline void + atomic_store(__shared_ptr<_Tp, _Lp>* __p, __shared_ptr<_Tp, _Lp> __r) + { std::atomic_store_explicit(__p, std::move(__r), memory_order_seq_cst); } + // @} + + /** + * @brief Atomic exchange for shared_ptr objects. + * @param __p A non-null pointer to a shared_ptr object. + * @param __r New value to store in @c *__p. + * @return The original value of @c *__p + * @{ + */ + template + inline shared_ptr<_Tp> + atomic_exchange_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r, + memory_order) + { + _Sp_locker __lock{__p}; + __p->swap(__r); + return __r; + } + + template + inline shared_ptr<_Tp> + atomic_exchange(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r) + { + return std::atomic_exchange_explicit(__p, std::move(__r), + memory_order_seq_cst); + } + + template + inline __shared_ptr<_Tp, _Lp> + atomic_exchange_explicit(__shared_ptr<_Tp, _Lp>* __p, + __shared_ptr<_Tp, _Lp> __r, + memory_order) + { + _Sp_locker __lock{__p}; + __p->swap(__r); + return __r; + } + + template + inline __shared_ptr<_Tp, _Lp> + atomic_exchange(__shared_ptr<_Tp, _Lp>* __p, __shared_ptr<_Tp, _Lp> __r) + { + return std::atomic_exchange_explicit(__p, std::move(__r), + memory_order_seq_cst); + } + // @} + + /** + * @brief Atomic compare-and-swap for shared_ptr objects. + * @param __p A non-null pointer to a shared_ptr object. + * @param __v A non-null pointer to a shared_ptr object. + * @param __w A non-null pointer to a shared_ptr object. + * @return True if @c *__p was equivalent to @c *__v, false otherwise. + * + * The memory order for failure shall not be @c memory_order_release or + * @c memory_order_acq_rel, or stronger than the memory order for success. + * @{ + */ + template + bool + atomic_compare_exchange_strong_explicit(shared_ptr<_Tp>* __p, + shared_ptr<_Tp>* __v, + shared_ptr<_Tp> __w, + memory_order, + memory_order) + { + shared_ptr<_Tp> __x; // goes out of scope after __lock + _Sp_locker __lock{__p, __v}; + owner_less> __less; + if (*__p == *__v && !__less(*__p, *__v) && !__less(*__v, *__p)) + { + __x = std::move(*__p); + *__p = std::move(__w); + return true; + } + __x = std::move(*__v); + *__v = *__p; + return false; + } + + template + inline bool + atomic_compare_exchange_strong(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, + shared_ptr<_Tp> __w) + { + return std::atomic_compare_exchange_strong_explicit(__p, __v, + std::move(__w), memory_order_seq_cst, memory_order_seq_cst); + } + + template + inline bool + atomic_compare_exchange_weak_explicit(shared_ptr<_Tp>* __p, + shared_ptr<_Tp>* __v, + shared_ptr<_Tp> __w, + memory_order __success, + memory_order __failure) + { + return std::atomic_compare_exchange_strong_explicit(__p, __v, + std::move(__w), __success, __failure); + } + + template + inline bool + atomic_compare_exchange_weak(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, + shared_ptr<_Tp> __w) + { + return std::atomic_compare_exchange_weak_explicit(__p, __v, + std::move(__w), memory_order_seq_cst, memory_order_seq_cst); + } + + template + bool + atomic_compare_exchange_strong_explicit(__shared_ptr<_Tp, _Lp>* __p, + __shared_ptr<_Tp, _Lp>* __v, + __shared_ptr<_Tp, _Lp> __w, + memory_order, + memory_order) + { + __shared_ptr<_Tp, _Lp> __x; // goes out of scope after __lock + _Sp_locker __lock{__p, __v}; + owner_less<__shared_ptr<_Tp, _Lp>> __less; + if (*__p == *__v && !__less(*__p, *__v) && !__less(*__v, *__p)) + { + __x = std::move(*__p); + *__p = std::move(__w); + return true; + } + __x = std::move(*__v); + *__v = *__p; + return false; + } + + template + inline bool + atomic_compare_exchange_strong(__shared_ptr<_Tp, _Lp>* __p, + __shared_ptr<_Tp, _Lp>* __v, + __shared_ptr<_Tp, _Lp> __w) + { + return std::atomic_compare_exchange_strong_explicit(__p, __v, + std::move(__w), memory_order_seq_cst, memory_order_seq_cst); + } + + template + inline bool + atomic_compare_exchange_weak_explicit(__shared_ptr<_Tp, _Lp>* __p, + __shared_ptr<_Tp, _Lp>* __v, + __shared_ptr<_Tp, _Lp> __w, + memory_order __success, + memory_order __failure) + { + return std::atomic_compare_exchange_strong_explicit(__p, __v, + std::move(__w), __success, __failure); + } + + template + inline bool + atomic_compare_exchange_weak(__shared_ptr<_Tp, _Lp>* __p, + __shared_ptr<_Tp, _Lp>* __v, + __shared_ptr<_Tp, _Lp> __w) + { + return std::atomic_compare_exchange_weak_explicit(__p, __v, + std::move(__w), memory_order_seq_cst, memory_order_seq_cst); + } + // @} + + // @} relates shared_ptr + // @} group pointer_abstractions + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif // _SHARED_PTR_ATOMIC_H diff --git a/include/bits/shared_ptr_base.h b/include/bits/shared_ptr_base.h new file mode 100644 index 0000000..ff578e6 --- /dev/null +++ b/include/bits/shared_ptr_base.h @@ -0,0 +1,1898 @@ +// shared_ptr and weak_ptr implementation details -*- C++ -*- + +// Copyright (C) 2007-2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +// GCC Note: Based on files from version 1.32.0 of the Boost library. + +// shared_count.hpp +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. + +// shared_ptr.hpp +// Copyright (C) 1998, 1999 Greg Colvin and Beman Dawes. +// Copyright (C) 2001, 2002, 2003 Peter Dimov + +// weak_ptr.hpp +// Copyright (C) 2001, 2002, 2003 Peter Dimov + +// enable_shared_from_this.hpp +// Copyright (C) 2002 Peter Dimov + +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +/** @file bits/shared_ptr_base.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{memory} + */ + +#ifndef _SHARED_PTR_BASE_H +#define _SHARED_PTR_BASE_H 1 + +#include +#include +#include +#include +#include +#if __cplusplus > 201703L +# include +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +#if _GLIBCXX_USE_DEPRECATED +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + template class auto_ptr; +#pragma GCC diagnostic pop +#endif + + /** + * @brief Exception possibly thrown by @c shared_ptr. + * @ingroup exceptions + */ + class bad_weak_ptr : public std::exception + { + public: + virtual char const* what() const noexcept; + + virtual ~bad_weak_ptr() noexcept; + }; + + // Substitute for bad_weak_ptr object in the case of -fno-exceptions. + inline void + __throw_bad_weak_ptr() + { _GLIBCXX_THROW_OR_ABORT(bad_weak_ptr()); } + + using __gnu_cxx::_Lock_policy; + using __gnu_cxx::__default_lock_policy; + using __gnu_cxx::_S_single; + using __gnu_cxx::_S_mutex; + using __gnu_cxx::_S_atomic; + + // Empty helper class except when the template argument is _S_mutex. + template<_Lock_policy _Lp> + class _Mutex_base + { + protected: + // The atomic policy uses fully-fenced builtins, single doesn't care. + enum { _S_need_barriers = 0 }; + }; + + template<> + class _Mutex_base<_S_mutex> + : public __gnu_cxx::__mutex + { + protected: + // This policy is used when atomic builtins are not available. + // The replacement atomic operations might not have the necessary + // memory barriers. + enum { _S_need_barriers = 1 }; + }; + + template<_Lock_policy _Lp = __default_lock_policy> + class _Sp_counted_base + : public _Mutex_base<_Lp> + { + public: + _Sp_counted_base() noexcept + : _M_use_count(1), _M_weak_count(1) { } + + virtual + ~_Sp_counted_base() noexcept + { } + + // Called when _M_use_count drops to zero, to release the resources + // managed by *this. + virtual void + _M_dispose() noexcept = 0; + + // Called when _M_weak_count drops to zero. + virtual void + _M_destroy() noexcept + { delete this; } + + virtual void* + _M_get_deleter(const std::type_info&) noexcept = 0; + + void + _M_add_ref_copy() + { __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); } + + void + _M_add_ref_lock(); + + bool + _M_add_ref_lock_nothrow(); + + void + _M_release() noexcept + { + // Be race-detector-friendly. For more info see bits/c++config. + _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count); + if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1) + { + _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count); + _M_dispose(); + // There must be a memory barrier between dispose() and destroy() + // to ensure that the effects of dispose() are observed in the + // thread that runs destroy(). + // See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html + if (_Mutex_base<_Lp>::_S_need_barriers) + { + __atomic_thread_fence (__ATOMIC_ACQ_REL); + } + + // Be race-detector-friendly. For more info see bits/c++config. + _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count); + if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, + -1) == 1) + { + _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count); + _M_destroy(); + } + } + } + + void + _M_weak_add_ref() noexcept + { __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); } + + void + _M_weak_release() noexcept + { + // Be race-detector-friendly. For more info see bits/c++config. + _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count); + if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1) + { + _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count); + if (_Mutex_base<_Lp>::_S_need_barriers) + { + // See _M_release(), + // destroy() must observe results of dispose() + __atomic_thread_fence (__ATOMIC_ACQ_REL); + } + _M_destroy(); + } + } + + long + _M_get_use_count() const noexcept + { + // No memory barrier is used here so there is no synchronization + // with other threads. + return __atomic_load_n(&_M_use_count, __ATOMIC_RELAXED); + } + + private: + _Sp_counted_base(_Sp_counted_base const&) = delete; + _Sp_counted_base& operator=(_Sp_counted_base const&) = delete; + + _Atomic_word _M_use_count; // #shared + _Atomic_word _M_weak_count; // #weak + (#shared != 0) + }; + + template<> + inline void + _Sp_counted_base<_S_single>:: + _M_add_ref_lock() + { + if (_M_use_count == 0) + __throw_bad_weak_ptr(); + ++_M_use_count; + } + + template<> + inline void + _Sp_counted_base<_S_mutex>:: + _M_add_ref_lock() + { + __gnu_cxx::__scoped_lock sentry(*this); + if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0) + { + _M_use_count = 0; + __throw_bad_weak_ptr(); + } + } + + template<> + inline void + _Sp_counted_base<_S_atomic>:: + _M_add_ref_lock() + { + // Perform lock-free add-if-not-zero operation. + _Atomic_word __count = _M_get_use_count(); + do + { + if (__count == 0) + __throw_bad_weak_ptr(); + // Replace the current counter value with the old value + 1, as + // long as it's not changed meanwhile. + } + while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1, + true, __ATOMIC_ACQ_REL, + __ATOMIC_RELAXED)); + } + + template<> + inline bool + _Sp_counted_base<_S_single>:: + _M_add_ref_lock_nothrow() + { + if (_M_use_count == 0) + return false; + ++_M_use_count; + return true; + } + + template<> + inline bool + _Sp_counted_base<_S_mutex>:: + _M_add_ref_lock_nothrow() + { + __gnu_cxx::__scoped_lock sentry(*this); + if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0) + { + _M_use_count = 0; + return false; + } + return true; + } + + template<> + inline bool + _Sp_counted_base<_S_atomic>:: + _M_add_ref_lock_nothrow() + { + // Perform lock-free add-if-not-zero operation. + _Atomic_word __count = _M_get_use_count(); + do + { + if (__count == 0) + return false; + // Replace the current counter value with the old value + 1, as + // long as it's not changed meanwhile. + } + while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1, + true, __ATOMIC_ACQ_REL, + __ATOMIC_RELAXED)); + return true; + } + + template<> + inline void + _Sp_counted_base<_S_single>::_M_add_ref_copy() + { ++_M_use_count; } + + template<> + inline void + _Sp_counted_base<_S_single>::_M_release() noexcept + { + if (--_M_use_count == 0) + { + _M_dispose(); + if (--_M_weak_count == 0) + _M_destroy(); + } + } + + template<> + inline void + _Sp_counted_base<_S_single>::_M_weak_add_ref() noexcept + { ++_M_weak_count; } + + template<> + inline void + _Sp_counted_base<_S_single>::_M_weak_release() noexcept + { + if (--_M_weak_count == 0) + _M_destroy(); + } + + template<> + inline long + _Sp_counted_base<_S_single>::_M_get_use_count() const noexcept + { return _M_use_count; } + + + // Forward declarations. + template + class __shared_ptr; + + template + class __weak_ptr; + + template + class __enable_shared_from_this; + + template + class shared_ptr; + + template + class weak_ptr; + + template + struct owner_less; + + template + class enable_shared_from_this; + + template<_Lock_policy _Lp = __default_lock_policy> + class __weak_count; + + template<_Lock_policy _Lp = __default_lock_policy> + class __shared_count; + + + // Counted ptr with no deleter or allocator support + template + class _Sp_counted_ptr final : public _Sp_counted_base<_Lp> + { + public: + explicit + _Sp_counted_ptr(_Ptr __p) noexcept + : _M_ptr(__p) { } + + virtual void + _M_dispose() noexcept + { delete _M_ptr; } + + virtual void + _M_destroy() noexcept + { delete this; } + + virtual void* + _M_get_deleter(const std::type_info&) noexcept + { return nullptr; } + + _Sp_counted_ptr(const _Sp_counted_ptr&) = delete; + _Sp_counted_ptr& operator=(const _Sp_counted_ptr&) = delete; + + private: + _Ptr _M_ptr; + }; + + template<> + inline void + _Sp_counted_ptr::_M_dispose() noexcept { } + + template<> + inline void + _Sp_counted_ptr::_M_dispose() noexcept { } + + template<> + inline void + _Sp_counted_ptr::_M_dispose() noexcept { } + + template + struct _Sp_ebo_helper; + + /// Specialization using EBO. + template + struct _Sp_ebo_helper<_Nm, _Tp, true> : private _Tp + { + explicit _Sp_ebo_helper(const _Tp& __tp) : _Tp(__tp) { } + explicit _Sp_ebo_helper(_Tp&& __tp) : _Tp(std::move(__tp)) { } + + static _Tp& + _S_get(_Sp_ebo_helper& __eboh) { return static_cast<_Tp&>(__eboh); } + }; + + /// Specialization not using EBO. + template + struct _Sp_ebo_helper<_Nm, _Tp, false> + { + explicit _Sp_ebo_helper(const _Tp& __tp) : _M_tp(__tp) { } + explicit _Sp_ebo_helper(_Tp&& __tp) : _M_tp(std::move(__tp)) { } + + static _Tp& + _S_get(_Sp_ebo_helper& __eboh) + { return __eboh._M_tp; } + + private: + _Tp _M_tp; + }; + + // Support for custom deleter and/or allocator + template + class _Sp_counted_deleter final : public _Sp_counted_base<_Lp> + { + class _Impl : _Sp_ebo_helper<0, _Deleter>, _Sp_ebo_helper<1, _Alloc> + { + typedef _Sp_ebo_helper<0, _Deleter> _Del_base; + typedef _Sp_ebo_helper<1, _Alloc> _Alloc_base; + + public: + _Impl(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept + : _M_ptr(__p), _Del_base(std::move(__d)), _Alloc_base(__a) + { } + + _Deleter& _M_del() noexcept { return _Del_base::_S_get(*this); } + _Alloc& _M_alloc() noexcept { return _Alloc_base::_S_get(*this); } + + _Ptr _M_ptr; + }; + + public: + using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_deleter>; + + // __d(__p) must not throw. + _Sp_counted_deleter(_Ptr __p, _Deleter __d) noexcept + : _M_impl(__p, std::move(__d), _Alloc()) { } + + // __d(__p) must not throw. + _Sp_counted_deleter(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept + : _M_impl(__p, std::move(__d), __a) { } + + ~_Sp_counted_deleter() noexcept { } + + virtual void + _M_dispose() noexcept + { _M_impl._M_del()(_M_impl._M_ptr); } + + virtual void + _M_destroy() noexcept + { + __allocator_type __a(_M_impl._M_alloc()); + __allocated_ptr<__allocator_type> __guard_ptr{ __a, this }; + this->~_Sp_counted_deleter(); + } + + virtual void* + _M_get_deleter(const std::type_info& __ti) noexcept + { +#if __cpp_rtti + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2400. shared_ptr's get_deleter() should use addressof() + return __ti == typeid(_Deleter) + ? std::__addressof(_M_impl._M_del()) + : nullptr; +#else + return nullptr; +#endif + } + + private: + _Impl _M_impl; + }; + + // helpers for make_shared / allocate_shared + + struct _Sp_make_shared_tag + { + private: + template + friend class _Sp_counted_ptr_inplace; + + static const type_info& + _S_ti() noexcept _GLIBCXX_VISIBILITY(default) + { + alignas(type_info) static constexpr char __tag[sizeof(type_info)] = { }; + return reinterpret_cast(__tag); + } + + static bool _S_eq(const type_info&) noexcept; + }; + + template + struct _Sp_alloc_shared_tag + { + const _Alloc& _M_a; + }; + + template + class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp> + { + class _Impl : _Sp_ebo_helper<0, _Alloc> + { + typedef _Sp_ebo_helper<0, _Alloc> _A_base; + + public: + explicit _Impl(_Alloc __a) noexcept : _A_base(__a) { } + + _Alloc& _M_alloc() noexcept { return _A_base::_S_get(*this); } + + __gnu_cxx::__aligned_buffer<_Tp> _M_storage; + }; + + public: + using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_ptr_inplace>; + + // Alloc parameter is not a reference so doesn't alias anything in __args + template + _Sp_counted_ptr_inplace(_Alloc __a, _Args&&... __args) + : _M_impl(__a) + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2070. allocate_shared should use allocator_traits::construct + allocator_traits<_Alloc>::construct(__a, _M_ptr(), + std::forward<_Args>(__args)...); // might throw + } + + ~_Sp_counted_ptr_inplace() noexcept { } + + virtual void + _M_dispose() noexcept + { + allocator_traits<_Alloc>::destroy(_M_impl._M_alloc(), _M_ptr()); + } + + // Override because the allocator needs to know the dynamic type + virtual void + _M_destroy() noexcept + { + __allocator_type __a(_M_impl._M_alloc()); + __allocated_ptr<__allocator_type> __guard_ptr{ __a, this }; + this->~_Sp_counted_ptr_inplace(); + } + + private: + friend class __shared_count<_Lp>; // To be able to call _M_ptr(). + + // No longer used, but code compiled against old libstdc++ headers + // might still call it from __shared_ptr ctor to get the pointer out. + virtual void* + _M_get_deleter(const std::type_info& __ti) noexcept override + { + auto __ptr = const_cast::type*>(_M_ptr()); + // Check for the fake type_info first, so we don't try to access it + // as a real type_info object. Otherwise, check if it's the real + // type_info for this class. With RTTI enabled we can check directly, + // or call a library function to do it. + if (&__ti == &_Sp_make_shared_tag::_S_ti() + || +#if __cpp_rtti + __ti == typeid(_Sp_make_shared_tag) +#else + _Sp_make_shared_tag::_S_eq(__ti) +#endif + ) + return __ptr; + return nullptr; + } + + _Tp* _M_ptr() noexcept { return _M_impl._M_storage._M_ptr(); } + + _Impl _M_impl; + }; + + // The default deleter for shared_ptr and shared_ptr. + struct __sp_array_delete + { + template + void operator()(_Yp* __p) const { delete[] __p; } + }; + + template<_Lock_policy _Lp> + class __shared_count + { + template + struct __not_alloc_shared_tag { using type = void; }; + + template + struct __not_alloc_shared_tag<_Sp_alloc_shared_tag<_Tp>> { }; + + public: + constexpr __shared_count() noexcept : _M_pi(0) + { } + + template + explicit + __shared_count(_Ptr __p) : _M_pi(0) + { + __try + { + _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p); + } + __catch(...) + { + delete __p; + __throw_exception_again; + } + } + + template + __shared_count(_Ptr __p, /* is_array = */ false_type) + : __shared_count(__p) + { } + + template + __shared_count(_Ptr __p, /* is_array = */ true_type) + : __shared_count(__p, __sp_array_delete{}, allocator()) + { } + + template::type> + __shared_count(_Ptr __p, _Deleter __d) + : __shared_count(__p, std::move(__d), allocator()) + { } + + template::type> + __shared_count(_Ptr __p, _Deleter __d, _Alloc __a) : _M_pi(0) + { + typedef _Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp> _Sp_cd_type; + __try + { + typename _Sp_cd_type::__allocator_type __a2(__a); + auto __guard = std::__allocate_guarded(__a2); + _Sp_cd_type* __mem = __guard.get(); + ::new (__mem) _Sp_cd_type(__p, std::move(__d), std::move(__a)); + _M_pi = __mem; + __guard = nullptr; + } + __catch(...) + { + __d(__p); // Call _Deleter on __p. + __throw_exception_again; + } + } + + template + __shared_count(_Tp*& __p, _Sp_alloc_shared_tag<_Alloc> __a, + _Args&&... __args) + { + typedef _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> _Sp_cp_type; + typename _Sp_cp_type::__allocator_type __a2(__a._M_a); + auto __guard = std::__allocate_guarded(__a2); + _Sp_cp_type* __mem = __guard.get(); + auto __pi = ::new (__mem) + _Sp_cp_type(__a._M_a, std::forward<_Args>(__args)...); + __guard = nullptr; + _M_pi = __pi; + __p = __pi->_M_ptr(); + } + +#if _GLIBCXX_USE_DEPRECATED +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + // Special case for auto_ptr<_Tp> to provide the strong guarantee. + template + explicit + __shared_count(std::auto_ptr<_Tp>&& __r); +#pragma GCC diagnostic pop +#endif + + // Special case for unique_ptr<_Tp,_Del> to provide the strong guarantee. + template + explicit + __shared_count(std::unique_ptr<_Tp, _Del>&& __r) : _M_pi(0) + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2415. Inconsistency between unique_ptr and shared_ptr + if (__r.get() == nullptr) + return; + + using _Ptr = typename unique_ptr<_Tp, _Del>::pointer; + using _Del2 = typename conditional::value, + reference_wrapper::type>, + _Del>::type; + using _Sp_cd_type + = _Sp_counted_deleter<_Ptr, _Del2, allocator, _Lp>; + using _Alloc = allocator<_Sp_cd_type>; + using _Alloc_traits = allocator_traits<_Alloc>; + _Alloc __a; + _Sp_cd_type* __mem = _Alloc_traits::allocate(__a, 1); + _Alloc_traits::construct(__a, __mem, __r.release(), + __r.get_deleter()); // non-throwing + _M_pi = __mem; + } + + // Throw bad_weak_ptr when __r._M_get_use_count() == 0. + explicit __shared_count(const __weak_count<_Lp>& __r); + + // Does not throw if __r._M_get_use_count() == 0, caller must check. + explicit __shared_count(const __weak_count<_Lp>& __r, std::nothrow_t); + + ~__shared_count() noexcept + { + if (_M_pi != nullptr) + _M_pi->_M_release(); + } + + __shared_count(const __shared_count& __r) noexcept + : _M_pi(__r._M_pi) + { + if (_M_pi != 0) + _M_pi->_M_add_ref_copy(); + } + + __shared_count& + operator=(const __shared_count& __r) noexcept + { + _Sp_counted_base<_Lp>* __tmp = __r._M_pi; + if (__tmp != _M_pi) + { + if (__tmp != 0) + __tmp->_M_add_ref_copy(); + if (_M_pi != 0) + _M_pi->_M_release(); + _M_pi = __tmp; + } + return *this; + } + + void + _M_swap(__shared_count& __r) noexcept + { + _Sp_counted_base<_Lp>* __tmp = __r._M_pi; + __r._M_pi = _M_pi; + _M_pi = __tmp; + } + + long + _M_get_use_count() const noexcept + { return _M_pi != 0 ? _M_pi->_M_get_use_count() : 0; } + + bool + _M_unique() const noexcept + { return this->_M_get_use_count() == 1; } + + void* + _M_get_deleter(const std::type_info& __ti) const noexcept + { return _M_pi ? _M_pi->_M_get_deleter(__ti) : nullptr; } + + bool + _M_less(const __shared_count& __rhs) const noexcept + { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); } + + bool + _M_less(const __weak_count<_Lp>& __rhs) const noexcept + { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); } + + // Friend function injected into enclosing namespace and found by ADL + friend inline bool + operator==(const __shared_count& __a, const __shared_count& __b) noexcept + { return __a._M_pi == __b._M_pi; } + + private: + friend class __weak_count<_Lp>; + + _Sp_counted_base<_Lp>* _M_pi; + }; + + + template<_Lock_policy _Lp> + class __weak_count + { + public: + constexpr __weak_count() noexcept : _M_pi(nullptr) + { } + + __weak_count(const __shared_count<_Lp>& __r) noexcept + : _M_pi(__r._M_pi) + { + if (_M_pi != nullptr) + _M_pi->_M_weak_add_ref(); + } + + __weak_count(const __weak_count& __r) noexcept + : _M_pi(__r._M_pi) + { + if (_M_pi != nullptr) + _M_pi->_M_weak_add_ref(); + } + + __weak_count(__weak_count&& __r) noexcept + : _M_pi(__r._M_pi) + { __r._M_pi = nullptr; } + + ~__weak_count() noexcept + { + if (_M_pi != nullptr) + _M_pi->_M_weak_release(); + } + + __weak_count& + operator=(const __shared_count<_Lp>& __r) noexcept + { + _Sp_counted_base<_Lp>* __tmp = __r._M_pi; + if (__tmp != nullptr) + __tmp->_M_weak_add_ref(); + if (_M_pi != nullptr) + _M_pi->_M_weak_release(); + _M_pi = __tmp; + return *this; + } + + __weak_count& + operator=(const __weak_count& __r) noexcept + { + _Sp_counted_base<_Lp>* __tmp = __r._M_pi; + if (__tmp != nullptr) + __tmp->_M_weak_add_ref(); + if (_M_pi != nullptr) + _M_pi->_M_weak_release(); + _M_pi = __tmp; + return *this; + } + + __weak_count& + operator=(__weak_count&& __r) noexcept + { + if (_M_pi != nullptr) + _M_pi->_M_weak_release(); + _M_pi = __r._M_pi; + __r._M_pi = nullptr; + return *this; + } + + void + _M_swap(__weak_count& __r) noexcept + { + _Sp_counted_base<_Lp>* __tmp = __r._M_pi; + __r._M_pi = _M_pi; + _M_pi = __tmp; + } + + long + _M_get_use_count() const noexcept + { return _M_pi != nullptr ? _M_pi->_M_get_use_count() : 0; } + + bool + _M_less(const __weak_count& __rhs) const noexcept + { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); } + + bool + _M_less(const __shared_count<_Lp>& __rhs) const noexcept + { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); } + + // Friend function injected into enclosing namespace and found by ADL + friend inline bool + operator==(const __weak_count& __a, const __weak_count& __b) noexcept + { return __a._M_pi == __b._M_pi; } + + private: + friend class __shared_count<_Lp>; + + _Sp_counted_base<_Lp>* _M_pi; + }; + + // Now that __weak_count is defined we can define this constructor: + template<_Lock_policy _Lp> + inline + __shared_count<_Lp>::__shared_count(const __weak_count<_Lp>& __r) + : _M_pi(__r._M_pi) + { + if (_M_pi != nullptr) + _M_pi->_M_add_ref_lock(); + else + __throw_bad_weak_ptr(); + } + + // Now that __weak_count is defined we can define this constructor: + template<_Lock_policy _Lp> + inline + __shared_count<_Lp>:: + __shared_count(const __weak_count<_Lp>& __r, std::nothrow_t) + : _M_pi(__r._M_pi) + { + if (_M_pi != nullptr) + if (!_M_pi->_M_add_ref_lock_nothrow()) + _M_pi = nullptr; + } + +#define __cpp_lib_shared_ptr_arrays 201611L + + // Helper traits for shared_ptr of array: + + // A pointer type Y* is said to be compatible with a pointer type T* when + // either Y* is convertible to T* or Y is U[N] and T is U cv []. + template + struct __sp_compatible_with + : false_type + { }; + + template + struct __sp_compatible_with<_Yp*, _Tp*> + : is_convertible<_Yp*, _Tp*>::type + { }; + + template + struct __sp_compatible_with<_Up(*)[_Nm], _Up(*)[]> + : true_type + { }; + + template + struct __sp_compatible_with<_Up(*)[_Nm], const _Up(*)[]> + : true_type + { }; + + template + struct __sp_compatible_with<_Up(*)[_Nm], volatile _Up(*)[]> + : true_type + { }; + + template + struct __sp_compatible_with<_Up(*)[_Nm], const volatile _Up(*)[]> + : true_type + { }; + + // Test conversion from Y(*)[N] to U(*)[N] without forming invalid type Y[N]. + template + struct __sp_is_constructible_arrN + : false_type + { }; + + template + struct __sp_is_constructible_arrN<_Up, _Nm, _Yp, __void_t<_Yp[_Nm]>> + : is_convertible<_Yp(*)[_Nm], _Up(*)[_Nm]>::type + { }; + + // Test conversion from Y(*)[] to U(*)[] without forming invalid type Y[]. + template + struct __sp_is_constructible_arr + : false_type + { }; + + template + struct __sp_is_constructible_arr<_Up, _Yp, __void_t<_Yp[]>> + : is_convertible<_Yp(*)[], _Up(*)[]>::type + { }; + + // Trait to check if shared_ptr can be constructed from Y*. + template + struct __sp_is_constructible; + + // When T is U[N], Y(*)[N] shall be convertible to T*; + template + struct __sp_is_constructible<_Up[_Nm], _Yp> + : __sp_is_constructible_arrN<_Up, _Nm, _Yp>::type + { }; + + // when T is U[], Y(*)[] shall be convertible to T*; + template + struct __sp_is_constructible<_Up[], _Yp> + : __sp_is_constructible_arr<_Up, _Yp>::type + { }; + + // otherwise, Y* shall be convertible to T*. + template + struct __sp_is_constructible + : is_convertible<_Yp*, _Tp*>::type + { }; + + + // Define operator* and operator-> for shared_ptr. + template::value, bool = is_void<_Tp>::value> + class __shared_ptr_access + { + public: + using element_type = _Tp; + + element_type& + operator*() const noexcept + { + __glibcxx_assert(_M_get() != nullptr); + return *_M_get(); + } + + element_type* + operator->() const noexcept + { + _GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr); + return _M_get(); + } + + private: + element_type* + _M_get() const noexcept + { return static_cast*>(this)->get(); } + }; + + // Define operator-> for shared_ptr. + template + class __shared_ptr_access<_Tp, _Lp, false, true> + { + public: + using element_type = _Tp; + + element_type* + operator->() const noexcept + { + auto __ptr = static_cast*>(this)->get(); + _GLIBCXX_DEBUG_PEDASSERT(__ptr != nullptr); + return __ptr; + } + }; + + // Define operator[] for shared_ptr and shared_ptr. + template + class __shared_ptr_access<_Tp, _Lp, true, false> + { + public: + using element_type = typename remove_extent<_Tp>::type; + +#if __cplusplus <= 201402L + [[__deprecated__("shared_ptr::operator* is absent from C++17")]] + element_type& + operator*() const noexcept + { + __glibcxx_assert(_M_get() != nullptr); + return *_M_get(); + } + + [[__deprecated__("shared_ptr::operator-> is absent from C++17")]] + element_type* + operator->() const noexcept + { + _GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr); + return _M_get(); + } +#endif + + element_type& + operator[](ptrdiff_t __i) const + { + __glibcxx_assert(_M_get() != nullptr); + __glibcxx_assert(!extent<_Tp>::value || __i < extent<_Tp>::value); + return _M_get()[__i]; + } + + private: + element_type* + _M_get() const noexcept + { return static_cast*>(this)->get(); } + }; + + template + class __shared_ptr + : public __shared_ptr_access<_Tp, _Lp> + { + public: + using element_type = typename remove_extent<_Tp>::type; + + private: + // Constraint for taking ownership of a pointer of type _Yp*: + template + using _SafeConv + = typename enable_if<__sp_is_constructible<_Tp, _Yp>::value>::type; + + // Constraint for construction from shared_ptr and weak_ptr: + template + using _Compatible = typename + enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type; + + // Constraint for assignment from shared_ptr and weak_ptr: + template + using _Assignable = _Compatible<_Yp, __shared_ptr&>; + + // Constraint for construction from unique_ptr: + template::pointer> + using _UniqCompatible = typename enable_if<__and_< + __sp_compatible_with<_Yp*, _Tp*>, is_convertible<_Ptr, element_type*> + >::value, _Res>::type; + + // Constraint for assignment from unique_ptr: + template + using _UniqAssignable = _UniqCompatible<_Yp, _Del, __shared_ptr&>; + + public: + +#if __cplusplus > 201402L + using weak_type = __weak_ptr<_Tp, _Lp>; +#endif + + constexpr __shared_ptr() noexcept + : _M_ptr(0), _M_refcount() + { } + + template> + explicit + __shared_ptr(_Yp* __p) + : _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type()) + { + static_assert( !is_void<_Yp>::value, "incomplete type" ); + static_assert( sizeof(_Yp) > 0, "incomplete type" ); + _M_enable_shared_from_this_with(__p); + } + + template> + __shared_ptr(_Yp* __p, _Deleter __d) + : _M_ptr(__p), _M_refcount(__p, std::move(__d)) + { + static_assert(__is_invocable<_Deleter&, _Yp*&>::value, + "deleter expression d(p) is well-formed"); + _M_enable_shared_from_this_with(__p); + } + + template> + __shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a) + : _M_ptr(__p), _M_refcount(__p, std::move(__d), std::move(__a)) + { + static_assert(__is_invocable<_Deleter&, _Yp*&>::value, + "deleter expression d(p) is well-formed"); + _M_enable_shared_from_this_with(__p); + } + + template + __shared_ptr(nullptr_t __p, _Deleter __d) + : _M_ptr(0), _M_refcount(__p, std::move(__d)) + { } + + template + __shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a) + : _M_ptr(0), _M_refcount(__p, std::move(__d), std::move(__a)) + { } + + // Aliasing constructor + template + __shared_ptr(const __shared_ptr<_Yp, _Lp>& __r, + element_type* __p) noexcept + : _M_ptr(__p), _M_refcount(__r._M_refcount) // never throws + { } + + // Aliasing constructor + template + __shared_ptr(__shared_ptr<_Yp, _Lp>&& __r, + element_type* __p) noexcept + : _M_ptr(__p), _M_refcount() + { + _M_refcount._M_swap(__r._M_refcount); + __r._M_ptr = 0; + } + + __shared_ptr(const __shared_ptr&) noexcept = default; + __shared_ptr& operator=(const __shared_ptr&) noexcept = default; + ~__shared_ptr() = default; + + template> + __shared_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept + : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) + { } + + __shared_ptr(__shared_ptr&& __r) noexcept + : _M_ptr(__r._M_ptr), _M_refcount() + { + _M_refcount._M_swap(__r._M_refcount); + __r._M_ptr = 0; + } + + template> + __shared_ptr(__shared_ptr<_Yp, _Lp>&& __r) noexcept + : _M_ptr(__r._M_ptr), _M_refcount() + { + _M_refcount._M_swap(__r._M_refcount); + __r._M_ptr = 0; + } + + template> + explicit __shared_ptr(const __weak_ptr<_Yp, _Lp>& __r) + : _M_refcount(__r._M_refcount) // may throw + { + // It is now safe to copy __r._M_ptr, as + // _M_refcount(__r._M_refcount) did not throw. + _M_ptr = __r._M_ptr; + } + + // If an exception is thrown this constructor has no effect. + template> + __shared_ptr(unique_ptr<_Yp, _Del>&& __r) + : _M_ptr(__r.get()), _M_refcount() + { + auto __raw = __to_address(__r.get()); + _M_refcount = __shared_count<_Lp>(std::move(__r)); + _M_enable_shared_from_this_with(__raw); + } + +#if __cplusplus <= 201402L && _GLIBCXX_USE_DEPRECATED + protected: + // If an exception is thrown this constructor has no effect. + template>, is_array<_Tp1>, + is_convertible::pointer, _Tp*> + >::value, bool>::type = true> + __shared_ptr(unique_ptr<_Tp1, _Del>&& __r, __sp_array_delete) + : _M_ptr(__r.get()), _M_refcount() + { + auto __raw = __to_address(__r.get()); + _M_refcount = __shared_count<_Lp>(std::move(__r)); + _M_enable_shared_from_this_with(__raw); + } + public: +#endif + +#if _GLIBCXX_USE_DEPRECATED +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + // Postcondition: use_count() == 1 and __r.get() == 0 + template> + __shared_ptr(auto_ptr<_Yp>&& __r); +#pragma GCC diagnostic pop +#endif + + constexpr __shared_ptr(nullptr_t) noexcept : __shared_ptr() { } + + template + _Assignable<_Yp> + operator=(const __shared_ptr<_Yp, _Lp>& __r) noexcept + { + _M_ptr = __r._M_ptr; + _M_refcount = __r._M_refcount; // __shared_count::op= doesn't throw + return *this; + } + +#if _GLIBCXX_USE_DEPRECATED +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + template + _Assignable<_Yp> + operator=(auto_ptr<_Yp>&& __r) + { + __shared_ptr(std::move(__r)).swap(*this); + return *this; + } +#pragma GCC diagnostic pop +#endif + + __shared_ptr& + operator=(__shared_ptr&& __r) noexcept + { + __shared_ptr(std::move(__r)).swap(*this); + return *this; + } + + template + _Assignable<_Yp> + operator=(__shared_ptr<_Yp, _Lp>&& __r) noexcept + { + __shared_ptr(std::move(__r)).swap(*this); + return *this; + } + + template + _UniqAssignable<_Yp, _Del> + operator=(unique_ptr<_Yp, _Del>&& __r) + { + __shared_ptr(std::move(__r)).swap(*this); + return *this; + } + + void + reset() noexcept + { __shared_ptr().swap(*this); } + + template + _SafeConv<_Yp> + reset(_Yp* __p) // _Yp must be complete. + { + // Catch self-reset errors. + __glibcxx_assert(__p == 0 || __p != _M_ptr); + __shared_ptr(__p).swap(*this); + } + + template + _SafeConv<_Yp> + reset(_Yp* __p, _Deleter __d) + { __shared_ptr(__p, std::move(__d)).swap(*this); } + + template + _SafeConv<_Yp> + reset(_Yp* __p, _Deleter __d, _Alloc __a) + { __shared_ptr(__p, std::move(__d), std::move(__a)).swap(*this); } + + /// Return the stored pointer. + element_type* + get() const noexcept + { return _M_ptr; } + + /// Return true if the stored pointer is not null. + explicit operator bool() const // never throws + { return _M_ptr == 0 ? false : true; } + + /// Return true if use_count() == 1. + bool + unique() const noexcept + { return _M_refcount._M_unique(); } + + /// If *this owns a pointer, return the number of owners, otherwise zero. + long + use_count() const noexcept + { return _M_refcount._M_get_use_count(); } + + /// Exchange both the owned pointer and the stored pointer. + void + swap(__shared_ptr<_Tp, _Lp>& __other) noexcept + { + std::swap(_M_ptr, __other._M_ptr); + _M_refcount._M_swap(__other._M_refcount); + } + + /** @brief Define an ordering based on ownership. + * + * This function defines a strict weak ordering between two shared_ptr + * or weak_ptr objects, such that one object is less than the other + * unless they share ownership of the same pointer, or are both empty. + * @{ + */ + template + bool + owner_before(__shared_ptr<_Tp1, _Lp> const& __rhs) const noexcept + { return _M_refcount._M_less(__rhs._M_refcount); } + + template + bool + owner_before(__weak_ptr<_Tp1, _Lp> const& __rhs) const noexcept + { return _M_refcount._M_less(__rhs._M_refcount); } + // @} + + protected: + // This constructor is non-standard, it is used by allocate_shared. + template + __shared_ptr(_Sp_alloc_shared_tag<_Alloc> __tag, _Args&&... __args) + : _M_ptr(), _M_refcount(_M_ptr, __tag, std::forward<_Args>(__args)...) + { _M_enable_shared_from_this_with(_M_ptr); } + + template + friend __shared_ptr<_Tp1, _Lp1> + __allocate_shared(const _Alloc& __a, _Args&&... __args); + + // This constructor is used by __weak_ptr::lock() and + // shared_ptr::shared_ptr(const weak_ptr&, std::nothrow_t). + __shared_ptr(const __weak_ptr<_Tp, _Lp>& __r, std::nothrow_t) + : _M_refcount(__r._M_refcount, std::nothrow) + { + _M_ptr = _M_refcount._M_get_use_count() ? __r._M_ptr : nullptr; + } + + friend class __weak_ptr<_Tp, _Lp>; + + private: + + template + using __esft_base_t = decltype(__enable_shared_from_this_base( + std::declval&>(), + std::declval<_Yp*>())); + + // Detect an accessible and unambiguous enable_shared_from_this base. + template + struct __has_esft_base + : false_type { }; + + template + struct __has_esft_base<_Yp, __void_t<__esft_base_t<_Yp>>> + : __not_> { }; // No enable shared_from_this for arrays + + template::type> + typename enable_if<__has_esft_base<_Yp2>::value>::type + _M_enable_shared_from_this_with(_Yp* __p) noexcept + { + if (auto __base = __enable_shared_from_this_base(_M_refcount, __p)) + __base->_M_weak_assign(const_cast<_Yp2*>(__p), _M_refcount); + } + + template::type> + typename enable_if::value>::type + _M_enable_shared_from_this_with(_Yp*) noexcept + { } + + void* + _M_get_deleter(const std::type_info& __ti) const noexcept + { return _M_refcount._M_get_deleter(__ti); } + + template friend class __shared_ptr; + template friend class __weak_ptr; + + template + friend _Del* get_deleter(const __shared_ptr<_Tp1, _Lp1>&) noexcept; + + template + friend _Del* get_deleter(const shared_ptr<_Tp1>&) noexcept; + + element_type* _M_ptr; // Contained pointer. + __shared_count<_Lp> _M_refcount; // Reference counter. + }; + + + // 20.7.2.2.7 shared_ptr comparisons + template + inline bool + operator==(const __shared_ptr<_Tp1, _Lp>& __a, + const __shared_ptr<_Tp2, _Lp>& __b) noexcept + { return __a.get() == __b.get(); } + + template + inline bool + operator==(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept + { return !__a; } + +#ifdef __cpp_lib_three_way_comparison + template + inline strong_ordering + operator<=>(const __shared_ptr<_Tp, _Lp>& __a, + const __shared_ptr<_Up, _Lp>& __b) noexcept + { return compare_three_way()(__a.get(), __b.get()); } + + template + inline strong_ordering + operator<=>(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept + { + using pointer = typename __shared_ptr<_Tp, _Lp>::element_type*; + return compare_three_way()(__a.get(), static_cast(nullptr)); + } +#else + template + inline bool + operator==(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept + { return !__a; } + + template + inline bool + operator!=(const __shared_ptr<_Tp1, _Lp>& __a, + const __shared_ptr<_Tp2, _Lp>& __b) noexcept + { return __a.get() != __b.get(); } + + template + inline bool + operator!=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept + { return (bool)__a; } + + template + inline bool + operator!=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept + { return (bool)__a; } + + template + inline bool + operator<(const __shared_ptr<_Tp, _Lp>& __a, + const __shared_ptr<_Up, _Lp>& __b) noexcept + { + using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type; + using _Up_elt = typename __shared_ptr<_Up, _Lp>::element_type; + using _Vp = typename common_type<_Tp_elt*, _Up_elt*>::type; + return less<_Vp>()(__a.get(), __b.get()); + } + + template + inline bool + operator<(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept + { + using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type; + return less<_Tp_elt*>()(__a.get(), nullptr); + } + + template + inline bool + operator<(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept + { + using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type; + return less<_Tp_elt*>()(nullptr, __a.get()); + } + + template + inline bool + operator<=(const __shared_ptr<_Tp1, _Lp>& __a, + const __shared_ptr<_Tp2, _Lp>& __b) noexcept + { return !(__b < __a); } + + template + inline bool + operator<=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept + { return !(nullptr < __a); } + + template + inline bool + operator<=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept + { return !(__a < nullptr); } + + template + inline bool + operator>(const __shared_ptr<_Tp1, _Lp>& __a, + const __shared_ptr<_Tp2, _Lp>& __b) noexcept + { return (__b < __a); } + + template + inline bool + operator>(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept + { return nullptr < __a; } + + template + inline bool + operator>(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept + { return __a < nullptr; } + + template + inline bool + operator>=(const __shared_ptr<_Tp1, _Lp>& __a, + const __shared_ptr<_Tp2, _Lp>& __b) noexcept + { return !(__a < __b); } + + template + inline bool + operator>=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept + { return !(__a < nullptr); } + + template + inline bool + operator>=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept + { return !(nullptr < __a); } +#endif // three-way comparison + + // 20.7.2.2.8 shared_ptr specialized algorithms. + template + inline void + swap(__shared_ptr<_Tp, _Lp>& __a, __shared_ptr<_Tp, _Lp>& __b) noexcept + { __a.swap(__b); } + + // 20.7.2.2.9 shared_ptr casts + + // The seemingly equivalent code: + // shared_ptr<_Tp, _Lp>(static_cast<_Tp*>(__r.get())) + // will eventually result in undefined behaviour, attempting to + // delete the same object twice. + /// static_pointer_cast + template + inline __shared_ptr<_Tp, _Lp> + static_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept + { + using _Sp = __shared_ptr<_Tp, _Lp>; + return _Sp(__r, static_cast(__r.get())); + } + + // The seemingly equivalent code: + // shared_ptr<_Tp, _Lp>(const_cast<_Tp*>(__r.get())) + // will eventually result in undefined behaviour, attempting to + // delete the same object twice. + /// const_pointer_cast + template + inline __shared_ptr<_Tp, _Lp> + const_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept + { + using _Sp = __shared_ptr<_Tp, _Lp>; + return _Sp(__r, const_cast(__r.get())); + } + + // The seemingly equivalent code: + // shared_ptr<_Tp, _Lp>(dynamic_cast<_Tp*>(__r.get())) + // will eventually result in undefined behaviour, attempting to + // delete the same object twice. + /// dynamic_pointer_cast + template + inline __shared_ptr<_Tp, _Lp> + dynamic_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept + { + using _Sp = __shared_ptr<_Tp, _Lp>; + if (auto* __p = dynamic_cast(__r.get())) + return _Sp(__r, __p); + return _Sp(); + } + +#if __cplusplus > 201402L + template + inline __shared_ptr<_Tp, _Lp> + reinterpret_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept + { + using _Sp = __shared_ptr<_Tp, _Lp>; + return _Sp(__r, reinterpret_cast(__r.get())); + } +#endif + + template + class __weak_ptr + { + template + using _Compatible = typename + enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type; + + // Constraint for assignment from shared_ptr and weak_ptr: + template + using _Assignable = _Compatible<_Yp, __weak_ptr&>; + + public: + using element_type = typename remove_extent<_Tp>::type; + + constexpr __weak_ptr() noexcept + : _M_ptr(nullptr), _M_refcount() + { } + + __weak_ptr(const __weak_ptr&) noexcept = default; + + ~__weak_ptr() = default; + + // The "obvious" converting constructor implementation: + // + // template + // __weak_ptr(const __weak_ptr<_Tp1, _Lp>& __r) + // : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) // never throws + // { } + // + // has a serious problem. + // + // __r._M_ptr may already have been invalidated. The _M_ptr(__r._M_ptr) + // conversion may require access to *__r._M_ptr (virtual inheritance). + // + // It is not possible to avoid spurious access violations since + // in multithreaded programs __r._M_ptr may be invalidated at any point. + template> + __weak_ptr(const __weak_ptr<_Yp, _Lp>& __r) noexcept + : _M_refcount(__r._M_refcount) + { _M_ptr = __r.lock().get(); } + + template> + __weak_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept + : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) + { } + + __weak_ptr(__weak_ptr&& __r) noexcept + : _M_ptr(__r._M_ptr), _M_refcount(std::move(__r._M_refcount)) + { __r._M_ptr = nullptr; } + + template> + __weak_ptr(__weak_ptr<_Yp, _Lp>&& __r) noexcept + : _M_ptr(__r.lock().get()), _M_refcount(std::move(__r._M_refcount)) + { __r._M_ptr = nullptr; } + + __weak_ptr& + operator=(const __weak_ptr& __r) noexcept = default; + + template + _Assignable<_Yp> + operator=(const __weak_ptr<_Yp, _Lp>& __r) noexcept + { + _M_ptr = __r.lock().get(); + _M_refcount = __r._M_refcount; + return *this; + } + + template + _Assignable<_Yp> + operator=(const __shared_ptr<_Yp, _Lp>& __r) noexcept + { + _M_ptr = __r._M_ptr; + _M_refcount = __r._M_refcount; + return *this; + } + + __weak_ptr& + operator=(__weak_ptr&& __r) noexcept + { + _M_ptr = __r._M_ptr; + _M_refcount = std::move(__r._M_refcount); + __r._M_ptr = nullptr; + return *this; + } + + template + _Assignable<_Yp> + operator=(__weak_ptr<_Yp, _Lp>&& __r) noexcept + { + _M_ptr = __r.lock().get(); + _M_refcount = std::move(__r._M_refcount); + __r._M_ptr = nullptr; + return *this; + } + + __shared_ptr<_Tp, _Lp> + lock() const noexcept + { return __shared_ptr(*this, std::nothrow); } + + long + use_count() const noexcept + { return _M_refcount._M_get_use_count(); } + + bool + expired() const noexcept + { return _M_refcount._M_get_use_count() == 0; } + + template + bool + owner_before(const __shared_ptr<_Tp1, _Lp>& __rhs) const noexcept + { return _M_refcount._M_less(__rhs._M_refcount); } + + template + bool + owner_before(const __weak_ptr<_Tp1, _Lp>& __rhs) const noexcept + { return _M_refcount._M_less(__rhs._M_refcount); } + + void + reset() noexcept + { __weak_ptr().swap(*this); } + + void + swap(__weak_ptr& __s) noexcept + { + std::swap(_M_ptr, __s._M_ptr); + _M_refcount._M_swap(__s._M_refcount); + } + + private: + // Used by __enable_shared_from_this. + void + _M_assign(_Tp* __ptr, const __shared_count<_Lp>& __refcount) noexcept + { + if (use_count() == 0) + { + _M_ptr = __ptr; + _M_refcount = __refcount; + } + } + + template friend class __shared_ptr; + template friend class __weak_ptr; + friend class __enable_shared_from_this<_Tp, _Lp>; + friend class enable_shared_from_this<_Tp>; + + element_type* _M_ptr; // Contained pointer. + __weak_count<_Lp> _M_refcount; // Reference counter. + }; + + // 20.7.2.3.6 weak_ptr specialized algorithms. + template + inline void + swap(__weak_ptr<_Tp, _Lp>& __a, __weak_ptr<_Tp, _Lp>& __b) noexcept + { __a.swap(__b); } + + template + struct _Sp_owner_less : public binary_function<_Tp, _Tp, bool> + { + bool + operator()(const _Tp& __lhs, const _Tp& __rhs) const noexcept + { return __lhs.owner_before(__rhs); } + + bool + operator()(const _Tp& __lhs, const _Tp1& __rhs) const noexcept + { return __lhs.owner_before(__rhs); } + + bool + operator()(const _Tp1& __lhs, const _Tp& __rhs) const noexcept + { return __lhs.owner_before(__rhs); } + }; + + template<> + struct _Sp_owner_less + { + template + auto + operator()(const _Tp& __lhs, const _Up& __rhs) const noexcept + -> decltype(__lhs.owner_before(__rhs)) + { return __lhs.owner_before(__rhs); } + + using is_transparent = void; + }; + + template + struct owner_less<__shared_ptr<_Tp, _Lp>> + : public _Sp_owner_less<__shared_ptr<_Tp, _Lp>, __weak_ptr<_Tp, _Lp>> + { }; + + template + struct owner_less<__weak_ptr<_Tp, _Lp>> + : public _Sp_owner_less<__weak_ptr<_Tp, _Lp>, __shared_ptr<_Tp, _Lp>> + { }; + + + template + class __enable_shared_from_this + { + protected: + constexpr __enable_shared_from_this() noexcept { } + + __enable_shared_from_this(const __enable_shared_from_this&) noexcept { } + + __enable_shared_from_this& + operator=(const __enable_shared_from_this&) noexcept + { return *this; } + + ~__enable_shared_from_this() { } + + public: + __shared_ptr<_Tp, _Lp> + shared_from_this() + { return __shared_ptr<_Tp, _Lp>(this->_M_weak_this); } + + __shared_ptr + shared_from_this() const + { return __shared_ptr(this->_M_weak_this); } + +#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 + __weak_ptr<_Tp, _Lp> + weak_from_this() noexcept + { return this->_M_weak_this; } + + __weak_ptr + weak_from_this() const noexcept + { return this->_M_weak_this; } +#endif + + private: + template + void + _M_weak_assign(_Tp1* __p, const __shared_count<_Lp>& __n) const noexcept + { _M_weak_this._M_assign(__p, __n); } + + friend const __enable_shared_from_this* + __enable_shared_from_this_base(const __shared_count<_Lp>&, + const __enable_shared_from_this* __p) + { return __p; } + + template + friend class __shared_ptr; + + mutable __weak_ptr<_Tp, _Lp> _M_weak_this; + }; + + template + inline __shared_ptr<_Tp, _Lp> + __allocate_shared(const _Alloc& __a, _Args&&... __args) + { + return __shared_ptr<_Tp, _Lp>(_Sp_alloc_shared_tag<_Alloc>{__a}, + std::forward<_Args>(__args)...); + } + + template + inline __shared_ptr<_Tp, _Lp> + __make_shared(_Args&&... __args) + { + typedef typename std::remove_const<_Tp>::type _Tp_nc; + return std::__allocate_shared<_Tp, _Lp>(std::allocator<_Tp_nc>(), + std::forward<_Args>(__args)...); + } + + /// std::hash specialization for __shared_ptr. + template + struct hash<__shared_ptr<_Tp, _Lp>> + : public __hash_base> + { + size_t + operator()(const __shared_ptr<_Tp, _Lp>& __s) const noexcept + { + return hash::element_type*>()( + __s.get()); + } + }; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif // _SHARED_PTR_BASE_H diff --git a/include/memory b/include/memory index 0ed1a86..eef4f58 100644 --- a/include/memory +++ b/include/memory @@ -77,6 +77,13 @@ # include # include # include +# include +# include +# if _GLIBCXX_USE_DEPRECATED +# include +# endif +#else +# include #endif #if __cplusplus >= 201103L