ArrayData* StructArray::SetStr( ArrayData* ad, StringData* k, Cell v, bool copy ) { auto structArray = asStructArray(ad); auto shape = structArray->shape(); auto result = structArray; auto offset = shape->offsetFor(k); bool isNewProperty = offset == PropertyTable::kInvalidOffset; auto convertToMixedAndAdd = [&]() { auto mixed = copy ? ToMixedCopy(structArray) : ToMixed(structArray); return mixed->addValNoAsserts(k, v); }; if (isNewProperty) { StringData* staticKey; // We don't support adding non-static strings yet. if (k->isStatic()) { staticKey = k; } else { staticKey = lookupStaticString(k); if (!staticKey) return convertToMixedAndAdd(); } auto newShape = shape->transition(staticKey); if (!newShape) return convertToMixedAndAdd(); result = copy ? CopyAndResizeIfNeeded(structArray, newShape) : ResizeIfNeeded(structArray, newShape); offset = result->shape()->offsetFor(staticKey); assert(offset != PropertyTable::kInvalidOffset); TypedValue* dst = &result->data()[offset]; // TODO(#3888164): we should restructure things so we don't have to // check KindOfUninit here. if (UNLIKELY(v.m_type == KindOfUninit)) v = make_tv<KindOfNull>(); cellDup(v, *dst); return result; } if (copy) { result = asStructArray(Copy(structArray)); } assert(offset != PropertyTable::kInvalidOffset); TypedValue* dst = &result->data()[offset]; if (UNLIKELY(v.m_type == KindOfUninit)) v = make_tv<KindOfNull>(); cellSet(v, *tvToCell(dst)); return result; }
ArrayData* PackedArray::LvalNew(ArrayData* adIn, Variant*& ret, bool copy) { assert(checkInvariants(adIn)); auto const ad = copy ? CopyAndResizeIfNeeded(adIn) : ResizeIfNeeded(adIn); if (UNLIKELY(!ad)) { auto const mixed = copy ? ToMixedCopy(adIn) : ToMixed(ad); return MixedArray::LvalNew(mixed, ret, copy); } if (ad->m_pos == ArrayData::invalid_index) { ad->m_pos = ad->m_size; } auto& tv = packedData(ad)[ad->m_size++]; tv.m_type = KindOfNull; ret = &tvAsVariant(&tv); return ad; }
ArrayData* PackedArray::Append(ArrayData* adIn, const Variant& v, bool copy) { assert(checkInvariants(adIn)); auto const ad = copy ? CopyAndResizeIfNeeded(adIn) : ResizeIfNeeded(adIn); if (UNLIKELY(!ad)) { auto const mixed = copy ? ToMixedCopy(adIn) : ToMixed(adIn); return MixedArray::Append(mixed, v, copy); } if (ad->m_pos == ArrayData::invalid_index) { ad->m_pos = ad->m_size; } auto& dst = packedData(ad)[ad->m_size++]; cellDup(*v.asCell(), dst); // TODO(#3888164): restructure this so we don't need KindOfUninit checks. if (dst.m_type == KindOfUninit) dst.m_type = KindOfNull; return ad; }
ArrayData* PackedArray::AppendWithRef(ArrayData* adIn, const Variant& v, bool copy) { assert(checkInvariants(adIn)); auto const ad = copy ? CopyAndResizeIfNeeded(adIn) : ResizeIfNeeded(adIn); if (UNLIKELY(!ad)) { auto const mixed = copy ? ToMixedCopy(adIn) : ToMixed(adIn); // XXX: constness return MixedArray::AppendRef(mixed, const_cast<Variant&>(v), copy); } if (ad->m_pos == ArrayData::invalid_index) { ad->m_pos = ad->m_size; } auto& dst = packedData(ad)[ad->m_size++]; dst.m_type = KindOfNull; tvAsVariant(&dst).setWithRef(v); return ad; }
ArrayData* PackedArray::AppendRef(ArrayData* adIn, Variant& v, bool copy) { assert(checkInvariants(adIn)); auto const ad = copy ? CopyAndResizeIfNeeded(adIn) : ResizeIfNeeded(adIn); if (UNLIKELY(!ad)) { auto const mixed = copy ? ToMixedCopy(adIn) : ToMixed(adIn); return MixedArray::AppendRef(mixed, v, copy); } if (ad->m_pos == ArrayData::invalid_index) { ad->m_pos = ad->m_size; } auto& dst = packedData(ad)[ad->m_size++]; dst.m_data.pref = v.asRef()->m_data.pref; dst.m_type = KindOfRef; dst.m_data.pref->incRefCount(); return ad; }
ArrayData* StructArray::LvalStr( ArrayData* ad, StringData* property, Variant*& ret, bool copy ) { auto structArray = asStructArray(ad); auto shape = structArray->shape(); auto offset = shape->offsetFor(property); if (offset != PropertyTable::kInvalidOffset) { auto const result = asStructArray( copy ? Copy(structArray) : structArray); ret = &tvAsVariant(&result->data()[offset]); return result; } auto convertToMixedAndAdd = [&]() { auto mixed = copy ? ToMixedCopy(structArray) : ToMixed(structArray); return mixed->addLvalImpl(property, ret); }; // We don't support adding non-static strings yet. StringData* staticKey; if (property->isStatic()) { staticKey = property; } else { staticKey = lookupStaticString(property); if (!staticKey) return convertToMixedAndAdd(); } auto newShape = shape->transition(staticKey); if (!newShape) return convertToMixedAndAdd(); auto result = copy ? CopyAndResizeIfNeeded(structArray, newShape) : ResizeIfNeeded(structArray, newShape); assert(newShape->hasOffsetFor(staticKey)); offset = newShape->offsetFor(staticKey); tvWriteNull(&result->data()[offset]); ret = &tvAsVariant(&result->data()[offset]); return result; }
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; }