2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
25 //////////////////////////////////////////////////////////////////////
28 * A refcounted smart pointer that does deep copies if you ask for a
29 * mutable copy when the ref-count is greater than one.
33 copy_ptr() noexcept
{}
34 copy_ptr(const copy_ptr
& o
) {
37 copy_ptr(copy_ptr
&& o
) noexcept
{
41 template <typename
... Args
> explicit copy_ptr(Args
&&... args
) {
42 construct(nullptr, std::forward
<Args
>(args
)...);
44 ~copy_ptr() { dec_ref(m_p
); }
45 copy_ptr
& operator=(const copy_ptr
& o
) {
46 auto const save
= m_p
;
51 copy_ptr
& operator=(copy_ptr
&& o
) noexcept
{
52 std::swap(m_p
, o
.m_p
);
56 explicit operator bool() const { return !isNull(); }
57 bool isNull() const { return m_p
== nullptr; }
59 const T
& operator*() const { return *m_p
; }
60 const T
* operator->() const { return m_p
; }
61 const T
* get() const { return m_p
; }
63 if (m_p
&& get_ref(m_p
) != 1) {
74 template <typename
... Args
> void emplace(Args
&&... args
) {
75 auto const save
= m_p
;
76 construct(save
, std::forward
<Args
>(args
)...);
81 operator==(const copy_ptr
& a
, const copy_ptr
& b
) { return a
.m_p
== b
.m_p
; }
83 operator==(const copy_ptr
& a
, const T
* b
) { return a
.m_p
== b
; }
85 operator==(const T
* a
, const copy_ptr
& b
) { return a
== b
.m_p
; }
87 operator!=(const copy_ptr
& a
, const copy_ptr
& b
) { return a
.m_p
!= b
.m_p
; }
89 operator!=(const copy_ptr
& a
, const T
* b
) { return a
.m_p
!= b
; }
91 operator!=(const T
* a
, const copy_ptr
& b
) { return a
!= b
.m_p
; }
94 template <typename
... Args
> void construct(T
* save
, Args
&&... args
) {
95 auto const mem
= std::malloc(data_offset() + sizeof(T
));
96 if (!mem
) throw std::bad_alloc();
97 new (mem
) refcount_type
{1};
98 m_p
= (T
*)((char*)mem
+ data_offset());
100 new (m_p
) T(std::forward
<Args
>(args
)...);
108 using refcount_type
= std::atomic
<uint32_t>;
112 static constexpr size_t data_offset() {
113 return alignof(T
) >= sizeof(refcount_type
) ?
114 alignof(T
) : sizeof(refcount_type
);
117 static refcount_type
* get_ref_ptr(T
* p
) {
118 return (refcount_type
*)((char*)p
- data_offset());
121 static uint32_t get_ref(T
* p
) {
122 return get_ref_ptr(p
)->load(std::memory_order_relaxed
);
125 static void dec_ref(T
* p
) {
127 auto ref
= get_ref_ptr(p
);
128 if (ref
->fetch_sub(1, std::memory_order_relaxed
) == 1) {
130 ref
->~refcount_type();
135 static void inc_ref(T
* p
) {
137 get_ref_ptr(p
)->fetch_add(1, std::memory_order_relaxed
);
141 //////////////////////////////////////////////////////////////////////