static int collator_numeric_compare_function(CVarRef v1, CVarRef v2, const void *data, bool ascending) { Variant num1; Variant num2; if (v1.isString()) { num1 = collator_convert_string_to_double(v1); } else { num1 = v1.toDouble(); } if (v2.isString()) { num2 = collator_convert_string_to_double(v2); } else { num2 = v2.toDouble(); } if (ascending) { if (num1.less(num2)) return -1; if (num1.equal(num2)) return 0; return 1; } if (num1.less(num2)) return 1; if (num1.equal(num2)) return 0; return -1; }
int Array::SortNumericDescending(CVarRef v1, CVarRef v2, const void *data) { double d1 = v1.toDouble(); double d2 = v2.toDouble(); if (d1 < d2) return 1; if (d1 == d2) return 0; return -1; }
double VariantToMilliseconds(CVarRef arg) { if (arg.isNumeric(true)) { return U_MILLIS_PER_SECOND * arg.toDouble(); } // TODO: Handle object IntlCalendar and DateTime return NAN; }
static bool HHVM_METHOD(IntlCalendar, setTime, CVarRef date) { CAL_FETCH(data, this_, false); UErrorCode error = U_ZERO_ERROR; data->calendar()->setTime((UDate)date.toDouble(), error); if (U_FAILURE(error)) { data->setError(error, "Call to underlying method failed"); return false; } return true; }
Variant f_range(CVarRef low, CVarRef high, CVarRef step /* = 1 */) { bool is_step_double = false; double dstep = 1.0; if (step.isDouble()) { dstep = step.toDouble(); is_step_double = true; } else if (step.isString()) { int64_t sn; double sd; DataType stype = step.toString()->isNumericWithVal(sn, sd, 0); if (stype == KindOfDouble) { is_step_double = true; dstep = sd; } else if (stype == KindOfInt64) { dstep = (double)sn; } else { dstep = step.toDouble(); } } else { dstep = step.toDouble(); } /* We only want positive step values. */ if (dstep < 0.0) dstep *= -1; if (low.isString() && high.isString()) { String slow = low.toString(); String shigh = high.toString(); if (slow.size() >= 1 && shigh.size() >=1) { int64_t n1, n2; double d1, d2; DataType type1 = slow->isNumericWithVal(n1, d1, 0); DataType type2 = shigh->isNumericWithVal(n2, d2, 0); if (type1 == KindOfDouble || type2 == KindOfDouble || is_step_double) { if (type1 != KindOfDouble) d1 = slow.toDouble(); if (type2 != KindOfDouble) d2 = shigh.toDouble(); return ArrayUtil::Range(d1, d2, dstep); } int64_t lstep = (int64_t) dstep; if (type1 == KindOfInt64 || type2 == KindOfInt64) { if (type1 != KindOfInt64) n1 = slow.toInt64(); if (type2 != KindOfInt64) n2 = shigh.toInt64(); return ArrayUtil::Range((double)n1, (double)n2, lstep); } return ArrayUtil::Range((unsigned char)slow.charAt(0), (unsigned char)shigh.charAt(0), lstep); } } if (low.is(KindOfDouble) || high.is(KindOfDouble) || is_step_double) { return ArrayUtil::Range(low.toDouble(), high.toDouble(), dstep); } int64_t lstep = (int64_t) dstep; return ArrayUtil::Range(low.toDouble(), high.toDouble(), lstep); }
static bool HHVM_METHOD(IntlCalendar, isWeekend, CVarRef date) { CAL_FETCH(data, this_, false); if (date.isNull()) { return data->calendar()->isWeekend(); } UErrorCode error = U_ZERO_ERROR; bool ret = data->calendar()->isWeekend((UDate)date.toDouble(), error); if (U_FAILURE(error)) { data->setError(error, "intlcal_is_weekend: Error calling ICU method"); return false; } return ret; }
static Variant HHVM_METHOD(IntlCalendar, fieldDifference, CVarRef when, int64_t field) { CAL_FETCH(data, this_, false); CAL_CHECK_FIELD(field, "intlcal_field_difference"); UErrorCode error = U_ZERO_ERROR; int64_t ret = data->calendar()->fieldDifference( (UDate)when.toDouble(), (UCalendarDateFields)field, error); if (U_FAILURE(error)) { data->setError(error, "intlcal_field_difference: " "Call to ICU method has failed"); return false; } return ret; }
Numeric f_pow(CVarRef base, CVarRef exp) { int64_t bint, eint; double bdbl, edbl; DataType bt = base.toNumeric(bint, bdbl, true); DataType et = exp.toNumeric(eint, edbl, true); if (bt == KindOfInt64 && et == KindOfInt64 && eint >= 0) { if (eint == 0) return 1LL; if (bint == 0) return 0LL; // calculate pow(long,long) in O(log exp) operations, bail if overflow int64_t l1 = 1; while (eint >= 1) { int overflow; double dval = 0.0; if (eint % 2) { --eint; ZEND_SIGNED_MULTIPLY_LONG(l1, bint, l1, dval, overflow); if (overflow) return dval * pow(bint, eint); } else { eint /= 2; ZEND_SIGNED_MULTIPLY_LONG(bint, bint, bint, dval, overflow); if (overflow) return (double)l1 * pow(dval, eint); } if (eint == 0) { return l1; } } } if (bt != KindOfDouble) { bdbl = base.toDouble(); } if (et != KindOfDouble) { edbl = exp.toDouble(); } return pow(bdbl, edbl); }
double f_round(CVarRef val, int64 precision /* = 0 */) { int64 ival; double dval; DataType k = val.toNumeric(ival, dval, true); if (k == KindOfInt64) { if (precision >= 0) { return ival; } else { dval = ival; } } else if (k != KindOfDouble) { dval = val.toDouble(); } PHP_ROUND_WITH_FUZZ(dval, precision); return dval; }
double f_round(CVarRef val, int64_t precision /* = 0 */, int64_t mode /* = PHP_ROUND_HALF_UP */) { int64_t ival; double dval; DataType k = val.toNumeric(ival, dval, true); if (k == KindOfInt64) { if (precision >= 0) { return ival; } else { dval = ival; } } else if (k != KindOfDouble) { dval = val.toDouble(); } dval = php_math_round(dval, precision, mode); return dval; }
int hphp_ffi_exportVariant(CVarRef v, void** result) { switch (v.getType()) { case KindOfNull: return 0; case KindOfBoolean: *result = (void*)v.toBoolean(); return 1; case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: { *result = (void*)v.toInt64(); return 2; } case KindOfDouble: { union { double d; void* p; } u; u.d = v.toDouble(); *result = u.p; return 3; } case LiteralString: *result = (void*)v.getLiteralString(); return 4; case KindOfString: { StringData *sd = v.getStringData(); sd->incRefCount(); *result = (void*)sd; return 5; } case KindOfArray: { ArrayData *ad = v.getArrayData(); ad->incRefCount(); *result = (void*)ad; return 6; } case KindOfObject: { ObjectData *od = v.getObjectData(); od->incRefCount(); *result = (void*)od; return 7; } default: ASSERT(false); return 0; } }
ThreadSharedVariant::ThreadSharedVariant(CVarRef source, bool serialized, bool inner /* = false */) { ASSERT(!serialized || source.isString()); setOwner(); m_ref = 1; switch (source.getType()) { case KindOfBoolean: { m_type = KindOfBoolean; m_data.num = source.toBoolean(); break; } case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: { m_type = KindOfInt64; m_data.num = source.toInt64(); break; } case KindOfDouble: { m_type = KindOfDouble; m_data.dbl = source.toDouble(); break; } case KindOfStaticString: case KindOfString: { String s = source.toString(); m_type = serialized ? KindOfObject : KindOfString; if (serialized) { // It is priming, and there might not be the right class definitions // for unserialization. s = apc_reserialize(s); } m_data.str = s->copy(true); break; } case KindOfArray: { m_type = KindOfArray; ArrayData *arr = source.getArrayData(); if (!inner) { // only need to call hasInternalReference() on the toplevel array PointerSet seen; if (arr->hasInternalReference(seen)) { setSerializedArray(); setShouldCache(); String s = apc_serialize(source); m_data.str = new StringData(s.data(), s.size(), CopyString); break; } } size_t size = arr->size(); if (arr->isVectorData()) { setIsVector(); m_data.vec = new VectorData(size); uint i = 0; for (ArrayIter it(arr); !it.end(); it.next(), i++) { ThreadSharedVariant* val = createAnother(it.second(), false, true); if (val->shouldCache()) setShouldCache(); m_data.vec->vals[i] = val; } } else { m_data.map = new ImmutableMap(size); uint i = 0; for (ArrayIter it(arr); !it.end(); it.next(), i++) { ThreadSharedVariant* key = createAnother(it.first(), false); ThreadSharedVariant* val = createAnother(it.second(), false, true); if (val->shouldCache()) setShouldCache(); m_data.map->add(key, val); } } break; } default: { m_type = KindOfObject; setShouldCache(); String s = apc_serialize(source); m_data.str = new StringData(s.data(), s.size(), CopyString); break; } } }
SharedVariant::SharedVariant(CVarRef source, bool serialized, bool inner /* = false */, bool unserializeObj /* = false */) : m_count (1), m_shouldCache(false), m_flags(0){ ASSERT(!serialized || source.isString()); m_type = source.getType(); switch (m_type) { case KindOfBoolean: { m_data.num = source.toBoolean(); break; } case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: { m_type = KindOfInt64; m_data.num = source.toInt64(); break; } case KindOfDouble: { m_data.dbl = source.toDouble(); break; } case KindOfStaticString: case KindOfString: { String s = source.toString(); if (serialized) { m_type = KindOfObject; // It is priming, and there might not be the right class definitions // for unserialization. s = apc_reserialize(s); } m_data.str = s->copy(true); break; } case KindOfArray: { ArrayData *arr = source.getArrayData(); if (!inner) { // only need to call hasInternalReference() on the toplevel array PointerSet seen; if (arr->hasInternalReference(seen)) { setSerializedArray(); m_shouldCache = true; String s = apc_serialize(source); m_data.str = new StringData(s.data(), s.size(), CopyString); break; } } size_t size = arr->size(); if (arr->isVectorData()) { setIsVector(); m_data.vec = new VectorData(size); uint i = 0; for (ArrayIter it(arr); !it.end(); it.next(), i++) { SharedVariant* val = Create(it.secondRef(), false, true, unserializeObj); if (val->m_shouldCache) m_shouldCache = true; m_data.vec->vals[i] = val; } } else { m_data.map = new ImmutableMap(size); for (ArrayIter it(arr); !it.end(); it.next()) { SharedVariant* key = Create(it.first(), false, true, unserializeObj); SharedVariant* val = Create(it.secondRef(), false, true, unserializeObj); if (val->m_shouldCache) m_shouldCache = true; m_data.map->add(key, val); } } break; } case KindOfNull: { m_data.num = 0; break; } default: { ASSERT(source.isObject()); m_shouldCache = true; if (unserializeObj) { // This assumes hasInternalReference(seen, true) is false ImmutableObj* obj = new ImmutableObj(source.getObjectData()); m_data.obj = obj; setIsObj(); } else { String s = apc_serialize(source); m_data.str = new StringData(s.data(), s.size(), CopyString); } break; } } }
double f_floatval(CVarRef v) { return v.toDouble();}
double f_doubleval(CVarRef v) { return v.toDouble();}
void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport, CVarRef value, CArrRef fieldspec) { // At this point the typeID (and field num, if applicable) should've already // been written to the output so all we need to do is write the payload. switch (thrift_typeID) { case T_STOP: case T_VOID: return; case T_STRUCT: { if (!value.is(KindOfObject)) { throw_tprotocolexception("Attempt to send non-object " "type as a T_STRUCT", INVALID_DATA); } binary_serialize_spec(value.toObject(), transport, f_hphp_get_static_property(value.toObject()-> o_getClassName(), s_TSPEC, false).toArray()); } return; case T_BOOL: transport.writeI8(value.toBoolean() ? 1 : 0); return; case T_BYTE: transport.writeI8(value.toByte()); return; case T_I16: transport.writeI16(value.toInt16()); return; case T_I32: transport.writeI32(value.toInt32()); return; case T_I64: case T_U64: transport.writeI64(value.toInt64()); return; case T_DOUBLE: { union { int64_t c; double d; } a; a.d = value.toDouble(); transport.writeI64(a.c); } return; case T_FLOAT: { union { int32_t c; float d; } a; a.d = (float)value.toDouble(); transport.writeI32(a.c); } return; //case T_UTF7: case T_UTF8: case T_UTF16: case T_STRING: { String sv = value.toString(); transport.writeString(sv.data(), sv.size()); } return; case T_MAP: { Array ht = value.toArray(); uint8_t keytype = fieldspec.rvalAt(PHPTransport::s_ktype, AccessFlags::Error_Key).toByte(); transport.writeI8(keytype); uint8_t valtype = fieldspec.rvalAt(PHPTransport::s_vtype, AccessFlags::Error_Key).toByte(); transport.writeI8(valtype); Array valspec = fieldspec.rvalAt(PHPTransport::s_val, AccessFlags::Error_Key).toArray(); transport.writeI32(ht.size()); for (ArrayIter key_ptr = ht.begin(); !key_ptr.end(); ++key_ptr) { binary_serialize_hashtable_key(keytype, transport, key_ptr.first()); binary_serialize(valtype, transport, key_ptr.second(), valspec); } } return; case T_LIST: { Array ht = value.toArray(); Variant val; uint8_t valtype = fieldspec.rvalAt(PHPTransport::s_etype, AccessFlags::Error_Key).toInt64(); transport.writeI8(valtype); Array valspec = fieldspec.rvalAt(PHPTransport::s_elem, AccessFlags::Error_Key).toArray(); transport.writeI32(ht.size()); for (ArrayIter key_ptr = ht.begin(); !key_ptr.end(); ++key_ptr) { binary_serialize(valtype, transport, key_ptr.second(), valspec); } } return; case T_SET: { Array ht = value.toArray(); uint8_t keytype = fieldspec.rvalAt(PHPTransport::s_etype, AccessFlags::Error_Key).toByte(); transport.writeI8(keytype); transport.writeI32(ht.size()); for (ArrayIter key_ptr = ht.begin(); !key_ptr.end(); ++key_ptr) { binary_serialize_hashtable_key(keytype, transport, key_ptr.first()); } } return; }; char errbuf[128]; sprintf(errbuf, "Unknown thrift typeID %d", thrift_typeID); throw_tprotocolexception(String(errbuf, CopyString), INVALID_DATA); }
ProcessSharedVariant::ProcessSharedVariant(CVarRef source, ProcessSharedVariantLock* lock) : m_lock(putPtr(lock)) { switch (source.getType()) { case KindOfBoolean: { m_type = KindOfBoolean; m_data.num = source.toBoolean(); break; } case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: { m_type = KindOfInt64; m_data.num = source.toInt64(); break; } case KindOfDouble: { m_type = KindOfDouble; m_data.dbl = source.toDouble(); break; } case LiteralString: case KindOfStaticString: case KindOfString: { String s = source.toString(); m_type = KindOfString; if (lock) { m_data.str = putPtr(SharedMemoryManager::GetSegment() ->construct<SharedMemoryString> (boost::interprocess::anonymous_instance) (s.data(), s.size())); } else { // Just need this string to live long enough for the key lookup so // don't store in shared memory. m_data.str = putPtr(new SharedMemoryString(s.data(), s.size())); } break; } case KindOfArray: { ASSERT(lock); m_type = KindOfArray; uint i = 0; ProcessSharedVariantMapData* mapData = SharedMemoryManager::GetSegment() ->construct<ProcessSharedVariantMapData> (boost::interprocess::anonymous_instance)(); m_data.map = putPtr(mapData); ProcessSharedVariantToIntMap* map = SharedMemoryManager::GetSegment() ->construct<ProcessSharedVariantToIntMap> (boost::interprocess::anonymous_instance)(); mapData->map = putPtr(map); SharedMemoryVector<SharedVariant*>* keys = SharedMemoryManager::GetSegment() ->construct<SharedMemoryVector<SharedVariant*> > (boost::interprocess::anonymous_instance)(); mapData->keys = putPtr(keys); SharedMemoryVector<SharedVariant*>* vals = SharedMemoryManager::GetSegment() ->construct<SharedMemoryVector<SharedVariant*> > (boost::interprocess::anonymous_instance)(); mapData->vals = putPtr(vals); for (ArrayIterPtr it = source.begin(); !it->end(); it->next()) { ProcessSharedVariant* key = SharedMemoryManager::GetSegment() ->construct<ProcessSharedVariant> (boost::interprocess::anonymous_instance) (it->first(), getLock()); ProcessSharedVariant* val = SharedMemoryManager::GetSegment() ->construct<ProcessSharedVariant> (boost::interprocess::anonymous_instance) (it->second(), getLock()); (*map)[key] = i++; keys->push_back(putPtr(key)); vals->push_back(putPtr(val)); } break; } default: { m_type = KindOfObject; String s = f_serialize(source); m_data.str = putPtr(SharedMemoryManager::GetSegment() ->construct<SharedMemoryString> (boost::interprocess::anonymous_instance) (s.data(), s.size())); break; } } }
SharedVariant::SharedVariant(CVarRef source, bool serialized, bool inner /* = false */, bool unserializeObj /* = false */) : m_shouldCache(false), m_flags(0) { assert(!serialized || source.isString()); m_count = 1; m_type = source.getType(); switch (m_type) { case KindOfBoolean: { m_data.num = source.toBoolean(); break; } case KindOfInt64: { m_type = KindOfInt64; m_data.num = source.toInt64(); break; } case KindOfDouble: { m_data.dbl = source.toDouble(); break; } case KindOfStaticString: { if (serialized) goto StringCase; m_data.str = source.getStringData(); break; } StringCase: case KindOfString: { String s = source.toString(); if (serialized) { m_type = KindOfObject; // It is priming, and there might not be the right class definitions // for unserialization. s = apc_reserialize(s); } StringData* st = StringData::LookupStaticString(s.get()); if (st) { m_data.str = st; m_type = KindOfStaticString; break; } m_data.str = s->copy(true); break; } case KindOfArray: { ArrayData *arr = source.getArrayData(); if (!inner) { // only need to call hasInternalReference() on the toplevel array PointerSet seen; if (arr->hasInternalReference(seen)) { setSerializedArray(); m_shouldCache = true; String s = apc_serialize(source); m_data.str = StringData::MakeMalloced(s.data(), s.size()); break; } } if (arr->isVectorData()) { setIsVector(); m_data.vec = new (arr->size()) VectorData(); for (ArrayIter it(arr); !it.end(); it.next()) { SharedVariant* val = Create(it.secondRef(), false, true, unserializeObj); if (val->m_shouldCache) m_shouldCache = true; m_data.vec->vals()[m_data.vec->m_size++] = val; } } else { m_data.map = ImmutableMap::Create(arr, unserializeObj, m_shouldCache); } break; } case KindOfUninit: case KindOfNull: { break; } case KindOfResource: { // TODO Task #2661075: Here and elsewhere in the runtime, we convert // Resources to the empty array during various serialization operations, // which does not match Zend behavior. We should fix this. m_type = KindOfArray; setIsVector(); m_data.vec = new (0) VectorData(); break; } default: { assert(source.isObject()); m_shouldCache = true; if (unserializeObj) { // This assumes hasInternalReference(seen, true) is false ImmutableObj* obj = new ImmutableObj(source.getObjectData()); m_data.obj = obj; setIsObj(); } else { String s = apc_serialize(source); m_data.str = StringData::MakeMalloced(s.data(), s.size()); } break; } } assert(m_type != KindOfResource); }