const EnumValues* EnumCache::loadEnumValues(const Class* klass, bool recurse) { auto const numConstants = klass->numConstants(); auto values = Array::CreateDArray(); auto names = Array::CreateDArray(); auto const consts = klass->constants(); bool persist = true; for (size_t i = 0; i < numConstants; i++) { if (consts[i].isAbstract() || consts[i].isType()) { continue; } if (consts[i].cls != klass && !recurse) { continue; } Cell value = consts[i].val; // Handle dynamically set constants if (value.m_type == KindOfUninit) { persist = false; value = klass->clsCnsGet(consts[i].name); } assertx(value.m_type != KindOfUninit); if (UNLIKELY(!(isIntType(value.m_type) || tvIsString(&value)))) { // only int and string values allowed for enums. std::string msg; msg += klass->name()->data(); msg += " enum can only contain string and int values"; EnumCache::failLookup(msg); } values.set(StrNR(consts[i].name), cellAsCVarRef(value)); // Manually perform int-like key coercion even if names is a dict for // backwards compatibility. int64_t n; if (tvIsString(&value) && value.m_data.pstr->isStrictlyInteger(n)) { names.set(n, make_tv<KindOfPersistentString>(consts[i].name)); } else { names.set(value, make_tv<KindOfPersistentString>(consts[i].name), true); } } assertx(names.isDictOrDArray()); assertx(values.isDictOrDArray()); // If we saw dynamic constants we cannot cache the enum values across requests // as they may not be the same in every request. return persist ? cachePersistentEnumValues( klass, recurse, std::move(names), std::move(values)) : cacheRequestEnumValues( klass, recurse, std::move(names), std::move(values)); }
void find_var_recursive(const TypedValue* tv, WddxPacket* wddxPacket) { if (tvIsString(tv)) { String var_name = tvCastToString(tv); wddxPacket->add_var(var_name, true); } if (tv->m_type == KindOfArray) { for (ArrayIter iter(tv->m_data.parr); iter; ++iter) { find_var_recursive(iter.secondRef().asTypedValue(), wddxPacket); } } }
void find_var_recursive(const TypedValue* tv, const req::ptr<WddxPacket>& wddxPacket) { if (tvIsString(tv)) { String var_name{tvCastToString(tv)}; wddxPacket->add_var(var_name, true); } if (isArrayType(tv->m_type)) { for (ArrayIter iter(tv->m_data.parr); iter; ++iter) { find_var_recursive(iter.secondRef().asTypedValue(), wddxPacket); } } }
const EnumCache::EnumValues* EnumCache::loadEnumValues(const Class* klass, bool recurse) { auto const numConstants = klass->numConstants(); size_t foundOnClass = 0; Array values; Array names; auto const consts = klass->constants(); for (size_t i = 0; i < numConstants; i++) { if (consts[i].isAbstract() || consts[i].isType()) { continue; } if (consts[i].m_class == klass) foundOnClass++; else if (!recurse) continue; Cell value = consts[i].m_val; // Handle dynamically set constants if (value.m_type == KindOfUninit) { value = klass->clsCnsGet(consts[i].m_name); } assert(value.m_type != KindOfUninit); if (UNLIKELY(!(isIntType(value.m_type) || (tvIsString(&value) && value.m_data.pstr->isStatic())))) { // only int and string values allowed for enums. Moreover the strings // must be static std::string msg; msg += klass->name()->data(); msg += " enum can only contain static string and int values"; EnumCache::failLookup(msg); } values.set(StrNR(consts[i].m_name), cellAsCVarRef(value)); names.set(cellAsCVarRef(value), VarNR(consts[i].m_name)); } if (UNLIKELY(foundOnClass == 0)) { std::string msg; msg += klass->name()->data(); msg += " enum must contain values"; EnumCache::failLookup(msg); } { std::unique_ptr<EnumCache::EnumValues> enums(new EnumCache::EnumValues()); enums->values = ArrayData::GetScalarArray(values.get()); enums->names = ArrayData::GetScalarArray(names.get()); intptr_t key = getKey(klass, recurse); EnumValuesMap::accessor acc; if (!m_enumValuesMap.insert(acc, key)) { return acc->second; } // add to the map the newly created values acc->second = enums.release(); return acc->second; } }
const EnumValues* EnumCache::loadEnumValues(const Class* klass, bool recurse) { auto const numConstants = klass->numConstants(); auto values = Array::Create(); auto names = Array::Create(); auto const consts = klass->constants(); bool persist = true; for (size_t i = 0; i < numConstants; i++) { if (consts[i].isAbstract() || consts[i].isType()) { continue; } if (consts[i].cls != klass && !recurse) { continue; } Cell value = consts[i].val; // Handle dynamically set constants if (value.m_type == KindOfUninit) { persist = false; value = klass->clsCnsGet(consts[i].name); } assert(value.m_type != KindOfUninit); if (UNLIKELY(!(isIntType(value.m_type) || (tvIsString(&value) && value.m_data.pstr->isStatic())))) { // only int and string values allowed for enums. Moreover the strings // must be static std::string msg; msg += klass->name()->data(); msg += " enum can only contain static string and int values"; EnumCache::failLookup(msg); } values.set(StrNR(consts[i].name), cellAsCVarRef(value)); names.set(value, make_tv<KindOfPersistentString>(consts[i].name)); } // If we saw dynamic constants we cannot cache the enum values across requests // as they may not be the same in every request. return persist ? cachePersistentEnumValues( klass, recurse, std::move(names), std::move(values)) : cacheRequestEnumValues( klass, recurse, std::move(names), std::move(values)); }