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}; }
NEVER_INLINE void HashCollection::reserve(int64_t sz) { assert(m_size <= posLimit() && posLimit() <= cap()); auto cap = static_cast<int64_t>(this->cap()); if (LIKELY(sz > cap)) { if (UNLIKELY(sz > int64_t(MaxReserveSize))) { throwReserveTooLarge(); } // Fast path: The requested capacity is greater than the current capacity. // Grow to the smallest allowed capacity that is sufficient. grow(MixedArray::computeScaleFromSize(sz)); assert(canMutateBuffer()); return; } if (LIKELY(!hasTombstones())) { // Fast path: There are no tombstones and the requested capacity is less // than or equal to the current capacity. mutate(); return; } if (sz + int64_t(posLimit() - m_size) <= cap || isDensityTooLow()) { // If we reach this case, then either (1) density is too low (this is // possible because of methods like retain()), in which case we compact // to make room and return, OR (2) density is not too low and either // sz < m_size or there's enough room to add sz-m_size elements, in // which case we do nothing and return. compactOrShrinkIfDensityTooLow(); assert(sz + int64_t(posLimit() - m_size) <= cap); mutate(); return; } // If we reach this case, then density is not too low and sz > m_size and // there is not enough room to add sz-m_size elements. While would could // compact to make room, it's better for Hysteresis if we grow capacity // by 2x instead. assert(!isDensityTooLow()); assert(sz + int64_t(posLimit() - m_size) > cap); assert(cap < MaxSize && tableMask() != 0); auto newScale = scale() * 2; assert(sz > 0 && MixedArray::Capacity(newScale) >= sz); grow(newScale); assert(canMutateBuffer()); }