ArrayData* PackedArray::Dequeue(ArrayData* adIn, Variant& value) { assert(checkInvariants(adIn)); auto const ad = adIn->hasMultipleRefs() ? Copy(adIn) : adIn; // To conform to PHP behavior, we invalidate all strong iterators when an // element is removed from the beginning of the array. if (UNLIKELY(strong_iterators_exist())) { free_strong_iterators(ad); } if (UNLIKELY(ad->m_size == 0)) { value = uninit_null(); ad->m_pos = ArrayData::invalid_index; return ad; } // This is O(N), but so is Dequeue on a mixed array, because it // needs to renumber keys. So it makes sense to stay packed. auto n = ad->m_size - 1; auto const data = packedData(ad); value = std::move(tvAsVariant(data)); // no incref+decref std::memmove(data, data + 1, n * sizeof *data); ad->m_size = n; ad->m_pos = n > 0 ? 0 : ArrayData::invalid_index; return ad; }
void PackedArray::Sort(ArrayData* ad, int sort_flags, bool ascending) { assert(ad->isPacked()); if (ad->m_size <= 1) { return; } assert(!ad->hasMultipleRefs()); auto a = ad; if (UNLIKELY(strong_iterators_exist())) { free_strong_iterators(a); } SortFlavor flav = preSort(ad); a->m_pos = 0; auto data_begin = packedData(ad); auto data_end = data_begin + a->m_size; CALL_SORT(TVAccessor); }
void StructArray::Release(ArrayData* ad) { assert(ad->isRefCounted()); assert(ad->hasExactlyOneRef()); auto array = asStructArray(ad); auto const size = array->size(); auto const data = array->data(); auto const stop = data + size; for (auto ptr = data; ptr != stop; ++ptr) { tvRefcountedDecRef(ptr); } if (UNLIKELY(strong_iterators_exist())) { free_strong_iterators(ad); } auto const cap = array->capacity(); MM().objFree(array, sizeof(StructArray) + sizeof(TypedValue) * cap); }
NEVER_INLINE void PackedArray::Release(ArrayData* ad) { assert(checkInvariants(ad)); assert(ad->isRefCounted()); auto const size = ad->m_size; auto const data = packedData(ad); auto const stop = data + size; for (auto ptr = data; ptr != stop; ++ptr) { tvRefcountedDecRef(*ptr); } if (UNLIKELY(strong_iterators_exist())) { free_strong_iterators(ad); } auto const cap = ad->m_packedCap; MM().objFreeLogged(ad, sizeof(ArrayData) + sizeof(TypedValue) * cap); }
bool PackedArray::Usort(ArrayData* ad, const Variant& cmp_function) { assert(ad->isPacked()); if (ad->m_size <= 1) { return true; } assert(!ad->hasMultipleRefs()); if (UNLIKELY(strong_iterators_exist())) { free_strong_iterators(ad); } ElmUCompare<TVAccessor> comp; CallCtx ctx; CallerFrame cf; vm_decode_function(cmp_function, cf(), false, ctx); if (!ctx.func) { return false; } comp.ctx = &ctx; auto const data = packedData(ad); Sort::sort(data, data + ad->m_size, comp); return true; }
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; }