Add sub-controls for Hack array compat runtime checks
[hiphop-php.git] / hphp / runtime / base / array-data-defs.h
blobd20fcca80e0b2df4a55d896068784fe5dd681d47
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_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/member-val.h"
23 #include "hphp/runtime/base/string-data.h"
24 #include "hphp/runtime/base/type-variant.h"
26 #include <algorithm>
28 namespace HPHP {
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 inline ArrayData* ArrayData::CreateWithRef(const Variant& name,
50 TypedValue value) {
51 return CreateWithRef(*name.asTypedValue(), value);
54 inline ArrayData* ArrayData::CreateRef(const Variant& name, Variant& value) {
55 return CreateRef(*name.asTypedValue(), value);
58 ///////////////////////////////////////////////////////////////////////////////
59 // ArrayFunction dispatch.
61 inline ArrayData* ArrayData::copy() const {
62 return g_array_funcs.copy[kind()](this);
65 inline ArrayData* ArrayData::copyStatic() const {
66 auto ret = g_array_funcs.copyStatic[kind()](this);
67 assert(ret != this && ret->isStatic());
68 return ret;
71 inline ArrayData* ArrayData::toPHPArray(bool copy) {
72 return g_array_funcs.toPHPArray[kind()](this, copy);
75 inline ArrayData* ArrayData::toDict(bool copy) {
76 return g_array_funcs.toDict[kind()](this, copy);
79 inline ArrayData* ArrayData::toVec(bool copy) {
80 return g_array_funcs.toVec[kind()](this, copy);
83 inline ArrayData* ArrayData::toKeyset(bool copy) {
84 return g_array_funcs.toKeyset[kind()](this, copy);
87 inline ArrayData* ArrayData::toVArray(bool copy) {
88 return g_array_funcs.toVArray[kind()](this, copy);
91 inline ArrayData* ArrayData::toDArray(bool copy) {
92 return g_array_funcs.toDArray[kind()](this, copy);
95 inline ArrayData* ArrayData::escalate() const {
96 return g_array_funcs.escalate[kind()](this);
99 inline bool ArrayData::isVectorData() const {
100 return g_array_funcs.isVectorData[kind()](this);
103 inline void ArrayData::release() noexcept {
104 assert(hasExactlyOneRef());
105 g_array_funcs.release[kind()](this);
106 AARCH64_WALKABLE_FRAME();
109 inline bool ArrayData::exists(int64_t k) const {
110 return g_array_funcs.existsInt[kind()](this, k);
113 inline bool ArrayData::exists(const StringData* k) const {
114 return g_array_funcs.existsStr[kind()](this, k);
117 inline member_lval ArrayData::lval(int64_t k, bool copy) {
118 return g_array_funcs.lvalInt[kind()](this, k, copy);
121 inline member_lval ArrayData::lval(StringData* k, bool copy) {
122 return g_array_funcs.lvalStr[kind()](this, k, copy);
125 inline member_lval ArrayData::lvalRef(int64_t k, bool copy) {
126 return g_array_funcs.lvalIntRef[kind()](this, k, copy);
129 inline member_lval ArrayData::lvalRef(StringData* k, bool copy) {
130 return g_array_funcs.lvalStrRef[kind()](this, k, copy);
133 inline member_lval ArrayData::lvalNew(bool copy) {
134 return g_array_funcs.lvalNew[kind()](this, copy);
137 inline member_lval ArrayData::lvalNewRef(bool copy) {
138 return g_array_funcs.lvalNewRef[kind()](this, copy);
141 inline member_rval ArrayData::rval(int64_t k) const {
142 return member_rval { this, g_array_funcs.nvGetInt[kind()](this, k) };
145 inline member_rval ArrayData::rval(const StringData* k) const {
146 return member_rval { this, g_array_funcs.nvGetStr[kind()](this, k) };
149 inline member_rval ArrayData::rvalStrict(int64_t k) const {
150 return member_rval { this, g_array_funcs.nvTryGetInt[kind()](this, k) };
153 inline member_rval ArrayData::rvalStrict(const StringData* k) const {
154 return member_rval { this, g_array_funcs.nvTryGetStr[kind()](this, k) };
157 inline member_rval ArrayData::rvalPos(ssize_t pos) const {
158 return member_rval { this, g_array_funcs.nvGetPos[kind()](this, pos) };
161 inline Cell ArrayData::nvGetKey(ssize_t pos) const {
162 return g_array_funcs.nvGetKey[kind()](this, pos);
165 inline ArrayData* ArrayData::set(int64_t k, Cell v, bool copy) {
166 assertx(cellIsPlausible(v));
167 return g_array_funcs.setInt[kind()](this, k, v, copy);
170 inline ArrayData* ArrayData::set(StringData* k, Cell v, bool copy) {
171 assertx(cellIsPlausible(v));
172 return g_array_funcs.setStr[kind()](this, k, v, copy);
175 inline ArrayData* ArrayData::set(int64_t k, const Variant& v, bool copy) {
176 return g_array_funcs.setInt[kind()](this, k, *v.asCell(), copy);
179 inline ArrayData* ArrayData::set(StringData* k, const Variant& v, bool copy) {
180 return g_array_funcs.setStr[kind()](this, k, *v.asCell(), copy);
183 inline ArrayData* ArrayData::setWithRef(int64_t k, TypedValue v, bool copy) {
184 assertx(tvIsPlausible(v));
185 return g_array_funcs.setWithRefInt[kind()](this, k, v, copy);
188 inline ArrayData* ArrayData::setWithRef(StringData* k,
189 TypedValue v, bool copy) {
190 assertx(tvIsPlausible(v));
191 return g_array_funcs.setWithRefStr[kind()](this, k, v, copy);
194 inline ArrayData* ArrayData::setRef(int64_t k, member_lval v, bool copy) {
195 return g_array_funcs.setRefInt[kind()](this, k, v, copy);
198 inline ArrayData* ArrayData::setRef(StringData* k, member_lval v, bool copy) {
199 return g_array_funcs.setRefStr[kind()](this, k, v, copy);
202 inline ArrayData* ArrayData::add(int64_t k, Cell v, bool copy) {
203 assertx(cellIsPlausible(v));
204 return g_array_funcs.addInt[kind()](this, k, v, copy);
207 inline ArrayData* ArrayData::add(StringData* k, Cell v, bool copy) {
208 assertx(cellIsPlausible(v));
209 return g_array_funcs.addStr[kind()](this, k, v, copy);
212 inline ArrayData* ArrayData::add(int64_t k, const Variant& v, bool copy) {
213 return g_array_funcs.addInt[kind()](this, k, *v.asCell(), copy);
216 inline ArrayData* ArrayData::add(StringData* k, const Variant& v, bool copy) {
217 return g_array_funcs.addStr[kind()](this, k, *v.asCell(), copy);
220 inline ArrayData* ArrayData::remove(int64_t k, bool copy) {
221 return g_array_funcs.removeInt[kind()](this, k, copy);
224 inline ArrayData* ArrayData::remove(const StringData* k, bool copy) {
225 return g_array_funcs.removeStr[kind()](this, k, copy);
228 inline ArrayData* ArrayData::append(Cell v, bool copy) {
229 assertx(v.m_type != KindOfUninit);
230 return g_array_funcs.append[kind()](this, v, copy);
233 inline ArrayData* ArrayData::appendWithRef(TypedValue v, bool copy) {
234 return g_array_funcs.appendWithRef[kind()](this, v, copy);
237 inline ArrayData* ArrayData::appendWithRef(const Variant& v, bool copy) {
238 return g_array_funcs.appendWithRef[kind()](this, *v.asTypedValue(), copy);
241 inline ArrayData* ArrayData::appendRef(member_lval v, bool copy) {
242 return g_array_funcs.appendRef[kind()](this, v, copy);
245 inline ssize_t ArrayData::iter_begin() const {
246 return g_array_funcs.iterBegin[kind()](this);
249 inline ssize_t ArrayData::iter_last() const {
250 return g_array_funcs.iterLast[kind()](this);
253 inline ssize_t ArrayData::iter_end() const {
254 return g_array_funcs.iterEnd[kind()](this);
257 inline ssize_t ArrayData::iter_advance(ssize_t pos) const {
258 return g_array_funcs.iterAdvance[kind()](this, pos);
261 inline ssize_t ArrayData::iter_rewind(ssize_t pos) const {
262 return g_array_funcs.iterRewind[kind()](this, pos);
265 inline bool ArrayData::validMArrayIter(const MArrayIter& fp) const {
266 return g_array_funcs.validMArrayIter[kind()](this, fp);
269 inline bool ArrayData::advanceMArrayIter(MArrayIter& fp) {
270 return g_array_funcs.advanceMArrayIter[kind()](this, fp);
273 inline ArrayData* ArrayData::escalateForSort(SortFunction sf) {
274 return g_array_funcs.escalateForSort[kind()](this, sf);
277 inline void ArrayData::ksort(int sort_flags, bool ascending) {
278 return g_array_funcs.ksort[kind()](this, sort_flags, ascending);
281 inline void ArrayData::sort(int sort_flags, bool ascending) {
282 return g_array_funcs.sort[kind()](this, sort_flags, ascending);
285 inline void ArrayData::asort(int sort_flags, bool ascending) {
286 return g_array_funcs.asort[kind()](this, sort_flags, ascending);
289 inline bool ArrayData::uksort(const Variant& compare) {
290 return g_array_funcs.uksort[kind()](this, compare);
293 inline bool ArrayData::usort(const Variant& compare) {
294 return g_array_funcs.usort[kind()](this, compare);
297 inline bool ArrayData::uasort(const Variant& compare) {
298 return g_array_funcs.uasort[kind()](this, compare);
301 inline ArrayData* ArrayData::plusEq(const ArrayData* elms) {
302 return g_array_funcs.plusEq[kind()](this, elms);
305 inline ArrayData* ArrayData::merge(const ArrayData* elms) {
306 auto ret = g_array_funcs.merge[kind()](this, elms);
307 assertx(ret->isPHPArray());
308 assertx(ret->isNotDVArray());
309 return ret;
312 inline ArrayData* ArrayData::pop(Variant& value) {
313 return g_array_funcs.pop[kind()](this, value);
316 inline ArrayData* ArrayData::dequeue(Variant& value) {
317 return g_array_funcs.dequeue[kind()](this, value);
320 inline ArrayData* ArrayData::prepend(Cell v, bool copy) {
321 assertx(v.m_type != KindOfUninit);
322 return g_array_funcs.prepend[kind()](this, v, copy);
325 inline void ArrayData::onSetEvalScalar() {
326 return g_array_funcs.onSetEvalScalar[kind()](this);
329 inline void ArrayData::renumber() {
330 return g_array_funcs.renumber[kind()](this);
333 ///////////////////////////////////////////////////////////////////////////////
335 namespace detail {
337 inline bool isIntKey(Cell cell) {
338 assert(isIntType(cell.m_type) || isStringType(cell.m_type));
339 return isIntType(cell.m_type);
342 inline int64_t getIntKey(Cell cell) {
343 assert(isIntType(cell.m_type));
344 return cell.m_data.num;
347 inline StringData* getStringKey(Cell cell) {
348 assert(isStringType(cell.m_type));
349 return cell.m_data.pstr;
354 ///////////////////////////////////////////////////////////////////////////////
355 // Element manipulation.
357 inline bool ArrayData::exists(Cell k) const {
358 assert(IsValidKey(k));
359 return detail::isIntKey(k) ? exists(detail::getIntKey(k))
360 : exists(detail::getStringKey(k));
363 inline member_lval ArrayData::lval(Cell k, bool copy) {
364 assert(IsValidKey(k));
365 return detail::isIntKey(k) ? lval(detail::getIntKey(k), copy)
366 : lval(detail::getStringKey(k), copy);
369 inline member_lval ArrayData::lvalRef(Cell k, bool copy) {
370 assert(IsValidKey(k));
371 return detail::isIntKey(k) ? lvalRef(detail::getIntKey(k), copy)
372 : lvalRef(detail::getStringKey(k), copy);
375 inline member_rval ArrayData::get(int64_t k, bool error) const {
376 auto r = error ? rvalStrict(k) : rval(k);
377 return r ? r : getNotFound(k, error);
380 inline member_rval ArrayData::get(const StringData* k, bool error) const {
381 auto r = error ? rvalStrict(k) : rval(k);
382 return r ? r : getNotFound(k, error);
385 inline member_rval ArrayData::get(Cell k, bool error) const {
386 assert(IsValidKey(k));
387 return detail::isIntKey(k) ? get(detail::getIntKey(k), error)
388 : get(detail::getStringKey(k), error);
391 inline TypedValue ArrayData::at(int64_t k) const {
392 return rval(k).tv();
395 inline TypedValue ArrayData::at(const StringData* k) const {
396 return rval(k).tv();
399 inline TypedValue ArrayData::atPos(ssize_t pos) const {
400 return rvalPos(pos).tv();
403 inline ArrayData* ArrayData::set(Cell k, Cell v, bool copy) {
404 assertx(cellIsPlausible(k));
405 assertx(cellIsPlausible(v));
406 assertx(IsValidKey(k));
408 return detail::isIntKey(k) ? set(detail::getIntKey(k), v, copy)
409 : set(detail::getStringKey(k), v, copy);
412 inline ArrayData* ArrayData::setWithRef(Cell k, TypedValue v, bool copy) {
413 assertx(cellIsPlausible(k));
414 assertx(tvIsPlausible(v));
415 assertx(IsValidKey(k));
417 return detail::isIntKey(k) ? setWithRef(detail::getIntKey(k), v, copy)
418 : setWithRef(detail::getStringKey(k), v, copy);
421 inline ArrayData* ArrayData::setRef(Cell k, member_lval v, bool copy) {
422 assert(IsValidKey(k));
423 return detail::isIntKey(k) ? setRef(detail::getIntKey(k), v, copy)
424 : setRef(detail::getStringKey(k), v, copy);
427 inline ArrayData* ArrayData::setRef(int64_t k, Variant& v, bool copy) {
428 return setRef(k, member_lval::raw(v.asTypedValue()), copy);
431 inline ArrayData* ArrayData::setRef(StringData* k, Variant& v, bool copy) {
432 return setRef(k, member_lval::raw(v.asTypedValue()), copy);
435 inline ArrayData* ArrayData::setRef(Cell k, Variant& v, bool copy) {
436 return setRef(k, member_lval::raw(v.asTypedValue()), copy);
439 inline ArrayData* ArrayData::add(Cell k, Cell v, bool copy) {
440 assertx(cellIsPlausible(k));
441 assertx(cellIsPlausible(v));
442 assertx(IsValidKey(k));
444 return detail::isIntKey(k) ? add(detail::getIntKey(k), v, copy)
445 : add(detail::getStringKey(k), v, copy);
448 inline ArrayData* ArrayData::remove(Cell k, bool copy) {
449 assert(IsValidKey(k));
450 return detail::isIntKey(k) ? remove(detail::getIntKey(k), copy)
451 : remove(detail::getStringKey(k), copy);
454 ///////////////////////////////////////////////////////////////////////////////
456 inline bool ArrayData::exists(const String& k) const {
457 assert(IsValidKey(k));
458 return exists(k.get());
461 inline bool ArrayData::exists(const Variant& k) const {
462 return exists(*k.asCell());
465 inline member_lval ArrayData::lval(const String& k, bool copy) {
466 assert(IsValidKey(k));
467 return lval(k.get(), copy);
470 inline member_lval ArrayData::lval(const Variant& k, bool copy) {
471 return lval(*k.asCell(), copy);
474 inline member_lval ArrayData::lvalRef(const String& k, bool copy) {
475 assert(IsValidKey(k));
476 return lvalRef(k.get(), copy);
479 inline member_lval ArrayData::lvalRef(const Variant& k, bool copy) {
480 return lvalRef(*k.asCell(), copy);
483 inline member_rval ArrayData::get(const String& k, bool error) const {
484 assert(IsValidKey(k));
485 return get(k.get(), error);
488 inline member_rval ArrayData::get(const Variant& k, bool error) const {
489 return get(*k.asCell(), error);
492 inline ArrayData* ArrayData::set(const String& k, Cell v, bool copy) {
493 assertx(cellIsPlausible(v));
494 assertx(IsValidKey(k));
495 return set(k.get(), v, copy);
498 inline ArrayData* ArrayData::set(const String& k, const Variant& v,
499 bool copy) {
500 return set(k, *v.asCell(), copy);
503 inline ArrayData* ArrayData::set(const Variant& k, const Variant& v,
504 bool copy) {
505 return set(*k.asCell(), *v.asCell(), copy);
508 inline ArrayData* ArrayData::setWithRef(const String& k,
509 TypedValue v, bool copy) {
510 assertx(tvIsPlausible(v));
511 assertx(IsValidKey(k));
512 return setWithRef(k.get(), v, copy);
515 inline ArrayData*
516 ArrayData::setRef(const String& k, member_lval v, bool copy) {
517 assert(IsValidKey(k));
518 return setRef(k.get(), v, copy);
521 inline ArrayData*
522 ArrayData::setRef(const Variant& k, member_lval v, bool copy) {
523 return setRef(*k.asCell(), v, copy);
526 inline ArrayData* ArrayData::setRef(const String& k, Variant& v, bool copy) {
527 return setRef(k, member_lval::raw(v.asTypedValue()), copy);
530 inline ArrayData* ArrayData::setRef(const Variant& k, Variant& v, bool copy) {
531 return setRef(k, member_lval::raw(v.asTypedValue()), copy);
534 inline ArrayData* ArrayData::add(const String& k, Cell v, bool copy) {
535 assertx(cellIsPlausible(v));
536 assert(IsValidKey(k));
537 return add(k.get(), v, copy);
540 inline ArrayData* ArrayData::add(const String& k, const Variant& v,
541 bool copy) {
542 return add(k, *v.asCell(), copy);
545 inline ArrayData* ArrayData::add(const Variant& k, const Variant& v,
546 bool copy) {
547 return add(*k.asCell(), *v.asCell(), copy);
550 inline ArrayData* ArrayData::remove(const String& k, bool copy) {
551 assert(IsValidKey(k));
552 return remove(k.get(), copy);
555 inline ArrayData* ArrayData::remove(const Variant& k, bool copy) {
556 return remove(*k.asCell(), copy);
559 inline ArrayData* ArrayData::appendRef(Variant& v, bool copy) {
560 return appendRef(member_lval::raw(v.asTypedValue()), copy);
563 inline Variant ArrayData::getValue(ssize_t pos) const {
564 return tvAsCVarRef(rvalPos(pos).tv_ptr());
567 inline Variant ArrayData::getKey(ssize_t pos) const {
568 auto key = nvGetKey(pos);
569 return std::move(cellAsVariant(key));
572 ///////////////////////////////////////////////////////////////////////////////
574 ALWAYS_INLINE bool ArrayData::convertKey(const StringData* key,
575 int64_t& i,
576 bool notice) const {
577 auto const result = key->isStrictlyInteger(i) && useWeakKeys();
578 if (UNLIKELY(result && notice)) raise_intish_index_cast();
579 return result;
582 ///////////////////////////////////////////////////////////////////////////////
586 #endif