typename std::enable_if< std::is_base_of<BaseSet, TSet>::value, TSet*>::type BaseSet::Clone(ObjectData* obj) { auto thiz = static_cast<TSet*>(obj); auto target = static_cast<TSet*>(TSet::instanceCtor(TSet::classof())); if (!thiz->m_size) { return target; } thiz->arrayData()->incRefCount(); target->m_size = thiz->m_size; target->m_arr = thiz->m_arr; target->setIntLikeStrKeys(thiz->intLikeStrKeys()); return target; }
typename std::enable_if< std::is_base_of<BaseMap, TMap>::value, TMap*>::type BaseMap::Clone(ObjectData* obj) { auto thiz = static_cast<TMap*>(obj); auto target = static_cast<TMap*>(obj->cloneImpl()); if (!thiz->m_size) { return target; } thiz->arrayData()->incRefCount(); target->m_size = thiz->m_size; target->m_arr = thiz->m_arr; target->setIntLikeStrKeys(thiz->intLikeStrKeys()); return target; }
// This function will create a immutable copy of this Set (if it doesn't // already exist) and then return it Object c_Set::getImmutableCopy() { if (m_immCopy.isNull()) { auto set = req::make<c_ImmSet>(); set->m_size = m_size; set->m_version = m_version; set->m_arr = m_arr; set->setIntLikeStrKeys(intLikeStrKeys()); m_immCopy = std::move(set); arrayData()->incRefCount(); } assert(!m_immCopy.isNull()); assert(data() == static_cast<c_ImmSet*>(m_immCopy.get())->data()); assert(arrayData()->hasMultipleRefs()); return m_immCopy; }
ALWAYS_INLINE typename std::enable_if< std::is_base_of<BaseMap, TMap>::value, Object>::type BaseMap::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 map = req::make<TMap>(); if (!m_size) return Object{std::move(map)}; assert(posLimit() != 0); assert(hashSize() > 0); assert(map->arrayData() == staticEmptyMixedArray()); map->m_arr = MixedArray::asMixed(MixedArray::MakeReserveMixed(cap())); map->setIntLikeStrKeys(intLikeStrKeys()); wordcpy(map->hashTab(), hashTab(), hashSize()); { uint32_t used = posLimit(); int32_t version = m_version; uint32_t i = 0; // When the loop below finishes or when an exception is thrown, // make sure that posLimit() get set to the correct value and // that m_pos gets set to point to the first element. SCOPE_EXIT { map->setPosLimit(i); map->arrayData()->m_pos = map->nthElmPos(0); }; constexpr int64_t argc = useKey ? 2 : 1; TypedValue argv[argc]; for (; i < used; ++i) { const Elm& e = data()[i]; Elm& ne = map->data()[i]; if (isTombstone(i)) { ne.data.m_type = e.data.m_type; continue; } TypedValue* tv = &ne.data; 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; g_context->invokeFuncFew(tv, ctx, argc, argv); if (UNLIKELY(version != m_version)) { tvRefcountedDecRef(tv); throw_collection_modified(); } if (e.hasStrKey()) { e.skey->incRefCount(); } ne.ikey = e.ikey; ne.data.hash() = e.data.hash(); map->incSize(); // Needed so that the new elements are accounted for when GC scanning. map->incPosLimit(); } } return Object{std::move(map)}; }