Add a HHIR-level peephole optimization to reorder CheckTypes
[hiphop-php.git] / hphp / util / copy-ptr.h
blob9f0df5eea65aea8ccd9a188c990475f44b0b349b
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 #pragma once
18 #include <atomic>
19 #include <cstdlib>
20 #include <memory>
21 #include <utility>
23 namespace HPHP {
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.
31 template<class T>
32 struct copy_ptr {
33 copy_ptr() noexcept {}
34 copy_ptr(const copy_ptr& o) {
35 inc_ref(m_p = o.m_p);
37 copy_ptr(copy_ptr&& o) noexcept {
38 m_p = o.m_p;
39 o.m_p = nullptr;
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;
47 inc_ref(m_p = o.m_p);
48 dec_ref(save);
49 return *this;
51 copy_ptr& operator=(copy_ptr&& o) noexcept {
52 std::swap(m_p, o.m_p);
53 return *this;
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; }
62 T* mutate() {
63 if (m_p && get_ref(m_p) != 1) {
64 emplace(*m_p);
66 return m_p;
69 void reset() {
70 dec_ref(m_p);
71 m_p = nullptr;
74 template <typename... Args> void emplace(Args&&... args) {
75 auto const save = m_p;
76 construct(save, std::forward<Args>(args)...);
77 dec_ref(save);
80 friend bool
81 operator==(const copy_ptr& a, const copy_ptr& b) { return a.m_p == b.m_p; }
82 friend bool
83 operator==(const copy_ptr& a, const T* b) { return a.m_p == b; }
84 friend bool
85 operator==(const T* a, const copy_ptr& b) { return a == b.m_p; }
86 friend bool
87 operator!=(const copy_ptr& a, const copy_ptr& b) { return a.m_p != b.m_p; }
88 friend bool
89 operator!=(const copy_ptr& a, const T* b) { return a.m_p != b; }
90 friend bool
91 operator!=(const T* a, const copy_ptr& b) { return a != b.m_p; }
93 private:
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());
99 try {
100 new (m_p) T(std::forward<Args>(args)...);
101 } catch (...) {
102 std::free(mem);
103 m_p = save;
104 throw;
108 using refcount_type = std::atomic<uint32_t>;
110 T* m_p{};
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) {
126 if (!p) return;
127 auto ref = get_ref_ptr(p);
128 if (ref->fetch_sub(1, std::memory_order_relaxed) == 1) {
129 p->~T();
130 ref->~refcount_type();
131 std::free(ref);
135 static void inc_ref(T* p) {
136 if (!p) return;
137 get_ref_ptr(p)->fetch_add(1, std::memory_order_relaxed);
141 //////////////////////////////////////////////////////////////////////