ArrayData* ArrayCommon::ToKeyset(ArrayData* a, bool) { auto const size = a->size(); if (!size) return staticEmptyKeysetArray(); KeysetInit init{size}; IterateV( a, [&](const TypedValue* v) { if (UNLIKELY(v->m_type == KindOfRef)) { if (v->m_data.pref->isReferenced()) { throwRefInvalidArrayValueException(init.toArray()); } v = v->m_data.pref->tv(); assertx(v->m_type != KindOfRef); } if (LIKELY(isStringType(v->m_type))) { init.add(v->m_data.pstr); } else if (LIKELY(isIntType(v->m_type))) { init.add(v->m_data.num); } else { throwInvalidArrayKeyException(v, init.toArray().get()); } } ); return init.create(); }
ArrayData* ArrayCommon::ToVec(ArrayData* a, bool) { auto const size = a->size(); if (!size) return staticEmptyVecArray(); VecArrayInit init{size}; IterateV( a, [&](const TypedValue* v) { if (UNLIKELY(v->m_type == KindOfRef)) { if (v->m_data.pref->isReferenced()) { throwRefInvalidArrayValueException(init.toArray()); } } init.append(tvAsCVarRef(v)); } ); return init.create(); }
ArrayCommon::RefCheckResult ArrayCommon::CheckForRefs(const ArrayData* ad) { auto result = RefCheckResult::Pass; IterateV( ad, [&](const TypedValue* v) { if (UNLIKELY(v->m_type == KindOfRef)) { auto const ref = v->m_data.pref; if (ref->isReferenced() || ref->tv()->m_data.parr == ad) { result = RefCheckResult::Fail; return true; } result = RefCheckResult::Collapse; } return false; } ); return result; }
void BaseSet::addAll(const Variant& t) { if (t.isNull()) { return; } // nothing to do decltype(cap()) oldCap = 0; bool ok = IterateV( *t.asTypedValue(), [&](ArrayData* adata) { auto sz = adata->size(); if (!sz) return true; if (m_size) { oldCap = cap(); // assume minimal collisions } reserve(m_size + sz); mutateAndBump(); return false; }, [this](const TypedValue* value) { addRaw(tvAsCVarRef(value)); }, [this](ObjectData* coll) { if (!m_size && coll->collectionType() == CollectionType::Set) { auto hc = static_cast<HashCollection*>(coll); replaceArray(hc->arrayData()); setIntLikeStrKeys(BaseSet::intLikeStrKeys(hc)); return true; } if (coll->collectionType() == CollectionType::Pair) { mutateAndBump(); } return false; }, [this](const TypedValue* value) { add(tvAsCVarRef(value)); }); if (UNLIKELY(!ok)) { throw_invalid_collection_parameter(); } // ... and shrink back if that was incorrect if (oldCap) shrinkIfCapacityTooHigh(oldCap); }