Make write_props be callable from policied code
[hiphop-php.git] / hphp / util / low-ptr.h
blob063b1ff3dc59afc67c1236984a55a45118526f72
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 #pragma once
19 #include "hphp/util/low-ptr-def.h"
20 #include "hphp/util/assertions.h"
21 #include "hphp/util/portability.h"
23 #include <folly/Format.h>
25 #include <algorithm>
26 #include <atomic>
27 #include <cstddef>
28 #include <cstdint>
29 #include <type_traits>
30 #include <utility>
32 namespace HPHP {
33 ///////////////////////////////////////////////////////////////////////////////
35 #ifdef USE_LOWPTR
36 constexpr bool use_lowptr = true;
38 namespace detail {
39 using low_storage_t = uint32_t;
41 #else
42 constexpr bool use_lowptr = false;
44 namespace detail {
45 using low_storage_t = uintptr_t;
47 #endif
49 inline bool is_low_mem(void* m) {
50 assertx(use_lowptr);
51 const uint32_t mask = ~0;
52 auto const i = reinterpret_cast<intptr_t>(m);
53 return (mask & i) == i;
56 ///////////////////////////////////////////////////////////////////////////////
57 namespace detail {
59 template<class T>
60 inline bool is_low(T* px) {
61 low_storage_t ones = ~0;
62 auto ptr = reinterpret_cast<uintptr_t>(px);
63 return (ptr & ones) == ptr;
66 template<class T>
67 inline low_storage_t to_low(T* px) {
68 always_assert(is_low(px));
69 return (low_storage_t)(reinterpret_cast<uintptr_t>(px));
72 template<class T>
73 inline low_storage_t to_low_unchecked(T* px) {
74 assertx(is_low(px));
75 return (low_storage_t)(reinterpret_cast<uintptr_t>(px));
78 ///////////////////////////////////////////////////////////////////////////////
81 /**
82 * Low memory pointer template.
84 template <class T, class S>
85 struct LowPtrImpl {
86 using storage_type = typename S::storage_type;
87 enum class Unchecked {};
90 * Constructors.
92 LowPtrImpl() {}
94 /* implicit */ LowPtrImpl(T* px) : m_s{to_low(px)} {}
95 /* implicit */ LowPtrImpl(Unchecked, T* px) : m_s{to_low_unchecked(px)} {}
97 /* implicit */ LowPtrImpl(std::nullptr_t /*px*/) : m_s{ 0 } {}
99 LowPtrImpl(const LowPtrImpl<T, S>& r) : m_s{S::get(r.m_s)} {}
101 LowPtrImpl(LowPtrImpl<T, S>&& r) : m_s{S::get(r.m_s)} {
102 S::set(r.m_s, 0);
106 * Assignments.
108 LowPtrImpl& operator=(T* px) {
109 S::set(m_s, to_low(px));
110 return *this;
113 LowPtrImpl& operator=(std::nullptr_t /*px*/) {
114 S::set(m_s, 0);
115 return *this;
118 LowPtrImpl& operator=(const LowPtrImpl<T, S>& r) {
119 S::set(m_s, S::get(r.m_s));
120 return *this;
123 template <typename Q = S>
124 typename std::enable_if<
125 std::is_move_assignable<typename Q::storage_type>::value,
126 LowPtrImpl&
127 >::type operator=(LowPtrImpl<T, S>&& r) {
128 m_s = std::move(r.m_s);
129 return *this;
132 template <typename Q = S>
133 typename std::enable_if<
134 !std::is_move_assignable<typename Q::storage_type>::value,
135 LowPtrImpl&
136 >::type operator=(LowPtrImpl<T, S>&& r) {
137 S::set(m_s, S::get(r.m_s));
138 S::set(r.m_s, 0);
139 return *this;
143 * Observers.
145 T* get() const { return reinterpret_cast<T*>(S::get(m_s)); }
146 T& operator*() const { return *get(); }
147 T* operator->() const { return get(); }
148 /* implicit */ operator T*() const { return get(); }
149 explicit operator bool() const { return get(); }
152 * Modifiers.
154 void reset() { operator=(nullptr); }
156 template <typename Q = T>
157 typename std::enable_if<
158 std::is_move_assignable<typename Q::storage_type>::value,
159 void
160 >::type swap(LowPtrImpl& r) {
161 std::swap(m_s, r.m_s);
164 template <typename Q = T>
165 typename std::enable_if<
166 !std::is_move_assignable<typename Q::storage_type>::value,
167 void
168 >::type swap(LowPtrImpl& r) {
169 auto const tmp = S::get(m_s);
170 S::set(m_s, S::get(r.m_s));
171 S::set(r.m_s, tmp);
174 private:
175 typename S::storage_type m_s{0};
178 ///////////////////////////////////////////////////////////////////////////////
180 template <class S, std::memory_order read_order, std::memory_order write_order>
181 struct AtomicStorage {
182 using storage_type = std::atomic<S>;
184 static ALWAYS_INLINE low_storage_t get(const storage_type& s) {
185 return s.load(read_order);
187 static ALWAYS_INLINE void set(storage_type& s, low_storage_t r) {
188 s.store(r, write_order);
192 ///////////////////////////////////////////////////////////////////////////////
196 ///////////////////////////////////////////////////////////////////////////////
198 template<class T>
199 struct LowPtr {
200 using storage_type = detail::low_storage_t;
201 enum class Unchecked {};
204 * Constructors.
206 LowPtr() = default;
208 /* implicit */ LowPtr(T* px) : m_s{detail::to_low(px)} {}
209 /* implicit */ LowPtr(Unchecked, T* px) : m_s{detail::to_low_unchecked(px)} {}
210 /* implicit */ LowPtr(std::nullptr_t /*px*/) : m_s{0} {}
212 LowPtr(const LowPtr<T>&) = default;
213 LowPtr(LowPtr<T>&&) = default;
216 * Assignments.
218 LowPtr& operator=(T* px) {
219 m_s = detail::to_low(px);
220 return *this;
222 LowPtr& operator=(const LowPtr<T>&) = default;
223 LowPtr& operator=(std::nullptr_t /*px*/) {
224 m_s = 0;
225 return *this;
227 LowPtr& operator=(LowPtr<T>&&) = default;
230 * Observers.
232 T* get() const { return reinterpret_cast<T*>(m_s); }
233 T& operator*() const { return *get(); }
234 T* operator->() const { return get(); }
235 /* implicit */ operator T*() const { return get(); }
236 explicit operator bool() const { return get(); }
239 * Modifiers.
241 void reset() { operator=(nullptr); }
243 private:
244 storage_type m_s{0};
247 template<class T,
248 std::memory_order read_order = std::memory_order_relaxed,
249 std::memory_order write_order = std::memory_order_relaxed>
250 using AtomicLowPtr =
251 detail::LowPtrImpl<T, detail::AtomicStorage<detail::low_storage_t,
252 read_order,
253 write_order>>;
255 template<class T> struct lowptr_traits : std::false_type {};
256 template<class T> struct lowptr_traits<LowPtr<T>> : std::true_type {
257 using element_type = T;
258 using pointer = T*;
260 template<class T, std::memory_order R, std::memory_order W>
261 struct lowptr_traits<AtomicLowPtr<T, R, W>> : std::true_type {
262 using element_type = T;
263 using pointer = T*;
265 template<class T> constexpr bool is_lowptr_v = lowptr_traits<T>::value;
267 ///////////////////////////////////////////////////////////////////////////////
270 namespace folly {
271 template<class T> class FormatValue<HPHP::LowPtr<T>> {
272 public:
273 explicit FormatValue(HPHP::LowPtr<T> v) : m_val(v) {}
275 template<typename Callback>
276 void format(FormatArg& arg, Callback& cb) const {
277 FormatValue<T*>(m_val.get()).format(arg, cb);
280 private:
281 const HPHP::LowPtr<T> m_val;