Implement Tuple
Implement a Tuple class as part of collections.
Esse commit está contido em:
@@ -2851,6 +2851,8 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
cType = Collection::MapType;
|
||||
} else if (!strcasecmp(clsName->c_str(), "stablemap")) {
|
||||
cType = Collection::StableMapType;
|
||||
} else if (!strcasecmp(clsName->c_str(), "tuple")) {
|
||||
cType = Collection::TupleType;
|
||||
} else {
|
||||
throw IncludeTimeFatalException(b,
|
||||
"Cannot use collection initialization for "
|
||||
|
||||
@@ -71,6 +71,8 @@ BinaryOpExpression::BinaryOpExpression
|
||||
cType = Collection::MapType;
|
||||
} else if (strcasecmp(s.c_str(), "stablemap") == 0) {
|
||||
cType = Collection::StableMapType;
|
||||
} else if (strcasecmp(s.c_str(), "tuple") == 0) {
|
||||
cType = Collection::TupleType;
|
||||
}
|
||||
ExpressionListPtr el = static_pointer_cast<ExpressionList>(m_exp2);
|
||||
el->setCollectionType(cType);
|
||||
|
||||
+742
-741
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -227,7 +227,6 @@ DefineFunction(
|
||||
),
|
||||
));
|
||||
|
||||
|
||||
DefineFunction(
|
||||
array(
|
||||
'name' => "contains",
|
||||
@@ -1615,3 +1614,176 @@ DefineFunction(
|
||||
EndClass(
|
||||
);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BeginClass(
|
||||
array(
|
||||
'name' => "Tuple",
|
||||
'ifaces' => array('KeyedIterable', 'Countable'),
|
||||
'desc' => "An ordered fixed-sized container.",
|
||||
'flags' => IsFinal | HasDocComment,
|
||||
'footer' => <<<EOT
|
||||
|
||||
private:
|
||||
int size;
|
||||
int capacity;
|
||||
EOT
|
||||
,
|
||||
));
|
||||
|
||||
DefineFunction(
|
||||
array(
|
||||
'name' => "__construct",
|
||||
'return' => array(
|
||||
'type' => null,
|
||||
),
|
||||
));
|
||||
|
||||
DefineFunction(
|
||||
array(
|
||||
'name' => "isEmpty",
|
||||
'flags' => HasDocComment,
|
||||
'desc' => "Returns true if this Tuple is empty, false otherwise.",
|
||||
'return' => array(
|
||||
'type' => Boolean,
|
||||
),
|
||||
));
|
||||
|
||||
DefineFunction(
|
||||
array(
|
||||
'name' => "count",
|
||||
'flags' => HasDocComment,
|
||||
'desc' => "Returns the number of values in the Tuple.",
|
||||
'return' => array(
|
||||
'type' => Int64,
|
||||
),
|
||||
));
|
||||
|
||||
DefineFunction(
|
||||
array(
|
||||
'name' => "toArray",
|
||||
'flags' => HasDocComment,
|
||||
'desc' => "Returns an array containing the values from this Tuple.",
|
||||
'return' => array(
|
||||
'type' => VariantMap,
|
||||
),
|
||||
));
|
||||
|
||||
DefineFunction(
|
||||
array(
|
||||
'name' => "getIterator",
|
||||
'flags' => HasDocComment,
|
||||
'desc' => "Returns an iterator that points to beginning of this ".
|
||||
"Tuple.",
|
||||
'return' => array(
|
||||
'type' => Object,
|
||||
),
|
||||
));
|
||||
|
||||
DefineFunction(
|
||||
array(
|
||||
'name' => "at",
|
||||
'flags' => HasDocComment,
|
||||
'desc' => "Returns the value at the specified key. If the key is ".
|
||||
"not present, an exception is thrown.",
|
||||
'return' => array(
|
||||
'type' => Variant,
|
||||
),
|
||||
'args' => array(
|
||||
array(
|
||||
'name' => "key",
|
||||
'type' => Variant,
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
DefineFunction(
|
||||
array(
|
||||
'name' => "get",
|
||||
'flags' => HasDocComment,
|
||||
'desc' => "Returns the value at the specified key. If the key is ".
|
||||
"not present, null is returned.",
|
||||
'return' => array(
|
||||
'type' => Variant,
|
||||
),
|
||||
'args' => array(
|
||||
array(
|
||||
'name' => "key",
|
||||
'type' => Variant,
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
EndClass(
|
||||
);
|
||||
|
||||
BeginClass(
|
||||
array(
|
||||
'name' => "TupleIterator",
|
||||
'ifaces' => array('KeyedIterator'),
|
||||
'desc' => "An iterator implementation for iterating over a Tuple.",
|
||||
'flags' => IsFinal | HasDocComment,
|
||||
));
|
||||
|
||||
DefineFunction(
|
||||
array(
|
||||
'name' => "__construct",
|
||||
'return' => array(
|
||||
'type' => null,
|
||||
),
|
||||
));
|
||||
|
||||
DefineFunction(
|
||||
array(
|
||||
'name' => "current",
|
||||
'desc' => "Returns the current value that the iterator points to.",
|
||||
'flags' => HasDocComment,
|
||||
'return' => array(
|
||||
'type' => Variant,
|
||||
),
|
||||
));
|
||||
|
||||
DefineFunction(
|
||||
array(
|
||||
'name' => "key",
|
||||
'desc' => "Returns the current key that the iterator points to.",
|
||||
'flags' => HasDocComment,
|
||||
'return' => array(
|
||||
'type' => Variant,
|
||||
),
|
||||
));
|
||||
|
||||
DefineFunction(
|
||||
array(
|
||||
'name' => "valid",
|
||||
'desc' => "Returns true if the iterator points to a valid value, ".
|
||||
"returns false otherwise.",
|
||||
'flags' => HasDocComment,
|
||||
'return' => array(
|
||||
'type' => Boolean,
|
||||
),
|
||||
));
|
||||
|
||||
DefineFunction(
|
||||
array(
|
||||
'name' => "next",
|
||||
'desc' => "Advance this iterator forward one position.",
|
||||
'flags' => HasDocComment,
|
||||
'return' => array(
|
||||
'type' => null,
|
||||
),
|
||||
));
|
||||
|
||||
DefineFunction(
|
||||
array(
|
||||
'name' => "rewind",
|
||||
'desc' => "Move this iterator back to the first position.",
|
||||
'flags' => HasDocComment,
|
||||
'return' => array(
|
||||
'type' => null,
|
||||
),
|
||||
));
|
||||
|
||||
EndClass(
|
||||
);
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ void ArrayIter::reset() {
|
||||
if (ad) decRefArr(const_cast<ArrayData*>(ad));
|
||||
return;
|
||||
}
|
||||
ObjectData* obj = getRawObject();
|
||||
ObjectData* obj = getObject();
|
||||
m_data = nullptr;
|
||||
assert(obj);
|
||||
decRefObj(obj);
|
||||
@@ -83,24 +83,33 @@ void ArrayIter::objInit(ObjectData *obj) {
|
||||
if (incRef) {
|
||||
obj->incRefCount();
|
||||
}
|
||||
if (!obj->isCollection()) {
|
||||
assert(obj->instanceof(SystemLib::s_IteratorClass));
|
||||
obj->o_invoke(s_rewind, Array());
|
||||
} else {
|
||||
if (hasVector()) {
|
||||
switch (getCollectionType()) {
|
||||
case Collection::VectorType: {
|
||||
c_Vector* vec = getVector();
|
||||
m_versionNumber = vec->getVersionNumber();
|
||||
m_pos = 0;
|
||||
} else if (hasMap()) {
|
||||
break;
|
||||
}
|
||||
case Collection::MapType: {
|
||||
c_Map* mp = getMap();
|
||||
m_versionNumber = mp->getVersionNumber();
|
||||
m_pos = mp->iter_begin();
|
||||
} else if (hasStableMap()) {
|
||||
break;
|
||||
}
|
||||
case Collection::StableMapType: {
|
||||
c_StableMap* smp = getStableMap();
|
||||
m_versionNumber = smp->getVersionNumber();
|
||||
m_pos = smp->iter_begin();
|
||||
} else {
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
case Collection::TupleType: {
|
||||
m_pos = 0;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert(obj->instanceof(SystemLib::s_IteratorClass));
|
||||
obj->o_invoke(s_rewind, Array());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,7 +138,7 @@ ArrayIter::~ArrayIter() {
|
||||
const ArrayData* ad = getArrayData();
|
||||
if (ad) decRefArr(const_cast<ArrayData*>(ad));
|
||||
} else {
|
||||
ObjectData* obj = getRawObject();
|
||||
ObjectData* obj = getObject();
|
||||
assert(obj);
|
||||
decRefObj(obj);
|
||||
}
|
||||
@@ -139,136 +148,169 @@ ArrayIter::~ArrayIter() {
|
||||
}
|
||||
|
||||
bool ArrayIter::endHelper() {
|
||||
if (hasVector()) {
|
||||
c_Vector* vec = getVector();
|
||||
return m_pos >= vec->t_count();
|
||||
switch (getCollectionType()) {
|
||||
case Collection::VectorType: {
|
||||
c_Vector* vec = getVector();
|
||||
return m_pos >= vec->t_count();
|
||||
}
|
||||
case Collection::MapType: {
|
||||
return m_pos == 0;
|
||||
}
|
||||
case Collection::StableMapType: {
|
||||
return m_pos == 0;
|
||||
}
|
||||
case Collection::TupleType: {
|
||||
c_Tuple* tup = getTuple();
|
||||
return m_pos >= tup->t_count();
|
||||
}
|
||||
default: {
|
||||
ObjectData* obj = getIteratorObj();
|
||||
return !obj->o_invoke(s_valid, Array());
|
||||
}
|
||||
}
|
||||
if (hasMap()) {
|
||||
return m_pos == 0;
|
||||
}
|
||||
if (hasStableMap()) {
|
||||
return m_pos == 0;
|
||||
}
|
||||
assert(hasObject());
|
||||
ObjectData* obj = getObject();
|
||||
return !obj->o_invoke(s_valid, Array());
|
||||
}
|
||||
|
||||
void ArrayIter::nextHelper() {
|
||||
if (hasVector()) {
|
||||
m_pos++;
|
||||
return;
|
||||
}
|
||||
if (hasMap()) {
|
||||
assert(m_pos != 0);
|
||||
c_Map* mp = getMap();
|
||||
if (UNLIKELY(m_versionNumber != mp->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
switch (getCollectionType()) {
|
||||
case Collection::VectorType: {
|
||||
m_pos++;
|
||||
return;
|
||||
}
|
||||
m_pos = mp->iter_next(m_pos);
|
||||
return;
|
||||
}
|
||||
if (hasStableMap()) {
|
||||
assert(m_pos != 0);
|
||||
c_StableMap* smp = getStableMap();
|
||||
if (UNLIKELY(m_versionNumber != smp->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
case Collection::MapType: {
|
||||
assert(m_pos != 0);
|
||||
c_Map* mp = getMap();
|
||||
if (UNLIKELY(m_versionNumber != mp->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
}
|
||||
m_pos = mp->iter_next(m_pos);
|
||||
return;
|
||||
}
|
||||
m_pos = smp->iter_next(m_pos);
|
||||
return;
|
||||
case Collection::StableMapType: {
|
||||
assert(m_pos != 0);
|
||||
c_StableMap* smp = getStableMap();
|
||||
if (UNLIKELY(m_versionNumber != smp->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
}
|
||||
m_pos = smp->iter_next(m_pos);
|
||||
return;
|
||||
}
|
||||
case Collection::TupleType: {
|
||||
m_pos++;
|
||||
return;
|
||||
}
|
||||
default:
|
||||
ObjectData* obj = getIteratorObj();
|
||||
obj->o_invoke(s_next, Array());
|
||||
}
|
||||
assert(hasObject());
|
||||
ObjectData* obj = getObject();
|
||||
obj->o_invoke(s_next, Array());
|
||||
}
|
||||
|
||||
Variant ArrayIter::firstHelper() {
|
||||
if (hasVector()) {
|
||||
return m_pos;
|
||||
}
|
||||
if (hasMap()) {
|
||||
assert(m_pos != 0);
|
||||
c_Map* mp = getMap();
|
||||
if (UNLIKELY(m_versionNumber != mp->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
switch (getCollectionType()) {
|
||||
case Collection::VectorType: {
|
||||
return m_pos;
|
||||
}
|
||||
return mp->iter_key(m_pos);
|
||||
}
|
||||
if (hasStableMap()) {
|
||||
assert(m_pos != 0);
|
||||
c_StableMap* smp = getStableMap();
|
||||
if (UNLIKELY(m_versionNumber != smp->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
case Collection::MapType: {
|
||||
assert(m_pos != 0);
|
||||
c_Map* mp = getMap();
|
||||
if (UNLIKELY(m_versionNumber != mp->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
}
|
||||
return mp->iter_key(m_pos);
|
||||
}
|
||||
case Collection::StableMapType: {
|
||||
assert(m_pos != 0);
|
||||
c_StableMap* smp = getStableMap();
|
||||
if (UNLIKELY(m_versionNumber != smp->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
}
|
||||
return smp->iter_key(m_pos);
|
||||
}
|
||||
case Collection::TupleType: {
|
||||
return m_pos;
|
||||
}
|
||||
default: {
|
||||
ObjectData* obj = getIteratorObj();
|
||||
return obj->o_invoke(s_key, Array());
|
||||
}
|
||||
return smp->iter_key(m_pos);
|
||||
}
|
||||
assert(hasObject());
|
||||
ObjectData* obj = getObject();
|
||||
return obj->o_invoke(s_key, Array());
|
||||
}
|
||||
|
||||
HOT_FUNC
|
||||
Variant ArrayIter::second() {
|
||||
if (hasVector()) {
|
||||
c_Vector* vec = getVector();
|
||||
if (UNLIKELY(m_versionNumber != vec->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
if (hasArrayData()) {
|
||||
assert(m_pos != ArrayData::invalid_index);
|
||||
const ArrayData* ad = getArrayData();
|
||||
assert(ad);
|
||||
return ad->getValue(m_pos);
|
||||
}
|
||||
switch (getCollectionType()) {
|
||||
case Collection::VectorType: {
|
||||
c_Vector* vec = getVector();
|
||||
if (UNLIKELY(m_versionNumber != vec->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
}
|
||||
return tvAsCVarRef(vec->at(m_pos));
|
||||
}
|
||||
return tvAsCVarRef(vec->at(m_pos));
|
||||
}
|
||||
if (hasMap()) {
|
||||
c_Map* mp = getMap();
|
||||
if (UNLIKELY(m_versionNumber != mp->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
case Collection::MapType: {
|
||||
c_Map* mp = getMap();
|
||||
if (UNLIKELY(m_versionNumber != mp->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
}
|
||||
return mp->iter_value(m_pos);
|
||||
}
|
||||
return mp->iter_value(m_pos);
|
||||
}
|
||||
if (hasStableMap()) {
|
||||
c_StableMap* smp = getStableMap();
|
||||
if (UNLIKELY(m_versionNumber != smp->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
case Collection::StableMapType: {
|
||||
c_StableMap* smp = getStableMap();
|
||||
if (UNLIKELY(m_versionNumber != smp->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
}
|
||||
return smp->iter_value(m_pos);
|
||||
}
|
||||
case Collection::TupleType: {
|
||||
return tvAsCVarRef(getTuple()->at(m_pos));
|
||||
}
|
||||
default: {
|
||||
ObjectData* obj = getIteratorObj();
|
||||
return obj->o_invoke(s_current, Array());
|
||||
}
|
||||
return smp->iter_value(m_pos);
|
||||
}
|
||||
if (hasObject()) {
|
||||
ObjectData* obj = getObject();
|
||||
return obj->o_invoke(s_current, Array());
|
||||
}
|
||||
assert(hasArrayData());
|
||||
assert(m_pos != ArrayData::invalid_index);
|
||||
const ArrayData* ad = getArrayData();
|
||||
assert(ad);
|
||||
return ad->getValue(m_pos);
|
||||
}
|
||||
|
||||
void ArrayIter::secondHelper(Variant & v) {
|
||||
if (hasVector()) {
|
||||
c_Vector* vec = getVector();
|
||||
if (UNLIKELY(m_versionNumber != vec->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
void ArrayIter::secondHelper(Variant& v) {
|
||||
switch (getCollectionType()) {
|
||||
case Collection::VectorType: {
|
||||
c_Vector* vec = getVector();
|
||||
if (UNLIKELY(m_versionNumber != vec->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
}
|
||||
v = tvAsCVarRef(vec->at(m_pos));
|
||||
break;
|
||||
}
|
||||
v = tvAsCVarRef(vec->at(m_pos));
|
||||
return;
|
||||
}
|
||||
if (hasMap()) {
|
||||
c_Map* mp = getMap();
|
||||
if (UNLIKELY(m_versionNumber != mp->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
case Collection::MapType: {
|
||||
c_Map* mp = getMap();
|
||||
if (UNLIKELY(m_versionNumber != mp->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
}
|
||||
v = mp->iter_value(m_pos);
|
||||
break;
|
||||
}
|
||||
v = mp->iter_value(m_pos);
|
||||
return;
|
||||
}
|
||||
if (hasStableMap()) {
|
||||
c_StableMap* smp = getStableMap();
|
||||
if (UNLIKELY(m_versionNumber != smp->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
case Collection::StableMapType: {
|
||||
c_StableMap* smp = getStableMap();
|
||||
if (UNLIKELY(m_versionNumber != smp->getVersionNumber())) {
|
||||
throw_collection_modified();
|
||||
}
|
||||
v = smp->iter_value(m_pos);
|
||||
break;
|
||||
}
|
||||
case Collection::TupleType: {
|
||||
v = tvAsCVarRef(getTuple()->at(m_pos));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ObjectData* obj = getIteratorObj();
|
||||
v = obj->o_invoke(s_current, Array());
|
||||
break;
|
||||
}
|
||||
v = smp->iter_value(m_pos);
|
||||
return;
|
||||
}
|
||||
assert(hasObject());
|
||||
ObjectData* obj = getObject();
|
||||
v = obj->o_invoke(s_current, Array());
|
||||
}
|
||||
|
||||
HOT_FUNC
|
||||
|
||||
@@ -30,6 +30,7 @@ struct TypedValue;
|
||||
class c_Vector;
|
||||
class c_Map;
|
||||
class c_StableMap;
|
||||
class c_Tuple;
|
||||
namespace VM {
|
||||
struct Iter;
|
||||
}
|
||||
@@ -129,7 +130,7 @@ class ArrayIter {
|
||||
return firstHelper();
|
||||
}
|
||||
Variant second();
|
||||
void second(Variant &v) {
|
||||
void second(Variant& v) {
|
||||
if (LIKELY(hasArrayData())) {
|
||||
const ArrayData* ad = getArrayData();
|
||||
assert(ad);
|
||||
@@ -155,24 +156,13 @@ class ArrayIter {
|
||||
bool hasArrayData() {
|
||||
return !((intptr_t)m_data & 1);
|
||||
}
|
||||
bool hasCollection() {
|
||||
return (!hasArrayData() && getObject()->isCollection());
|
||||
}
|
||||
bool hasIteratorObj() {
|
||||
return (!hasArrayData() && !getObject()->isCollection());
|
||||
}
|
||||
|
||||
private:
|
||||
bool hasVector() {
|
||||
return (!hasArrayData() &&
|
||||
getRawObject()->getCollectionType() == Collection::VectorType);
|
||||
}
|
||||
bool hasMap() {
|
||||
return (!hasArrayData() &&
|
||||
getRawObject()->getCollectionType() == Collection::MapType);
|
||||
}
|
||||
bool hasStableMap() {
|
||||
return (!hasArrayData() &&
|
||||
getRawObject()->getCollectionType() == Collection::StableMapType);
|
||||
}
|
||||
bool hasObject() {
|
||||
return (!hasArrayData() &&
|
||||
getRawObject()->getCollectionType() == Collection::InvalidType);
|
||||
}
|
||||
public:
|
||||
const ArrayData* getArrayData() {
|
||||
assert(hasArrayData());
|
||||
@@ -190,27 +180,36 @@ class ArrayIter {
|
||||
void setIterType(Type iterType) {
|
||||
m_itype = iterType;
|
||||
}
|
||||
|
||||
private:
|
||||
c_Vector* getVector() {
|
||||
assert(hasVector());
|
||||
assert(hasCollection() && getCollectionType() == Collection::VectorType);
|
||||
return (c_Vector*)((intptr_t)m_obj & ~1);
|
||||
}
|
||||
c_Map* getMap() {
|
||||
assert(hasMap());
|
||||
assert(hasCollection() && getCollectionType() == Collection::MapType);
|
||||
return (c_Map*)((intptr_t)m_obj & ~1);
|
||||
}
|
||||
c_StableMap* getStableMap() {
|
||||
assert(hasStableMap());
|
||||
assert(hasCollection() && getCollectionType() == Collection::StableMapType);
|
||||
return (c_StableMap*)((intptr_t)m_obj & ~1);
|
||||
}
|
||||
ObjectData* getObject() {
|
||||
assert(hasObject());
|
||||
return (ObjectData*)((intptr_t)m_obj & ~1);
|
||||
c_Tuple* getTuple() {
|
||||
assert(hasCollection() && getCollectionType() == Collection::TupleType);
|
||||
return (c_Tuple*)((intptr_t)m_obj & ~1);
|
||||
}
|
||||
ObjectData* getRawObject() {
|
||||
ObjectData* getObject() {
|
||||
assert(!hasArrayData());
|
||||
return (ObjectData*)((intptr_t)m_obj & ~1);
|
||||
}
|
||||
Collection::Type getCollectionType() {
|
||||
ObjectData* obj = getObject();
|
||||
return obj->getCollectionType();
|
||||
}
|
||||
ObjectData* getIteratorObj() {
|
||||
assert(hasIteratorObj());
|
||||
return getObject();
|
||||
}
|
||||
|
||||
void setArrayData(const ArrayData* ad) {
|
||||
assert((intptr_t(ad) & 1) == 0);
|
||||
@@ -224,7 +223,7 @@ class ArrayIter {
|
||||
bool endHelper();
|
||||
void nextHelper();
|
||||
Variant firstHelper();
|
||||
void secondHelper(Variant &v);
|
||||
void secondHelper(Variant& v);
|
||||
|
||||
union {
|
||||
const ArrayData* m_data;
|
||||
|
||||
@@ -78,6 +78,7 @@ class ObjectData : public CountableNF {
|
||||
VectorAttrInit = (Collection::VectorType << 13),
|
||||
MapAttrInit = (Collection::MapType << 13),
|
||||
StableMapAttrInit = (Collection::StableMapType << 13),
|
||||
TupleAttrInit = (Collection::TupleType << 13),
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -114,9 +115,9 @@ class ObjectData : public CountableNF {
|
||||
bool isCollection() const {
|
||||
return getCollectionType() != Collection::InvalidType;
|
||||
}
|
||||
int getCollectionType() const {
|
||||
Collection::Type getCollectionType() const {
|
||||
// Return the upper 3 bits of o_attribute
|
||||
return (int)(o_attribute >> 13) & 7;
|
||||
return (Collection::Type)((uint16_t)(o_attribute >> 13) & 7);
|
||||
}
|
||||
bool supportsUnsetElem() const {
|
||||
return isCollection() || instanceof(SystemLib::s_ArrayAccessClass);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <util/parser/hphp.tab.hpp>
|
||||
#include <runtime/vm/translator/translator-x64.h>
|
||||
#include <runtime/vm/runtime.h>
|
||||
#include <runtime/vm/instance.h>
|
||||
#include <system/lib/systemlib.h>
|
||||
#include <runtime/ext/ext_collections.h>
|
||||
|
||||
@@ -3260,16 +3261,6 @@ void Variant::unserialize(VariableUnserializer *uns) {
|
||||
if (sep != ':') {
|
||||
throw Exception("Expected ':' but got '%c'", sep);
|
||||
}
|
||||
|
||||
Object obj;
|
||||
try {
|
||||
obj = create_object_only(clsName);
|
||||
obj.get()->clearNoDestruct();
|
||||
} catch (ClassNotFoundException &e) {
|
||||
obj = create_object_only(s_PHP_Incomplete_Class);
|
||||
obj->o_set(s_PHP_Incomplete_Class_Name, clsName);
|
||||
}
|
||||
operator=(obj);
|
||||
int64_t size = uns->readInt();
|
||||
char sep = uns->readChar();
|
||||
if (sep != ':') {
|
||||
@@ -3279,9 +3270,25 @@ void Variant::unserialize(VariableUnserializer *uns) {
|
||||
if (sep != '{') {
|
||||
throw Exception("Expected '{' but got '%c'", sep);
|
||||
}
|
||||
|
||||
VM::Class* cls = VM::Unit::loadClass(clsName.get());
|
||||
Object obj;
|
||||
if (cls) {
|
||||
if (LIKELY(cls != c_Tuple::s_cls)) {
|
||||
obj = VM::Instance::newInstance(cls);
|
||||
} else {
|
||||
obj = c_Tuple::alloc(size);
|
||||
}
|
||||
} else {
|
||||
obj = VM::Instance::newInstance(
|
||||
SystemLib::s___PHP_Incomplete_ClassClass);
|
||||
obj->o_set(s_PHP_Incomplete_Class_Name, clsName);
|
||||
}
|
||||
operator=(obj);
|
||||
|
||||
if (size > 0) {
|
||||
if (type == 'O') {
|
||||
// Collection are not allowed
|
||||
// Collections are not allowed
|
||||
if (obj->isCollection()) {
|
||||
if (size > 0) {
|
||||
throw Exception("%s does not support the 'O' serialization "
|
||||
|
||||
@@ -298,7 +298,8 @@ enum Type {
|
||||
VectorType = 1,
|
||||
MapType = 2,
|
||||
StableMapType = 3,
|
||||
MaxNumTypes = 4
|
||||
TupleType = 4,
|
||||
MaxNumTypes = 5
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -129,10 +129,6 @@ void c_Vector::t___construct(CVarRef iterable /* = null_variant */) {
|
||||
}
|
||||
}
|
||||
|
||||
Variant c_Vector::t___destruct() {
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
void c_Vector::grow() {
|
||||
if (m_capacity) {
|
||||
m_capacity += m_capacity;
|
||||
@@ -882,10 +878,6 @@ void c_Map::t___construct(CVarRef iterable /* = null_variant */) {
|
||||
}
|
||||
}
|
||||
|
||||
Variant c_Map::t___destruct() {
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
Array c_Map::toArrayImpl() const {
|
||||
ArrayInit ai(m_size);
|
||||
for (uint i = 0; i <= m_nLastSlot; ++i) {
|
||||
@@ -1792,10 +1784,6 @@ void c_StableMap::t___construct(CVarRef iterable /* = null_variant */) {
|
||||
}
|
||||
}
|
||||
|
||||
Variant c_StableMap::t___destruct() {
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
Array c_StableMap::toArrayImpl() const {
|
||||
ArrayInit ai(m_size);
|
||||
Bucket* p = m_pListHead;
|
||||
@@ -2726,6 +2714,231 @@ void c_StableMapIterator::t_rewind() {
|
||||
m_pos = smp->iter_begin();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
c_Tuple::c_Tuple(VM::Class* cb) :
|
||||
ExtObjectDataFlags<ObjectData::TupleAttrInit|
|
||||
ObjectData::UseGet|
|
||||
ObjectData::UseSet|
|
||||
ObjectData::UseIsset|
|
||||
ObjectData::UseUnset>(cb),
|
||||
m_size(0), m_capacity(0) {
|
||||
}
|
||||
|
||||
c_Tuple::~c_Tuple() {
|
||||
uint sz = m_size;
|
||||
for (uint i = 0; i < sz; ++i) {
|
||||
tvRefcountedDecRef(&getData()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void c_Tuple::t___construct() {
|
||||
Object e(SystemLib::AllocRuntimeExceptionObject(
|
||||
"Tuples cannot be created using the new operator"));
|
||||
throw e;
|
||||
}
|
||||
|
||||
Array c_Tuple::toArrayImpl() const {
|
||||
ArrayInit ai(m_size, ArrayInit::vectorInit);
|
||||
uint sz = m_size;
|
||||
for (uint i = 0; i < sz; ++i) {
|
||||
ai.set(tvAsCVarRef(&getData()[i]));
|
||||
}
|
||||
return ai.create();
|
||||
}
|
||||
|
||||
Array c_Tuple::o_toArray() const {
|
||||
check_collection_cast_to_array();
|
||||
return toArrayImpl();
|
||||
}
|
||||
|
||||
ObjectData* c_Tuple::clone() {
|
||||
auto tup = c_Tuple::alloc(m_size);
|
||||
tup->incRefCount();
|
||||
uint sz = tup->m_size = m_size;
|
||||
TypedValue* src = getData();
|
||||
TypedValue* dst = tup->getData();
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
tvDup(&src[i], &dst[i]);
|
||||
}
|
||||
return tup;
|
||||
}
|
||||
|
||||
bool c_Tuple::t_isempty() {
|
||||
return (m_size == 0);
|
||||
}
|
||||
|
||||
int64_t c_Tuple::t_count() {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
Variant c_Tuple::t_at(CVarRef key) {
|
||||
if (key.isInteger()) {
|
||||
return tvAsCVarRef(at(key.toInt64()));
|
||||
}
|
||||
throwBadKeyType();
|
||||
return init_null_variant;
|
||||
}
|
||||
|
||||
Variant c_Tuple::t_get(CVarRef key) {
|
||||
if (key.isInteger()) {
|
||||
TypedValue* tv = get(key.toInt64());
|
||||
if (tv) {
|
||||
return tvAsCVarRef(tv);
|
||||
} else {
|
||||
return init_null_variant;
|
||||
}
|
||||
}
|
||||
throwBadKeyType();
|
||||
return init_null_variant;
|
||||
}
|
||||
|
||||
Array c_Tuple::t_toarray() {
|
||||
return toArrayImpl();
|
||||
}
|
||||
|
||||
Object c_Tuple::t_getiterator() {
|
||||
c_TupleIterator* it = NEWOBJ(c_TupleIterator)();
|
||||
it->m_obj = this;
|
||||
it->m_pos = 0;
|
||||
return it;
|
||||
}
|
||||
|
||||
void c_Tuple::throwOOB(int64_t key) {
|
||||
throwIntOOB(key, true);
|
||||
}
|
||||
|
||||
void c_Tuple::throwBadKeyType() {
|
||||
Object e(SystemLib::AllocInvalidArgumentExceptionObject(
|
||||
"Only integer keys may be used with Tuples"));
|
||||
throw e;
|
||||
}
|
||||
|
||||
TypedValue* c_Tuple::OffsetGet(ObjectData* obj, TypedValue* key) {
|
||||
assert(key->m_type != KindOfRef);
|
||||
auto tup = static_cast<c_Tuple*>(obj);
|
||||
if (key->m_type == KindOfInt64) {
|
||||
return tup->at(key->m_data.num);
|
||||
}
|
||||
throwBadKeyType();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void c_Tuple::OffsetSet(ObjectData* obj, TypedValue* key, TypedValue* val) {
|
||||
Object e(SystemLib::AllocRuntimeExceptionObject(
|
||||
"Cannot assign to an element of a Tuple"));
|
||||
throw e;
|
||||
}
|
||||
|
||||
bool c_Tuple::OffsetIsset(ObjectData* obj, TypedValue* key) {
|
||||
assert(key->m_type != KindOfRef);
|
||||
auto tup = static_cast<c_Tuple*>(obj);
|
||||
TypedValue* result;
|
||||
if (key->m_type == KindOfInt64) {
|
||||
result = tup->get(key->m_data.num);
|
||||
} else {
|
||||
throwBadKeyType();
|
||||
result = NULL;
|
||||
}
|
||||
return result ? isset(tvAsCVarRef(result)) : false;
|
||||
}
|
||||
|
||||
bool c_Tuple::OffsetEmpty(ObjectData* obj, TypedValue* key) {
|
||||
assert(key->m_type != KindOfRef);
|
||||
auto tup = static_cast<c_Tuple*>(obj);
|
||||
TypedValue* result;
|
||||
if (key->m_type == KindOfInt64) {
|
||||
result = tup->get(key->m_data.num);
|
||||
} else {
|
||||
throwBadKeyType();
|
||||
result = NULL;
|
||||
}
|
||||
return result ? empty(tvAsCVarRef(result)) : true;
|
||||
}
|
||||
|
||||
bool c_Tuple::OffsetContains(ObjectData* obj, TypedValue* key) {
|
||||
assert(key->m_type != KindOfRef);
|
||||
auto tup = static_cast<c_Tuple*>(obj);
|
||||
if (key->m_type == KindOfInt64) {
|
||||
return tup->contains(key->m_data.num);
|
||||
} else {
|
||||
throwBadKeyType();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void c_Tuple::OffsetAppend(ObjectData* obj, TypedValue* val) {
|
||||
assert(val->m_type != KindOfRef);
|
||||
auto tup = static_cast<c_Tuple*>(obj);
|
||||
tup->add(val);
|
||||
}
|
||||
|
||||
void c_Tuple::OffsetUnset(ObjectData* obj, TypedValue* key) {
|
||||
Object e(SystemLib::AllocRuntimeExceptionObject(
|
||||
"Cannot unset element of a Tuple"));
|
||||
throw e;
|
||||
}
|
||||
|
||||
bool c_Tuple::Equals(ObjectData* obj1, ObjectData* obj2) {
|
||||
auto tup1 = static_cast<c_Tuple*>(obj1);
|
||||
auto tup2 = static_cast<c_Tuple*>(obj2);
|
||||
uint sz = tup1->m_size;
|
||||
if (sz != tup2->m_size) {
|
||||
return false;
|
||||
}
|
||||
TypedValue* data1 = tup1->getData();
|
||||
TypedValue* data2 = tup2->getData();
|
||||
for (uint i = 0; i < sz; ++i) {
|
||||
if (!equal(tvAsCVarRef(&data1[i]),
|
||||
tvAsCVarRef(&data2[i]))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
c_TupleIterator::c_TupleIterator(VM::Class* cb) :
|
||||
ExtObjectData(cb) {
|
||||
}
|
||||
|
||||
c_TupleIterator::~c_TupleIterator() {
|
||||
}
|
||||
|
||||
void c_TupleIterator::t___construct() {
|
||||
}
|
||||
|
||||
Variant c_TupleIterator::t_current() {
|
||||
c_Tuple* tup = m_obj.get();
|
||||
if (!tup->contains(m_pos)) {
|
||||
throw_iterator_not_valid();
|
||||
}
|
||||
return tvAsCVarRef(&tup->getData()[m_pos]);
|
||||
}
|
||||
|
||||
Variant c_TupleIterator::t_key() {
|
||||
c_Tuple* tup = m_obj.get();
|
||||
if (!tup->contains(m_pos)) {
|
||||
throw_iterator_not_valid();
|
||||
}
|
||||
return m_pos;
|
||||
}
|
||||
|
||||
bool c_TupleIterator::t_valid() {
|
||||
assert(m_pos >= 0);
|
||||
c_Tuple* tup = m_obj.get();
|
||||
return tup && (m_pos < (ssize_t)tup->m_size);
|
||||
}
|
||||
|
||||
void c_TupleIterator::t_next() {
|
||||
m_pos++;
|
||||
}
|
||||
|
||||
void c_TupleIterator::t_rewind() {
|
||||
m_pos = 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define COLLECTION_MAGIC_METHODS(cls) \
|
||||
String c_##cls::t___tostring() { \
|
||||
return #cls; \
|
||||
@@ -2746,13 +2959,15 @@ void c_StableMapIterator::t_rewind() {
|
||||
COLLECTION_MAGIC_METHODS(Vector)
|
||||
COLLECTION_MAGIC_METHODS(Map)
|
||||
COLLECTION_MAGIC_METHODS(StableMap)
|
||||
COLLECTION_MAGIC_METHODS(Tuple)
|
||||
|
||||
#undef COLLECTION_MAGIC_METHODS
|
||||
|
||||
void collectionSerialize(ObjectData* obj, VariableSerializer* serializer) {
|
||||
assert(obj->isCollection());
|
||||
int64_t sz = collectionSize(obj);
|
||||
if (obj->getCollectionType() == Collection::VectorType) {
|
||||
if (obj->getCollectionType() == Collection::VectorType ||
|
||||
obj->getCollectionType() == Collection::TupleType) {
|
||||
serializer->setObjectInfo(obj->o_getClassName(), obj->o_getId(), 'V');
|
||||
serializer->writeArrayHeader(sz, true);
|
||||
if (serializer->getType() == VariableSerializer::Serialize ||
|
||||
@@ -2830,6 +3045,9 @@ void collectionDeepCopyTV(TypedValue* tv) {
|
||||
case Collection::StableMapType:
|
||||
obj = collectionDeepCopyStableMap(static_cast<c_StableMap*>(obj));
|
||||
break;
|
||||
case Collection::TupleType:
|
||||
obj = collectionDeepCopyTuple(static_cast<c_Tuple*>(obj));
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
obj = NULL;
|
||||
@@ -2841,6 +3059,10 @@ void collectionDeepCopyTV(TypedValue* tv) {
|
||||
tv->m_data.pobj = obj;
|
||||
break;
|
||||
}
|
||||
case KindOfRef: {
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@@ -2882,18 +3104,29 @@ ObjectData* collectionDeepCopyStableMap(c_StableMap* smp) {
|
||||
return o.detach();
|
||||
}
|
||||
|
||||
CollectionInit::CollectionInit(int cType, ssize_t nElems) {
|
||||
ObjectData* collectionDeepCopyTuple(c_Tuple* tup) {
|
||||
Object o = tup = static_cast<c_Tuple*>(tup->clone());
|
||||
size_t sz = tup->m_size;
|
||||
TypedValue* data = tup->getData();
|
||||
for (size_t i = 0; i < sz; ++i) {
|
||||
collectionDeepCopyTV(&data[i]);
|
||||
}
|
||||
return o.detach();
|
||||
}
|
||||
|
||||
CollectionInit::CollectionInit(int cType, ssize_t nElms) {
|
||||
switch (cType) {
|
||||
case Collection::VectorType: m_data = NEWOBJ(c_Vector)(); break;
|
||||
case Collection::MapType: m_data = NEWOBJ(c_Map)(); break;
|
||||
case Collection::StableMapType: m_data = NEWOBJ(c_StableMap)(); break;
|
||||
case Collection::TupleType: m_data = c_Tuple::alloc(nElms); break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
// Reserve enough room for nElems elements in advance
|
||||
if (nElems) {
|
||||
collectionReserve(m_data, nElems);
|
||||
// Reserve enough room for nElms elements in advance
|
||||
if (nElms) {
|
||||
collectionReserve(m_data, nElms);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3952,6 +3952,504 @@ TypedValue* tg_17StableMapIterator_rewind(HPHP::VM::ActRec *ar) {
|
||||
return &ar->m_r;
|
||||
}
|
||||
|
||||
HPHP::VM::Instance* new_Tuple_Instance(HPHP::VM::Class* cls) {
|
||||
size_t nProps = cls->numDeclProperties();
|
||||
size_t builtinPropSize = sizeof(c_Tuple) - sizeof(ObjectData);
|
||||
size_t size = HPHP::VM::Instance::sizeForNProps(nProps) + builtinPropSize;
|
||||
HPHP::VM::Instance *inst = (HPHP::VM::Instance*)ALLOCOBJSZ(size);
|
||||
new ((void *)inst) c_Tuple(cls);
|
||||
return inst;
|
||||
}
|
||||
|
||||
IMPLEMENT_CLASS(Tuple);
|
||||
/*
|
||||
void HPHP::c_Tuple::t___construct()
|
||||
_ZN4HPHP7c_Tuple13t___constructEv
|
||||
|
||||
this_ => rdi
|
||||
*/
|
||||
|
||||
void th_5Tuple___construct(ObjectData* this_) asm("_ZN4HPHP7c_Tuple13t___constructEv");
|
||||
|
||||
TypedValue* tg_5Tuple___construct(HPHP::VM::ActRec *ar) {
|
||||
TypedValue rv;
|
||||
int64_t count = ar->numArgs();
|
||||
TypedValue* args UNUSED = ((TypedValue*)ar) - 1;
|
||||
ObjectData* this_ = (ar->hasThis() ? ar->getThis() : NULL);
|
||||
if (this_) {
|
||||
if (count == 0LL) {
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
th_5Tuple___construct((this_));
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
} else {
|
||||
throw_toomany_arguments_nr("Tuple::__construct", 0, 1);
|
||||
}
|
||||
} else {
|
||||
throw_instance_method_fatal("Tuple::__construct");
|
||||
}
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
return &ar->m_r;
|
||||
}
|
||||
|
||||
/*
|
||||
bool HPHP::c_Tuple::t_isempty()
|
||||
_ZN4HPHP7c_Tuple9t_isemptyEv
|
||||
|
||||
(return value) => rax
|
||||
this_ => rdi
|
||||
*/
|
||||
|
||||
bool th_5Tuple_isEmpty(ObjectData* this_) asm("_ZN4HPHP7c_Tuple9t_isemptyEv");
|
||||
|
||||
TypedValue* tg_5Tuple_isEmpty(HPHP::VM::ActRec *ar) {
|
||||
TypedValue rv;
|
||||
int64_t count = ar->numArgs();
|
||||
TypedValue* args UNUSED = ((TypedValue*)ar) - 1;
|
||||
ObjectData* this_ = (ar->hasThis() ? ar->getThis() : NULL);
|
||||
if (this_) {
|
||||
if (count == 0LL) {
|
||||
rv.m_type = KindOfBoolean;
|
||||
rv.m_data.num = (th_5Tuple_isEmpty((this_))) ? 1LL : 0LL;
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
} else {
|
||||
throw_toomany_arguments_nr("Tuple::isEmpty", 0, 1);
|
||||
}
|
||||
} else {
|
||||
throw_instance_method_fatal("Tuple::isEmpty");
|
||||
}
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
return &ar->m_r;
|
||||
}
|
||||
|
||||
/*
|
||||
long HPHP::c_Tuple::t_count()
|
||||
_ZN4HPHP7c_Tuple7t_countEv
|
||||
|
||||
(return value) => rax
|
||||
this_ => rdi
|
||||
*/
|
||||
|
||||
long th_5Tuple_count(ObjectData* this_) asm("_ZN4HPHP7c_Tuple7t_countEv");
|
||||
|
||||
TypedValue* tg_5Tuple_count(HPHP::VM::ActRec *ar) {
|
||||
TypedValue rv;
|
||||
int64_t count = ar->numArgs();
|
||||
TypedValue* args UNUSED = ((TypedValue*)ar) - 1;
|
||||
ObjectData* this_ = (ar->hasThis() ? ar->getThis() : NULL);
|
||||
if (this_) {
|
||||
if (count == 0LL) {
|
||||
rv.m_type = KindOfInt64;
|
||||
rv.m_data.num = (int64_t)th_5Tuple_count((this_));
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
} else {
|
||||
throw_toomany_arguments_nr("Tuple::count", 0, 1);
|
||||
}
|
||||
} else {
|
||||
throw_instance_method_fatal("Tuple::count");
|
||||
}
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
return &ar->m_r;
|
||||
}
|
||||
|
||||
/*
|
||||
HPHP::Array HPHP::c_Tuple::t_toarray()
|
||||
_ZN4HPHP7c_Tuple9t_toarrayEv
|
||||
|
||||
(return value) => rax
|
||||
_rv => rdi
|
||||
this_ => rsi
|
||||
*/
|
||||
|
||||
Value* th_5Tuple_toArray(Value* _rv, ObjectData* this_) asm("_ZN4HPHP7c_Tuple9t_toarrayEv");
|
||||
|
||||
TypedValue* tg_5Tuple_toArray(HPHP::VM::ActRec *ar) {
|
||||
TypedValue rv;
|
||||
int64_t count = ar->numArgs();
|
||||
TypedValue* args UNUSED = ((TypedValue*)ar) - 1;
|
||||
ObjectData* this_ = (ar->hasThis() ? ar->getThis() : NULL);
|
||||
if (this_) {
|
||||
if (count == 0LL) {
|
||||
rv.m_type = KindOfArray;
|
||||
th_5Tuple_toArray((Value*)(&(rv)), (this_));
|
||||
if (rv.m_data.num == 0LL) rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
} else {
|
||||
throw_toomany_arguments_nr("Tuple::toArray", 0, 1);
|
||||
}
|
||||
} else {
|
||||
throw_instance_method_fatal("Tuple::toArray");
|
||||
}
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
return &ar->m_r;
|
||||
}
|
||||
|
||||
/*
|
||||
HPHP::Object HPHP::c_Tuple::t_getiterator()
|
||||
_ZN4HPHP7c_Tuple13t_getiteratorEv
|
||||
|
||||
(return value) => rax
|
||||
_rv => rdi
|
||||
this_ => rsi
|
||||
*/
|
||||
|
||||
Value* th_5Tuple_getIterator(Value* _rv, ObjectData* this_) asm("_ZN4HPHP7c_Tuple13t_getiteratorEv");
|
||||
|
||||
TypedValue* tg_5Tuple_getIterator(HPHP::VM::ActRec *ar) {
|
||||
TypedValue rv;
|
||||
int64_t count = ar->numArgs();
|
||||
TypedValue* args UNUSED = ((TypedValue*)ar) - 1;
|
||||
ObjectData* this_ = (ar->hasThis() ? ar->getThis() : NULL);
|
||||
if (this_) {
|
||||
if (count == 0LL) {
|
||||
rv.m_type = KindOfObject;
|
||||
th_5Tuple_getIterator((Value*)(&(rv)), (this_));
|
||||
if (rv.m_data.num == 0LL) rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
} else {
|
||||
throw_toomany_arguments_nr("Tuple::getIterator", 0, 1);
|
||||
}
|
||||
} else {
|
||||
throw_instance_method_fatal("Tuple::getIterator");
|
||||
}
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
return &ar->m_r;
|
||||
}
|
||||
|
||||
/*
|
||||
HPHP::Variant HPHP::c_Tuple::t_at(HPHP::Variant const&)
|
||||
_ZN4HPHP7c_Tuple4t_atERKNS_7VariantE
|
||||
|
||||
(return value) => rax
|
||||
_rv => rdi
|
||||
this_ => rsi
|
||||
key => rdx
|
||||
*/
|
||||
|
||||
TypedValue* th_5Tuple_at(TypedValue* _rv, ObjectData* this_, TypedValue* key) asm("_ZN4HPHP7c_Tuple4t_atERKNS_7VariantE");
|
||||
|
||||
TypedValue* tg_5Tuple_at(HPHP::VM::ActRec *ar) {
|
||||
TypedValue rv;
|
||||
int64_t count = ar->numArgs();
|
||||
TypedValue* args UNUSED = ((TypedValue*)ar) - 1;
|
||||
ObjectData* this_ = (ar->hasThis() ? ar->getThis() : NULL);
|
||||
if (this_) {
|
||||
if (count == 1LL) {
|
||||
th_5Tuple_at((&(rv)), (this_), (args-0));
|
||||
if (rv.m_type == KindOfUninit) rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 1);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
} else {
|
||||
throw_wrong_arguments_nr("Tuple::at", count, 1, 1, 1);
|
||||
}
|
||||
} else {
|
||||
throw_instance_method_fatal("Tuple::at");
|
||||
}
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 1);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
return &ar->m_r;
|
||||
}
|
||||
|
||||
/*
|
||||
HPHP::Variant HPHP::c_Tuple::t_get(HPHP::Variant const&)
|
||||
_ZN4HPHP7c_Tuple5t_getERKNS_7VariantE
|
||||
|
||||
(return value) => rax
|
||||
_rv => rdi
|
||||
this_ => rsi
|
||||
key => rdx
|
||||
*/
|
||||
|
||||
TypedValue* th_5Tuple_get(TypedValue* _rv, ObjectData* this_, TypedValue* key) asm("_ZN4HPHP7c_Tuple5t_getERKNS_7VariantE");
|
||||
|
||||
TypedValue* tg_5Tuple_get(HPHP::VM::ActRec *ar) {
|
||||
TypedValue rv;
|
||||
int64_t count = ar->numArgs();
|
||||
TypedValue* args UNUSED = ((TypedValue*)ar) - 1;
|
||||
ObjectData* this_ = (ar->hasThis() ? ar->getThis() : NULL);
|
||||
if (this_) {
|
||||
if (count == 1LL) {
|
||||
th_5Tuple_get((&(rv)), (this_), (args-0));
|
||||
if (rv.m_type == KindOfUninit) rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 1);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
} else {
|
||||
throw_wrong_arguments_nr("Tuple::get", count, 1, 1, 1);
|
||||
}
|
||||
} else {
|
||||
throw_instance_method_fatal("Tuple::get");
|
||||
}
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 1);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
return &ar->m_r;
|
||||
}
|
||||
|
||||
HPHP::VM::Instance* new_TupleIterator_Instance(HPHP::VM::Class* cls) {
|
||||
size_t nProps = cls->numDeclProperties();
|
||||
size_t builtinPropSize = sizeof(c_TupleIterator) - sizeof(ObjectData);
|
||||
size_t size = HPHP::VM::Instance::sizeForNProps(nProps) + builtinPropSize;
|
||||
HPHP::VM::Instance *inst = (HPHP::VM::Instance*)ALLOCOBJSZ(size);
|
||||
new ((void *)inst) c_TupleIterator(cls);
|
||||
return inst;
|
||||
}
|
||||
|
||||
IMPLEMENT_CLASS(TupleIterator);
|
||||
/*
|
||||
void HPHP::c_TupleIterator::t___construct()
|
||||
_ZN4HPHP15c_TupleIterator13t___constructEv
|
||||
|
||||
this_ => rdi
|
||||
*/
|
||||
|
||||
void th_13TupleIterator___construct(ObjectData* this_) asm("_ZN4HPHP15c_TupleIterator13t___constructEv");
|
||||
|
||||
TypedValue* tg_13TupleIterator___construct(HPHP::VM::ActRec *ar) {
|
||||
TypedValue rv;
|
||||
int64_t count = ar->numArgs();
|
||||
TypedValue* args UNUSED = ((TypedValue*)ar) - 1;
|
||||
ObjectData* this_ = (ar->hasThis() ? ar->getThis() : NULL);
|
||||
if (this_) {
|
||||
if (count == 0LL) {
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
th_13TupleIterator___construct((this_));
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
} else {
|
||||
throw_toomany_arguments_nr("TupleIterator::__construct", 0, 1);
|
||||
}
|
||||
} else {
|
||||
throw_instance_method_fatal("TupleIterator::__construct");
|
||||
}
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
return &ar->m_r;
|
||||
}
|
||||
|
||||
/*
|
||||
HPHP::Variant HPHP::c_TupleIterator::t_current()
|
||||
_ZN4HPHP15c_TupleIterator9t_currentEv
|
||||
|
||||
(return value) => rax
|
||||
_rv => rdi
|
||||
this_ => rsi
|
||||
*/
|
||||
|
||||
TypedValue* th_13TupleIterator_current(TypedValue* _rv, ObjectData* this_) asm("_ZN4HPHP15c_TupleIterator9t_currentEv");
|
||||
|
||||
TypedValue* tg_13TupleIterator_current(HPHP::VM::ActRec *ar) {
|
||||
TypedValue rv;
|
||||
int64_t count = ar->numArgs();
|
||||
TypedValue* args UNUSED = ((TypedValue*)ar) - 1;
|
||||
ObjectData* this_ = (ar->hasThis() ? ar->getThis() : NULL);
|
||||
if (this_) {
|
||||
if (count == 0LL) {
|
||||
th_13TupleIterator_current((&(rv)), (this_));
|
||||
if (rv.m_type == KindOfUninit) rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
} else {
|
||||
throw_toomany_arguments_nr("TupleIterator::current", 0, 1);
|
||||
}
|
||||
} else {
|
||||
throw_instance_method_fatal("TupleIterator::current");
|
||||
}
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
return &ar->m_r;
|
||||
}
|
||||
|
||||
/*
|
||||
HPHP::Variant HPHP::c_TupleIterator::t_key()
|
||||
_ZN4HPHP15c_TupleIterator5t_keyEv
|
||||
|
||||
(return value) => rax
|
||||
_rv => rdi
|
||||
this_ => rsi
|
||||
*/
|
||||
|
||||
TypedValue* th_13TupleIterator_key(TypedValue* _rv, ObjectData* this_) asm("_ZN4HPHP15c_TupleIterator5t_keyEv");
|
||||
|
||||
TypedValue* tg_13TupleIterator_key(HPHP::VM::ActRec *ar) {
|
||||
TypedValue rv;
|
||||
int64_t count = ar->numArgs();
|
||||
TypedValue* args UNUSED = ((TypedValue*)ar) - 1;
|
||||
ObjectData* this_ = (ar->hasThis() ? ar->getThis() : NULL);
|
||||
if (this_) {
|
||||
if (count == 0LL) {
|
||||
th_13TupleIterator_key((&(rv)), (this_));
|
||||
if (rv.m_type == KindOfUninit) rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
} else {
|
||||
throw_toomany_arguments_nr("TupleIterator::key", 0, 1);
|
||||
}
|
||||
} else {
|
||||
throw_instance_method_fatal("TupleIterator::key");
|
||||
}
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
return &ar->m_r;
|
||||
}
|
||||
|
||||
/*
|
||||
bool HPHP::c_TupleIterator::t_valid()
|
||||
_ZN4HPHP15c_TupleIterator7t_validEv
|
||||
|
||||
(return value) => rax
|
||||
this_ => rdi
|
||||
*/
|
||||
|
||||
bool th_13TupleIterator_valid(ObjectData* this_) asm("_ZN4HPHP15c_TupleIterator7t_validEv");
|
||||
|
||||
TypedValue* tg_13TupleIterator_valid(HPHP::VM::ActRec *ar) {
|
||||
TypedValue rv;
|
||||
int64_t count = ar->numArgs();
|
||||
TypedValue* args UNUSED = ((TypedValue*)ar) - 1;
|
||||
ObjectData* this_ = (ar->hasThis() ? ar->getThis() : NULL);
|
||||
if (this_) {
|
||||
if (count == 0LL) {
|
||||
rv.m_type = KindOfBoolean;
|
||||
rv.m_data.num = (th_13TupleIterator_valid((this_))) ? 1LL : 0LL;
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
} else {
|
||||
throw_toomany_arguments_nr("TupleIterator::valid", 0, 1);
|
||||
}
|
||||
} else {
|
||||
throw_instance_method_fatal("TupleIterator::valid");
|
||||
}
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
return &ar->m_r;
|
||||
}
|
||||
|
||||
/*
|
||||
void HPHP::c_TupleIterator::t_next()
|
||||
_ZN4HPHP15c_TupleIterator6t_nextEv
|
||||
|
||||
this_ => rdi
|
||||
*/
|
||||
|
||||
void th_13TupleIterator_next(ObjectData* this_) asm("_ZN4HPHP15c_TupleIterator6t_nextEv");
|
||||
|
||||
TypedValue* tg_13TupleIterator_next(HPHP::VM::ActRec *ar) {
|
||||
TypedValue rv;
|
||||
int64_t count = ar->numArgs();
|
||||
TypedValue* args UNUSED = ((TypedValue*)ar) - 1;
|
||||
ObjectData* this_ = (ar->hasThis() ? ar->getThis() : NULL);
|
||||
if (this_) {
|
||||
if (count == 0LL) {
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
th_13TupleIterator_next((this_));
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
} else {
|
||||
throw_toomany_arguments_nr("TupleIterator::next", 0, 1);
|
||||
}
|
||||
} else {
|
||||
throw_instance_method_fatal("TupleIterator::next");
|
||||
}
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
return &ar->m_r;
|
||||
}
|
||||
|
||||
/*
|
||||
void HPHP::c_TupleIterator::t_rewind()
|
||||
_ZN4HPHP15c_TupleIterator8t_rewindEv
|
||||
|
||||
this_ => rdi
|
||||
*/
|
||||
|
||||
void th_13TupleIterator_rewind(ObjectData* this_) asm("_ZN4HPHP15c_TupleIterator8t_rewindEv");
|
||||
|
||||
TypedValue* tg_13TupleIterator_rewind(HPHP::VM::ActRec *ar) {
|
||||
TypedValue rv;
|
||||
int64_t count = ar->numArgs();
|
||||
TypedValue* args UNUSED = ((TypedValue*)ar) - 1;
|
||||
ObjectData* this_ = (ar->hasThis() ? ar->getThis() : NULL);
|
||||
if (this_) {
|
||||
if (count == 0LL) {
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
th_13TupleIterator_rewind((this_));
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
} else {
|
||||
throw_toomany_arguments_nr("TupleIterator::rewind", 0, 1);
|
||||
}
|
||||
} else {
|
||||
throw_instance_method_fatal("TupleIterator::rewind");
|
||||
}
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
frame_free_locals_inl(ar, 0);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
return &ar->m_r;
|
||||
}
|
||||
|
||||
|
||||
} // !HPHP
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@ class c_Vector : public ExtObjectDataFlags<ObjectData::VectorAttrInit|
|
||||
public: ~c_Vector();
|
||||
public: void freeData();
|
||||
public: void t___construct(CVarRef iterable = null_variant);
|
||||
public: Variant t___destruct();
|
||||
public: Object t_add(CVarRef val);
|
||||
public: Object t_append(CVarRef val);
|
||||
public: Variant t_pop();
|
||||
@@ -219,7 +218,6 @@ class c_Map : public ExtObjectDataFlags<ObjectData::MapAttrInit|
|
||||
public: ~c_Map();
|
||||
public: void freeData();
|
||||
public: void t___construct(CVarRef iterable = null_variant);
|
||||
public: Variant t___destruct();
|
||||
public: Object t_clear();
|
||||
public: bool t_isempty();
|
||||
public: int64_t t_count();
|
||||
@@ -507,7 +505,6 @@ class c_StableMap : public ExtObjectDataFlags<ObjectData::StableMapAttrInit|
|
||||
public: ~c_StableMap();
|
||||
public: void freeData();
|
||||
public: void t___construct(CVarRef iterable = null_variant);
|
||||
public: Variant t___destruct();
|
||||
public: Object t_clear();
|
||||
public: bool t_isempty();
|
||||
public: int64_t t_count();
|
||||
@@ -734,21 +731,153 @@ class c_StableMapIterator : public ExtObjectData {
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// class Tuple
|
||||
|
||||
// Helpers for hhvm
|
||||
FORWARD_DECLARE_CLASS_BUILTIN(Tuple);
|
||||
class c_Tuple : public ExtObjectDataFlags<ObjectData::TupleAttrInit|
|
||||
ObjectData::UseGet|
|
||||
ObjectData::UseSet|
|
||||
ObjectData::UseIsset|
|
||||
ObjectData::UseUnset> {
|
||||
public:
|
||||
DECLARE_CLASS_NO_ALLOCATION(Tuple, Tuple, ObjectData)
|
||||
virtual void sweep();
|
||||
void operator delete(void* p) {
|
||||
c_Tuple* this_ = (c_Tuple*)p;
|
||||
DELETEOBJSZ(sizeForNumElms(this_->m_capacity))(this_);
|
||||
}
|
||||
|
||||
friend class c_TupleIterator;
|
||||
friend class c_Vector;
|
||||
friend class c_Map;
|
||||
friend class c_StableMap;
|
||||
friend class ArrayIter;
|
||||
|
||||
public: c_Tuple(VM::Class* cls = c_Tuple::s_cls);
|
||||
public: ~c_Tuple();
|
||||
public: void t___construct();
|
||||
public: bool t_isempty();
|
||||
public: int64_t t_count();
|
||||
public: Variant t_at(CVarRef key);
|
||||
public: Variant t_get(CVarRef key);
|
||||
public: Array t_toarray();
|
||||
public: Object t_getiterator();
|
||||
public: String t___tostring();
|
||||
public: Variant t___get(Variant name);
|
||||
public: Variant t___set(Variant name, Variant value);
|
||||
public: bool t___isset(Variant name);
|
||||
public: Variant t___unset(Variant name);
|
||||
|
||||
public: static void throwOOB(int64_t key) ATTRIBUTE_COLD;
|
||||
|
||||
public: TypedValue* at(int64_t key) {
|
||||
if (UNLIKELY((uint64_t)key >= (uint64_t)m_size)) {
|
||||
throwOOB(key);
|
||||
return NULL;
|
||||
}
|
||||
return &getData()[key];
|
||||
}
|
||||
public: TypedValue* get(int64_t key) {
|
||||
if ((uint64_t)key >= (uint64_t)m_size) {
|
||||
return NULL;
|
||||
}
|
||||
return &getData()[key];
|
||||
}
|
||||
public: void add(TypedValue* val) {
|
||||
assert(val->m_type != KindOfRef);
|
||||
if (m_size == m_capacity) {
|
||||
Object e(SystemLib::AllocRuntimeExceptionObject(
|
||||
"Cannot add a new element to a Tuple"));
|
||||
throw e;
|
||||
}
|
||||
tvRefcountedIncRef(val);
|
||||
TypedValue* tv = &getData()[m_size];
|
||||
tv->m_data.num = val->m_data.num;
|
||||
tv->m_type = val->m_type;
|
||||
++m_size;
|
||||
}
|
||||
public: bool contains(int64_t key) {
|
||||
return ((uint64_t)key < (uint64_t)m_size);
|
||||
}
|
||||
|
||||
public: Array toArrayImpl() const;
|
||||
|
||||
public: Array o_toArray() const;
|
||||
public: ObjectData* clone();
|
||||
|
||||
public: static TypedValue* OffsetGet(ObjectData* obj, TypedValue* key);
|
||||
public: static void OffsetSet(ObjectData* obj, TypedValue* key,
|
||||
TypedValue* val);
|
||||
public: static bool OffsetIsset(ObjectData* obj, TypedValue* key);
|
||||
public: static bool OffsetEmpty(ObjectData* obj, TypedValue* key);
|
||||
public: static bool OffsetContains(ObjectData* obj, TypedValue* key);
|
||||
public: static void OffsetUnset(ObjectData* obj, TypedValue* key);
|
||||
public: static void OffsetAppend(ObjectData* obj, TypedValue* val);
|
||||
public: static bool Equals(ObjectData* obj1, ObjectData* obj2);
|
||||
|
||||
public: static size_t sizeForNumElms(int nElms) {
|
||||
return sizeof(c_Tuple) + sizeof(TypedValue) * nElms;
|
||||
}
|
||||
|
||||
public: static c_Tuple* alloc(int nElms) {
|
||||
c_Tuple* tup = (c_Tuple*)ALLOCOBJSZ(sizeForNumElms(nElms));
|
||||
new ((void *)tup) c_Tuple();
|
||||
tup->m_capacity = nElms;
|
||||
return tup;
|
||||
}
|
||||
|
||||
private:
|
||||
static void throwBadKeyType();
|
||||
|
||||
uint m_size;
|
||||
uint m_capacity;
|
||||
TypedValue* getData() const {
|
||||
return (TypedValue*)(this+1);
|
||||
}
|
||||
|
||||
friend ObjectData* collectionDeepCopyTuple(c_Tuple* tup);
|
||||
} __attribute__((aligned(16)));
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// class TupleIterator
|
||||
|
||||
FORWARD_DECLARE_CLASS_BUILTIN(TupleIterator);
|
||||
class c_TupleIterator : public ExtObjectData {
|
||||
public:
|
||||
DECLARE_CLASS(TupleIterator, TupleIterator, ObjectData)
|
||||
friend class c_Tuple;
|
||||
|
||||
// need to implement
|
||||
public: c_TupleIterator(VM::Class* cls = c_TupleIterator::s_cls);
|
||||
public: ~c_TupleIterator();
|
||||
public: void t___construct();
|
||||
public: Variant t_current();
|
||||
public: Variant t_key();
|
||||
public: bool t_valid();
|
||||
public: void t_next();
|
||||
public: void t_rewind();
|
||||
|
||||
private:
|
||||
SmartPtr<c_Tuple> m_obj;
|
||||
ssize_t m_pos;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline TypedValue* collectionGet(ObjectData* obj, TypedValue* key) {
|
||||
assert(key->m_type != KindOfRef);
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
return c_Vector::OffsetGet(obj, key);
|
||||
} else if (ct == Collection::MapType) {
|
||||
return c_Map::OffsetGet(obj, key);
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
return c_StableMap::OffsetGet(obj, key);
|
||||
} else {
|
||||
assert(false);
|
||||
return NULL;
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType:
|
||||
return c_Vector::OffsetGet(obj, key);
|
||||
case Collection::MapType:
|
||||
return c_Map::OffsetGet(obj, key);
|
||||
case Collection::StableMapType:
|
||||
return c_StableMap::OffsetGet(obj, key);
|
||||
case Collection::TupleType:
|
||||
return c_Tuple::OffsetGet(obj, key);
|
||||
default:
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,113 +885,147 @@ inline void collectionSet(ObjectData* obj, TypedValue* key, TypedValue* val) {
|
||||
assert(key->m_type != KindOfRef);
|
||||
assert(val->m_type != KindOfRef);
|
||||
assert(val->m_type != KindOfUninit);
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
c_Vector::OffsetSet(obj, key, val);
|
||||
} else if (ct == Collection::MapType) {
|
||||
c_Map::OffsetSet(obj, key, val);
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
c_StableMap::OffsetSet(obj, key, val);
|
||||
} else {
|
||||
assert(false);
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType:
|
||||
c_Vector::OffsetSet(obj, key, val);
|
||||
break;
|
||||
case Collection::MapType:
|
||||
c_Map::OffsetSet(obj, key, val);
|
||||
break;
|
||||
case Collection::StableMapType:
|
||||
c_StableMap::OffsetSet(obj, key, val);
|
||||
break;
|
||||
case Collection::TupleType:
|
||||
c_Tuple::OffsetSet(obj, key, val);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool collectionIsset(ObjectData* obj, TypedValue* key) {
|
||||
assert(key->m_type != KindOfRef);
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
return c_Vector::OffsetIsset(obj, key);
|
||||
} else if (ct == Collection::MapType) {
|
||||
return c_Map::OffsetIsset(obj, key);
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
return c_StableMap::OffsetIsset(obj, key);
|
||||
} else {
|
||||
assert(false);
|
||||
return false;
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType:
|
||||
return c_Vector::OffsetIsset(obj, key);
|
||||
case Collection::MapType:
|
||||
return c_Map::OffsetIsset(obj, key);
|
||||
case Collection::StableMapType:
|
||||
return c_StableMap::OffsetIsset(obj, key);
|
||||
case Collection::TupleType:
|
||||
return c_Tuple::OffsetIsset(obj, key);
|
||||
default:
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool collectionEmpty(ObjectData* obj, TypedValue* key) {
|
||||
assert(key->m_type != KindOfRef);
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
return c_Vector::OffsetEmpty(obj, key);
|
||||
} else if (ct == Collection::MapType) {
|
||||
return c_Map::OffsetEmpty(obj, key);
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
return c_StableMap::OffsetEmpty(obj, key);
|
||||
} else {
|
||||
assert(false);
|
||||
return true;
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType:
|
||||
return c_Vector::OffsetEmpty(obj, key);
|
||||
case Collection::MapType:
|
||||
return c_Map::OffsetEmpty(obj, key);
|
||||
case Collection::StableMapType:
|
||||
return c_StableMap::OffsetEmpty(obj, key);
|
||||
case Collection::TupleType:
|
||||
return c_Tuple::OffsetEmpty(obj, key);
|
||||
default:
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline void collectionUnset(ObjectData* obj, TypedValue* key) {
|
||||
assert(key->m_type != KindOfRef);
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
c_Vector::OffsetUnset(obj, key);
|
||||
} else if (ct == Collection::MapType) {
|
||||
c_Map::OffsetUnset(obj, key);
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
c_StableMap::OffsetUnset(obj, key);
|
||||
} else {
|
||||
assert(false);
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType:
|
||||
c_Vector::OffsetUnset(obj, key);
|
||||
break;
|
||||
case Collection::MapType:
|
||||
c_Map::OffsetUnset(obj, key);
|
||||
break;
|
||||
case Collection::StableMapType:
|
||||
c_StableMap::OffsetUnset(obj, key);
|
||||
break;
|
||||
case Collection::TupleType:
|
||||
c_Tuple::OffsetUnset(obj, key);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
inline void collectionAppend(ObjectData* obj, TypedValue* val) {
|
||||
assert(val->m_type != KindOfRef);
|
||||
assert(val->m_type != KindOfUninit);
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
c_Vector::OffsetAppend(obj, val);
|
||||
} else if (ct == Collection::MapType) {
|
||||
c_Map::OffsetAppend(obj, val);
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
c_StableMap::OffsetAppend(obj, val);
|
||||
} else {
|
||||
assert(false);
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType:
|
||||
c_Vector::OffsetAppend(obj, val);
|
||||
break;
|
||||
case Collection::MapType:
|
||||
c_Map::OffsetAppend(obj, val);
|
||||
break;
|
||||
case Collection::StableMapType:
|
||||
c_StableMap::OffsetAppend(obj, val);
|
||||
break;
|
||||
case Collection::TupleType:
|
||||
c_Tuple::OffsetAppend(obj, val);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers for hphpc
|
||||
|
||||
inline Variant& collectionOffsetGet(ObjectData* obj, int64_t offset) {
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
c_Vector* vec = static_cast<c_Vector*>(obj);
|
||||
return *(Variant*)(vec->at(offset));
|
||||
} else if (ct == Collection::MapType) {
|
||||
c_Map* mp = static_cast<c_Map*>(obj);
|
||||
return *(Variant*)(mp->at(offset));
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
c_StableMap* smp = static_cast<c_StableMap*>(obj);
|
||||
return *(Variant*)(smp->at(offset));
|
||||
} else {
|
||||
assert(false);
|
||||
return *(Variant*)(NULL);
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType: {
|
||||
c_Vector* vec = static_cast<c_Vector*>(obj);
|
||||
return *(Variant*)(vec->at(offset));
|
||||
}
|
||||
case Collection::MapType: {
|
||||
c_Map* mp = static_cast<c_Map*>(obj);
|
||||
return *(Variant*)(mp->at(offset));
|
||||
}
|
||||
case Collection::StableMapType: {
|
||||
c_StableMap* smp = static_cast<c_StableMap*>(obj);
|
||||
return *(Variant*)(smp->at(offset));
|
||||
}
|
||||
case Collection::TupleType: {
|
||||
c_Tuple* tup = static_cast<c_Tuple*>(obj);
|
||||
return *(Variant*)(tup->at(offset));
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
return *(Variant*)(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
inline Variant& collectionOffsetGet(ObjectData* obj, CStrRef offset) {
|
||||
StringData* key = offset.get();
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
Object e(SystemLib::AllocInvalidArgumentExceptionObject(
|
||||
"Only integer keys may be used with Vectors"));
|
||||
throw e;
|
||||
return *(Variant*)(NULL);
|
||||
} else if (ct == Collection::MapType) {
|
||||
c_Map* mp = static_cast<c_Map*>(obj);
|
||||
return *(Variant*)(mp->at(key));
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
c_StableMap* smp = static_cast<c_StableMap*>(obj);
|
||||
return *(Variant*)(smp->at(key));
|
||||
} else {
|
||||
assert(false);
|
||||
return *(Variant*)(NULL);
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType: {
|
||||
Object e(SystemLib::AllocInvalidArgumentExceptionObject(
|
||||
"Only integer keys may be used with Vectors"));
|
||||
throw e;
|
||||
}
|
||||
case Collection::MapType: {
|
||||
c_Map* mp = static_cast<c_Map*>(obj);
|
||||
return *(Variant*)(mp->at(key));
|
||||
}
|
||||
case Collection::StableMapType: {
|
||||
c_StableMap* smp = static_cast<c_StableMap*>(obj);
|
||||
return *(Variant*)(smp->at(key));
|
||||
}
|
||||
case Collection::TupleType: {
|
||||
Object e(SystemLib::AllocInvalidArgumentExceptionObject(
|
||||
"Only integer keys may be used with Tuples"));
|
||||
throw e;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
return *(Variant*)(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -871,16 +1034,18 @@ inline Variant& collectionOffsetGet(ObjectData* obj, CVarRef offset) {
|
||||
if (key->m_type == KindOfRef) {
|
||||
key = key->m_data.pref->tv();
|
||||
}
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
return *(Variant*)(c_Vector::OffsetGet(obj, key));
|
||||
} else if (ct == Collection::MapType) {
|
||||
return *(Variant*)(c_Map::OffsetGet(obj, key));
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
return *(Variant*)(c_StableMap::OffsetGet(obj, key));
|
||||
} else {
|
||||
assert(false);
|
||||
return *(Variant*)(NULL);
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType:
|
||||
return *(Variant*)(c_Vector::OffsetGet(obj, key));
|
||||
case Collection::MapType:
|
||||
return *(Variant*)(c_Map::OffsetGet(obj, key));
|
||||
case Collection::StableMapType:
|
||||
return *(Variant*)(c_StableMap::OffsetGet(obj, key));
|
||||
case Collection::TupleType:
|
||||
return *(Variant*)(c_Tuple::OffsetGet(obj, key));
|
||||
default:
|
||||
assert(false);
|
||||
return *(Variant*)(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -904,18 +1069,29 @@ inline void collectionOffsetSet(ObjectData* obj, int64_t offset, CVarRef val) {
|
||||
if (UNLIKELY(tv->m_type == KindOfUninit)) {
|
||||
tv = (TypedValue*)(&init_null_variant);
|
||||
}
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
c_Vector* vec = static_cast<c_Vector*>(obj);
|
||||
vec->put(offset, tv);
|
||||
} else if (ct == Collection::MapType) {
|
||||
c_Map* mp = static_cast<c_Map*>(obj);
|
||||
mp->put(offset, tv);
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
c_StableMap* smp = static_cast<c_StableMap*>(obj);
|
||||
smp->put(offset, tv);
|
||||
} else {
|
||||
assert(false);
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType: {
|
||||
c_Vector* vec = static_cast<c_Vector*>(obj);
|
||||
vec->put(offset, tv);
|
||||
break;
|
||||
}
|
||||
case Collection::MapType: {
|
||||
c_Map* mp = static_cast<c_Map*>(obj);
|
||||
mp->put(offset, tv);
|
||||
break;
|
||||
}
|
||||
case Collection::StableMapType: {
|
||||
c_StableMap* smp = static_cast<c_StableMap*>(obj);
|
||||
smp->put(offset, tv);
|
||||
break;
|
||||
}
|
||||
case Collection::TupleType: {
|
||||
Object e(SystemLib::AllocRuntimeExceptionObject(
|
||||
"Cannot assign to an element of a Tuple"));
|
||||
throw e;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -928,19 +1104,29 @@ inline void collectionOffsetSet(ObjectData* obj, CStrRef offset, CVarRef val) {
|
||||
if (UNLIKELY(tv->m_type == KindOfUninit)) {
|
||||
tv = (TypedValue*)(&init_null_variant);
|
||||
}
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
Object e(SystemLib::AllocInvalidArgumentExceptionObject(
|
||||
"Only integer keys may be used with Vectors"));
|
||||
throw e;
|
||||
} else if (ct == Collection::MapType) {
|
||||
c_Map* mp = static_cast<c_Map*>(obj);
|
||||
mp->put(key, tv);
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
c_StableMap* smp = static_cast<c_StableMap*>(obj);
|
||||
smp->put(key, tv);
|
||||
} else {
|
||||
assert(false);
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType: {
|
||||
Object e(SystemLib::AllocInvalidArgumentExceptionObject(
|
||||
"Only integer keys may be used with Vectors"));
|
||||
throw e;
|
||||
}
|
||||
case Collection::MapType: {
|
||||
c_Map* mp = static_cast<c_Map*>(obj);
|
||||
mp->put(key, tv);
|
||||
break;
|
||||
}
|
||||
case Collection::StableMapType: {
|
||||
c_StableMap* smp = static_cast<c_StableMap*>(obj);
|
||||
smp->put(key, tv);
|
||||
break;
|
||||
}
|
||||
case Collection::TupleType: {
|
||||
Object e(SystemLib::AllocRuntimeExceptionObject(
|
||||
"Cannot assign to an element of a Tuple"));
|
||||
throw e;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -956,15 +1142,25 @@ inline void collectionOffsetSet(ObjectData* obj, CVarRef offset, CVarRef val) {
|
||||
if (UNLIKELY(tv->m_type == KindOfUninit)) {
|
||||
tv = (TypedValue*)(&init_null_variant);
|
||||
}
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
c_Vector::OffsetSet(obj, key, tv);
|
||||
} else if (ct == Collection::MapType) {
|
||||
c_Map::OffsetSet(obj, key, tv);
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
c_StableMap::OffsetSet(obj, key, tv);
|
||||
} else {
|
||||
assert(false);
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType: {
|
||||
c_Vector::OffsetSet(obj, key, tv);
|
||||
break;
|
||||
}
|
||||
case Collection::MapType: {
|
||||
c_Map::OffsetSet(obj, key, tv);
|
||||
break;
|
||||
}
|
||||
case Collection::StableMapType: {
|
||||
c_StableMap::OffsetSet(obj, key, tv);
|
||||
break;
|
||||
}
|
||||
case Collection::TupleType: {
|
||||
c_Tuple::OffsetSet(obj, key, tv);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -985,16 +1181,18 @@ inline bool collectionOffsetContains(ObjectData* obj, CVarRef offset) {
|
||||
if (key->m_type == KindOfRef) {
|
||||
key = key->m_data.pref->tv();
|
||||
}
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
return c_Vector::OffsetContains(obj, key);
|
||||
} else if (ct == Collection::MapType) {
|
||||
return c_Map::OffsetContains(obj, key);
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
return c_StableMap::OffsetContains(obj, key);
|
||||
} else {
|
||||
assert(false);
|
||||
return false;
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType:
|
||||
return c_Vector::OffsetContains(obj, key);
|
||||
case Collection::MapType:
|
||||
return c_Map::OffsetContains(obj, key);
|
||||
case Collection::StableMapType:
|
||||
return c_StableMap::OffsetContains(obj, key);
|
||||
case Collection::TupleType:
|
||||
return c_Tuple::OffsetContains(obj, key);
|
||||
default:
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1003,16 +1201,18 @@ inline bool collectionOffsetIsset(ObjectData* obj, CVarRef offset) {
|
||||
if (key->m_type == KindOfRef) {
|
||||
key = key->m_data.pref->tv();
|
||||
}
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
return c_Vector::OffsetIsset(obj, key);
|
||||
} else if (ct == Collection::MapType) {
|
||||
return c_Map::OffsetIsset(obj, key);
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
return c_StableMap::OffsetIsset(obj, key);
|
||||
} else {
|
||||
assert(false);
|
||||
return false;
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType:
|
||||
return c_Vector::OffsetIsset(obj, key);
|
||||
case Collection::MapType:
|
||||
return c_Map::OffsetIsset(obj, key);
|
||||
case Collection::StableMapType:
|
||||
return c_StableMap::OffsetIsset(obj, key);
|
||||
case Collection::TupleType:
|
||||
return c_Tuple::OffsetIsset(obj, key);
|
||||
default:
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1021,16 +1221,18 @@ inline bool collectionOffsetEmpty(ObjectData* obj, CVarRef offset) {
|
||||
if (key->m_type == KindOfRef) {
|
||||
key = key->m_data.pref->tv();
|
||||
}
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
return c_Vector::OffsetEmpty(obj, key);
|
||||
} else if (ct == Collection::MapType) {
|
||||
return c_Map::OffsetEmpty(obj, key);
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
return c_StableMap::OffsetEmpty(obj, key);
|
||||
} else {
|
||||
assert(false);
|
||||
return true;
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType:
|
||||
return c_Vector::OffsetEmpty(obj, key);
|
||||
case Collection::MapType:
|
||||
return c_Map::OffsetEmpty(obj, key);
|
||||
case Collection::StableMapType:
|
||||
return c_StableMap::OffsetEmpty(obj, key);
|
||||
case Collection::TupleType:
|
||||
return c_Tuple::OffsetEmpty(obj, key);
|
||||
default:
|
||||
assert(false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1054,29 +1256,37 @@ inline void collectionOffsetAppend(ObjectData* obj, CVarRef val) {
|
||||
}
|
||||
|
||||
inline int64_t collectionSize(ObjectData* obj) {
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
return static_cast<c_Vector*>(obj)->t_count();
|
||||
} else if (ct == Collection::MapType) {
|
||||
return static_cast<c_Map*>(obj)->t_count();
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
return static_cast<c_StableMap*>(obj)->t_count();
|
||||
} else {
|
||||
assert(false);
|
||||
return 0;
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType:
|
||||
return static_cast<c_Vector*>(obj)->t_count();
|
||||
case Collection::MapType:
|
||||
return static_cast<c_Map*>(obj)->t_count();
|
||||
case Collection::StableMapType:
|
||||
return static_cast<c_StableMap*>(obj)->t_count();
|
||||
case Collection::TupleType:
|
||||
return static_cast<c_Tuple*>(obj)->t_count();
|
||||
default:
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void collectionReserve(ObjectData* obj, int64_t sz) {
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
static_cast<c_Vector*>(obj)->reserve(sz);
|
||||
} else if (ct == Collection::MapType) {
|
||||
static_cast<c_Map*>(obj)->reserve(sz);
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
static_cast<c_StableMap*>(obj)->reserve(sz);
|
||||
} else {
|
||||
assert(false);
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType:
|
||||
static_cast<c_Vector*>(obj)->reserve(sz);
|
||||
break;
|
||||
case Collection::MapType:
|
||||
static_cast<c_Map*>(obj)->reserve(sz);
|
||||
break;
|
||||
case Collection::StableMapType:
|
||||
static_cast<c_StableMap*>(obj)->reserve(sz);
|
||||
break;
|
||||
case Collection::TupleType:
|
||||
// do nothing
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1089,26 +1299,31 @@ void collectionUnserialize(ObjectData* obj,
|
||||
inline bool collectionEquals(ObjectData* obj1, ObjectData* obj2) {
|
||||
int ct = obj1->getCollectionType();
|
||||
assert(ct == obj2->getCollectionType());
|
||||
if (ct == Collection::VectorType) {
|
||||
return c_Vector::Equals(obj1, obj2);
|
||||
} else if (ct == Collection::MapType) {
|
||||
return c_Map::Equals(obj1, obj2);
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
return c_StableMap::Equals(obj1, obj2);
|
||||
switch (ct) {
|
||||
case Collection::VectorType:
|
||||
return c_Vector::Equals(obj1, obj2);
|
||||
case Collection::MapType:
|
||||
return c_Map::Equals(obj1, obj2);
|
||||
case Collection::StableMapType:
|
||||
return c_StableMap::Equals(obj1, obj2);
|
||||
case Collection::TupleType:
|
||||
return c_Tuple::Equals(obj1, obj2);
|
||||
default:
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
void collectionDeepCopyTV(TypedValue* tv);
|
||||
ArrayData* collectionDeepCopyArray(ArrayData* arr);
|
||||
ObjectData* collectionDeepCopyVector(c_Vector* vec);
|
||||
ObjectData* collectionDeepCopyMap(c_Map* vec);
|
||||
ObjectData* collectionDeepCopyStableMap(c_StableMap* vec);
|
||||
ObjectData* collectionDeepCopyMap(c_Map* mp);
|
||||
ObjectData* collectionDeepCopyStableMap(c_StableMap* smp);
|
||||
ObjectData* collectionDeepCopyTuple(c_Tuple* tup);
|
||||
|
||||
class CollectionInit {
|
||||
public:
|
||||
CollectionInit(int cType, ssize_t nElems);
|
||||
CollectionInit(int cType, ssize_t nElms);
|
||||
~CollectionInit() {
|
||||
// In case an exception interrupts the initialization.
|
||||
if (m_data) m_data->release();
|
||||
@@ -1174,6 +1389,7 @@ private:
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
|
||||
#endif // __EXT_COLLECTION_H__
|
||||
|
||||
@@ -2383,6 +2383,21 @@ TypedValue* tg_17StableMapIterator_key(VM::ActRec *ar);
|
||||
TypedValue* tg_17StableMapIterator_valid(VM::ActRec *ar);
|
||||
TypedValue* tg_17StableMapIterator_next(VM::ActRec *ar);
|
||||
TypedValue* tg_17StableMapIterator_rewind(VM::ActRec *ar);
|
||||
VM::Instance* new_Tuple_Instance(VM::Class*);
|
||||
TypedValue* tg_5Tuple___construct(VM::ActRec *ar);
|
||||
TypedValue* tg_5Tuple_isEmpty(VM::ActRec *ar);
|
||||
TypedValue* tg_5Tuple_count(VM::ActRec *ar);
|
||||
TypedValue* tg_5Tuple_toArray(VM::ActRec *ar);
|
||||
TypedValue* tg_5Tuple_getIterator(VM::ActRec *ar);
|
||||
TypedValue* tg_5Tuple_at(VM::ActRec *ar);
|
||||
TypedValue* tg_5Tuple_get(VM::ActRec *ar);
|
||||
VM::Instance* new_TupleIterator_Instance(VM::Class*);
|
||||
TypedValue* tg_13TupleIterator___construct(VM::ActRec *ar);
|
||||
TypedValue* tg_13TupleIterator_current(VM::ActRec *ar);
|
||||
TypedValue* tg_13TupleIterator_key(VM::ActRec *ar);
|
||||
TypedValue* tg_13TupleIterator_valid(VM::ActRec *ar);
|
||||
TypedValue* tg_13TupleIterator_next(VM::ActRec *ar);
|
||||
TypedValue* tg_13TupleIterator_rewind(VM::ActRec *ar);
|
||||
VM::Instance* new_Continuation_Instance(VM::Class*);
|
||||
TypedValue* tg_12Continuation___construct(VM::ActRec *ar);
|
||||
TypedValue* tg_12Continuation_update(VM::ActRec *ar);
|
||||
@@ -5427,6 +5442,27 @@ static const HhbcExtMethodInfo hhbc_ext_methods_StableMapIterator[] = {
|
||||
{ "rewind", tg_17StableMapIterator_rewind }
|
||||
};
|
||||
|
||||
static const long long hhbc_ext_method_count_Tuple = 7;
|
||||
static const HhbcExtMethodInfo hhbc_ext_methods_Tuple[] = {
|
||||
{ "__construct", tg_5Tuple___construct },
|
||||
{ "isEmpty", tg_5Tuple_isEmpty },
|
||||
{ "count", tg_5Tuple_count },
|
||||
{ "toArray", tg_5Tuple_toArray },
|
||||
{ "getIterator", tg_5Tuple_getIterator },
|
||||
{ "at", tg_5Tuple_at },
|
||||
{ "get", tg_5Tuple_get }
|
||||
};
|
||||
|
||||
static const long long hhbc_ext_method_count_TupleIterator = 6;
|
||||
static const HhbcExtMethodInfo hhbc_ext_methods_TupleIterator[] = {
|
||||
{ "__construct", tg_13TupleIterator___construct },
|
||||
{ "current", tg_13TupleIterator_current },
|
||||
{ "key", tg_13TupleIterator_key },
|
||||
{ "valid", tg_13TupleIterator_valid },
|
||||
{ "next", tg_13TupleIterator_next },
|
||||
{ "rewind", tg_13TupleIterator_rewind }
|
||||
};
|
||||
|
||||
static const long long hhbc_ext_method_count_Continuation = 18;
|
||||
static const HhbcExtMethodInfo hhbc_ext_methods_Continuation[] = {
|
||||
{ "__construct", tg_12Continuation___construct },
|
||||
@@ -6207,7 +6243,7 @@ static const HhbcExtMethodInfo hhbc_ext_methods_XMLWriter[] = {
|
||||
{ "outputMemory", tg_9XMLWriter_outputMemory }
|
||||
};
|
||||
|
||||
const long long hhbc_ext_class_count = 71;
|
||||
const long long hhbc_ext_class_count = 73;
|
||||
const HhbcExtClassInfo hhbc_ext_classes[] = {
|
||||
{ "WaitHandle", nullptr, sizeof(c_WaitHandle), hhbc_ext_method_count_WaitHandle, hhbc_ext_methods_WaitHandle, &c_WaitHandle::s_cls },
|
||||
{ "StaticWaitHandle", nullptr, sizeof(c_StaticWaitHandle), hhbc_ext_method_count_StaticWaitHandle, hhbc_ext_methods_StaticWaitHandle, &c_StaticWaitHandle::s_cls },
|
||||
@@ -6227,6 +6263,8 @@ const HhbcExtClassInfo hhbc_ext_classes[] = {
|
||||
{ "MapIterator", new_MapIterator_Instance, sizeof(c_MapIterator), hhbc_ext_method_count_MapIterator, hhbc_ext_methods_MapIterator, &c_MapIterator::s_cls },
|
||||
{ "StableMap", new_StableMap_Instance, sizeof(c_StableMap), hhbc_ext_method_count_StableMap, hhbc_ext_methods_StableMap, &c_StableMap::s_cls },
|
||||
{ "StableMapIterator", new_StableMapIterator_Instance, sizeof(c_StableMapIterator), hhbc_ext_method_count_StableMapIterator, hhbc_ext_methods_StableMapIterator, &c_StableMapIterator::s_cls },
|
||||
{ "Tuple", new_Tuple_Instance, sizeof(c_Tuple), hhbc_ext_method_count_Tuple, hhbc_ext_methods_Tuple, &c_Tuple::s_cls },
|
||||
{ "TupleIterator", new_TupleIterator_Instance, sizeof(c_TupleIterator), hhbc_ext_method_count_TupleIterator, hhbc_ext_methods_TupleIterator, &c_TupleIterator::s_cls },
|
||||
{ "Continuation", new_Continuation_Instance, sizeof(c_Continuation), hhbc_ext_method_count_Continuation, hhbc_ext_methods_Continuation, &c_Continuation::s_cls },
|
||||
{ "DummyContinuation", new_DummyContinuation_Instance, sizeof(c_DummyContinuation), hhbc_ext_method_count_DummyContinuation, hhbc_ext_methods_DummyContinuation, &c_DummyContinuation::s_cls },
|
||||
{ "DateTime", new_DateTime_Instance, sizeof(c_DateTime), hhbc_ext_method_count_DateTime, hhbc_ext_methods_DateTime, &c_DateTime::s_cls },
|
||||
|
||||
@@ -3942,20 +3942,21 @@ inline void OPTBLD_INLINE VMExecutionContext::iopAddNewElemV(PC& pc) {
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopNewCol(PC& pc) {
|
||||
NEXT();
|
||||
DECODE_IVA(cType);
|
||||
DECODE_IVA(nElems);
|
||||
DECODE_IVA(nElms);
|
||||
ObjectData* obj;
|
||||
switch (cType) {
|
||||
case Collection::VectorType: obj = NEWOBJ(c_Vector)(); break;
|
||||
case Collection::MapType: obj = NEWOBJ(c_Map)(); break;
|
||||
case Collection::StableMapType: obj = NEWOBJ(c_StableMap)(); break;
|
||||
case Collection::TupleType: obj = c_Tuple::alloc(nElms); break;
|
||||
default:
|
||||
obj = nullptr;
|
||||
raise_error("NewCol: Invalid collection type");
|
||||
break;
|
||||
}
|
||||
// Reserve enough room for nElems elements in advance
|
||||
if (nElems) {
|
||||
collectionReserve(obj, nElems);
|
||||
// Reserve enough room for nElms elements in advance
|
||||
if (nElms) {
|
||||
collectionReserve(obj, nElms);
|
||||
}
|
||||
m_stack.pushObject(obj);
|
||||
}
|
||||
|
||||
@@ -80,19 +80,26 @@ ArrayData* new_tuple(int n, const TypedValue* values) {
|
||||
|
||||
#define NEW_COLLECTION_HELPER(name) \
|
||||
ObjectData* \
|
||||
new##name##Helper(int nElems) { \
|
||||
new##name##Helper(int nElms) { \
|
||||
ObjectData *obj = NEWOBJ(c_##name)(); \
|
||||
obj->incRefCount(); \
|
||||
if (nElems) { \
|
||||
collectionReserve(obj, nElems); \
|
||||
if (nElms) { \
|
||||
collectionReserve(obj, nElms); \
|
||||
} \
|
||||
TRACE(2, "new" #name "Helper: capacity %d\n", nElems); \
|
||||
TRACE(2, "new" #name "Helper: capacity %d\n", nElms); \
|
||||
return obj; \
|
||||
}
|
||||
|
||||
NEW_COLLECTION_HELPER(Vector)
|
||||
NEW_COLLECTION_HELPER(Map)
|
||||
NEW_COLLECTION_HELPER(StableMap)
|
||||
|
||||
ObjectData* newTupleHelper(int nElms) {
|
||||
ObjectData *obj = c_Tuple::alloc(nElms);
|
||||
obj->incRefCount();
|
||||
TRACE(2, "newTupleHelper: capacity %d\n", nElms);
|
||||
return obj;
|
||||
}
|
||||
|
||||
#undef NEW_COLLECTION_HELPER
|
||||
|
||||
@@ -419,37 +426,58 @@ void collection_setm_wk1_v0(ObjectData* obj, TypedValue* value) {
|
||||
|
||||
void collection_setm_ik1_v0(ObjectData* obj, int64_t key, TypedValue* value) {
|
||||
assert(obj);
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
c_Vector* vec = static_cast<c_Vector*>(obj);
|
||||
vec->put(key, value);
|
||||
} else if (ct == Collection::MapType) {
|
||||
c_Map* mp = static_cast<c_Map*>(obj);
|
||||
mp->put(key, value);
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
c_StableMap* smp = static_cast<c_StableMap*>(obj);
|
||||
smp->put(key, value);
|
||||
} else {
|
||||
assert(false);
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType: {
|
||||
c_Vector* vec = static_cast<c_Vector*>(obj);
|
||||
vec->put(key, value);
|
||||
break;
|
||||
}
|
||||
case Collection::MapType: {
|
||||
c_Map* mp = static_cast<c_Map*>(obj);
|
||||
mp->put(key, value);
|
||||
break;
|
||||
}
|
||||
case Collection::StableMapType: {
|
||||
c_StableMap* smp = static_cast<c_StableMap*>(obj);
|
||||
smp->put(key, value);
|
||||
break;
|
||||
}
|
||||
case Collection::TupleType: {
|
||||
Object e(SystemLib::AllocRuntimeExceptionObject(
|
||||
"Cannot assign to an element of a Tuple"));
|
||||
throw e;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
tvRefcountedDecRef(value);
|
||||
}
|
||||
|
||||
void collection_setm_sk1_v0(ObjectData* obj, StringData* key,
|
||||
TypedValue* value) {
|
||||
int ct = obj->getCollectionType();
|
||||
if (ct == Collection::VectorType) {
|
||||
Object e(SystemLib::AllocInvalidArgumentExceptionObject(
|
||||
"Only integer keys may be used with Vectors"));
|
||||
throw e;
|
||||
} else if (ct == Collection::MapType) {
|
||||
c_Map* mp = static_cast<c_Map*>(obj);
|
||||
mp->put(key, value);
|
||||
} else if (ct == Collection::StableMapType) {
|
||||
c_StableMap* smp = static_cast<c_StableMap*>(obj);
|
||||
smp->put(key, value);
|
||||
} else {
|
||||
assert(false);
|
||||
switch (obj->getCollectionType()) {
|
||||
case Collection::VectorType: {
|
||||
Object e(SystemLib::AllocInvalidArgumentExceptionObject(
|
||||
"Only integer keys may be used with Vectors"));
|
||||
throw e;
|
||||
}
|
||||
case Collection::MapType: {
|
||||
c_Map* mp = static_cast<c_Map*>(obj);
|
||||
mp->put(key, value);
|
||||
break;
|
||||
}
|
||||
case Collection::StableMapType: {
|
||||
c_StableMap* smp = static_cast<c_StableMap*>(obj);
|
||||
smp->put(key, value);
|
||||
break;
|
||||
}
|
||||
case Collection::TupleType: {
|
||||
Object e(SystemLib::AllocRuntimeExceptionObject(
|
||||
"Cannot assign to an element of a Tuple"));
|
||||
throw e;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
tvRefcountedDecRef(value);
|
||||
}
|
||||
|
||||
@@ -28,9 +28,10 @@ namespace VM {
|
||||
ArrayData* new_array(int capacity);
|
||||
ArrayData* new_tuple(int numArgs, const TypedValue* args);
|
||||
|
||||
ObjectData* newVectorHelper(int nElems);
|
||||
ObjectData* newMapHelper(int nElems);
|
||||
ObjectData* newStableMapHelper(int nElems);
|
||||
ObjectData* newVectorHelper(int nElms);
|
||||
ObjectData* newMapHelper(int nElms);
|
||||
ObjectData* newStableMapHelper(int nElms);
|
||||
ObjectData* newTupleHelper(int nElms);
|
||||
|
||||
StringData* concat_is(int64_t v1, StringData* v2);
|
||||
StringData* concat_si(StringData* v1, int64_t v2);
|
||||
|
||||
@@ -5374,12 +5374,14 @@ TranslatorX64::translateNewCol(const Tracelet& t,
|
||||
case Collection::VectorType: fptr = (void*)newVectorHelper; break;
|
||||
case Collection::MapType: fptr = (void*)newMapHelper; break;
|
||||
case Collection::StableMapType: fptr = (void*)newStableMapHelper; break;
|
||||
case Collection::TupleType: fptr = (void*)newTupleHelper; break;
|
||||
default: assert(false); break;
|
||||
}
|
||||
if (false) {
|
||||
ObjectData* obj1 UNUSED = newVectorHelper(42);
|
||||
ObjectData* obj2 UNUSED = newMapHelper(42);
|
||||
ObjectData* obj3 UNUSED = newStableMapHelper(42);
|
||||
ObjectData* obj4 UNUSED = newTupleHelper(42);
|
||||
}
|
||||
EMIT_CALL(a, fptr, IMM(nElems));
|
||||
m_regMap.bind(rax, i.outStack->location, KindOfObject, RegInfo::DIRTY);
|
||||
|
||||
@@ -23009,6 +23009,87 @@ const char *g_class_map[] = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006020, "Tuple", "", "", (const char *)0, (const char *)0,
|
||||
"/**\n * ( excerpt from http://php.net/manual/en/class.tuple.php )\n *\n * An ordered fixed-sized container.\n *\n */",
|
||||
"keyediterable", "countable", NULL,
|
||||
(const char *)0x10006040, "__construct", "", (const char*)0, (const char*)0,
|
||||
"/**\n * ( excerpt from http://php.net/manual/en/tuple.construct.php )\n *\n *\n */",
|
||||
(const char *)-1, NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006040, "isEmpty", "", (const char*)0, (const char*)0,
|
||||
"/**\n * ( excerpt from http://php.net/manual/en/tuple.isempty.php )\n *\n * Returns true if this Tuple is empty, false otherwise.\n *\n * @return bool\n */",
|
||||
(const char *)0x9, NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006040, "count", "", (const char*)0, (const char*)0,
|
||||
"/**\n * ( excerpt from http://php.net/manual/en/tuple.count.php )\n *\n * Returns the number of values in the Tuple.\n *\n * @return int\n */",
|
||||
(const char *)0xa, NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006040, "toArray", "", (const char*)0, (const char*)0,
|
||||
"/**\n * ( excerpt from http://php.net/manual/en/tuple.toarray.php )\n *\n * Returns an array containing the values from this Tuple.\n *\n * @return map\n */",
|
||||
(const char *)0x20, NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006040, "getIterator", "", (const char*)0, (const char*)0,
|
||||
"/**\n * ( excerpt from http://php.net/manual/en/tuple.getiterator.php )\n *\n * Returns an iterator that points to beginning of this Tuple.\n *\n * @return object\n */",
|
||||
(const char *)0x40, NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006040, "at", "", (const char*)0, (const char*)0,
|
||||
"/**\n * ( excerpt from http://php.net/manual/en/tuple.at.php )\n *\n * Returns the value at the specified key. If the key is not present, an\n * exception is thrown.\n *\n * @key mixed\n *\n * @return mixed\n */",
|
||||
(const char *)0xffffffff, (const char *)0x2000, "key", "", (const char *)0xffffffff, "", "", NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006040, "get", "", (const char*)0, (const char*)0,
|
||||
"/**\n * ( excerpt from http://php.net/manual/en/tuple.get.php )\n *\n * Returns the value at the specified key. If the key is not present, null\n * is returned.\n *\n * @key mixed\n *\n * @return mixed\n */",
|
||||
(const char *)0xffffffff, (const char *)0x2000, "key", "", (const char *)0xffffffff, "", "", NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006020, "TupleIterator", "", "", (const char *)0, (const char *)0,
|
||||
"/**\n * ( excerpt from http://php.net/manual/en/class.tupleiterator.php )\n *\n * An iterator implementation for iterating over a Tuple.\n *\n */",
|
||||
"keyediterator", NULL,
|
||||
(const char *)0x10006040, "__construct", "", (const char*)0, (const char*)0,
|
||||
"/**\n * ( excerpt from http://php.net/manual/en/tupleiterator.construct.php )\n *\n *\n */",
|
||||
(const char *)-1, NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006040, "current", "", (const char*)0, (const char*)0,
|
||||
"/**\n * ( excerpt from http://php.net/manual/en/tupleiterator.current.php )\n *\n * Returns the current value that the iterator points to.\n *\n * @return mixed\n */",
|
||||
(const char *)0xffffffff, NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006040, "key", "", (const char*)0, (const char*)0,
|
||||
"/**\n * ( excerpt from http://php.net/manual/en/tupleiterator.key.php )\n *\n * Returns the current key that the iterator points to.\n *\n * @return mixed\n */",
|
||||
(const char *)0xffffffff, NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006040, "valid", "", (const char*)0, (const char*)0,
|
||||
"/**\n * ( excerpt from http://php.net/manual/en/tupleiterator.valid.php )\n *\n * Returns true if the iterator points to a valid value, returns false\n * otherwise.\n *\n * @return bool\n */",
|
||||
(const char *)0x9, NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006040, "next", "", (const char*)0, (const char*)0,
|
||||
"/**\n * ( excerpt from http://php.net/manual/en/tupleiterator.next.php )\n *\n * Advance this iterator forward one position.\n *\n */",
|
||||
(const char *)-1, NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006040, "rewind", "", (const char*)0, (const char*)0,
|
||||
"/**\n * ( excerpt from http://php.net/manual/en/tupleiterator.rewind.php )\n *\n * Move this iterator back to the first position.\n *\n */",
|
||||
(const char *)-1, NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006000, "PDO", "", "", (const char *)0, (const char *)0,
|
||||
"/**\n * ( excerpt from http://php.net/manual/en/class.pdo.php )\n *\n * Represents a connection between PHP and a database server.\n *\n */",
|
||||
NULL,
|
||||
|
||||
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
@@ -59,6 +59,7 @@ namespace Eval {
|
||||
x(JsonSerializable) \
|
||||
x(Traversable) \
|
||||
x(Countable) \
|
||||
x(__PHP_Incomplete_Class) \
|
||||
|
||||
class SystemLib {
|
||||
public:
|
||||
|
||||
@@ -9784,6 +9784,141 @@ bool TestCodeRun::TestCollectionClasses() {
|
||||
" int(72)\n"
|
||||
"}\n"
|
||||
);
|
||||
|
||||
MVCRO("<?hh\n"
|
||||
"function g((string,int,string) $t) {}\n"
|
||||
"class C {\n"
|
||||
" public $t = Tuple {'foo', 42, '!'};\n"
|
||||
"}\n"
|
||||
"function f() {\n"
|
||||
" $t = Tuple {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,\n"
|
||||
" 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,\n"
|
||||
" 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};\n"
|
||||
" var_dump(count($t));\n"
|
||||
" var_dump($t->count());\n"
|
||||
" var_dump($t->isEmpty());\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" $c = new C;\n"
|
||||
" $t = $c->t;\n"
|
||||
" var_dump(count($t));\n"
|
||||
" var_dump($t->count());\n"
|
||||
" var_dump($t->isEmpty());\n"
|
||||
" g($t);\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" foreach ($t as $k => $v) {\n"
|
||||
" var_dump($k, $v);\n"
|
||||
" }\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump($t[0], $t[1], $t[2]);\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump($t->at(0), $t->at(1), $t->at(2));\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump($t->get(0), $t->get(1), $t->get(2), $t->get(3));\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump((array)$t);\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump(serialize($t));\n"
|
||||
" var_dump(unserialize(serialize($t)));\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump($t->count());\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump($t->getIterator() instanceof Iterator);\n"
|
||||
" var_dump($t->getIterator() instanceof KeyedIterator);\n"
|
||||
" foreach ($t->getIterator() as $k => $v) {\n"
|
||||
" var_dump($k, $v);\n"
|
||||
" }\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump((array)$t);\n"
|
||||
" var_dump($t->toArray());\n"
|
||||
" echo \"==========\\n\";\n"
|
||||
" var_dump(clone $t);\n"
|
||||
"}\n"
|
||||
"f();\n"
|
||||
,
|
||||
"int(32)\n"
|
||||
"int(32)\n"
|
||||
"bool(false)\n"
|
||||
"==========\n"
|
||||
"int(3)\n"
|
||||
"int(3)\n"
|
||||
"bool(false)\n"
|
||||
"==========\n"
|
||||
"int(0)\n"
|
||||
"string(3) \"foo\"\n"
|
||||
"int(1)\n"
|
||||
"int(42)\n"
|
||||
"int(2)\n"
|
||||
"string(1) \"!\"\n"
|
||||
"==========\n"
|
||||
"string(3) \"foo\"\n"
|
||||
"int(42)\n"
|
||||
"string(1) \"!\"\n"
|
||||
"==========\n"
|
||||
"string(3) \"foo\"\n"
|
||||
"int(42)\n"
|
||||
"string(1) \"!\"\n"
|
||||
"==========\n"
|
||||
"string(3) \"foo\"\n"
|
||||
"int(42)\n"
|
||||
"string(1) \"!\"\n"
|
||||
"NULL\n"
|
||||
"==========\n"
|
||||
"array(3) {\n"
|
||||
" [0]=>\n"
|
||||
" string(3) \"foo\"\n"
|
||||
" [1]=>\n"
|
||||
" int(42)\n"
|
||||
" [2]=>\n"
|
||||
" string(1) \"!\"\n"
|
||||
"}\n"
|
||||
"==========\n"
|
||||
"string(39) \"V:5:\"Tuple\":3:{s:3:\"foo\";i:42;s:1:\"!\";}\"\n"
|
||||
"object(Tuple)#6 (3) {\n"
|
||||
" [0]=>\n"
|
||||
" string(3) \"foo\"\n"
|
||||
" [1]=>\n"
|
||||
" int(42)\n"
|
||||
" [2]=>\n"
|
||||
" string(1) \"!\"\n"
|
||||
"}\n"
|
||||
"==========\n"
|
||||
"int(3)\n"
|
||||
"==========\n"
|
||||
"bool(true)\n"
|
||||
"bool(true)\n"
|
||||
"int(0)\n"
|
||||
"string(3) \"foo\"\n"
|
||||
"int(1)\n"
|
||||
"int(42)\n"
|
||||
"int(2)\n"
|
||||
"string(1) \"!\"\n"
|
||||
"==========\n"
|
||||
"array(3) {\n"
|
||||
" [0]=>\n"
|
||||
" string(3) \"foo\"\n"
|
||||
" [1]=>\n"
|
||||
" int(42)\n"
|
||||
" [2]=>\n"
|
||||
" string(1) \"!\"\n"
|
||||
"}\n"
|
||||
"array(3) {\n"
|
||||
" [0]=>\n"
|
||||
" string(3) \"foo\"\n"
|
||||
" [1]=>\n"
|
||||
" int(42)\n"
|
||||
" [2]=>\n"
|
||||
" string(1) \"!\"\n"
|
||||
"}\n"
|
||||
"==========\n"
|
||||
"object(Tuple)#6 (3) {\n"
|
||||
" [0]=>\n"
|
||||
" string(3) \"foo\"\n"
|
||||
" [1]=>\n"
|
||||
" int(42)\n"
|
||||
" [2]=>\n"
|
||||
" string(1) \"!\"\n"
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -2532,15 +2532,16 @@ sm_type:
|
||||
}
|
||||
| T_ARRAY { $$.setText("array"); }
|
||||
| T_ARRAY T_TYPELIST_LT sm_type
|
||||
T_TYPELIST_GT { only_in_strict_mode(_p); $$.setText("array"); }
|
||||
T_TYPELIST_GT { only_in_strict_mode(_p);
|
||||
$$.setText("array"); }
|
||||
| T_ARRAY T_TYPELIST_LT sm_type ','
|
||||
sm_type T_TYPELIST_GT { only_in_strict_mode(_p); $$.setText("array"); }
|
||||
sm_type T_TYPELIST_GT { only_in_strict_mode(_p);
|
||||
$$.setText("array"); }
|
||||
| T_XHP_LABEL { $1.xhpLabel(); $$ = $1; }
|
||||
| '(' T_FUNCTION
|
||||
'(' sm_func_type_list ')'
|
||||
':' sm_type ')' { only_in_strict_mode(_p); $$.reset(); }
|
||||
| '(' sm_type_list ',' sm_type ')' { only_in_strict_mode(_p);
|
||||
$$.setText("array"); }
|
||||
| '(' sm_type_list ',' sm_type ')' { only_in_strict_mode(_p); $$.reset(); }
|
||||
;
|
||||
|
||||
sm_type_opt:
|
||||
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
Referência em uma Nova Issue
Bloquear um usuário