Update hhvm version.h
[hiphop-php.git] / hphp / util / low-ptr.h
blobe55c94c582483a809391be9e206c19e56ee664c9
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 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_LOW_PTR_H_
18 #define incl_HPHP_LOW_PTR_H_
20 #include "hphp/util/low-ptr-def.h"
21 #include "hphp/util/assertions.h"
22 #include "hphp/util/portability.h"
24 #include <folly/Format.h>
26 #include <algorithm>
27 #include <atomic>
28 #include <cstddef>
29 #include <cstdint>
30 #include <type_traits>
31 #include <utility>
33 namespace HPHP {
34 ///////////////////////////////////////////////////////////////////////////////
36 namespace detail {
38 ///////////////////////////////////////////////////////////////////////////////
40 /**
41 * Low memory pointer template.
43 template <class T, class S>
44 struct LowPtrImpl {
45 using storage_type = typename S::storage_type;
48 * Constructors.
50 LowPtrImpl() {}
52 /* implicit */ LowPtrImpl(T* px) : m_s{to_low(px)} {}
54 /* implicit */ LowPtrImpl(std::nullptr_t /*px*/) : m_s{ 0 } {}
56 LowPtrImpl(const LowPtrImpl<T, S>& r) : m_s{S::get(r.m_s)} {}
58 LowPtrImpl(LowPtrImpl<T, S>&& r) : m_s{S::get(r.m_s)} {
59 S::set(r.m_s, 0);
63 * Assignments.
65 LowPtrImpl& operator=(T* px) {
66 S::set(m_s, to_low(px));
67 return *this;
70 LowPtrImpl& operator=(std::nullptr_t /*px*/) {
71 S::set(m_s, 0);
72 return *this;
75 LowPtrImpl& operator=(const LowPtrImpl<T, S>& r) {
76 S::set(m_s, S::get(r.m_s));
77 return *this;
80 template <typename Q = S>
81 typename std::enable_if<
82 std::is_move_assignable<typename Q::storage_type>::value,
83 LowPtrImpl&
84 >::type operator=(LowPtrImpl<T, S>&& r) {
85 m_s = std::move(r.m_s);
86 return *this;
89 template <typename Q = S>
90 typename std::enable_if<
91 !std::is_move_assignable<typename Q::storage_type>::value,
92 LowPtrImpl&
93 >::type operator=(LowPtrImpl<T, S>&& r) {
94 S::set(m_s, S::get(r.m_s));
95 S::set(r.m_s, 0);
96 return *this;
100 * Observers.
102 T* get() const {
103 return reinterpret_cast<T*>(S::get(m_s));
106 T& operator*() const {
107 return *get();
110 T* operator->() const {
111 return get();
114 /* implicit */ operator T*() const {
115 return get();
118 explicit operator bool() const {
119 return get();
123 * Modifiers.
125 void reset() {
126 operator=(nullptr);
129 template <typename Q = T>
130 typename std::enable_if<
131 std::is_move_assignable<typename Q::storage_type>::value,
132 void
133 >::type swap(LowPtrImpl& r) {
134 std::swap(m_s, r.m_s);
137 template <typename Q = T>
138 typename std::enable_if<
139 !std::is_move_assignable<typename Q::storage_type>::value,
140 void
141 >::type swap(LowPtrImpl& r) {
142 auto const tmp = S::get(m_s);
143 S::set(m_s, S::get(r.m_s));
144 S::set(r.m_s, tmp);
147 private:
149 * Lowness.
151 static bool is_low(T* px) {
152 typename S::raw_type ones = ~0;
153 auto ptr = reinterpret_cast<uintptr_t>(px);
154 return (ptr & ones) == ptr;
157 static typename S::raw_type to_low(T* px) {
158 always_assert(is_low(px));
159 return (typename S::raw_type)(reinterpret_cast<uintptr_t>(px));
162 protected:
163 typename S::storage_type m_s;
166 ///////////////////////////////////////////////////////////////////////////////
168 template <class S>
169 struct RawStorage {
170 using raw_type = S;
171 using storage_type = S;
173 static ALWAYS_INLINE raw_type get(const storage_type& s) {
174 return s;
176 static ALWAYS_INLINE void set(storage_type& s, raw_type r) {
177 s = r;
181 template <class S, std::memory_order read_order, std::memory_order write_order>
182 struct AtomicStorage {
183 using raw_type = S;
184 using storage_type = std::atomic<S>;
186 static ALWAYS_INLINE raw_type get(const storage_type& s) {
187 return s.load(read_order);
189 static ALWAYS_INLINE void set(storage_type& s, raw_type r) {
190 s.store(r, write_order);
194 ///////////////////////////////////////////////////////////////////////////////
198 ///////////////////////////////////////////////////////////////////////////////
200 #ifdef USE_LOWPTR
201 constexpr bool use_lowptr = true;
203 namespace detail {
204 using low_storage_t = uint32_t;
206 #else
207 constexpr bool use_lowptr = false;
209 namespace detail {
210 using low_storage_t = uintptr_t;
212 #endif
214 template<class T>
215 using LowPtr =
216 detail::LowPtrImpl<T, detail::RawStorage<detail::low_storage_t>>;
218 template<class T,
219 std::memory_order read_order = std::memory_order_relaxed,
220 std::memory_order write_order = std::memory_order_relaxed>
221 using AtomicLowPtr =
222 detail::LowPtrImpl<T, detail::AtomicStorage<detail::low_storage_t,
223 read_order,
224 write_order>>;
226 ///////////////////////////////////////////////////////////////////////////////
229 namespace folly {
230 template<class T> class FormatValue<HPHP::LowPtr<T>> {
231 public:
232 explicit FormatValue(HPHP::LowPtr<T> v) : m_val(v) {}
234 template<typename Callback>
235 void format(FormatArg& arg, Callback& cb) const {
236 FormatValue<T*>(m_val.get()).format(arg, cb);
239 private:
240 const HPHP::LowPtr<T> m_val;
244 #endif // incl_HPHP_LOW_PTR_H_