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 +----------------------------------------------------------------------+
16 #ifndef incl_HPHP_COPY_PTR_H_
17 #define incl_HPHP_COPY_PTR_H_
26 //////////////////////////////////////////////////////////////////////
29 * A refcounted smart pointer that does deep copies if you ask for a
30 * mutable copy when the ref-count is greater than one.
34 copy_ptr() noexcept
{}
35 copy_ptr(const copy_ptr
& o
) {
38 copy_ptr(copy_ptr
&& o
) noexcept
{
42 ~copy_ptr() { dec_ref(m_p
); }
43 copy_ptr
& operator=(const copy_ptr
& o
) {
44 auto const save
= m_p
;
49 copy_ptr
& operator=(copy_ptr
&& o
) noexcept
{
50 std::swap(m_p
, o
.m_p
);
54 explicit operator bool() const { return m_p
!= nullptr; }
56 const T
& operator*() const { return *m_p
; }
57 const T
* operator->() const { return m_p
; }
58 const T
* get() const { return m_p
; }
60 if (m_p
&& get_ref(m_p
) != 1) {
71 template <typename
... Args
> void emplace(Args
&&... args
) {
72 auto const save
= m_p
;
73 auto const mem
= std::malloc(data_offset() + sizeof(T
));
74 if (!mem
) throw std::bad_alloc();
75 new (mem
) refcount_type
{1};
76 m_p
= (T
*)((char*)mem
+ data_offset());
78 new (m_p
) T(std::forward
<Args
>(args
)...);
87 using refcount_type
= std::atomic
<uint32_t>;
91 static constexpr size_t data_offset() {
92 return alignof(T
) >= sizeof(refcount_type
) ?
93 alignof(T
) : sizeof(refcount_type
);
96 static refcount_type
* get_ref_ptr(T
* p
) {
97 return (refcount_type
*)((char*)p
- data_offset());
100 static uint32_t get_ref(T
* p
) {
101 return get_ref_ptr(p
)->load(std::memory_order_relaxed
);
104 static void dec_ref(T
* p
) {
106 auto ref
= get_ref_ptr(p
);
107 if (ref
->fetch_sub(1, std::memory_order_relaxed
) == 1) {
109 ref
->~refcount_type();
114 static void inc_ref(T
* p
) {
116 get_ref_ptr(p
)->fetch_add(1, std::memory_order_relaxed
);
120 //////////////////////////////////////////////////////////////////////