ALWAYS_INLINE typename std::enable_if< std::is_base_of<BaseMap, TMap>::value, Object>::type BaseMap::php_takeWhile(const Variant& fn) { CallCtx ctx; vm_decode_function(fn, nullptr, false, ctx); if (!ctx.func) { SystemLib::throwInvalidArgumentExceptionObject( "Parameter must be a valid callback"); } auto map = req::make<TMap>(); if (!m_size) return Object{std::move(map)}; int32_t version UNUSED; if (std::is_same<c_Map, TMap>::value) { version = m_version; } for (ssize_t pos = iter_begin(); iter_valid(pos); pos = iter_next(pos)) { auto* e = iter_elm(pos); bool b = invokeAndCastToBool(ctx, 1, &e->data); if (std::is_same<c_Map, TMap>::value) { if (UNLIKELY(version != m_version)) { throw_collection_modified(); } } if (!b) break; e = iter_elm(pos); if (e->hasIntKey()) { map->set(e->ikey, &e->data); } else { assert(e->hasStrKey()); map->set(e->skey, &e->data); } } return Object{std::move(map)}; }
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}; }
ALWAYS_INLINE typename std::enable_if< std::is_base_of<BaseMap, TMap>::value, Object>::type BaseMap::php_filter(const Variant& callback) const { VMRegGuard _; CallCtx ctx; vm_decode_function(callback, nullptr, false, ctx); if (!ctx.func) { SystemLib::throwInvalidArgumentExceptionObject( "Parameter must be a valid callback"); } auto map = req::make<TMap>(); if (!m_size) return Object(std::move(map)); map->mutate(); int32_t version = m_version; 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; bool b = invokeAndCastToBool(ctx, argc, argv); if (UNLIKELY(version != m_version)) { throw_collection_modified(); } if (!b) continue; e = iter_elm(pos); if (e->hasIntKey()) { map->set(e->ikey, &e->data); } else { assert(e->hasStrKey()); map->set(e->skey, &e->data); } } return Object(std::move(map)); }
typename std::enable_if< std::is_base_of<BaseSet, TSet>::value, Object>::type BaseSet::php_filter(const Variant& callback) const { VMRegGuard _; CallCtx ctx; vm_decode_function(callback, nullptr, false, ctx); if (!ctx.func) { SystemLib::throwInvalidArgumentExceptionObject( "Parameter must be a valid callback"); } auto set = req::make<TSet>(); if (!m_size) return Object(std::move(set)); // we don't reserve(), because we don't know how selective callback will be set->mutate(); int32_t version = m_version; 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) { argv[0] = e->data; } argv[argc-1] = e->data; bool b = invokeAndCastToBool(ctx, argc, argv); if (UNLIKELY(version != m_version)) { throw_collection_modified(); } if (!b) continue; e = iter_elm(pos); if (e->hasIntKey()) { set->addRaw(e->data.m_data.num); } else { assert(e->hasStrKey()); set->addRaw(e->data.m_data.pstr); } } return Object(std::move(set)); }
typename std::enable_if< std::is_base_of<BaseSet, TSet>::value, Object>::type BaseSet::php_map(const Variant& callback) const { VMRegGuard _; CallCtx ctx; vm_decode_function(callback, nullptr, false, ctx); if (!ctx.func) { SystemLib::throwInvalidArgumentExceptionObject( "Parameter must be a valid callback"); } auto set = req::make<TSet>(); if (!m_size) return Object{std::move(set)}; assert(posLimit() != 0); assert(hashSize() > 0); assert(set->arrayData() == staticEmptyMixedArray()); auto oldCap = set->cap(); set->reserve(posLimit()); // presume minimum collisions ... assert(set->canMutateBuffer()); 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); TypedValue tvCbRet; int32_t pVer = m_version; if (useKey) { argv[0] = e->data; } argv[argc-1] = e->data; g_context->invokeFuncFew(&tvCbRet, ctx, argc, argv); // Now that tvCbRet is live, make sure to decref even if we throw. SCOPE_EXIT { tvRefcountedDecRef(&tvCbRet); }; if (UNLIKELY(m_version != pVer)) throw_collection_modified(); set->addRaw(&tvCbRet); } // ... and shrink back if that was incorrect set->shrinkIfCapacityTooHigh(oldCap); return Object{std::move(set)}; }