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 +----------------------------------------------------------------------+
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>
29 #include <type_traits>
33 ///////////////////////////////////////////////////////////////////////////////
36 constexpr bool use_lowptr
= true;
39 using low_storage_t
= uint32_t;
42 constexpr bool use_lowptr
= false;
45 using low_storage_t
= uintptr_t;
49 inline bool is_low_mem(void* m
) {
51 const uint32_t mask
= ~0;
52 auto const i
= reinterpret_cast<intptr_t>(m
);
53 return (mask
& i
) == i
;
56 ///////////////////////////////////////////////////////////////////////////////
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
;
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
));
73 inline low_storage_t
to_low_unchecked(T
* px
) {
75 return (low_storage_t
)(reinterpret_cast<uintptr_t>(px
));
78 ///////////////////////////////////////////////////////////////////////////////
82 * Low memory pointer template.
84 template <class T
, class S
>
86 using storage_type
= typename
S::storage_type
;
87 enum class Unchecked
{};
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
)} {
108 LowPtrImpl
& operator=(T
* px
) {
109 S::set(m_s
, to_low(px
));
113 LowPtrImpl
& operator=(std::nullptr_t
/*px*/) {
118 LowPtrImpl
& operator=(const LowPtrImpl
<T
, S
>& r
) {
119 S::set(m_s
, S::get(r
.m_s
));
123 template <typename Q
= S
>
124 typename
std::enable_if
<
125 std::is_move_assignable
<typename
Q::storage_type
>::value
,
127 >::type
operator=(LowPtrImpl
<T
, S
>&& r
) {
128 m_s
= std::move(r
.m_s
);
132 template <typename Q
= S
>
133 typename
std::enable_if
<
134 !std::is_move_assignable
<typename
Q::storage_type
>::value
,
136 >::type
operator=(LowPtrImpl
<T
, S
>&& r
) {
137 S::set(m_s
, S::get(r
.m_s
));
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(); }
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
,
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
,
168 >::type
swap(LowPtrImpl
& r
) {
169 auto const tmp
= S::get(m_s
);
170 S::set(m_s
, S::get(r
.m_s
));
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 ///////////////////////////////////////////////////////////////////////////////
200 using storage_type
= detail::low_storage_t
;
201 enum class Unchecked
{};
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;
218 LowPtr
& operator=(T
* px
) {
219 m_s
= detail::to_low(px
);
222 LowPtr
& operator=(const LowPtr
<T
>&) = default;
223 LowPtr
& operator=(std::nullptr_t
/*px*/) {
227 LowPtr
& operator=(LowPtr
<T
>&&) = default;
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(); }
241 void reset() { operator=(nullptr); }
248 std::memory_order read_order
= std::memory_order_relaxed
,
249 std::memory_order write_order
= std::memory_order_relaxed
>
251 detail::LowPtrImpl
<T
, detail::AtomicStorage
<detail::low_storage_t
,
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
;
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
;
265 template<class T
> constexpr bool is_lowptr_v
= lowptr_traits
<T
>::value
;
267 ///////////////////////////////////////////////////////////////////////////////
271 template<class T
> class FormatValue
<HPHP::LowPtr
<T
>> {
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
);
281 const HPHP::LowPtr
<T
> m_val
;