Remove less, more, and equal functions from Variant
Re-implement them in terms of TypedValue and Cell helpers.
Esse commit está contido em:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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)
|
||||
Referência em uma Nova Issue
Bloquear um usuário