Add sub-controls for Hack array compat runtime checks
[hiphop-php.git] / hphp / runtime / base / type-object.h
blob470af53b73c124eadc04796fc246fc476da3a078
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_OBJECT_H_
18 #define incl_HPHP_OBJECT_H_
20 #include "hphp/runtime/base/object-data.h"
21 #include "hphp/runtime/base/req-ptr.h"
22 #include "hphp/runtime/base/typed-value.h"
24 #include <algorithm>
26 namespace HPHP {
27 ///////////////////////////////////////////////////////////////////////////////
29 /**
30 * Object type wrapping around ObjectData to implement reference count.
32 struct Object {
33 private:
34 req::ptr<ObjectData> m_obj;
36 using NoIncRef = req::ptr<ObjectData>::NoIncRef;
38 public:
39 Object() {}
41 ObjectData* get() const { return m_obj.get(); }
42 void reset(ObjectData* obj = nullptr) { m_obj.reset(obj); }
44 ObjectData* operator->() const {
45 return m_obj.get();
48 /**
49 * Constructors
51 explicit Object(ObjectData *data) : m_obj(data) {
52 // The object must have at least two refs here. One pre-existing ref, and
53 // one caused by placing it under m_obj's control.
54 assert(!data || data->hasMultipleRefs());
56 /* implicit */ Object(const Object& src) : m_obj(src.m_obj) {
57 assert(!m_obj || m_obj->hasMultipleRefs());
60 template <typename T>
61 explicit Object(const req::ptr<T> &ptr) : m_obj(ptr) {
62 assert(!m_obj || m_obj->hasMultipleRefs());
65 template <typename T>
66 explicit Object(req::ptr<T>&& ptr) : m_obj(std::move(ptr)) {
67 assert(!m_obj || m_obj->checkCount());
70 explicit Object(Class* cls)
71 : m_obj(ObjectData::newInstance(cls), NoIncRef{}) {
72 // References to the object can escape inside newInstance, so we only know
73 // that the ref-count is at least 1 here.
74 assert(!m_obj || m_obj->checkCount());
77 // Move ctor
78 Object(Object&& src) noexcept : m_obj(std::move(src.m_obj)) {
79 assert(!m_obj || m_obj->checkCount());
82 // Regular assign
83 Object& operator=(const Object& src) {
84 m_obj = src.m_obj;
85 assert(!m_obj || m_obj->hasMultipleRefs());
86 return *this;
89 template <typename T>
90 Object& operator=(const req::ptr<T>& src) {
91 m_obj = src;
92 assert(!m_obj || m_obj->hasMultipleRefs());
93 return *this;
96 // Move assign
97 Object& operator=(Object&& src) {
98 m_obj = std::move(src.m_obj);
99 assert(!m_obj || m_obj->checkCount());
100 return *this;
103 template <typename T>
104 Object& operator=(req::ptr<T>&& src) {
105 m_obj = std::move(src);
106 assert(!m_obj || m_obj->checkCount());
107 return *this;
111 * Informational
113 explicit operator bool() const { return (bool)m_obj; }
115 bool isNull() const { return !m_obj; }
116 bool instanceof(const String& s) const {
117 return m_obj && m_obj->instanceof(s);
119 bool instanceof(const Class* cls) const {
120 return m_obj && m_obj->instanceof(cls);
124 * getTyped() and is() are intended for use with C++ classes that derive
125 * from ObjectData.
127 * Prefer using the following functions instead of getTyped:
128 * o.getTyped<T>(false, false) -> cast<T>(o)
129 * o.getTyped<T>(true, false) -> cast_or_null<T>(o)
130 * o.getTyped<T>(false, true) -> dyn_cast<T>(o)
131 * o.getTyped<T>(true, true) -> dyn_cast_or_null<T>(o)
133 template<typename T>
134 [[deprecated("Please use one of the cast family of functions instead.")]]
135 req::ptr<T> getTyped(bool nullOkay = false, bool badTypeOkay = false) const {
136 static_assert(std::is_base_of<ObjectData, T>::value, "");
138 ObjectData *cur = get();
139 if (!cur) {
140 if (!nullOkay) {
141 throw_null_pointer_exception();
143 return nullptr;
145 if (!cur->instanceof(T::classof())) {
146 if (!badTypeOkay) {
147 throw_invalid_object_type(classname_cstr());
149 return nullptr;
152 return req::ptr<T>(static_cast<T*>(cur));
155 template<typename T>
156 bool is() const {
157 return m_obj && m_obj->instanceof(T::classof());
161 * Type conversions
163 bool toBoolean() const { return m_obj ? m_obj->toBoolean() : false; }
164 char toByte () const { return toInt64(); }
165 int16_t toInt16 () const { return toInt64(); }
166 int32_t toInt32 () const { return toInt64(); }
167 int64_t toInt64 () const { return m_obj ? m_obj->toInt64() : 0; }
168 double toDouble () const { return m_obj ? m_obj->toDouble() : 0; }
169 String toString () const;
170 Array toArray () const;
172 int64_t toInt64ForCompare() const;
173 double toDoubleForCompare() const;
176 * Comparisons
178 bool same(const Object& v2) const { return m_obj == v2.m_obj; }
179 bool equal(const Object& v2) const {
180 return m_obj ?
181 (v2.m_obj && m_obj->equal(*v2.m_obj.get())) :
182 !v2.m_obj;
184 bool less(const Object& v2) const {
185 return m_obj ?
186 (v2.m_obj && m_obj->less(*v2.m_obj.get())) :
187 static_cast<bool>(v2.m_obj);
189 bool lessEqual(const Object& v2) const { return less(v2) || equal(v2); }
190 bool more(const Object& v2) const {
191 return m_obj && (!v2.m_obj || m_obj->more(*v2.m_obj.get()));
193 bool moreEqual(const Object& v2) const { return more(v2) || equal(v2); }
195 // Transfer ownership of our reference to this object.
196 ObjectData *detach() { return m_obj.detach(); }
198 // Take ownership of a reference without touching the ref count
199 static Object attach(ObjectData *object) {
200 assert(!object || object->checkCount());
201 return Object{req::ptr<ObjectData>::attach(object)};
204 private:
205 template <typename T>
206 friend typename std::enable_if<
207 std::is_base_of<ObjectData,T>::value,
208 ObjectData*
209 >::type deref(const Object& o) { return o.get(); }
211 template <typename T>
212 friend typename std::enable_if<
213 std::is_base_of<ObjectData,T>::value,
214 ObjectData*
215 >::type detach(Object&& o) { return o.detach(); }
217 static void compileTimeAssertions();
219 const char* classname_cstr() const;
222 extern const Object null_object;
224 ///////////////////////////////////////////////////////////////////////////////
225 // ObjNR
227 struct ObjNR {
228 explicit ObjNR(ObjectData* data) {
229 m_px = data;
232 Object& asObject() {
233 return *reinterpret_cast<Object*>(this); // XXX
236 const Object& asObject() const {
237 return const_cast<ObjNR*>(this)->asObject();
240 private:
241 ObjectData* m_px;
243 static void compileTimeAssertions();
246 ///////////////////////////////////////////////////////////////////////////////
249 #endif // incl_HPHP_OBJECT_H_