ArrayData *VectorArray::lval(int64 k, Variant *&ret, bool copy, bool checkExist /* = false */) { ret = inRange(k, m_size) ? &tvAsVariant(&m_elems[k]) : nullptr; if (ret == nullptr && k != m_size) { ZendArray *a = escalateToZendArray(); a->addLvalImpl(k, &ret, false); return a; } if (LIKELY(!copy)) { if (ret) return nullptr; assert(m_size == k); checkSize(); Variant& v = tvAsUninitializedVariant(&m_elems[k]); v.setUninitNull(); ret = &v; checkInsertIterator((ssize_t)k); m_size++; return nullptr; } if (checkExist && ret && (ret->isReferenced() || ret->isObject())) { return nullptr; } VectorArray *a = NEW(VectorArray)(this); if (ret) { Variant& v = tvAsVariant(&a->m_elems[k]); ret = &v; assert(ret); return a; } assert(m_size == k); a->VectorArray::lvalNew(ret, false); return a; }
ArrayData *VectorArray::prepend(CVarRef v, bool copy) { if (UNLIKELY(m_size == m_capacity)) { ZendArray *a = escalateToNonEmptyZendArray(); ArrayData *aa UNUSED = a->prepend(v, false); assert(!aa); return a; } if (UNLIKELY(copy)) { ArrayData *a = UNLIKELY(m_size >= FixedSize && Util::isPowerOfTwo(m_size)) ? // in this case, we would escalate in the capacity check anyway static_cast<ArrayData*>(escalateToNonEmptyZendArray()) : static_cast<ArrayData*>(NEW(VectorArray)(this)); ArrayData *aa UNUSED = a->prepend(v, false); assert(!aa); return a; } checkSize(); for (uint i = m_size; i > 0; i--) { // copying TV's by value, intentionally not refcounting. m_elems[i] = m_elems[i-1]; } tvAsUninitializedVariant(&m_elems[0]).constructValHelper(v); m_size++; // To match PHP-like semantics, the prepend operation resets the array's // internal iterator m_pos = (ssize_t)0; return nullptr; }
HOT_FUNC_HPHP ArrayData *VectorArray::append(CVarRef v, bool copy) { uint index = m_size; if (copy) { VectorArray *a = NEW(VectorArray)(this); a->checkSize(); tvAsUninitializedVariant(&a->m_elems[index]).constructValHelper(v); a->checkInsertIterator((ssize_t)index); a->m_size++; return a; } checkSize(); tvAsUninitializedVariant(&m_elems[index]).constructValHelper(v); checkInsertIterator((ssize_t)index); m_size++; return nullptr; }
HOT_FUNC_HPHP VectorArray::VectorArray(uint size, const Variant *values[]) { assert(size > 0); m_size = size; alloc(size); for (uint i = 0; i < size; i++) { Variant& to = tvAsUninitializedVariant(&m_elems[i]); to.constructValHelper(*values[i]); } assert(m_pos == 0); }
HOT_FUNC_HPHP ArrayData *VectorArray::append(const ArrayData *elems, ArrayOp op, bool copy) { if (UNLIKELY(!elems->isVectorArray())) { ZendArray *a = escalateToZendArray(); a->append(elems, op, false); return a; } if (UNLIKELY(copy)) { VectorArray *a = NEW(VectorArray)(this); a->VectorArray::append(elems, op, false); return a; } assert(dynamic_cast<const VectorArray *>(elems)); const VectorArray *velems = static_cast<const VectorArray *>(elems); if (op == Plus) { if (velems->m_size > m_size) { checkSize(velems->m_size - m_size); for (uint i = m_size; i < velems->m_size; i++) { Variant& to = tvAsUninitializedVariant(&m_elems[i]); CVarRef fm = tvAsCVarRef(&velems->m_elems[i]); to.constructWithRefHelper(fm, 0); } checkInsertIterator((ssize_t)m_size); m_size = velems->m_size; } } else { assert(op == Merge); if (velems->m_size > 0) { checkSize(velems->m_size); for (uint i = m_size; i < m_size + velems->m_size; i++) { Variant& to = tvAsUninitializedVariant(&m_elems[i]); CVarRef fm = tvAsCVarRef(&velems->m_elems[i - m_size]); to.constructWithRefHelper(fm, 0); } checkInsertIterator((ssize_t)m_size); m_size += velems->m_size; } } return nullptr; }
ArrayData *VectorArray::appendRef(CVarRef v, bool copy) { if (UNLIKELY(copy)) { VectorArray *a = NEW(VectorArray)(this); a->VectorArray::appendRef(v, false); return a; } uint index = m_size; checkSize(); tvAsUninitializedVariant(&m_elems[index]).constructRefHelper(v); checkInsertIterator((ssize_t)index); m_size++; return nullptr; }
ArrayData *VectorArray::lvalNew(Variant *&ret, bool copy) { if (UNLIKELY(copy)) { VectorArray *a = NEW(VectorArray)(this); a->VectorArray::lvalNew(ret, false); return a; } uint index = m_size; checkSize(); Variant& v = tvAsUninitializedVariant(&m_elems[index]); v.setUninitNull(); ret = &v; checkInsertIterator((ssize_t)index); m_size++; return nullptr; }
HOT_FUNC_HPHP VectorArray::VectorArray(const VectorArray *src, uint start /* = 0 */, uint size /* = 0 */) : ArrayData(src) { assert(src); assert(size == 0 || (size == src->m_size - 1L && size > 0)); assert(!src->strongIterators()); assert(m_pos == src->m_pos); m_size = size ? size : src->m_size; alloc(m_size); for (uint i = 0; i < m_size; i++) { Variant& to = tvAsUninitializedVariant(&m_elems[i]); CVarRef fm = tvAsCVarRef(&src->m_elems[i + start]); to.constructWithRefHelper(fm, src); } }
ArrayData *VectorArray::appendWithRef(CVarRef v, bool copy) { if (UNLIKELY(copy)) { VectorArray *a = NEW(VectorArray)(this); a->VectorArray::appendWithRef(v, false); return a; } uint index = m_size; checkSize(); Variant& to = tvAsUninitializedVariant(&m_elems[index]); to.setUninitNull(); to.setWithRef(v); checkInsertIterator((ssize_t)index); m_size++; return NULL; }
ArrayData *VectorArray::addLval(int64 k, Variant *&ret, bool copy) { assert(!exists(k)); if (k != m_size) { ZendArray *a = escalateToZendArray(); a->addLval(k, ret, false); return a; } uint index = m_size; if (UNLIKELY(copy)) { VectorArray *a = NEW(VectorArray)(this); a->VectorArray::addLval(k, ret, false); return a; } checkSize(); Variant& v = tvAsUninitializedVariant(&m_elems[index]); v.setUninitNull(); ret = &v; checkInsertIterator((ssize_t)index); m_size++; return nullptr; }
ArrayData* PackedArray::Prepend(ArrayData* adIn, const Variant& v, bool copy) { assert(checkInvariants(adIn)); auto const ad = adIn->hasMultipleRefs() ? CopyAndResizeIfNeeded(adIn) : ResizeIfNeeded(adIn); // To conform to PHP behavior, we invalidate all strong iterators when an // element is added to the beginning of the array. if (UNLIKELY(strong_iterators_exist())) { free_strong_iterators(ad); } auto const size = ad->m_size; auto const data = packedData(ad); std::memmove(data + 1, data, sizeof *data * size); // TODO(#3888164): constructValHelper is making KindOfUninit checks. tvAsUninitializedVariant(&data[0]).constructValHelper(v); ad->m_size = size + 1; ad->m_pos = 0; return ad; }
ArrayData *VectorArray::setRef(int64 k, CVarRef v, bool copy) { if (UNLIKELY(copy)) { if (inRange(k, m_size) || k == m_size) { VectorArray *a = NEW(VectorArray)(this); a->VectorArray::setRef(k, v, false); return a; } } else { if (inRange(k, m_size)) { tvAsVariant(&m_elems[k]).assignRef(v); return nullptr; } else if (k == m_size) { checkSize(); tvAsUninitializedVariant(&m_elems[k]).constructRefHelper(v); checkInsertIterator((ssize_t)k); m_size++; return nullptr; } } ZendArray *a = escalateToZendArray(); a->updateRef(k, v); return a; }
// This constructor is for nonSmartCopy() VectorArray::VectorArray(const VectorArray *src, bool sma /* ignored */) : ArrayData(src, kArrayData, /*nonsmart*/true) { assert(src); assert(!src->strongIterators()); m_size = src->m_size; if (m_size <= FixedSize) { m_capacity = FixedSize; m_elems = m_fixed; m_allocMode = kInline; } else { m_capacity = Util::nextPower2(m_size); m_elems = (TypedValue*) malloc(m_capacity * sizeof(TypedValue)); m_allocMode = kMalloc; } for (uint i = 0, n = m_size; i < n; i++) { assert(src->m_elems[i].m_type != KindOfRef && src->m_elems[i].m_type != KindOfObject); Variant& to = tvAsUninitializedVariant(&m_elems[i]); CVarRef fm = tvAsCVarRef(&src->m_elems[i]); to.constructWithRefHelper(fm, src); } assert(src->m_pos == 0 && m_pos == 0); }