Remove less, more, and equal functions from Variant

Re-implement them in terms of TypedValue and Cell helpers.
Esse commit está contido em:
Jordan DeLong
2013-06-08 14:11:11 -07:00
commit de sgolemon
commit d145ce88e3
22 arquivos alterados com 806 adições e 158 exclusões
@@ -178,9 +178,6 @@ ExpressionPtr BinaryOpExpression::unneededHelper() {
return static_pointer_cast<Expression>(shared_from_this());
}
///////////////////////////////////////////////////////////////////////////////
// parser functions
///////////////////////////////////////////////////////////////////////////////
// static analysis functions
@@ -193,7 +190,7 @@ int BinaryOpExpression::getLocalEffects() const {
case T_DIV_EQUAL:
case T_MOD_EQUAL: {
Variant v2;
if (!m_exp2->getScalarValue(v2) || v2.equal(0)) {
if (!m_exp2->getScalarValue(v2) || equal(v2, 0)) {
effect = CanThrow;
m_canThrow = true;
}
+6 -3
Ver Arquivo
@@ -156,8 +156,8 @@ int ArrayData::compare(const ArrayData *v2) const {
if (!v2->exists(key)) return 1;
auto value1 = iter.second();
auto value2 = v2->get(key);
if (value1.more(value2)) return 1;
if (value1.less(value2)) return -1;
if (HPHP::more(value1, value2)) return 1;
if (HPHP::less(value1, value2)) return -1;
}
return 0;
@@ -184,7 +184,10 @@ bool ArrayData::equal(const ArrayData *v2, bool strict) const {
for (ArrayIter iter(this); iter; ++iter) {
Variant key(iter.first());
if (!v2->exists(key)) return false;
if (!iter.second().equal(v2->get(key))) return false;
if (!tvEqual(iter.second().asTypedValue(),
v2->get(key).asTypedValue())) {
return false;
}
}
}
+1 -1
Ver Arquivo
@@ -673,7 +673,7 @@ Variant ArrayUtil::RegularSortUnique(CArrRef input) {
for (unsigned int i = 1; i < indices.size(); ++i) {
int currentIdx = indices[i];
Variant current = input->getValue(opaque.positions[currentIdx]);
if (current.equal(last)) {
if (equal(current, last)) {
if (currentIdx > lastIdx) {
duplicates[currentIdx] = true;
continue;
+1
Ver Arquivo
@@ -473,6 +473,7 @@ void throw_collection_compare_exception() {
raise_warning(msg);
}
// TODO
void check_collection_compare(ObjectData* obj) {
if (obj && obj->isCollection()) throw_collection_compare_exception();
}
+85 -30
Ver Arquivo
@@ -39,16 +39,29 @@ inline bool same(CVarRef v1, CVarRef v2) {
return tvSame(v1.asTypedValue(), v2.asTypedValue());
}
inline bool equal(CVarRef v1, bool v2) { return v1.equal(v2);}
inline bool equal(CVarRef v1, int v2) { return v1.equal(v2);}
inline bool equal(CVarRef v1, int64_t v2) { return v1.equal(v2);}
inline bool equal(CVarRef v1, double v2) { return v1.equal(v2);}
inline bool equal(CVarRef v1, const StringData *v2) { return v1.equal(v2);}
inline bool equal(CVarRef v1, CStrRef v2) { return v1.equal(v2);}
inline bool equal(CVarRef v1, litstr v2) { return v1.equal(v2);}
inline bool equal(CVarRef v1, CArrRef v2) { return v1.equal(v2);}
inline bool equal(CVarRef v1, CObjRef v2) { return v1.equal(v2);}
inline bool equal(CVarRef v1, CVarRef v2) { return v1.equal(v2);}
inline bool equal(CVarRef v1, bool v2) { return cellEqual(v1.asCell(), v2); }
inline bool equal(CVarRef v1, int v2) { return cellEqual(v1.asCell(), v2); }
inline bool equal(CVarRef v1, int64_t v2) { return cellEqual(v1.asCell(), v2);}
inline bool equal(CVarRef v1, double v2) { return cellEqual(v1.asCell(), v2);}
inline bool equal(CVarRef v1, const StringData* v2) {
return cellEqual(v1.asCell(), v2);
}
inline bool equal(CVarRef v1, CStrRef v2) {
if (!v2.get()) return cellEqual(v1.asCell(), false);
return cellEqual(v1.asCell(), v2.get());
}
inline bool equal(CVarRef v1, litstr v2) = delete;
inline bool equal(CVarRef v1, CArrRef v2) {
if (!v2.get()) return cellEqual(v1.asCell(), false);
return cellEqual(v1.asCell(), v2.get());
}
inline bool equal(CVarRef v1, CObjRef v2) {
if (!v2.get()) return cellEqual(v1.asCell(), false);
return cellEqual(v1.asCell(), v2.get());
}
inline bool equal(CVarRef v1, CVarRef v2) {
return tvEqual(v1.asTypedValue(), v2.asTypedValue());
}
inline bool equalAsStr(CVarRef v1, bool v2) { return v1.equalAsStr(v2);}
inline bool equalAsStr(CVarRef v1, int v2) { return v1.equalAsStr(v2);}
@@ -64,27 +77,69 @@ inline bool equalAsStr(CVarRef v1, CObjRef v2) { return v1.equalAsStr(v2);}
inline bool equalAsStr(CVarRef v1, CVarRef v2) { return v1.equalAsStr(v2);}
inline bool less(CVarRef v1, bool v2) { return v1.less(v2);}
inline bool less(CVarRef v1, int v2) { return v1.less(v2);}
inline bool less(CVarRef v1, int64_t v2) { return v1.less(v2);}
inline bool less(CVarRef v1, double v2) { return v1.less(v2);}
inline bool less(CVarRef v1, const StringData *v2) { return v1.less(v2);}
inline bool less(CVarRef v1, CStrRef v2) { return v1.less(v2);}
inline bool less(CVarRef v1, litstr v2) { return v1.less(v2);}
inline bool less(CVarRef v1, CArrRef v2) { return v1.less(v2);}
inline bool less(CVarRef v1, CObjRef v2) { return v1.less(v2);}
inline bool less(CVarRef v1, CVarRef v2) { return v1.less(v2);}
inline bool less(CVarRef v1, bool v2) {
return cellLess(v1.asCell(), v2);
}
inline bool less(CVarRef v1, int v2) {
return cellLess(v1.asCell(), v2);
}
inline bool less(CVarRef v1, int64_t v2) {
return cellLess(v1.asCell(), v2);
}
inline bool less(CVarRef v1, double v2) {
return cellLess(v1.asCell(), v2);
}
inline bool less(CVarRef v1, const StringData* v2) {
return cellLess(v1.asCell(), v2);
}
inline bool less(CVarRef v1, CStrRef v2) {
if (!v2.get()) return cellLess(v1.asCell(), false);
return cellLess(v1.asCell(), v2.get());
}
inline bool less(CVarRef v1, litstr v2) = delete;
inline bool less(CVarRef v1, CArrRef v2) {
if (!v2.get()) return cellLess(v1.asCell(), false);
return cellLess(v1.asCell(), v2.get());
}
inline bool less(CVarRef v1, CObjRef v2) {
if (!v2.get()) return cellLess(v1.asCell(), false);
return cellLess(v1.asCell(), v2.get());
}
inline bool less(CVarRef v1, CVarRef v2) {
return tvLess(v1.asTypedValue(), v2.asTypedValue());
}
inline bool more(CVarRef v1, bool v2) { return v1.more(v2);}
inline bool more(CVarRef v1, int v2) { return v1.more(v2);}
inline bool more(CVarRef v1, int64_t v2) { return v1.more(v2);}
inline bool more(CVarRef v1, double v2) { return v1.more(v2);}
inline bool more(CVarRef v1, const StringData *v2) { return v1.more(v2);}
inline bool more(CVarRef v1, CStrRef v2) { return v1.more(v2);}
inline bool more(CVarRef v1, litstr v2) { return v1.more(v2);}
inline bool more(CVarRef v1, CArrRef v2) { return v1.more(v2);}
inline bool more(CVarRef v1, CObjRef v2) { return v1.more(v2);}
inline bool more(CVarRef v1, CVarRef v2) { return v1.more(v2);}
inline bool more(CVarRef v1, bool v2) {
return cellGreater(v1.asCell(), v2);
}
inline bool more(CVarRef v1, int v2) {
return cellGreater(v1.asCell(), v2);
}
inline bool more(CVarRef v1, int64_t v2) {
return cellGreater(v1.asCell(), v2);
}
inline bool more(CVarRef v1, double v2) {
return cellGreater(v1.asCell(), v2);
}
inline bool more(CVarRef v1, const StringData* v2) {
return cellGreater(v1.asCell(), v2);
}
inline bool more(CVarRef v1, CStrRef v2) {
if (!v2.get()) return cellGreater(v1.asCell(), false);
return cellGreater(v1.asCell(), v2.get());
}
inline bool more(CVarRef v1, litstr v2) = delete;
inline bool more(CVarRef v1, CArrRef v2) {
if (!v2.get()) return cellGreater(v1.asCell(), false);
return cellGreater(v1.asCell(), v2.get());
}
inline bool more(CVarRef v1, CObjRef v2) {
if (!v2.get()) return cellGreater(v1.asCell(), false);
return cellGreater(v1.asCell(), v2.get());
}
inline bool more(CVarRef v1, CVarRef v2) {
return tvGreater(v1.asTypedValue(), v2.asTypedValue());
}
///////////////////////////////////////////////////////////////////////////////
// bool
+1 -1
Ver Arquivo
@@ -24,8 +24,8 @@
#include "hphp/runtime/base/type_array.h"
#include "hphp/runtime/base/type_object.h"
#include "hphp/runtime/base/ref_data.h"
#include "hphp/runtime/base/type_variant.h"
#include "hphp/runtime/base/tv_helpers.h"
#include "hphp/runtime/base/type_variant.h"
#include "hphp/runtime/base/array/array_inline.h"
#undef incl_HPHP_INSIDE_HPHP_COMPLEX_TYPES_H_
+10
Ver Arquivo
@@ -128,6 +128,16 @@ private:
}
};
/*
* These may be used to provide a little more self-documentation about
* whether typed values must be cells (not KindOfRef) or var (must be
* KindOfRef).
*
* See bytecode.specification for details.
*/
typedef TypedValue Cell;
typedef TypedValue Var;
///////////////////////////////////////////////////////////////////////////////
}
+35
Ver Arquivo
@@ -0,0 +1,35 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
namespace HPHP {
//////////////////////////////////////////////////////////////////////
inline bool cellEqual(const Cell* cell, int ival) {
return cellEqual(cell, static_cast<int64_t>(ival));
}
inline bool cellLess(const Cell* cell, int ival) {
return cellLess(cell, static_cast<int64_t>(ival));
}
inline bool cellGreater(const Cell* cell, int ival) {
return cellGreater(cell, static_cast<int64_t>(ival));
}
//////////////////////////////////////////////////////////////////////
}
+466 -3
Ver Arquivo
@@ -15,21 +15,389 @@
*/
#include "hphp/runtime/base/tv_comparisons.h"
#include "hphp/runtime/base/complex_types.h"
#include <type_traits>
#include "hphp/runtime/base/comparisons.h"
#include "hphp/runtime/base/type_conversions.h"
namespace HPHP {
//////////////////////////////////////////////////////////////////////
extern bool collectionEquals(ObjectData*, ObjectData*);
//////////////////////////////////////////////////////////////////////
namespace {
//////////////////////////////////////////////////////////////////////
bool cellToBool(const Cell* cell) {
assert(tvIsPlausible(cell));
assert(cell->m_type != KindOfRef);
switch (cell->m_type) {
case KindOfUninit:
case KindOfNull: return false;
case KindOfInt64: return cell->m_data.num != 0;
case KindOfBoolean: return cell->m_data.num;
case KindOfDouble: return cell->m_data.dbl != 0;
case KindOfStaticString:
case KindOfString: return cell->m_data.pstr->toBoolean();
case KindOfArray: return !cell->m_data.parr->empty();
case KindOfObject: // TODO: should handle o_toBoolean?
return true;
default: break;
}
not_reached();
}
//////////////////////////////////////////////////////////////////////
/*
* Family of relative op functions.
*
* These are used to implement the common parts of the php operators
* ==, <, and >. They handle some of the php behavior with regard to
* numeric-ish strings, and delegate to the 'op' functor to perform
* the actual comparison on primitive types, and between complex php
* types of the same type.
*
* See below for the implementations of the Op template parameter.
*/
template<class Op>
bool cellRelOp(Op op, const Cell* cell, bool val) {
return op(cellToBool(cell), val);
}
template<class Op>
bool cellRelOp(Op op, const Cell* cell, int64_t val) {
assert(tvIsPlausible(cell));
assert(cell->m_type != KindOfRef);
switch (cell->m_type) {
case KindOfUninit:
case KindOfNull: return op(false, !!val);
case KindOfBoolean: return op(!!cell->m_data.num, val != 0);
case KindOfInt64: return op(cell->m_data.num, val);
case KindOfDouble: return op(cell->m_data.dbl, val);
case KindOfArray: return op(true, false);
case KindOfObject:
return cell->m_data.pobj->isCollection()
? op.collectionVsNonObj()
: op(cell->m_data.pobj->o_toInt64(), val);
case KindOfStaticString:
case KindOfString:
{
auto const sdata = cell->m_data.pstr;
int64_t ival;
double dval;
auto const dt = sdata->isNumericWithVal(ival, dval,
/* allow_error */ true);
return dt == KindOfInt64 ? op(ival, val) :
dt == KindOfDouble ? op(dval, val) :
op(0, val);
}
default:
break;
}
not_reached();
}
template<class Op>
bool cellRelOp(Op op, const Cell* cell, double val) {
assert(tvIsPlausible(cell));
assert(cell->m_type != KindOfRef);
switch (cell->m_type) {
case KindOfUninit:
case KindOfNull: return op(false, val != 0);
case KindOfBoolean: return op(!!cell->m_data.num, val != 0);
case KindOfInt64: return op(cell->m_data.num, val);
case KindOfDouble: return op(cell->m_data.dbl, val);
case KindOfArray: return op(true, false);
case KindOfObject:
return cell->m_data.pobj->isCollection()
? op.collectionVsNonObj()
: op(cell->m_data.pobj->o_toDouble(), val);
case KindOfStaticString:
case KindOfString:
return op(toDouble(cell->m_data.pstr), val);
default:
break;
}
not_reached();
}
template<class Op>
bool cellRelOp(Op op, const Cell* cell, const StringData* val) {
assert(tvIsPlausible(cell));
assert(cell->m_type != KindOfRef);
switch (cell->m_type) {
case KindOfUninit:
case KindOfNull: return op(empty_string.get(), val);
case KindOfBoolean: return op(!!cell->m_data.num, toBoolean(val));
case KindOfDouble: return op(cell->m_data.dbl, val->toDouble());
case KindOfArray: return op(true, false);
case KindOfString:
case KindOfStaticString: return op(cell->m_data.pstr, val);
case KindOfInt64:
{
int64_t ival;
double dval;
auto const dt = val->isNumericWithVal(ival, dval,
/* allow_error */ true);
return dt == KindOfInt64 ? op(cell->m_data.num, ival) :
dt == KindOfDouble ? op(cell->m_data.num, dval) :
op(cell->m_data.num, 0);
}
case KindOfObject:
{
auto const od = cell->m_data.pobj;
if (od->isResource()) return op(true, false);
if (od->isCollection()) return op.collectionVsNonObj();
try {
String str(const_cast<ObjectData*>(od)->t___tostring());
return op(str.get(), val);
} catch (BadTypeConversionException&) {
return op(true, false);
}
}
default:
break;
}
not_reached();
}
template<class Op>
bool cellRelOp(Op op, const Cell* cell, const ArrayData* ad) {
assert(tvIsPlausible(cell));
assert(cell->m_type != KindOfRef);
switch (cell->m_type) {
case KindOfUninit:
case KindOfNull: return op(false, !ad->empty());
case KindOfBoolean: return op(cell->m_data.num, !ad->empty());
case KindOfInt64: return op(false, true);
case KindOfDouble: return op(false, true);
case KindOfArray: return op(cell->m_data.parr, ad);
case KindOfStaticString:
case KindOfString: return op(false, true);
case KindOfObject:
return cell->m_data.pobj->isCollection()
? op.collectionVsNonObj()
: op(true, false);
default:
break;
}
not_reached();
}
template<class Op>
bool cellRelOp(Op op, const Cell* cell, const ObjectData* od) {
assert(tvIsPlausible(cell));
assert(cell->m_type != KindOfRef);
switch (cell->m_type) {
case KindOfUninit:
case KindOfNull: // TODO: should use o_toBoolean
return op(false, true);
case KindOfBoolean: return op(!!cell->m_data.num, true);
case KindOfInt64:
return od->isCollection() ? op.collectionVsNonObj()
: op(cell->m_data.num, od->o_toInt64());
case KindOfDouble:
return od->isCollection() ? op.collectionVsNonObj()
: op(cell->m_data.dbl, od->o_toDouble());
case KindOfArray:
return od->isCollection() ? op.collectionVsNonObj() : op(false, true);
case KindOfString:
case KindOfStaticString:
if (od->isResource()) return op(false, true);
if (od->isCollection()) return op.collectionVsNonObj();
try {
String str(const_cast<ObjectData*>(od)->t___tostring());
return op(cell->m_data.pstr, str.get());
} catch (BadTypeConversionException&) {
return op(false, true);
}
case KindOfObject:
return op(cell->m_data.pobj, od);
default:
break;
}
not_reached();
}
template<class Op>
bool tvRelOp(Op op, const TypedValue* tv1, const TypedValue* tv2) {
assert(tvIsPlausible(tv1));
assert(tvIsPlausible(tv2));
tv1 = tvToCell(tv1);
tv2 = tvToCell(tv2);
switch (tv2->m_type) {
case KindOfUninit:
case KindOfNull:
return IS_STRING_TYPE(tv1->m_type)
? op(tv1->m_data.pstr, empty_string.get())
: cellRelOp(op, tv1, false);
case KindOfInt64: return cellRelOp(op, tv1, tv2->m_data.num);
case KindOfBoolean: return cellRelOp(op, tv1, !!tv2->m_data.num);
case KindOfDouble: return cellRelOp(op, tv1, tv2->m_data.dbl);
case KindOfStaticString:
case KindOfString: return cellRelOp(op, tv1, tv2->m_data.pstr);
case KindOfArray: return cellRelOp(op, tv1, tv2->m_data.parr);
case KindOfObject: return cellRelOp(op, tv1, tv2->m_data.pobj);
default:
break;
}
not_reached();
}
/*
* These relative ops helper function objects define operator() for
* each primitive type, and for the case of a complex type being
* compared with itself (that is obj with obj, string with string,
* array with array).
*
* They must also define a function called collectionVsNonObj() which
* is used when comparing collections with non-object types. (The obj
* vs obj function should handle the collection vs collection and
* collection vs non-collection object cases.) This is just to handle
* that php operator == returns false in these cases, while the Lt/Gt
* operators throw and exception.
*/
struct Eq {
template<class T, class U>
typename std::enable_if<
!std::is_pointer<T>::value &&
!std::is_pointer<U>::value,
bool
>::type operator()(T t, U u) const { return t == u; }
bool operator()(const StringData* sd1, const StringData* sd2) const {
return sd1->equal(sd2);
}
bool operator()(const ArrayData* ad1, const ArrayData* ad2) const {
return ad1->equal(ad2, false);
}
bool operator()(const ObjectData* od1, const ObjectData* od2) const {
if (od1 == od2) return true;
if (od1->isResource() || od2->isResource()) return false;
if (od1->getVMClass() != od2->getVMClass()) return false;
if (od1->isCollection()) {
// TODO constness
return collectionEquals(const_cast<ObjectData*>(od1),
const_cast<ObjectData*>(od2));
}
Array ar1(od1->o_toArray());
Array ar2(od2->o_toArray());
return ar1->equal(ar2.get(), false);
}
bool collectionVsNonObj() const { return false; }
};
struct Lt {
template<class T, class U>
typename std::enable_if<
!std::is_pointer<T>::value &&
!std::is_pointer<U>::value,
bool
>::type operator()(T t, U u) const { return t < u; }
bool operator()(const StringData* sd1, const StringData* sd2) const {
return sd1->compare(sd2) < 0;
}
bool operator()(const ArrayData* ad1, const ArrayData* ad2) const {
return ad1->compare(ad2) < 0;
}
bool operator()(const ObjectData* od1, const ObjectData* od2) const {
if (od1->isCollection() || od2->isCollection()) {
throw_collection_compare_exception();
}
if (od1 == od2) return false;
Array ar1(od1->o_toArray());
Array ar2(od2->o_toArray());
return (*this)(ar1.get(), ar2.get());
}
bool collectionVsNonObj() const {
throw_collection_compare_exception();
not_reached();
}
};
struct Gt {
template<class T, class U>
typename std::enable_if<
!std::is_pointer<T>::value &&
!std::is_pointer<U>::value,
bool
>::type operator()(T t, U u) const { return t > u; }
bool operator()(const StringData* sd1, const StringData* sd2) const {
return sd1->compare(sd2) > 0;
}
bool operator()(const ArrayData* ad1, const ArrayData* ad2) const {
return 0 > ad2->compare(ad1); // Not symmetric; order matters here.
}
bool operator()(const ObjectData* od1, const ObjectData* od2) const {
if (od1->isCollection() || od2->isCollection()) {
throw_collection_compare_exception();
}
if (od1 == od2) return false;
Array ar1(od1->o_toArray());
Array ar2(od2->o_toArray());
return (*this)(ar1.get(), ar2.get());
}
bool collectionVsNonObj() const {
throw_collection_compare_exception();
not_reached();
}
};
//////////////////////////////////////////////////////////////////////
}
bool tvSame(const TypedValue* tv1, const TypedValue* tv2) {
assert(tvIsPlausible(tv1));
assert(tvIsPlausible(tv2));
bool const null1 = IS_NULL_TYPE(tv1->m_type);
bool const null2 = IS_NULL_TYPE(tv2->m_type);
if (null1 && null2) return true;
if (null1 || null2) return false;
if (tv1->m_type == KindOfRef) tv1 = tv1->m_data.pref->tv();
if (tv2->m_type == KindOfRef) tv2 = tv2->m_data.pref->tv();
tv1 = tvToCell(tv1);
tv2 = tvToCell(tv2);
switch (tv1->m_type) {
case KindOfInt64:
@@ -61,5 +429,100 @@ bool tvSame(const TypedValue* tv1, const TypedValue* tv2) {
//////////////////////////////////////////////////////////////////////
/*
* XXX: HOT_FUNC selections are basically whatever random choices were
* in the old code ... we should probably re-evaluate this.
*/
bool cellEqual(const Cell* cell, bool val) {
return cellRelOp(Eq(), cell, val);
}
HOT_FUNC
bool cellEqual(const Cell* cell, int64_t val) {
return cellRelOp(Eq(), cell, val);
}
bool cellEqual(const Cell* cell, double val) {
return cellRelOp(Eq(), cell, val);
}
bool cellEqual(const Cell* cell, const StringData* val) {
return cellRelOp(Eq(), cell, val);
}
bool cellEqual(const Cell* cell, const ArrayData* val) {
return cellRelOp(Eq(), cell, val);
}
bool cellEqual(const Cell* cell, const ObjectData* val) {
return cellRelOp(Eq(), cell, val);
}
HOT_FUNC
bool tvEqual(const TypedValue* tv1, const TypedValue* tv2) {
return tvRelOp(Eq(), tv1, tv2);
}
bool cellLess(const Cell* cell, bool val) {
return cellRelOp(Lt(), cell, val);
}
bool cellLess(const Cell* cell, int64_t val) {
return cellRelOp(Lt(), cell, val);
}
bool cellLess(const Cell* cell, double val) {
return cellRelOp(Lt(), cell, val);
}
bool cellLess(const Cell* cell, const StringData* val) {
return cellRelOp(Lt(), cell, val);
}
bool cellLess(const Cell* cell, const ArrayData* val) {
return cellRelOp(Lt(), cell, val);
}
bool cellLess(const Cell* cell, const ObjectData* val) {
return cellRelOp(Lt(), cell, val);
}
HOT_FUNC
bool tvLess(const TypedValue* tv1, const TypedValue* tv2) {
return tvRelOp(Lt(), tv1, tv2);
}
bool cellGreater(const Cell* cell, bool val) {
return cellRelOp(Gt(), cell, val);
}
//NB: was HOT_FUNC in old code ... dunno if this makes sense anymore.
bool cellGreater(const Cell* cell, int64_t val) {
return cellRelOp(Gt(), cell, val);
}
bool cellGreater(const Cell* cell, double val) {
return cellRelOp(Gt(), cell, val);
}
bool cellGreater(const Cell* cell, const StringData* val) {
return cellRelOp(Gt(), cell, val);
}
bool cellGreater(const Cell* cell, const ArrayData* val) {
return cellRelOp(Gt(), cell, val);
}
bool cellGreater(const Cell* cell, const ObjectData* val) {
return cellRelOp(Gt(), cell, val);
}
bool tvGreater(const TypedValue* tv1, const TypedValue* tv2) {
return tvRelOp(Gt(), tv1, tv2);
}
//////////////////////////////////////////////////////////////////////
}
+66 -4
Ver Arquivo
@@ -16,13 +16,12 @@
#ifndef incl_HPHP_TV_COMPARISONS_H_
#define incl_HPHP_TV_COMPARISONS_H_
#include "hphp/runtime/vm/core_types.h"
namespace HPHP {
//////////////////////////////////////////////////////////////////////
struct TypedValue;
//////////////////////////////////////////////////////////////////////
// Php's operator ===
/*
* Returns whether two TypedValues have the same value, in sense of
@@ -30,8 +29,71 @@ struct TypedValue;
*/
bool tvSame(const TypedValue*, const TypedValue*);
//////////////////////////////////////////////////////////////////////
// Php's operator ==
/*
* Returns whether a Cell has the same value as an unpackaged type, in
* the sense of php's == operator.
*/
bool cellEqual(const Cell*, bool);
bool cellEqual(const Cell*, int);
bool cellEqual(const Cell*, int64_t);
bool cellEqual(const Cell*, double);
bool cellEqual(const Cell*, const StringData*);
bool cellEqual(const Cell*, const ArrayData*);
bool cellEqual(const Cell*, const ObjectData*);
/*
* Returns whether two TypedValues have the same value, in the sense
* of php's == operator.
*/
bool tvEqual(const TypedValue*, const TypedValue*);
//////////////////////////////////////////////////////////////////////
// Php's operator <
/*
* Returns whether a Cell is less than an unpackaged type, in the
* sense of php's < operator.
*/
bool cellLess(const Cell*, bool);
bool cellLess(const Cell*, int);
bool cellLess(const Cell*, int64_t);
bool cellLess(const Cell*, double);
bool cellLess(const Cell*, const StringData*);
bool cellLess(const Cell*, const ArrayData*);
bool cellLess(const Cell*, const ObjectData*);
/*
* Returns whether tv1 is less than tv2, as in php's < operator.
*/
bool tvLess(const TypedValue*, const TypedValue*);
//////////////////////////////////////////////////////////////////////
// Php's operator >
/*
* Returns whether a Cell is greater than an unpackaged type, in the
* sense of php's > operator.
*/
bool cellGreater(const Cell*, bool);
bool cellGreater(const Cell*, int);
bool cellGreater(const Cell*, int64_t);
bool cellGreater(const Cell*, double);
bool cellGreater(const Cell*, const StringData*);
bool cellGreater(const Cell*, const ArrayData*);
bool cellGreater(const Cell*, const ObjectData*);
/*
* Returns whether tv1 is greather than tv2, as in php's > operator.
*/
bool tvGreater(const TypedValue*, const TypedValue*);
//////////////////////////////////////////////////////////////////////
}
#include "hphp/runtime/base/tv_comparisons-inl.h"
#endif
+4 -2
Ver Arquivo
@@ -27,6 +27,8 @@
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
class Variant;
template<typename Data>
inline TypedValue tv(DataType type, Data data) {
static_assert(sizeof(Data) == sizeof(int64_t),
@@ -242,12 +244,12 @@ inline void tvWriteObject(ObjectData* pobj, TypedValue* tv) {
}
// conditionally unbox tv
inline TypedValue* tvToCell(TypedValue* tv) {
inline Cell* tvToCell(TypedValue* tv) {
return LIKELY(tv->m_type != KindOfRef) ? tv : tv->m_data.pref->tv();
}
// conditionally unbox tv, preserve constness.
inline const TypedValue* tvToCell(const TypedValue* tv) {
inline const Cell* tvToCell(const TypedValue* tv) {
return LIKELY(tv->m_type != KindOfRef) ? tv : tv->m_data.pref->tv();
}
+9 -9
Ver Arquivo
@@ -358,7 +358,7 @@ bool Array::less(CVarRef v2) const {
if (v2.getType() == KindOfArray) {
return m_px->compare(v2.toArray().get()) < 0;
}
return v2.more(*this);
return HPHP::more(v2, *this);
}
bool Array::more(CArrRef v2, bool flip /* = true */) const {
@@ -386,7 +386,7 @@ bool Array::more(CVarRef v2) const {
if (v2.getType() == KindOfArray) {
return v2.toArray().get()->compare(m_px) < 0;
}
return v2.less(*this);
return HPHP::less(v2, *this);
}
///////////////////////////////////////////////////////////////////////////////
@@ -634,7 +634,7 @@ bool Array::valueExists(CVarRef search_value,
bool strict /* = false */) const {
for (ArrayIter iter(*this); iter; ++iter) {
if ((strict && HPHP::same(iter.secondRef(), search_value)) ||
(!strict && iter.secondRef().equal(search_value))) {
(!strict && HPHP::equal(iter.secondRef(), search_value))) {
return true;
}
}
@@ -644,7 +644,7 @@ bool Array::valueExists(CVarRef search_value,
Variant Array::key(CVarRef search_value, bool strict /* = false */) const {
for (ArrayIter iter(*this); iter; ++iter) {
if ((strict && HPHP::same(iter.secondRef(), search_value)) ||
(!strict && iter.secondRef().equal(search_value))) {
(!strict && HPHP::equal(iter.secondRef(), search_value))) {
return iter.first();
}
}
@@ -663,7 +663,7 @@ Array Array::keys(CVarRef search_value /* = null_variant */,
Array ret = Array::Create();
for (ArrayIter iter(*this); iter; ++iter) {
if ((strict && HPHP::same(iter.secondRef(), search_value)) ||
(!strict && iter.secondRef().equal(search_value))) {
(!strict && HPHP::equal(iter.secondRef(), search_value))) {
ret.append(iter.first());
}
}
@@ -1006,13 +1006,13 @@ bool Array::MultiSort(std::vector<SortData> &data, bool renumber) {
}
int Array::SortRegularAscending(CVarRef v1, CVarRef v2, const void *data) {
if (v1.less(v2)) return -1;
if (v1.equal(v2)) return 0;
if (HPHP::less(v1, v2)) return -1;
if (tvEqual(v1.asTypedValue(), v2.asTypedValue())) return 0;
return 1;
}
int Array::SortRegularDescending(CVarRef v1, CVarRef v2, const void *data) {
if (v1.less(v2)) return 1;
if (v1.equal(v2)) return 0;
if (HPHP::less(v1, v2)) return 1;
if (tvEqual(v1.asTypedValue(), v2.asTypedValue())) return 0;
return -1;
}
-38
Ver Arquivo
@@ -1649,20 +1649,6 @@ Variant::operator Object() const {
} \
return false; \
bool Variant::equal(bool v2) const { UNWRAP(equal);}
bool Variant::equal(int v2) const { UNWRAP(equal);}
HOT_FUNC
bool Variant::equal(int64_t v2) const { UNWRAP(equal);}
bool Variant::equal(double v2) const { UNWRAP(equal);}
bool Variant::equal(litstr v2) const { UNWRAP_STR(equal);}
bool Variant::equal(const StringData *v2) const { UNWRAP_STR(equal);}
HOT_FUNC
bool Variant::equal(CStrRef v2) const { UNWRAP_STR(equal);}
bool Variant::equal(CArrRef v2) const { UNWRAP(equal);}
bool Variant::equal(CObjRef v2) const { UNWRAP(equal);}
HOT_FUNC
bool Variant::equal(CVarRef v2) const { UNWRAP_VAR(equal,equal);}
bool Variant::equalAsStr(bool v2) const { UNWRAP_STRING(equalAsStr);}
bool Variant::equalAsStr(int v2) const { UNWRAP_STRING(equalAsStr);}
bool Variant::equalAsStr(int64_t v2) const { UNWRAP_STRING(equalAsStr);}
@@ -1676,30 +1662,6 @@ bool Variant::equalAsStr(CArrRef v2) const { UNWRAP_STRING(equalAsStr);}
bool Variant::equalAsStr(CObjRef v2) const { UNWRAP_STRING(equalAsStr);}
bool Variant::equalAsStr(CVarRef v2) const { UNWRAP_STRING(equalAsStr);}
bool Variant::less(bool v2) const { UNWRAP(more);}
bool Variant::less(int v2) const { UNWRAP(more);}
bool Variant::less(int64_t v2) const { UNWRAP(more);}
bool Variant::less(double v2) const { UNWRAP(more);}
bool Variant::less(litstr v2) const { UNWRAP_STR(more);}
bool Variant::less(const StringData *v2) const { UNWRAP_STR(more);}
bool Variant::less(CStrRef v2) const { UNWRAP_STR(more);}
bool Variant::less(CArrRef v2) const { UNWRAP_ARR(less,more);}
bool Variant::less(CObjRef v2) const { UNWRAP(more);}
HOT_FUNC
bool Variant::less(CVarRef v2) const { UNWRAP_VAR(less,more);}
bool Variant::more(bool v2) const { UNWRAP(less);}
bool Variant::more(int v2) const { UNWRAP(less);}
HOT_FUNC
bool Variant::more(int64_t v2) const { UNWRAP(less);}
bool Variant::more(double v2) const { UNWRAP(less);}
bool Variant::more(litstr v2) const { UNWRAP_STR(less);}
bool Variant::more(const StringData *v2) const { UNWRAP_STR(less);}
bool Variant::more(CStrRef v2) const { UNWRAP_STR(less);}
bool Variant::more(CArrRef v2) const { UNWRAP_ARR(more,less);}
bool Variant::more(CObjRef v2) const { UNWRAP(less);}
bool Variant::more(CVarRef v2) const { UNWRAP_VAR(more,less);}
///////////////////////////////////////////////////////////////////////////////
// offset functions
+9 -41
Ver Arquivo
@@ -698,17 +698,6 @@ class Variant : private TypedValue {
* Comparisons
*/
bool equal(bool v2) const;
bool equal(int v2) const;
bool equal(int64_t v2) const;
bool equal(double v2) const;
bool equal(litstr v2) const;
bool equal(const StringData *v2) const;
bool equal(CStrRef v2) const;
bool equal(CArrRef v2) const;
bool equal(CObjRef v2) const;
bool equal(CVarRef v2) const;
bool equalAsStr(bool v2) const;
bool equalAsStr(int v2) const;
bool equalAsStr(int64_t v2) const;
@@ -720,28 +709,6 @@ class Variant : private TypedValue {
bool equalAsStr(CObjRef v2) const;
bool equalAsStr(CVarRef v2) const;
bool less(bool v2) const;
bool less(int v2) const;
bool less(int64_t v2) const;
bool less(double v2) const;
bool less(litstr v2) const;
bool less(const StringData *v2) const;
bool less(CStrRef v2) const;
bool less(CArrRef v2) const;
bool less(CObjRef v2) const;
bool less(CVarRef v2) const;
bool more(bool v2) const;
bool more(int v2) const;
bool more(int64_t v2) const;
bool more(double v2) const;
bool more(litstr v2) const;
bool more(const StringData *v2) const;
bool more(CStrRef v2) const;
bool more(CArrRef v2) const;
bool more(CObjRef v2) const;
bool more(CVarRef v2) const;
/**
* Output functions
*/
@@ -1008,16 +975,17 @@ class Variant : private TypedValue {
void setToDefaultObject();
/*
* Access this Variant as a TypedValue. Differs slightly from
* getTypedAccessor() by returning the outer TypedValue if it is
* Access this Variant as a TypedValue. Does not unbox refs, etc.
*/
const TypedValue* asTypedValue() const { return this; }
TypedValue* asTypedValue() { return this; }
/*
* Access this Variant as a Cell. I.e. unboxes it if it was a
* KindOfRef.
*/
TypedValue* asTypedValue() {
return reinterpret_cast<TypedValue*>(this);
}
const TypedValue* asTypedValue() const {
return reinterpret_cast<const TypedValue*>(this);
}
const Cell* asCell() const { return tvToCell(asTypedValue()); }
Cell* asCell() { return tvToCell(asTypedValue()); }
/**
* Based on the order in complex_types.h, TypedValue is defined before.
+8 -8
Ver Arquivo
@@ -454,12 +454,12 @@ static int collator_regular_compare_function(CVarRef v1, CVarRef v2,
norm2 = collator_normalize_sort_argument(str2);
}
if (ascending) {
if (norm1.less(norm2)) return -1;
if (norm1.equal(norm2)) return 0;
if (less(norm1, norm2)) return -1;
if (equal(norm1, norm2)) return 0;
return 1;
}
if (norm1.less(norm2)) return 1;
if (norm1.equal(norm2)) return 0;
if (less(norm1, norm2)) return 1;
if (equal(norm1, norm2)) return 0;
return -1;
}
@@ -490,12 +490,12 @@ static int collator_numeric_compare_function(CVarRef v1, CVarRef v2,
num2 = v2.toDouble();
}
if (ascending) {
if (num1.less(num2)) return -1;
if (num1.equal(num2)) return 0;
if (less(num1, num2)) return -1;
if (equal(num1, num2)) return 0;
return 1;
}
if (num1.less(num2)) return 1;
if (num1.equal(num2)) return 0;
if (less(num1, num2)) return 1;
if (equal(num1, num2)) return 0;
return -1;
}
+2 -1
Ver Arquivo
@@ -16,6 +16,7 @@
#include "hphp/runtime/debugger/cmd/cmd_where.h"
#include "hphp/runtime/base/array/array_iterator.h"
#include "hphp/runtime/base/comparisons.h"
namespace HPHP { namespace Eval {
///////////////////////////////////////////////////////////////////////////////
@@ -143,7 +144,7 @@ void CmdWhere::processStackTrace() {
CArrRef frame(iter.secondRef());
Array smallFrame;
for (ArrayIter iter2(frame); iter2; ++iter2) {
if (iter2.first().equal(s_args)) {
if (equal(iter2.first(), s_args)) {
continue;
}
smallFrame.set(iter2.first(), iter2.secondRef());
+1 -1
Ver Arquivo
@@ -373,7 +373,7 @@ String f_token_name(int64_t token) {
static const StaticString s_marauder("I solemnly swear that I am up to no good.");
Variant f_hphp_process_abort(CVarRef magic) {
if (magic.equal(s_marauder)) {
if (equal(magic, s_marauder)) {
*((int*)0) = 0xdead;
}
return null_variant;
+2 -2
Ver Arquivo
@@ -4551,13 +4551,13 @@ inline void OPTBLD_INLINE VMExecutionContext::iopSSwitch(PC& pc) {
StrVecItem* jmptab = (StrVecItem*)pc;
pc += veclen * sizeof(*jmptab);
TypedValue* val = m_stack.topTV();
Cell* val = tvToCell(m_stack.topTV());
Unit* u = m_fp->m_func->unit();
unsigned i;
for (i = 0; i < cases; ++i) {
auto& item = jmptab[i];
const StringData* str = u->lookupLitstrId(item.str);
if (tvAsVariant(val).equal(str)) {
if (cellEqual(val, str)) {
pc = origPC + item.dest;
break;
}
-8
Ver Arquivo
@@ -24,14 +24,6 @@
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
/*
* These may be used to provide a little more self-documentation about
* whether execution stack typed values are assumed to be cells or
* vars. (See bytecode.specification for details.)
*/
typedef TypedValue Cell;
typedef TypedValue Var;
/*
* Non-enumerated version of type for referring to opcodes or the
* bytecode stream. (Use the enum Op in hhbc.h for an enumerated
+2 -2
Ver Arquivo
@@ -2453,9 +2453,9 @@ static TCA sswitchHelperSlow(TypedValue typedVal,
const StringData** strs,
int numStrs,
TCA* jmptab) {
TypedValue* cell = tvToCell(&typedVal);
Cell* cell = tvToCell(&typedVal);
for (int i = 0; i < numStrs; ++i) {
if (tvAsCVarRef(cell).equal(strs[i])) return jmptab[i];
if (cellEqual(cell, strs[i])) return jmptab[i];
}
return jmptab[numStrs]; // default case
}
+58
Ver Arquivo
@@ -0,0 +1,58 @@
<?php
function eq($x, $y) {
var_dump($x == $y);
}
function lt($x, $y) {
var_dump($x < $y);
}
function gt($x, $y) {
var_dump($x > $y);
}
echo "======\n";
eq('Array', array(1,2));
eq('Array', array());
eq(array(), 'Array');
eq(array('a', 'b'), 'Array');
echo "\n";
lt('Array', array(1,2));
lt('Array', array());
lt(array(), 'Array');
lt(array('a', 'b'), 'Array');
echo "\n";
gt('Array', array(1,2));
gt('Array', array());
gt(array(), 'Array');
gt(array('a', 'b'), 'Array');
echo "======\n";
eq('', null);
eq(null, null);
eq(null, '');
eq('', '');
echo "\n";
lt('', null);
lt(null, null);
lt(null, '');
lt('', '');
echo "\n";
gt('', null);
gt(null, null);
gt(null, '');
gt('', '');
echo "======\n";
eq(-1.0, null);
eq(null, -1.0);
echo "\n";
lt(-1.0, null);
lt(null, -1.0);
echo "\n";
gt(-1.0, null);
gt(null, -1.0);
+39
Ver Arquivo
@@ -0,0 +1,39 @@
======
bool(false)
bool(false)
bool(false)
bool(false)
bool(true)
bool(true)
bool(false)
bool(false)
bool(false)
bool(false)
bool(true)
bool(true)
======
bool(true)
bool(true)
bool(true)
bool(true)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
======
bool(false)
bool(false)
bool(false)
bool(true)
bool(true)
bool(false)