Implement bitwise negation outside of Variant
Esse commit está contido em:
@@ -237,21 +237,30 @@ bool UnaryOpExpression::preCompute(CVarRef value, Variant &result) {
|
||||
*result.asCell());
|
||||
break;
|
||||
case '~':
|
||||
result = value.bitNot(); break;
|
||||
tvSet(*value.asCell(), *result.asTypedValue());
|
||||
cellBitNot(*result.asCell());
|
||||
break;
|
||||
case '@':
|
||||
result = value; break;
|
||||
result = value;
|
||||
break;
|
||||
case T_INT_CAST:
|
||||
result = value.toInt64(); break;
|
||||
result = value.toInt64();
|
||||
break;
|
||||
case T_DOUBLE_CAST:
|
||||
result = toDouble(value); break;
|
||||
result = toDouble(value);
|
||||
break;
|
||||
case T_STRING_CAST:
|
||||
result = toString(value); break;
|
||||
result = toString(value);
|
||||
break;
|
||||
case T_BOOL_CAST:
|
||||
result = toBoolean(value); break;
|
||||
result = toBoolean(value);
|
||||
break;
|
||||
case T_EMPTY:
|
||||
result = empty(value); break;
|
||||
result = empty(value);
|
||||
break;
|
||||
case T_ISSET:
|
||||
result = isset(value); break;
|
||||
result = isset(value);
|
||||
break;
|
||||
case T_INC:
|
||||
case T_DEC:
|
||||
assert(false);
|
||||
|
||||
@@ -239,7 +239,6 @@ struct MulEq {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class SzOp, class BitOp>
|
||||
StringData* stringBitOp(BitOp bop, SzOp sop, StringData* s1, StringData* s2) {
|
||||
auto const s1Size = s1->size();
|
||||
@@ -489,6 +488,38 @@ void cellDec(Cell& cell) {
|
||||
cellIncDecOp(Dec(), cell);
|
||||
}
|
||||
|
||||
void cellBitNot(Cell& cell) {
|
||||
assert(cellIsPlausible(&cell));
|
||||
|
||||
switch (cell.m_type) {
|
||||
case KindOfInt64:
|
||||
cell.m_data.num = ~cell.m_data.num;
|
||||
break;
|
||||
case KindOfDouble:
|
||||
cell.m_type = KindOfInt64;
|
||||
cell.m_data.num = ~toInt64(cell.m_data.dbl);
|
||||
break;
|
||||
|
||||
case KindOfString:
|
||||
if (cell.m_data.pstr->getCount() > 1) {
|
||||
case KindOfStaticString:
|
||||
auto const newSd = NEW(StringData)(
|
||||
cell.m_data.pstr->slice(),
|
||||
CopyString
|
||||
);
|
||||
newSd->incRefCount();
|
||||
cell.m_data.pstr->decRefCount(); // can't go to zero
|
||||
cell.m_data.pstr = newSd;
|
||||
cell.m_type = KindOfString;
|
||||
}
|
||||
cell.m_data.pstr->negate();
|
||||
break;
|
||||
|
||||
default:
|
||||
raise_error("Unsupported operand type for ~");
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
|
||||
@@ -112,6 +112,8 @@ void cellBitAndEq(Cell& c1, Cell);
|
||||
void cellBitOrEq(Cell& c1, Cell);
|
||||
void cellBitXorEq(Cell& c1, Cell);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* PHP operator ++ and --.
|
||||
*
|
||||
@@ -121,6 +123,15 @@ void cellBitXorEq(Cell& c1, Cell);
|
||||
void cellInc(Cell&);
|
||||
void cellDec(Cell&);
|
||||
|
||||
|
||||
/*
|
||||
* PHP unary operator ~.
|
||||
*
|
||||
* Mutates the argument in place, with the effects of php's unary
|
||||
* bitwise not operator.
|
||||
*/
|
||||
void cellBitNot(Cell&);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
|
||||
@@ -396,12 +396,6 @@ String operator+(const String & lhs, const String & rhs) {
|
||||
return NEW(StringData)(lhs.slice(), rhs.slice());
|
||||
}
|
||||
|
||||
String String::operator~() const {
|
||||
String ret(NEW(StringData)(slice(), CopyString));
|
||||
ret->negate();
|
||||
return ret;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// conversions
|
||||
|
||||
|
||||
@@ -318,7 +318,7 @@ public:
|
||||
String &operator |= (CStrRef v) = delete;
|
||||
String &operator &= (CStrRef v) = delete;
|
||||
String &operator ^= (CStrRef v) = delete;
|
||||
String operator ~ () const;
|
||||
String operator ~ () const = delete;
|
||||
explicit operator std::string () const {
|
||||
return std::string(c_str(), size());
|
||||
}
|
||||
|
||||
@@ -522,25 +522,6 @@ inline DataType Variant::convertToNumeric(int64_t *lval, double *dval) const {
|
||||
return s->isNumericWithVal(*lval, *dval, 1);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// bitwise
|
||||
|
||||
Variant Variant::bitNot() const {
|
||||
auto const cell = asCell();
|
||||
switch (cell->m_type) {
|
||||
case KindOfInt64:
|
||||
return ~cell->m_data.num;
|
||||
case KindOfDouble:
|
||||
return ~toInt64(cell->m_data.dbl);
|
||||
case KindOfStaticString:
|
||||
case KindOfString:
|
||||
return ~String(cell->m_data.pstr);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw InvalidOperandException("only numerics and strings can be negated");
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// iterator functions
|
||||
|
||||
|
||||
@@ -590,10 +590,6 @@ class Variant : private TypedValue {
|
||||
Variant &operator -- () = delete;
|
||||
Variant operator -- (int) = delete;
|
||||
|
||||
// Return the result of applying the php bitwise not operator to
|
||||
// this value.
|
||||
Variant bitNot() const;
|
||||
|
||||
/**
|
||||
* Iterator functions. See array_iterator.h for end() and next().
|
||||
*/
|
||||
|
||||
@@ -3768,17 +3768,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopShr(PC& pc) {
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopBitNot(PC& pc) {
|
||||
NEXT();
|
||||
Cell* c1 = m_stack.topC();
|
||||
if (LIKELY(c1->m_type == KindOfInt64)) {
|
||||
c1->m_data.num = ~c1->m_data.num;
|
||||
} else if (c1->m_type == KindOfDouble) {
|
||||
c1->m_type = KindOfInt64;
|
||||
c1->m_data.num = ~int64_t(c1->m_data.dbl);
|
||||
} else if (IS_STRING_TYPE(c1->m_type)) {
|
||||
cellAsVariant(*c1) = cellAsVariant(*c1).bitNot();
|
||||
} else {
|
||||
raise_error("Unsupported operand type for ~");
|
||||
}
|
||||
cellBitNot(*m_stack.topC());
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopCastBool(PC& pc) {
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário