bool objOffsetIsset(TypedValue& tvRef, ObjectData* base, const Variant& offset, bool validate /* = true */) { auto exists = objOffsetExists(base, offset); // Unless we called ArrayObject::offsetExists, there's nothing more to do if (exists != OffsetExistsResult::IssetIfNonNull) { return (int)exists; } // For ArrayObject::offsetExists, we need to check the value at `offset`. // If it's null, then we return false. TypedValue tvResult; tvWriteUninit(&tvResult); // We can't call the offsetGet method on `base` because users aren't // expecting offsetGet to be called for `isset(...)` expressions, so call // the method on the base ArrayObject class. auto const method = SystemLib::s_ArrayObjectClass->lookupMethod(s_offsetGet.get()); assert(method != nullptr); g_context->invokeFuncFew(&tvResult, method, base, nullptr, 1, offset.asCell()); auto const result = !isNullType(tvResult.m_type); tvRefcountedDecRef(&tvResult); return result; }
bool cellSame(Cell c1, Cell c2) { assert(cellIsPlausible(c1)); assert(cellIsPlausible(c2)); bool const null1 = isNullType(c1.m_type); bool const null2 = isNullType(c2.m_type); if (null1 && null2) return true; if (null1 || null2) return false; switch (c1.m_type) { case KindOfBoolean: case KindOfInt64: if (c2.m_type != c1.m_type) return false; return c1.m_data.num == c2.m_data.num; case KindOfDouble: if (c2.m_type != c1.m_type) return false; return c1.m_data.dbl == c2.m_data.dbl; case KindOfPersistentString: case KindOfString: if (!isStringType(c2.m_type)) return false; return c1.m_data.pstr->same(c2.m_data.pstr); case KindOfPersistentArray: case KindOfArray: if (!isArrayType(c2.m_type)) return false; return c1.m_data.parr->equal(c2.m_data.parr, true); case KindOfObject: return c2.m_type == KindOfObject && c1.m_data.pobj == c2.m_data.pobj; case KindOfResource: return c2.m_type == KindOfResource && c1.m_data.pres == c2.m_data.pres; case KindOfUninit: case KindOfNull: case KindOfRef: case KindOfClass: break; } not_reached(); }
bool tvCoerceParamToNullableObjectInPlace(TypedValue* tv) { assert(tvIsPlausible(*tv)); tvUnboxIfNeeded(tv); if (isNullType(tv->m_type)) { // See comment in tvCastToNullableObjectInPlace tv->m_data.pobj = nullptr; return true; } return tv->m_type == KindOfObject; }
////////////////////////////////////////////////////////////////////////////// // class ImagickDraw ALWAYS_INLINE static void getAffineMatrixElement( const Array& array, const String& key, double& ret) { auto const value = array.rvalAt(key).unboxed(); if (isNullType(value.type())) { IMAGICKDRAW_THROW( "AffineMatrix must contain keys: sx, rx, ry, sy, tx and ty"); } else { ret = cellToDouble(value.tv()); } }
NEVER_INLINE APCHandle::Pair APCObject::ConstructSlow(ObjectData* objectData, ClassOrName name) { Array odProps; objectData->o_getArray(odProps); auto const propCount = odProps.size(); auto size = sizeof(APCObject) + sizeof(Prop) * propCount; auto const apcObj = new (malloc_huge(size)) APCObject(name, propCount); if (!propCount) return {apcObj->getHandle(), size}; auto prop = apcObj->props(); for (ArrayIter it(odProps); !it.end(); it.next(), ++prop) { Variant key(it.first()); assert(key.isString()); auto const rval = it.secondRval(); if (!isNullType(tvToCell(rval).type())) { auto val = APCHandle::Create(VarNR(rval.tv()), false, APCHandleLevel::Inner, true); prop->val = val.handle; size += val.size; } else { prop->val = nullptr; } const String& keySD = key.asCStrRef(); if (!keySD.empty() && *keySD.data() == '\0') { int32_t subLen = keySD.find('\0', 1) + 1; String cls = keySD.substr(1, subLen - 2); if (cls.size() == 1 && cls[0] == '*') { // Protected. prop->ctx = nullptr; } else { // Private. auto* ctx = Unit::lookupClass(cls.get()); if (ctx && ctx->attrs() & AttrUnique) { prop->ctx = ctx; } else { prop->ctx = makeStaticString(cls.get()); } } prop->name = makeStaticString(keySD.substr(subLen)); } else { prop->ctx = nullptr; prop->name = makeStaticString(keySD.get()); } } assert(prop == apcObj->props() + propCount); return {apcObj->getHandle(), size}; }
void tvCastToNullableObjectInPlace(TypedValue* tv) { if (isNullType(tv->m_type)) { // XXX(t3879280) This happens immediately before calling an extension // function that takes an optional Object argument. We want to end up // passing const Object& holding nullptr, so by clearing out m_data.pobj we // can unconditionally treat &tv->m_data.pobj as a const Object& in the // function being called. This violates the invariant that the value of // m_data doesn't matter in a KindOfNull TypedValue. tv->m_data.pobj = nullptr; } else { tvCastToObjectInPlace(tv); } }
bool MySQLStmtVariables::bind_params(MYSQL_STMT *stmt) { m_value_arr.clear(); for (int i = 0; i < m_arr.size(); i++) { MYSQL_BIND *b = &m_vars[i]; auto const var = m_arr.lvalAt(i).unboxed(); Variant v; if (isNullType(var.type())) { *b->is_null = 1; } else { switch (b->buffer_type) { case MYSQL_TYPE_LONGLONG: { m_value_arr.push_back(cellToInt(var.tv())); b->buffer = m_value_arr.back().getInt64Data(); } break; case MYSQL_TYPE_DOUBLE: { m_value_arr.push_back(tvCastToDouble(var.tv())); b->buffer = m_value_arr.back().getDoubleData(); } break; case MYSQL_TYPE_STRING: { m_value_arr.push_back(tvCastToString(var.tv())); StringData *sd = m_value_arr.back().getStringData(); b->buffer = (void *)sd->data(); // FIXME: setting buffer_length will cause the destructor to free // memory owned by the string *b->length = sd->size(); } break; case MYSQL_TYPE_LONG_BLOB: // The value are set using send_long_data so we don't have to do // anything here break; default: assertx(false); } } } return !mysql_stmt_bind_param(stmt, m_vars); }