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 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_ARRAY_DATA_DEFS_H_
18 #define incl_HPHP_ARRAY_DATA_DEFS_H_
20 #include "hphp/runtime/base/array-data.h"
22 #include "hphp/runtime/base/tv-val.h"
23 #include "hphp/runtime/base/string-data.h"
24 #include "hphp/runtime/base/type-variant.h"
30 ///////////////////////////////////////////////////////////////////////////////
32 extern const StaticString s_InvalidKeysetOperationMsg
;
33 extern const StaticString s_VecUnsetMsg
;
35 ///////////////////////////////////////////////////////////////////////////////
37 inline ArrayData
* ArrayData::Create(const Variant
& value
) {
38 return Create(*value
.asTypedValue());
41 inline ArrayData
* ArrayData::Create(const Variant
& name
, TypedValue value
) {
42 return Create(*name
.asTypedValue(), value
);
45 inline ArrayData
* ArrayData::Create(const Variant
& name
, const Variant
& value
) {
46 return Create(*name
.asTypedValue(), *value
.asTypedValue());
49 ///////////////////////////////////////////////////////////////////////////////
50 // ArrayFunction dispatch.
52 inline bool ArrayData::notCyclic(TypedValue v
) const {
53 return !tvIsArrayLike(v
) || v
.m_data
.parr
!= this;
56 inline ArrayData
* ArrayData::copy() const {
57 return g_array_funcs
.copy
[kind()](this);
60 inline ArrayData
* ArrayData::copyStatic() const {
61 auto ret
= g_array_funcs
.copyStatic
[kind()](this);
62 assertx(ret
!= this && ret
->isStatic());
66 inline ArrayData
* ArrayData::toPHPArray(bool copy
) {
67 return g_array_funcs
.toPHPArray
[kind()](this, copy
);
70 inline ArrayData
* ArrayData::toPHPArrayIntishCast(bool copy
) {
71 return g_array_funcs
.toPHPArrayIntishCast
[kind()](this, copy
);
74 inline ArrayData
* ArrayData::toDict(bool copy
) {
75 return g_array_funcs
.toDict
[kind()](this, copy
);
78 inline ArrayData
* ArrayData::toVec(bool copy
) {
79 return g_array_funcs
.toVec
[kind()](this, copy
);
82 inline ArrayData
* ArrayData::toKeyset(bool copy
) {
83 return g_array_funcs
.toKeyset
[kind()](this, copy
);
86 inline ArrayData
* ArrayData::toVArray(bool copy
) {
87 return g_array_funcs
.toVArray
[kind()](this, copy
);
90 inline ArrayData
* ArrayData::toDArray(bool copy
) {
91 return g_array_funcs
.toDArray
[kind()](this, copy
);
94 inline bool ArrayData::isVectorData() const {
95 return g_array_funcs
.isVectorData
[kind()](this);
98 inline void ArrayData::release() noexcept
{
99 assertx(!hasMultipleRefs());
100 g_array_funcs
.release
[kind()](this);
101 AARCH64_WALKABLE_FRAME();
104 inline bool ArrayData::exists(int64_t k
) const {
105 return g_array_funcs
.existsInt
[kind()](this, k
);
108 inline bool ArrayData::exists(const StringData
* k
) const {
109 return g_array_funcs
.existsStr
[kind()](this, k
);
112 inline arr_lval
ArrayData::lval(int64_t k
) {
113 return g_array_funcs
.lvalInt
[kind()](this, k
);
116 inline arr_lval
ArrayData::lval(StringData
* k
) {
117 return g_array_funcs
.lvalStr
[kind()](this, k
);
120 inline ssize_t
ArrayData::nvGetIntPos(int64_t k
) const {
121 return g_array_funcs
.nvGetIntPos
[kind()](this, k
);
124 inline ssize_t
ArrayData::nvGetStrPos(const StringData
* k
) const {
125 return g_array_funcs
.nvGetStrPos
[kind()](this, k
);
128 inline TypedValue
ArrayData::nvGetKey(ssize_t pos
) const {
129 return g_array_funcs
.getPosKey
[kind()](this, pos
);
132 inline TypedValue
ArrayData::nvGetVal(ssize_t pos
) const {
133 return g_array_funcs
.getPosVal
[kind()](this, pos
);
136 inline Variant
ArrayData::getKey(ssize_t pos
) const {
137 return Variant::wrap(nvGetKey(pos
));
140 inline Variant
ArrayData::getValue(ssize_t pos
) const {
141 return Variant::wrap(nvGetVal(pos
));
144 inline ArrayData
* ArrayData::set(int64_t k
, TypedValue v
) {
145 assertx(tvIsPlausible(v
));
146 assertx(cowCheck() || notCyclic(v
));
147 return g_array_funcs
.setInt
[kind()](this, k
, v
);
150 inline ArrayData
* ArrayData::setMove(int64_t k
, TypedValue v
) {
151 assertx(tvIsPlausible(v
));
152 assertx(cowCheck() || notCyclic(v
));
153 return g_array_funcs
.setIntMove
[kind()](this, k
, v
);
156 inline ArrayData
* ArrayData::set(StringData
* k
, TypedValue v
) {
157 assertx(tvIsPlausible(v
));
158 assertx(cowCheck() || notCyclic(v
));
159 return g_array_funcs
.setStr
[kind()](this, k
, v
);
162 inline ArrayData
* ArrayData::setMove(StringData
* k
, TypedValue v
) {
163 assertx(tvIsPlausible(v
));
164 assertx(cowCheck() || notCyclic(v
));
165 return g_array_funcs
.setStrMove
[kind()](this, k
, v
);
168 inline ArrayData
* ArrayData::set(int64_t k
, const Variant
& v
) {
169 auto c
= *v
.asTypedValue();
170 assertx(cowCheck() || notCyclic(c
));
171 return g_array_funcs
.setInt
[kind()](this, k
, c
);
174 inline ArrayData
* ArrayData::set(StringData
* k
, const Variant
& v
) {
175 auto c
= *v
.asTypedValue();
176 assertx(cowCheck() || notCyclic(c
));
177 return g_array_funcs
.setStr
[kind()](this, k
, c
);
180 inline ArrayData
* ArrayData::remove(int64_t k
) {
181 return g_array_funcs
.removeInt
[kind()](this, k
);
184 inline ArrayData
* ArrayData::remove(const StringData
* k
) {
185 return g_array_funcs
.removeStr
[kind()](this, k
);
188 inline ArrayData
* ArrayData::append(TypedValue v
) {
189 assertx(v
.m_type
!= KindOfUninit
);
190 assertx(cowCheck() || notCyclic(v
));
191 return g_array_funcs
.append
[kind()](this, v
);
194 inline ssize_t
ArrayData::iter_begin() const {
195 return g_array_funcs
.iterBegin
[kind()](this);
198 inline ssize_t
ArrayData::iter_last() const {
199 return g_array_funcs
.iterLast
[kind()](this);
202 inline ssize_t
ArrayData::iter_end() const {
203 return g_array_funcs
.iterEnd
[kind()](this);
206 inline ssize_t
ArrayData::iter_advance(ssize_t pos
) const {
207 return g_array_funcs
.iterAdvance
[kind()](this, pos
);
210 inline ssize_t
ArrayData::iter_rewind(ssize_t pos
) const {
211 return g_array_funcs
.iterRewind
[kind()](this, pos
);
214 inline ArrayData
* ArrayData::escalateForSort(SortFunction sf
) {
215 return g_array_funcs
.escalateForSort
[kind()](this, sf
);
218 inline void ArrayData::ksort(int sort_flags
, bool ascending
) {
219 return g_array_funcs
.ksort
[kind()](this, sort_flags
, ascending
);
222 inline void ArrayData::sort(int sort_flags
, bool ascending
) {
223 return g_array_funcs
.sort
[kind()](this, sort_flags
, ascending
);
226 inline void ArrayData::asort(int sort_flags
, bool ascending
) {
227 return g_array_funcs
.asort
[kind()](this, sort_flags
, ascending
);
230 inline bool ArrayData::uksort(const Variant
& compare
) {
231 return g_array_funcs
.uksort
[kind()](this, compare
);
234 inline bool ArrayData::usort(const Variant
& compare
) {
235 return g_array_funcs
.usort
[kind()](this, compare
);
238 inline bool ArrayData::uasort(const Variant
& compare
) {
239 return g_array_funcs
.uasort
[kind()](this, compare
);
242 inline ArrayData
* ArrayData::plusEq(const ArrayData
* elms
) {
243 return g_array_funcs
.plusEq
[kind()](this, elms
);
246 inline ArrayData
* ArrayData::merge(const ArrayData
* elms
) {
247 auto ret
= g_array_funcs
.merge
[kind()](this, elms
);
248 assertx(ret
->isPHPArrayType());
249 assertx(ret
->isNotDVArray());
253 inline ArrayData
* ArrayData::pop(Variant
& value
) {
254 return g_array_funcs
.pop
[kind()](this, value
);
257 inline ArrayData
* ArrayData::dequeue(Variant
& value
) {
258 return g_array_funcs
.dequeue
[kind()](this, value
);
261 inline ArrayData
* ArrayData::prepend(TypedValue v
) {
262 assertx(v
.m_type
!= KindOfUninit
);
263 return g_array_funcs
.prepend
[kind()](this, v
);
266 inline void ArrayData::onSetEvalScalar() {
267 return g_array_funcs
.onSetEvalScalar
[kind()](this);
270 inline ArrayData
* ArrayData::renumber() {
271 return g_array_funcs
.renumber
[kind()](this);
274 ///////////////////////////////////////////////////////////////////////////////
278 inline bool isIntKey(TypedValue cell
) {
279 assertx(isIntType(cell
.m_type
) || isStringType(cell
.m_type
));
280 return isIntType(cell
.m_type
);
283 inline int64_t getIntKey(TypedValue cell
) {
284 assertx(isIntType(cell
.m_type
));
285 return cell
.m_data
.num
;
288 inline StringData
* getStringKey(TypedValue cell
) {
289 assertx(isStringType(cell
.m_type
));
290 return cell
.m_data
.pstr
;
295 ///////////////////////////////////////////////////////////////////////////////
296 // Element manipulation.
298 inline bool ArrayData::exists(TypedValue k
) const {
299 assertx(IsValidKey(k
));
300 return detail::isIntKey(k
) ? exists(detail::getIntKey(k
))
301 : exists(detail::getStringKey(k
));
304 inline arr_lval
ArrayData::lval(TypedValue k
) {
305 assertx(IsValidKey(k
));
306 return detail::isIntKey(k
) ? lval(detail::getIntKey(k
))
307 : lval(detail::getStringKey(k
));
310 inline TypedValue
ArrayData::get(int64_t k
, bool error
) const {
311 auto const result
= g_array_funcs
.nvGetInt
[kind()](this, k
);
312 if (error
&& !result
.is_init()) getNotFound(k
);
316 inline TypedValue
ArrayData::get(const StringData
* k
, bool error
) const {
317 auto const result
= g_array_funcs
.nvGetStr
[kind()](this, k
);
318 if (error
&& !result
.is_init()) getNotFound(k
);
322 inline TypedValue
ArrayData::get(TypedValue k
, bool error
) const {
323 assertx(IsValidKey(k
));
324 return detail::isIntKey(k
) ? get(detail::getIntKey(k
), error
)
325 : get(detail::getStringKey(k
), error
);
328 inline TypedValue
ArrayData::at(int64_t k
) const {
329 auto const result
= get(k
);
330 assertx(result
.is_init());
334 inline TypedValue
ArrayData::at(const StringData
* k
) const {
335 auto const result
= get(k
);
336 assertx(result
.is_init());
340 inline TypedValue
ArrayData::at(TypedValue k
) const {
341 assertx(IsValidKey(k
));
342 return detail::isIntKey(k
) ? at(detail::getIntKey(k
))
343 : at(detail::getStringKey(k
));
346 inline ArrayData
* ArrayData::set(TypedValue k
, TypedValue v
) {
347 assertx(tvIsPlausible(k
));
348 assertx(tvIsPlausible(v
));
349 assertx(IsValidKey(k
));
351 return detail::isIntKey(k
) ? set(detail::getIntKey(k
), v
)
352 : set(detail::getStringKey(k
), v
);
355 inline ArrayData
* ArrayData::remove(TypedValue k
) {
356 assertx(IsValidKey(k
));
357 return detail::isIntKey(k
) ? remove(detail::getIntKey(k
))
358 : remove(detail::getStringKey(k
));
361 ///////////////////////////////////////////////////////////////////////////////
363 inline bool ArrayData::exists(const String
& k
) const {
364 assertx(IsValidKey(k
));
365 return exists(k
.get());
368 inline bool ArrayData::exists(const Variant
& k
) const {
369 return exists(*k
.asTypedValue());
372 inline arr_lval
ArrayData::lval(const String
& k
) {
373 assertx(IsValidKey(k
));
374 return lval(k
.get());
377 inline arr_lval
ArrayData::lval(const Variant
& k
) {
378 return lval(*k
.asTypedValue());
381 inline TypedValue
ArrayData::get(const String
& k
, bool error
) const {
382 assertx(IsValidKey(k
));
383 return get(k
.get(), error
);
386 inline TypedValue
ArrayData::get(const Variant
& k
, bool error
) const {
387 return get(*k
.asTypedValue(), error
);
390 inline ArrayData
* ArrayData::set(const String
& k
, TypedValue v
) {
391 assertx(tvIsPlausible(v
));
392 assertx(IsValidKey(k
));
393 return set(k
.get(), v
);
396 inline ArrayData
* ArrayData::set(const String
& k
, const Variant
& v
) {
397 return set(k
, *v
.asTypedValue());
400 inline ArrayData
* ArrayData::set(const Variant
& k
, const Variant
& v
) {
401 return set(*k
.asTypedValue(), *v
.asTypedValue());
404 inline ArrayData
* ArrayData::remove(const String
& k
) {
405 assertx(IsValidKey(k
));
406 return remove(k
.get());
409 inline ArrayData
* ArrayData::remove(const Variant
& k
) {
410 return remove(*k
.asTypedValue());
413 ///////////////////////////////////////////////////////////////////////////////
415 template <IntishCast IC
>
416 ALWAYS_INLINE
bool ArrayData::convertKey(const StringData
* key
,
418 return IC
== IntishCast::Cast
&&
419 key
->isStrictlyInteger(i
) &&
423 template <IntishCast IC
>
425 folly::Optional
<int64_t> tryIntishCast(const StringData
* key
) {
427 if (UNLIKELY(IC
== IntishCast::Cast
&&
428 key
->isStrictlyInteger(i
))) {
434 ///////////////////////////////////////////////////////////////////////////////