Fix semdiff syntactic output
[hiphop-php.git] / hphp / util / copy-ptr.h
blob467f6dc1a8d4ed3bf3f97f865b2dbfda0df1c3d5
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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_
19 #include <atomic>
20 #include <cstdlib>
21 #include <memory>
22 #include <utility>
24 namespace HPHP {
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.
32 template<class T>
33 struct copy_ptr {
34 copy_ptr() noexcept {}
35 copy_ptr(const copy_ptr& o) {
36 inc_ref(m_p = o.m_p);
38 copy_ptr(copy_ptr&& o) noexcept {
39 m_p = o.m_p;
40 o.m_p = nullptr;
42 ~copy_ptr() { dec_ref(m_p); }
43 copy_ptr& operator=(const copy_ptr& o) {
44 auto const save = m_p;
45 inc_ref(m_p = o.m_p);
46 dec_ref(save);
47 return *this;
49 copy_ptr& operator=(copy_ptr&& o) noexcept {
50 std::swap(m_p, o.m_p);
51 return *this;
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; }
59 T* mutate() {
60 if (m_p && get_ref(m_p) != 1) {
61 emplace(*m_p);
63 return m_p;
66 void reset() {
67 dec_ref(m_p);
68 m_p = nullptr;
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());
77 try {
78 new (m_p) T(std::forward<Args>(args)...);
79 } catch (...) {
80 std::free(mem);
81 m_p = save;
82 throw;
84 dec_ref(save);
86 private:
87 using refcount_type = std::atomic<uint32_t>;
89 T* m_p{};
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) {
105 if (!p) return;
106 auto ref = get_ref_ptr(p);
107 if (ref->fetch_sub(1, std::memory_order_relaxed) == 1) {
108 p->~T();
109 ref->~refcount_type();
110 std::free(ref);
114 static void inc_ref(T* p) {
115 if (!p) return;
116 get_ref_ptr(p)->fetch_add(1, std::memory_order_relaxed);
120 //////////////////////////////////////////////////////////////////////
124 #endif