Implement +=, -=, *=, /= and %= outside of Variant

Esse commit está contido em:
Jordan DeLong
2013-06-27 14:35:21 -07:00
commit de Sara Golemon
commit 6e4e52197e
15 arquivos alterados com 334 adições e 616 exclusões
-119
Ver Arquivo
@@ -1,119 +0,0 @@
/*
+----------------------------------------------------------------------+
| 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. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_BINARY_OPERATIONS_H_
#define incl_HPHP_BINARY_OPERATIONS_H_
#include "hphp/runtime/base/complex_types.h"
/**
* This file contains binary operations that are frequently used and they
* are overloaded to ease the code generation so that we need fewer type
* casts.
*/
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
// Variant
inline Variant operator+(bool n, CVarRef v) { return Variant(v) += n;}
inline Variant operator+(char n, CVarRef v) { return Variant(v) += n;}
inline Variant operator+(short n, CVarRef v) { return Variant(v) += n;}
inline Variant operator+(int n, CVarRef v) { return Variant(v) += n;}
inline Variant operator+(int64_t n, CVarRef v) { return Variant(v) += n;}
inline Variant operator+(double n, CVarRef v) { return Variant(v) += n;}
// String + Variant means string concatenation
inline Variant operator+(String&& n, CVarRef v) {
return Variant(std::move(n += v.toString()));
}
inline Variant operator+(CStrRef n, CVarRef v) {
return String(n) += v.toString();
}
// Array + Variant is already defined in type_array.h
inline Variant operator+(CObjRef n, CVarRef v) { return Variant(v) += n;}
#define HPHP_DEFINE_ADDITION(T) \
inline Variant&& operator+(Variant&& lhs, T rhs) { \
return std::move(lhs += rhs); \
} \
inline Variant operator+(CVarRef lhs, T rhs) { \
return Variant(lhs) += rhs; \
}
HPHP_DEFINE_ADDITION(bool);
HPHP_DEFINE_ADDITION(int);
HPHP_DEFINE_ADDITION(int64_t);
HPHP_DEFINE_ADDITION(double);
HPHP_DEFINE_ADDITION(CStrRef);
HPHP_DEFINE_ADDITION(litstr);
HPHP_DEFINE_ADDITION(CArrRef);
HPHP_DEFINE_ADDITION(CObjRef);
#undef HPHP_DEFINE_ADDITION
// String + String is already defined in type_string.h
// Array + Array is already defined in type_array.h
inline Variant operator+(CObjRef v, CObjRef n) { return Variant(v) += n;}
inline Variant operator-(bool n, CVarRef v) { return v.negate() += n;}
inline Variant operator-(char n, CVarRef v) { return v.negate() += n;}
inline Variant operator-(short n, CVarRef v) { return v.negate() += n;}
inline Variant operator-(int n, CVarRef v) { return v.negate() += n;}
inline Variant operator-(int64_t n, CVarRef v) { return v.negate() += n;}
inline Variant operator-(double n, CVarRef v) { return v.negate() += n;}
inline Variant operator-(CStrRef n, CVarRef v) { return v.negate() += n;}
inline Variant operator-(litstr n, CVarRef v) { return v.negate() += n;}
inline Variant operator-(CArrRef n, CVarRef v) { return v.negate() += n;}
inline Variant operator-(CObjRef n, CVarRef v) { return v.negate() += n;}
inline Variant operator-(CVarRef v, bool n) { return Variant(v) -= n;}
inline Variant operator-(CVarRef v, char n) { return Variant(v) -= n;}
inline Variant operator-(CVarRef v, short n) { return Variant(v) -= n;}
inline Variant operator-(CVarRef v, int n) { return Variant(v) -= n;}
inline Variant operator-(CVarRef v, int64_t n) { return Variant(v) -= n;}
inline Variant operator-(CVarRef v, double n) { return Variant(v) -= n;}
inline Variant operator-(CVarRef v, CStrRef n) { return Variant(v) -= n;}
inline Variant operator-(CVarRef v, litstr n) { return Variant(v) -= n;}
inline Variant operator-(CVarRef v, CArrRef n) { return Variant(v) -= n;}
inline Variant operator-(CVarRef v, CObjRef n) { return Variant(v) -= n;}
inline Variant operator*(bool n, CVarRef v) { return Variant(v) *= n;}
inline Variant operator*(char n, CVarRef v) { return Variant(v) *= n;}
inline Variant operator*(short n, CVarRef v) { return Variant(v) *= n;}
inline Variant operator*(int n, CVarRef v) { return Variant(v) *= n;}
inline Variant operator*(int64_t n, CVarRef v) { return Variant(v) *= n;}
inline Variant operator*(double n, CVarRef v) { return Variant(v) *= n;}
inline Variant operator*(CStrRef n, CVarRef v) { return Variant(v) *= n;}
inline Variant operator*(litstr n, CVarRef v) { return Variant(v) *= n;}
inline Variant operator*(CArrRef n, CVarRef v) { return Variant(v) *= n;}
inline Variant operator*(CObjRef n, CVarRef v) { return Variant(v) *= n;}
inline Variant operator*(CVarRef v, bool n) { return Variant(v) *= n;}
inline Variant operator*(CVarRef v, char n) { return Variant(v) *= n;}
inline Variant operator*(CVarRef v, short n) { return Variant(v) *= n;}
inline Variant operator*(CVarRef v, int n) { return Variant(v) *= n;}
inline Variant operator*(CVarRef v, int64_t n) { return Variant(v) *= n;}
inline Variant operator*(CVarRef v, double n) { return Variant(v) *= n;}
inline Variant operator*(CVarRef v, CStrRef n) { return Variant(v) *= n;}
inline Variant operator*(CVarRef v, litstr n) { return Variant(v) *= n;}
inline Variant operator*(CVarRef v, CArrRef n) { return Variant(v) *= n;}
inline Variant operator*(CVarRef v, CObjRef n) { return Variant(v) *= n;}
///////////////////////////////////////////////////////////////////////////////
}
#endif // incl_HPHP_BINARY_OPERATIONS_H_
-30
Ver Arquivo
@@ -20,7 +20,6 @@
#include "hphp/runtime/base/execution_context.h"
#include "hphp/runtime/base/types.h"
#include "hphp/runtime/base/complex_types.h"
#include "hphp/runtime/base/binary_operations.h"
#include "hphp/runtime/base/intercept.h"
#include "hphp/runtime/base/runtime_error.h"
#include "hphp/runtime/base/runtime_option.h"
@@ -111,35 +110,6 @@ inline String concat(CStrRef s1, CStrRef s2) {
String concat3(CStrRef s1, CStrRef s2, CStrRef s3);
String concat4(CStrRef s1, CStrRef s2, CStrRef s3, CStrRef s4);
inline Variant &concat_assign(Variant &v1, litstr s2) {
if (v1.getType() == KindOfString) {
StringData *data = v1.getStringData();
if (data->getCount() == 1) {
data->append(s2, strlen(s2));
return v1;
}
}
String s1 = v1.toString();
s1 += s2;
v1 = s1;
return v1;
}
inline Variant &concat_assign(Variant &v1, CStrRef s2) {
if (v1.getType() == KindOfString) {
StringData *data = v1.getStringData();
if (data->getCount() == 1) {
data->append(s2.data(), s2.size());
return v1;
}
}
String s1 = v1.toString();
s1 += s2;
v1 = s1;
return v1;
}
template <class K, class V>
const V &String::set(K key, const V &value) {
StringData *s = StringData::Escalate(m_px);
+2 -1
Ver Arquivo
@@ -20,6 +20,7 @@
#include "hphp/runtime/base/server/http_request_handler.h"
#include "hphp/runtime/base/server/transport.h"
#include "hphp/runtime/debugger/debugger.h"
#include "hphp/runtime/base/tv_arith.h"
using std::map;
@@ -198,7 +199,7 @@ void SourceRootInfo::setServerVariables(Variant &server) const {
}
if (!m_serverVars.empty()) {
server += m_serverVars;
cellAddEq(*server.asCell(), make_tv<KindOfArray>(m_serverVars.get()));
}
}
+135 -25
Ver Arquivo
@@ -28,7 +28,7 @@ namespace HPHP {
namespace {
// Helper for converting String, Array, Bool, Null or Obj to Dbl|Int.
// Other types must be handled outside of this.
// Other types (i.e. Int and Double) must be handled outside of this.
TypedNum numericConvHelper(Cell cell) {
assert(cellIsPlausible(&cell));
@@ -48,32 +48,32 @@ TypedNum numericConvHelper(Cell cell) {
template<class Op>
Cell cellArith(Op o, Cell c1, Cell c2) {
for (;;) {
if (c1.m_type == KindOfInt64) {
for (;;) {
if (c2.m_type == KindOfInt64) return o(c1.m_data.num, c2.m_data.num);
if (c2.m_type == KindOfDouble) return o(c1.m_data.num, c2.m_data.dbl);
c2 = numericConvHelper(c2);
assert(c1.m_type == KindOfInt64 || c1.m_type == KindOfDouble);
}
again:
if (c1.m_type == KindOfInt64) {
for (;;) {
if (c2.m_type == KindOfInt64) return o(c1.m_data.num, c2.m_data.num);
if (c2.m_type == KindOfDouble) return o(c1.m_data.num, c2.m_data.dbl);
c2 = numericConvHelper(c2);
assert(c2.m_type == KindOfInt64 || c2.m_type == KindOfDouble);
}
if (c1.m_type == KindOfDouble) {
for (;;) {
if (c2.m_type == KindOfDouble) return o(c1.m_data.dbl, c2.m_data.dbl);
if (c2.m_type == KindOfInt64) return o(c1.m_data.dbl, c2.m_data.num);
c2 = numericConvHelper(c2);
assert(c1.m_type == KindOfInt64 || c1.m_type == KindOfDouble);
}
}
if (c1.m_type == KindOfArray && c2.m_type == KindOfArray) {
return make_tv<KindOfArray>(o(c1.m_data.parr, c2.m_data.parr));
}
c1 = numericConvHelper(c1);
assert(c1.m_type == KindOfInt64 || c1.m_type == KindOfDouble);
}
if (c1.m_type == KindOfDouble) {
for (;;) {
if (c2.m_type == KindOfDouble) return o(c1.m_data.dbl, c2.m_data.dbl);
if (c2.m_type == KindOfInt64) return o(c1.m_data.dbl, c2.m_data.num);
c2 = numericConvHelper(c2);
assert(c2.m_type == KindOfInt64 || c2.m_type == KindOfDouble);
}
}
if (c1.m_type == KindOfArray && c2.m_type == KindOfArray) {
return make_tv<KindOfArray>(o(c1.m_data.parr, c2.m_data.parr));
}
c1 = numericConvHelper(c1);
assert(c1.m_type == KindOfInt64 || c1.m_type == KindOfDouble);
goto again;
}
Cell num(int64_t n) { return make_tv<KindOfInt64>(n); }
@@ -152,6 +152,91 @@ struct Div {
}
};
template<class Op>
void cellOpEq(Op op, Cell& c1, Cell c2) {
again:
if (c1.m_type == KindOfInt64) {
for (;;) {
if (c2.m_type == KindOfInt64) {
c1.m_data.num = op(c1.m_data.num, c2.m_data.num);
return;
}
if (c2.m_type == KindOfDouble) {
c1.m_type = KindOfDouble;
c1.m_data.dbl = op(c1.m_data.num, c2.m_data.dbl);
return;
}
c2 = numericConvHelper(c2);
assert(c2.m_type == KindOfInt64 || c2.m_type == KindOfDouble);
}
}
if (c1.m_type == KindOfDouble) {
for (;;) {
if (c2.m_type == KindOfInt64) {
c1.m_data.dbl = op(c1.m_data.dbl, c2.m_data.num);
return;
}
if (c2.m_type == KindOfDouble) {
c1.m_data.dbl = op(c1.m_data.dbl, c2.m_data.dbl);
return;
}
c2 = numericConvHelper(c2);
assert(c2.m_type == KindOfInt64 || c2.m_type == KindOfDouble);
}
}
if (c1.m_type == KindOfArray && c2.m_type == KindOfArray) {
auto const ad1 = c1.m_data.parr;
auto const newArr = op(ad1, c2.m_data.parr);
if (newArr != ad1) {
newArr->incRefCount();
c1.m_data.parr = newArr;
decRefArr(ad1);
}
return;
}
cellCopy(numericConvHelper(c1), c1);
assert(c1.m_type == KindOfInt64 || c1.m_type == KindOfDouble);
goto again;
}
struct AddEq {
int64_t operator()(int64_t a, int64_t b) const { return a + b; }
double operator()(double a, int64_t b) const { return a + b; }
double operator()(int64_t a, double b) const { return a + b; }
double operator()(double a, double b) const { return a + b; }
ArrayData* operator()(ArrayData* ad1, ArrayData* ad2) const {
if (ad2->empty() || ad1 == ad2) return ad1;
if (ad1->empty()) return ad2;
return ad1->plus(ad2, ad1->getCount() > 1 /* copy */);
}
};
struct SubEq {
int64_t operator()(int64_t a, int64_t b) const { return a - b; }
double operator()(double a, int64_t b) const { return a - b; }
double operator()(int64_t a, double b) const { return a - b; }
double operator()(double a, double b) const { return a - b; }
ArrayData* operator()(ArrayData* ad1, ArrayData* ad2) const {
throw BadArrayOperandException();
}
};
struct MulEq {
int64_t operator()(int64_t a, int64_t b) const { return a * b; }
double operator()(double a, int64_t b) const { return a * b; }
double operator()(int64_t a, double b) const { return a * b; }
double operator()(double a, double b) const { return a * b; }
ArrayData* operator()(ArrayData* ad1, ArrayData* ad2) const {
throw BadArrayOperandException();
}
};
}
//////////////////////////////////////////////////////////////////////
@@ -186,6 +271,31 @@ Cell cellMod(Cell c1, Cell c2) {
return make_tv<KindOfInt64>(i1 % i2);
}
void cellAddEq(Cell& c1, Cell c2) {
cellOpEq(AddEq(), c1, c2);
}
void cellSubEq(Cell& c1, Cell c2) {
cellOpEq(SubEq(), c1, c2);
}
void cellMulEq(Cell& c1, Cell c2) {
cellOpEq(MulEq(), c1, c2);
}
void cellDivEq(Cell& c1, Cell c2) {
assert(cellIsPlausible(&c1));
assert(cellIsPlausible(&c2));
if (!isTypedNum(c1)) {
cellSet(numericConvHelper(c1), c1);
}
cellCopy(cellDiv(c1, c2), c1);
}
void cellModEq(Cell& c1, Cell c2) {
cellCopy(cellMod(c1, c2), c1);
}
//////////////////////////////////////////////////////////////////////
}
+39 -7
Ver Arquivo
@@ -23,17 +23,13 @@ namespace HPHP {
//////////////////////////////////////////////////////////////////////
/*
* Functions that implement php arithmetic.
*
* These functions return Cells by value. In cases where they may
* return reference counted types, the value is already incRef'd when
* returned.
*/
//////////////////////////////////////////////////////////////////////
/*
* Operator +.
* PHP operator +
*
* Returns a TypedNum, unless both arguments are KindOfArray, in which
* case it returns an Cell that contains an Array.
@@ -41,7 +37,7 @@ namespace HPHP {
Cell cellAdd(Cell, Cell);
/*
* Operators - and *.
* PHP operators - and *.
*
* These arithmetic operators on any php value only return numbers.
*/
@@ -49,7 +45,7 @@ TypedNum cellSub(Cell, Cell);
TypedNum cellMul(Cell, Cell);
/*
* Operators / and %.
* PHP operators / and %.
*
* The operators return numbers unless the second argument converts to
* zero, in which case they return boolean false.
@@ -59,6 +55,42 @@ Cell cellMod(Cell, Cell);
//////////////////////////////////////////////////////////////////////
/*
* PHP operator +=
*
* Mutates the first argument in place, by adding the second argument
* to it in the sense of php's operator +=.
*
* Post: isTypedNum(c1), unless both arguments are KindOfArray, in
* which case it will contain a Cell of KindOfArray.
*/
void cellAddEq(Cell& c1, Cell);
/*
* PHP operators -= and *=.
*
* Mutates the first argument in place, by combining the second
* argument with it in the sense of either php operator -= or *=.
*
* Post: isTypedNum(c1)
*/
void cellSubEq(Cell& c1, Cell);
void cellMulEq(Cell& c1, Cell);
/*
* PHP operators /= and %=.
*
* Mutates the first argument in place, by combining the second
* argument with it in the sense of either php operator /= or %=.
*
* Post: isTypedNum(c1), unless the second argument converts to zero,
* in which case c1 will contain boolean false.
*/
void cellDivEq(Cell& c1, Cell);
void cellModEq(Cell& c1, Cell);
//////////////////////////////////////////////////////////////////////
}
#endif
+21
Ver Arquivo
@@ -37,6 +37,14 @@ bool tvIsPlausible(const TypedValue*);
bool cellIsPlausible(const Cell*);
bool varIsPlausible(const Var*);
/*
* Returns: true if the supplied TypedValue is KindOfDouble or
* KindOfInt64. I.e. if it is a TypedNum.
*/
inline bool isTypedNum(const TypedValue& tv) {
return tv.m_type == KindOfInt64 || tv.m_type == KindOfDouble;
}
// Assumes 'data' is live
// Assumes 'IS_REFCOUNTED_TYPE(type)'
void tvDecRefHelper(DataType type, uint64_t datum);
@@ -305,6 +313,19 @@ inline void tvSetIgnoreRef(const Cell& fr, TypedValue& to) {
tvRefcountedDecRefHelper(oldType, oldDatum);
}
/*
* Assigned the value of the Cell in `fr' to the Cell `to', with
* appropriate reference count modifications.
*
* This function has the same effects as tvSetIgnoreRef, with stronger
* assertions on `to'.
*/
inline void cellSet(const Cell& fr, Cell& to) {
assert(cellIsPlausible(&fr));
assert(cellIsPlausible(&to));
tvSetIgnoreRef(fr, to);
}
// Assumes 'to' and 'fr' are live
// Assumes that 'fr->m_type == KindOfRef'
inline void tvBind(TypedValue* fr, TypedValue* to) {
-23
Ver Arquivo
@@ -754,29 +754,6 @@ CVarRef Array::appendWithRef(CVarRef v) {
return v;
}
Variant Array::appendOpEqual(int op, CVarRef v) {
if (!m_px) ArrayBase::operator=(ArrayData::Create());
Variant *cv = nullptr;
ArrayData *escalated = m_px->lvalNew(cv, m_px->getCount() > 1);
if (escalated != m_px) ArrayBase::operator=(escalated);
assert(cv);
switch (op) {
case T_CONCAT_EQUAL: return concat_assign((*cv), v.toString());
case T_PLUS_EQUAL: return ((*cv) += v);
case T_MINUS_EQUAL: return ((*cv) -= v);
case T_MUL_EQUAL: return ((*cv) *= v);
case T_DIV_EQUAL: return ((*cv) /= v);
case T_MOD_EQUAL: return ((*cv) %= v);
case T_AND_EQUAL: return ((*cv) &= v);
case T_OR_EQUAL: return ((*cv) |= v);
case T_XOR_EQUAL: return ((*cv) ^= v);
case T_SL_EQUAL: return ((*cv) <<= v.toInt64());
case T_SR_EQUAL: return ((*cv) >>= v.toInt64());
default:
throw FatalErrorException(0, "invalid operator %d", op);
}
}
Variant Array::pop() {
if (m_px) {
Variant ret;
-1
Ver Arquivo
@@ -430,7 +430,6 @@ class Array : protected SmartPtr<ArrayData> {
CVarRef append(RefResult v) { return appendRef(variant(v)); }
CVarRef appendRef(CVarRef v);
CVarRef appendWithRef(CVarRef v);
Variant appendOpEqual(int op, CVarRef v);
Variant pop();
Variant dequeue();
void prepend(CVarRef v);
-357
Ver Arquivo
@@ -633,97 +633,6 @@ Variant Variant::operator+() const {
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// add or array append
Variant &Variant::operator+=(CVarRef var) {
if (m_type == KindOfInt64 && var.m_type == KindOfInt64) {
m_data.num += var.m_data.num;
return *this;
}
if (isIntVal() && var.isIntVal()) {
set(toInt64() + var.toInt64());
return *this;
}
int na = is(KindOfArray) + var.is(KindOfArray);
if (na == 2) {
ArrayData *arr1 = getArrayData();
ArrayData *arr2 = var.getArrayData();
if (arr1 == nullptr || arr2 == nullptr) {
throw BadArrayMergeException();
}
if (arr2->empty() || arr1 == arr2) return *this;
if (arr1->empty()) {
set(arr2);
return *this;
}
ArrayData *escalated = arr1->plus(arr2, arr1->getCount() > 1);
if (escalated != arr1) set(escalated);
return *this;
}
if (na) throw BadArrayMergeException();
if (isDouble() || var.isDouble()) {
set(toDouble() + var.toDouble());
return *this;
}
if (isString()) {
int64_t lval; double dval;
DataType ret = convertToNumeric(&lval, &dval);
if (ret == KindOfDouble) {
set(dval + var.toDouble());
return *this;
}
}
if (var.isString()) {
int64_t lval; double dval;
DataType ret = var.convertToNumeric(&lval, &dval);
if (ret == KindOfDouble) {
set(toDouble() + dval);
return *this;
}
}
set(toInt64() + var.toInt64());
return *this;
}
Variant &Variant::operator+=(int64_t n) {
if (m_type == KindOfInt64) {
m_data.num += n;
return *this;
}
if (isIntVal()) {
set(toInt64() + n);
return *this;
}
if (isDouble()) {
set(toDouble() + n);
return *this;
}
if (is(KindOfArray)) {
throw BadArrayMergeException();
}
if (isString()) {
int64_t lval; double dval;
DataType ret = convertToNumeric(&lval, &dval);
if (ret == KindOfDouble) {
set(dval + n);
return *this;
}
} else {
assert(false);
}
set(toInt64() + n);
return *this;
}
Variant &Variant::operator+=(double n) {
if (is(KindOfArray)) {
throw BadArrayMergeException();
}
set(toDouble() + n);
return *this;
}
///////////////////////////////////////////////////////////////////////////////
// minus
@@ -753,272 +662,6 @@ Variant Variant::operator-() const {
return *this;
}
Variant &Variant::operator-=(CVarRef var) {
if (is(KindOfArray) || var.is(KindOfArray)) {
throw BadArrayOperandException();
}
if (isDouble() || var.isDouble()) {
set(toDouble() - var.toDouble());
} else if (isIntVal() && var.isIntVal()) {
set(toInt64() - var.toInt64());
} else {
if (isString()) {
int64_t lval; double dval;
DataType ret = convertToNumeric(&lval, &dval);
if (ret == KindOfDouble) {
set(dval - var.toDouble());
return *this;
}
}
if (var.isString()) {
int64_t lval; double dval;
DataType ret = var.convertToNumeric(&lval, &dval);
if (ret == KindOfDouble) {
set(toDouble() - dval);
return *this;
}
}
set(toInt64() - var.toInt64());
}
return *this;
}
Variant &Variant::operator-=(int64_t n) {
if (is(KindOfArray)) {
throw BadArrayOperandException();
}
if (isDouble()) {
set(toDouble() - n);
} else if (isIntVal()) {
set(toInt64() - n);
} else {
if (isString()) {
int64_t lval; double dval;
DataType ret = convertToNumeric(&lval, &dval);
if (ret == KindOfDouble) {
set(dval - n);
return *this;
}
} else {
assert(false);
}
set(toInt64() - n);
}
return *this;
}
Variant &Variant::operator-=(double n) {
if (is(KindOfArray)) {
throw BadArrayOperandException();
}
set(toDouble() - n);
return *this;
}
///////////////////////////////////////////////////////////////////////////////
// multiply
Variant &Variant::operator*=(CVarRef var) {
if (is(KindOfArray) || var.is(KindOfArray)) {
throw BadArrayOperandException();
}
if (isDouble() || var.isDouble()) {
set(toDouble() * var.toDouble());
} else if (isIntVal() && var.isIntVal()) {
set(toInt64() * var.toInt64());
} else {
if (isString()) {
int64_t lval; double dval;
DataType ret = convertToNumeric(&lval, &dval);
if (ret == KindOfDouble) {
set(dval * var.toDouble());
return *this;
}
}
if (var.isString()) {
int64_t lval; double dval;
DataType ret = var.convertToNumeric(&lval, &dval);
if (ret == KindOfDouble) {
set(toDouble() * dval);
return *this;
}
}
set(toInt64() * var.toInt64());
}
return *this;
}
Variant &Variant::operator*=(int64_t n) {
if (is(KindOfArray)) {
throw BadArrayOperandException();
}
if (isDouble()) {
set(toDouble() * n);
} else if (isIntVal()) {
set(toInt64() * n);
} else {
if (isString()) {
int64_t lval; double dval;
DataType ret = convertToNumeric(&lval, &dval);
if (ret == KindOfDouble) {
set(dval * n);
return *this;
}
} else {
assert(false);
}
set(toInt64() * n);
}
return *this;
}
Variant &Variant::operator*=(double n) {
if (is(KindOfArray)) {
throw BadArrayOperandException();
}
set(toDouble() * n);
return *this;
}
///////////////////////////////////////////////////////////////////////////////
// divide
Variant &Variant::operator/=(CVarRef var) {
if (is(KindOfArray) || var.is(KindOfArray)) {
throw BadArrayOperandException();
}
int64_t lval; double dval; bool int1 = true;
int64_t lval2; double dval2; bool int2 = true;
if (isDouble()) {
dval = toDouble();
int1 = false;
} else if (isIntVal()) {
lval = toInt64();
} else if (isString()) {
DataType ret = convertToNumeric(&lval, &dval);
if (ret == KindOfDouble) {
int1 = false;
} else if (ret != KindOfInt64) {
lval = 0;
}
} else {
assert(false);
}
if (var.isDouble()) {
dval2 = var.toDouble();
int2 = false;
} else if (var.isIntVal()) {
lval2 = var.toInt64();
} else if (var.isString()) {
DataType ret = var.convertToNumeric(&lval2, &dval2);
if (ret == KindOfDouble) {
int2 = false;
} else if (ret != KindOfInt64) {
lval2 = 0;
}
} else {
assert(false);
}
if ((int2 && lval2 == 0) || (!int2 && dval2 == 0)) {
raise_warning(Strings::DIVISION_BY_ZERO);
set(false);
return *this;
}
if (int1 && int2) {
if (lval % lval2 == 0) {
set(lval / lval2);
} else {
set((double)lval / lval2);
}
} else if (int1 && !int2) {
set(lval / dval2);
} else if (!int1 && int2) {
set(dval / lval2);
} else {
set(dval / dval2);
}
return *this;
}
Variant &Variant::operator/=(int64_t n) {
if (is(KindOfArray)) {
throw BadArrayOperandException();
}
if (n == 0) {
raise_warning(Strings::DIVISION_BY_ZERO);
set(false);
return *this;
}
if (isIntVal() && toInt64() % n == 0) {
set(toInt64() / n);
} else if (isDouble()) {
set(toDouble() / n);
} else {
if (isString()) {
int64_t lval; double dval;
DataType ret = convertToNumeric(&lval, &dval);
if (ret == KindOfInt64 && lval % n == 0) {
set(lval / n);
return *this;
}
}
set(toDouble() / n);
}
return *this;
}
Variant &Variant::operator/=(double n) {
if (is(KindOfArray)) {
throw BadArrayOperandException();
}
if (n == 0.0) {
raise_warning(Strings::DIVISION_BY_ZERO);
set(false);
return *this;
}
set(toDouble() / n);
return *this;
}
///////////////////////////////////////////////////////////////////////////////
// modulus
Variant &Variant::operator%=(CVarRef var) {
int64_t lval = toInt64();
int64_t lval2 = var.toInt64();
if (lval2 == 0) {
raise_warning(Strings::DIVISION_BY_ZERO);
set(false);
return *this;
}
set(lval % lval2);
return *this;
}
Variant &Variant::operator%=(int64_t n) {
if (n == 0) {
raise_warning(Strings::DIVISION_BY_ZERO);
set(false);
return *this;
}
set(toInt64() % n);
return *this;
}
Variant &Variant::operator%=(double n) {
if ((int64_t)n == 0) {
raise_warning(Strings::DIVISION_BY_ZERO);
set(false);
return *this;
}
set(toInt64() % (int64_t)n);
return *this;
}
///////////////////////////////////////////////////////////////////////////////
// bitwise
+38 -20
Ver Arquivo
@@ -541,36 +541,36 @@ class Variant : private TypedValue {
Variant operator + () const;
Variant unary_plus() const { return Variant(*this).operator+();}
Variant &operator += (CVarRef v);
Variant &operator += (int n) { return operator+=((int64_t)n);}
Variant &operator += (int64_t n);
Variant &operator += (double n);
Variant &operator += (CVarRef v) = delete;
Variant &operator += (int n) = delete;
Variant &operator += (int64_t n) = delete;
Variant &operator += (double n) = delete;
Variant negate() const { return Variant(*this).operator-();}
Variant operator - () const;
Variant operator - (CVarRef v) const = delete;
Variant &operator -= (CVarRef v);
Variant &operator -= (int n) { return operator-=((int64_t)n);}
Variant &operator -= (int64_t n);
Variant &operator -= (double n);
Variant &operator -= (CVarRef v) = delete;
Variant &operator -= (int n) = delete;
Variant &operator -= (int64_t n) = delete;
Variant &operator -= (double n) = delete;
Variant operator * (CVarRef v) const = delete;
Variant &operator *= (CVarRef v);
Variant &operator *= (int n) { return operator*=((int64_t)n);}
Variant &operator *= (int64_t n);
Variant &operator *= (double n);
Variant &operator *= (CVarRef v) = delete;
Variant &operator *= (int n) = delete;
Variant &operator *= (int64_t n) = delete;
Variant &operator *= (double n) = delete;
Variant operator / (CVarRef v) const = delete;
Variant &operator /= (CVarRef v);
Variant &operator /= (int n) { return operator/=((int64_t)n);}
Variant &operator /= (int64_t n);
Variant &operator /= (double n);
Variant &operator /= (CVarRef v) = delete;
Variant &operator /= (int n) = delete;
Variant &operator /= (int64_t n) = delete;
Variant &operator /= (double n) = delete;
int64_t operator % (CVarRef v) const = delete;
Variant &operator %= (CVarRef v);
Variant &operator %= (int n) { return operator%=((int64_t)n);}
Variant &operator %= (int64_t n);
Variant &operator %= (double n);
Variant &operator %= (CVarRef v) = delete;
Variant &operator %= (int n) = delete;
Variant &operator %= (int64_t n) = delete;
Variant &operator %= (double n) = delete;
Variant operator | (CVarRef v) const;
Variant &operator |= (CVarRef v);
@@ -1340,6 +1340,24 @@ inline Variant uninit_null() {
return Variant();
}
// TODO(#2298051) litstr must die
inline Variant &concat_assign(Variant &v1, litstr s2) = delete;
inline Variant &concat_assign(Variant &v1, CStrRef s2) {
if (v1.getType() == KindOfString) {
StringData *data = v1.getStringData();
if (data->getCount() == 1) {
data->append(s2.data(), s2.size());
return v1;
}
}
String s1 = v1.toString();
s1 += s2;
v1 = s1;
return v1;
}
///////////////////////////////////////////////////////////////////////////////
}
+1 -1
Ver Arquivo
@@ -343,7 +343,7 @@ void f_spl_autoload(CStrRef class_name,
String lClass = StringUtil::ToLower(class_name);
bool found = false;
for (ArrayIter iter(ext); iter; ++iter) {
String fileName = lClass + iter.second();
String fileName = lClass + iter.second().toString();
include(fileName, true, "", false);
if (f_class_exists(class_name, false)) {
found = true;
+25 -23
Ver Arquivo
@@ -22,6 +22,7 @@
#include "hphp/util/util.h"
#include "hphp/runtime/base/complex_types.h"
#include "hphp/runtime/base/tv_arith.h"
#include "hphp/runtime/base/class_info.h"
#include "hphp/runtime/base/array/array_iterator.h"
#include "hphp/runtime/vm/class.h"
@@ -32,29 +33,30 @@
namespace HPHP {
// SETOP_BODY() would ideally be an inline function, but the header
// dependencies for concat_assign() make this unfeasible.
#define SETOP_BODY(lhs, op, rhs) do { \
switch (op) { \
case SetOpPlusEqual: tvAsVariant(lhs) += tvCellAsCVarRef(rhs); break; \
case SetOpMinusEqual: tvAsVariant(lhs) -= tvCellAsCVarRef(rhs); break; \
case SetOpMulEqual: tvAsVariant(lhs) *= tvCellAsCVarRef(rhs); break; \
case SetOpDivEqual: tvAsVariant(lhs) /= tvCellAsCVarRef(rhs); break; \
case SetOpConcatEqual: { \
concat_assign(tvAsVariant(lhs), tvCellAsCVarRef(rhs).toString()); \
break; \
} \
case SetOpModEqual: tvAsVariant(lhs) %= tvCellAsCVarRef(rhs); break; \
case SetOpAndEqual: tvAsVariant(lhs) &= tvCellAsCVarRef(rhs); break; \
case SetOpOrEqual: tvAsVariant(lhs) |= tvCellAsCVarRef(rhs); break; \
case SetOpXorEqual: tvAsVariant(lhs) ^= tvCellAsCVarRef(rhs); break; \
case SetOpSlEqual: tvAsVariant(lhs) <<= \
tvCellAsCVarRef(rhs).toInt64(); break; \
case SetOpSrEqual: tvAsVariant(lhs) >>= \
tvCellAsCVarRef(rhs).toInt64(); break; \
default: assert(false); \
} \
} while (0)
inline ALWAYS_INLINE
void SETOP_BODY(TypedValue* lhs, unsigned char op, Cell* rhs) {
assert(cellIsPlausible(rhs));
lhs = tvToCell(lhs);
switch (op) {
case SetOpPlusEqual: cellAddEq(*lhs, *rhs); break;
case SetOpMinusEqual: cellSubEq(*lhs, *rhs); break;
case SetOpMulEqual: cellMulEq(*lhs, *rhs); break;
case SetOpDivEqual: cellDivEq(*lhs, *rhs); break;
case SetOpModEqual: cellModEq(*lhs, *rhs); break;
case SetOpConcatEqual:
concat_assign(tvAsVariant(lhs), tvCellAsCVarRef(rhs).toString());
break;
case SetOpAndEqual: tvAsVariant(lhs) &= tvCellAsCVarRef(rhs); break;
case SetOpOrEqual: tvAsVariant(lhs) |= tvCellAsCVarRef(rhs); break;
case SetOpXorEqual: tvAsVariant(lhs) ^= tvCellAsCVarRef(rhs); break;
case SetOpSlEqual: tvAsVariant(lhs) <<=
tvCellAsCVarRef(rhs).toInt64(); break;
case SetOpSrEqual: tvAsVariant(lhs) >>=
tvCellAsCVarRef(rhs).toInt64(); break;
default: not_reached();
}
}
class Func;
class ActRec;
-9
Ver Arquivo
@@ -621,15 +621,6 @@ bool TestCppBase::TestObject() {
}
bool TestCppBase::TestVariant() {
// operators
{
Variant v(15);
v += 20;
VERIFY(v.isNumeric());
VERIFY(v.is(KindOfInt64));
VERIFY(equal(v, Variant(35)));
}
// conversions
{
Variant v("123");
+56
Ver Arquivo
@@ -26,4 +26,60 @@ function main() {
var_dump(foo() * twelve());
}
function setop_main() {
$a = array(zero());
$a[0] += foo();
var_dump($a[0]);
$a = array(zero());
$a[0] -= foo();
var_dump($a[0]);
$a = array(zero());
$a[0] /= foo();
var_dump($a[0]);
$a = array(zero());
$a[0] *= foo();
var_dump($a[0]);
$a = array(foo());
$a[0] += zero();
var_dump($a[0]);
$a = array(foo());
$a[0] -= zero();
var_dump($a[0]);
$a = array(foo());
$a[0] /= zero();
var_dump($a[0]);
$a = array(foo());
$a[0] *= zero();
var_dump($a[0]);
$a = array(twelve());
$a[0] += foo();
var_dump($a[0]);
$a = array(twelve());
$a[0] -= foo();
var_dump($a[0]);
$a = array(twelve());
$a[0] /= foo();
var_dump($a[0]);
$a = array(twelve());
$a[0] *= foo();
var_dump($a[0]);
$a = array(foo());
$a[0] += twelve();
var_dump($a[0]);
$a = array(foo());
$a[0] -= twelve();
var_dump($a[0]);
$a = array(foo());
$a[0] /= twelve();
var_dump($a[0]);
$a = array(foo());
$a[0] *= twelve();
var_dump($a[0]);
}
main();
setop_main();
+17
Ver Arquivo
@@ -15,3 +15,20 @@ int(28)
int(4)
float(1.3333333333333)
int(192)
int(16)
int(-16)
int(0)
int(0)
int(16)
int(16)
HipHop Warning: Division by zero in %s on line 50
bool(false)
int(0)
int(28)
int(-4)
float(0.75)
int(192)
int(28)
int(4)
float(1.3333333333333)
int(192)