Make NvGetInt / NvGetStr return values
[hiphop-php.git] / hphp / runtime / base / array-data-defs.h
blob4a874ae71335a59af614362274b2ec4c30d1f59d
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/tv-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 ///////////////////////////////////////////////////////////////////////////////
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());
63 return ret;
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());
250 return ret;
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 ///////////////////////////////////////////////////////////////////////////////
276 namespace detail {
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);
313 return result;
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);
319 return result;
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());
331 return result;
334 inline TypedValue ArrayData::at(const StringData* k) const {
335 auto const result = get(k);
336 assertx(result.is_init());
337 return result;
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,
417 int64_t& i) const {
418 return IC == IntishCast::Cast &&
419 key->isStrictlyInteger(i) &&
420 useWeakKeys();
423 template <IntishCast IC>
424 ALWAYS_INLINE
425 folly::Optional<int64_t> tryIntishCast(const StringData* key) {
426 int64_t i;
427 if (UNLIKELY(IC == IntishCast::Cast &&
428 key->isStrictlyInteger(i))) {
429 return i;
431 return {};
434 ///////////////////////////////////////////////////////////////////////////////
438 #endif