void BaseMap::addAllImpl(const Variant& iterable) { if (iterable.isNull()) return; VMRegGuard _; decltype(cap()) oldCap = 0; bool ok = IterateKV( *iterable.asTypedValue(), [&](ArrayData* adata) { auto sz = adata->size(); if (!sz) return true; if (!m_size) { if (adata->isMixed()) { replaceArray(adata); updateIntLikeStrKeys(); return true; } } else { oldCap = cap(); // assume minimal collisions } reserve(m_size + sz); mutateAndBump(); return false; }, [this](const TypedValue* key, const TypedValue* value) { setRaw(tvAsCVarRef(key), tvAsCVarRef(value)); }, [this](ObjectData* coll) { switch (coll->collectionType()) { case CollectionType::Map: case CollectionType::Set: { if (m_size) break; auto hc = static_cast<HashCollection*>(coll); replaceArray(hc->arrayData()); setIntLikeStrKeys(BaseMap::intLikeStrKeys(hc)); return true; } case CollectionType::Pair: mutateAndBump(); break; default: break; } return false; }, [this](const TypedValue* key, const TypedValue* value) { set(tvAsCVarRef(key), tvAsCVarRef(value)); }); if (UNLIKELY(!ok)) { throw_invalid_collection_parameter(); } // ... and shrink back if that was incorrect if (oldCap) shrinkIfCapacityTooHigh(oldCap); }
void HashCollection::remove(StringData* key) { mutateAndBump(); auto p = findForRemove(key, key->hash()); if (validPos(p)) { erase(p); } }
void HashCollection::remove(int64_t key) { mutateAndBump(); auto p = findForRemove(key, hash_int64(key)); if (validPos(p)) { erase(p); } }
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); }
Object BaseMap::php_retain(const Variant& callback) { CallCtx ctx; vm_decode_function(callback, nullptr, false, ctx); if (!ctx.func) { SystemLib::throwInvalidArgumentExceptionObject( "Parameter must be a valid callback"); } auto size = m_size; if (!size) { return Object{this}; } constexpr int64_t argc = useKey ? 2 : 1; TypedValue argv[argc]; for (ssize_t pos = iter_begin(); iter_valid(pos); pos = iter_next(pos)) { auto* e = iter_elm(pos); if (useKey) { if (e->hasIntKey()) { argv[0].m_type = KindOfInt64; argv[0].m_data.num = e->ikey; } else { argv[0].m_type = KindOfString; argv[0].m_data.pstr = e->skey; } } argv[argc-1] = e->data; int32_t version = m_version; bool b = invokeAndCastToBool(ctx, argc, argv); if (UNLIKELY(version != m_version)) { throw_collection_modified(); } if (b) { continue; } mutateAndBump(); version = m_version; e = iter_elm(pos); ssize_t pp = (e->hasIntKey() ? findForRemove(e->ikey) : findForRemove(e->skey, e->skey->hash())); eraseNoCompact(pp); if (UNLIKELY(version != m_version)) { throw_collection_modified(); } } assert(m_size <= size); compactOrShrinkIfDensityTooLow(); return Object{this}; }
Variant BaseSet::popFront() { if (UNLIKELY(m_size == 0)) { SystemLib::throwInvalidOperationExceptionObject("Cannot pop empty Set"); } mutateAndBump(); auto e = data(); for (;; ++e) { assert(e != elmLimit()); if (!isTombstone(e)) break; } Variant ret = tvAsCVarRef(&e->data); auto h = e->hash(); auto ei = e->hasIntKey() ? findForRemove(e->ikey, h) : findForRemove(e->skey, h); erase(ei); return ret; }
Variant BaseMap::popFront() { if (m_size) { mutateAndBump(); auto* e = data(); for (;; ++e) { assert(e != elmLimit()); if (!isTombstone(e)) break; } Variant ret = tvAsCVarRef(&e->data); ssize_t ei; if (e->hasIntKey()) { ei = findForRemove(e->ikey); } else { assert(e->hasStrKey()); ei = findForRemove(e->skey, e->skey->hash()); } erase(ei); return ret; } else { SystemLib::throwInvalidOperationExceptionObject( "Cannot pop empty Map"); } }
bool HashCollection::uksort(const Variant& cmp_function) { if (m_size <= 1) return true; mutateAndBump(); USER_SORT_BODY(AssocKeyAccessor<HashCollection::Elm>); }
void HashCollection::ksort(int sort_flags, bool ascending) { if (m_size <= 1) return; mutateAndBump(); SORT_BODY(AssocKeyAccessor<HashCollection::Elm>); }