Devirtualize ArrayData part 1
Moves about half of ArrayData virtual methods to g_array_funcs as static functions instead of virtual functions. This is mostly a mechanical factor, except a handful of methods that are specialized for Vector instead of generic HphpArray.
Esse commit está contido em:
@@ -193,6 +193,100 @@ inline ArrayData* ArrayData::set(StringData* k, CVarRef v, bool copy) {
|
||||
return g_array_funcs.setStr[m_kind](this, k, v, copy);
|
||||
}
|
||||
|
||||
inline size_t ArrayData::vsize() const {
|
||||
return g_array_funcs.vsize[m_kind](this);
|
||||
}
|
||||
|
||||
inline CVarRef ArrayData::getValueRef(ssize_t pos) const {
|
||||
return g_array_funcs.getValueRef[m_kind](this, pos);
|
||||
}
|
||||
|
||||
inline bool ArrayData::noCopyOnWrite() const {
|
||||
return g_array_funcs.noCopyOnWrite[m_kind];
|
||||
}
|
||||
|
||||
inline bool ArrayData::isVectorData() const {
|
||||
return g_array_funcs.isVectorData[m_kind](this);
|
||||
}
|
||||
|
||||
inline bool ArrayData::exists(int64_t k) const {
|
||||
return g_array_funcs.existsInt[m_kind](this, k);
|
||||
}
|
||||
|
||||
inline bool ArrayData::exists(const StringData* k) const {
|
||||
return g_array_funcs.existsStr[m_kind](this, k);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::lval(int64_t k, Variant*& ret, bool copy) {
|
||||
return g_array_funcs.lvalInt[m_kind](this, k, ret, copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::lval(StringData* k, Variant*& ret, bool copy) {
|
||||
return g_array_funcs.lvalStr[m_kind](this, k, ret, copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::lvalNew(Variant*& ret, bool copy) {
|
||||
return g_array_funcs.lvalNew[m_kind](this, ret, copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::createLvalPtr(StringData* k, Variant*& ret,
|
||||
bool copy) {
|
||||
return g_array_funcs.createLvalPtr[m_kind](this, k, ret, copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::getLvalPtr(StringData* k, Variant*& ret,
|
||||
bool copy) {
|
||||
return g_array_funcs.getLvalPtr[m_kind](this, k, ret, copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::setRef(int64_t k, CVarRef v, bool copy) {
|
||||
return g_array_funcs.setRefInt[m_kind](this, k, v, copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::setRef(StringData* k, CVarRef v, bool copy) {
|
||||
return g_array_funcs.setRefStr[m_kind](this, k, v, copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::add(int64_t k, CVarRef v, bool copy) {
|
||||
return g_array_funcs.addInt[m_kind](this, k, v, copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::add(StringData* k, CVarRef v, bool copy) {
|
||||
return g_array_funcs.addStr[m_kind](this, k, v, copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::addLval(int64_t k, Variant *&ret, bool copy) {
|
||||
return g_array_funcs.addLvalInt[m_kind](this, k, ret, copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::addLval(StringData* k, Variant *&ret, bool copy) {
|
||||
return g_array_funcs.addLvalStr[m_kind](this, k, ret, copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::remove(int64_t k, bool copy) {
|
||||
return g_array_funcs.removeInt[m_kind](this, k, copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::remove(const StringData* k, bool copy) {
|
||||
return g_array_funcs.removeStr[m_kind](this, k, copy);
|
||||
}
|
||||
|
||||
inline ssize_t ArrayData::iter_begin() const {
|
||||
return g_array_funcs.iterBegin[m_kind](this);
|
||||
}
|
||||
|
||||
inline ssize_t ArrayData::iter_end() const {
|
||||
return g_array_funcs.iterEnd[m_kind](this);
|
||||
}
|
||||
|
||||
inline ssize_t ArrayData::iter_advance(ssize_t pos) const {
|
||||
return g_array_funcs.iterAdvance[m_kind](this, pos);
|
||||
}
|
||||
|
||||
inline ssize_t ArrayData::iter_rewind(ssize_t pos) const {
|
||||
return g_array_funcs.iterRewind[m_kind](this, pos);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,11 @@ ArrayData *ArrayData::GetScalarArray(ArrayData *arr,
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static size_t VsizeNop(const ArrayData* ad) {
|
||||
assert(false);
|
||||
return ad->getSize();
|
||||
}
|
||||
|
||||
// order: kVectorKind, kMixedKind, kSharedKind, kNvtwKind, kPolicyKind
|
||||
extern const ArrayFunctions g_array_funcs = {
|
||||
// release
|
||||
@@ -101,6 +106,121 @@ extern const ArrayFunctions g_array_funcs = {
|
||||
&SharedMap::SetStr,
|
||||
&NameValueTableWrapper::SetStr,
|
||||
&PolicyArray::SetStr },
|
||||
// vsize
|
||||
{ &VsizeNop, &VsizeNop,
|
||||
&VsizeNop,
|
||||
&NameValueTableWrapper::Vsize,
|
||||
&VsizeNop },
|
||||
// getValueRef
|
||||
{ &HphpArray::GetValueRef, &HphpArray::GetValueRef,
|
||||
&SharedMap::GetValueRef,
|
||||
&NameValueTableWrapper::GetValueRef,
|
||||
&PolicyArray::GetValueRef },
|
||||
// noCopyOnWrite
|
||||
{ false, false,
|
||||
false,
|
||||
true, // NameValueTableWrapper doesn't support COW.
|
||||
false },
|
||||
// isVectorData
|
||||
{ &HphpArray::IsVectorDataVec, &HphpArray::IsVectorData,
|
||||
&SharedMap::IsVectorData,
|
||||
&NameValueTableWrapper::IsVectorData,
|
||||
&PolicyArray::IsVectorData },
|
||||
// existsInt
|
||||
{ &HphpArray::ExistsIntVec, &HphpArray::ExistsInt,
|
||||
&SharedMap::ExistsInt,
|
||||
&NameValueTableWrapper::ExistsInt,
|
||||
&PolicyArray::ExistsInt },
|
||||
// existsStr
|
||||
{ &HphpArray::ExistsStrVec, &HphpArray::ExistsStr,
|
||||
&SharedMap::ExistsStr,
|
||||
&NameValueTableWrapper::ExistsStr,
|
||||
&PolicyArray::ExistsStr },
|
||||
// lvalInt
|
||||
{ &HphpArray::LvalIntVec, &HphpArray::LvalInt,
|
||||
&SharedMap::LvalInt,
|
||||
&NameValueTableWrapper::LvalInt,
|
||||
&PolicyArray::LvalInt },
|
||||
// lvalStr
|
||||
{ &HphpArray::LvalStrVec, &HphpArray::LvalStr,
|
||||
&SharedMap::LvalStr,
|
||||
&NameValueTableWrapper::LvalStr,
|
||||
&PolicyArray::LvalStr },
|
||||
// lvalNew
|
||||
{ &HphpArray::LvalNewVec, &HphpArray::LvalNew,
|
||||
&SharedMap::LvalNew,
|
||||
&NameValueTableWrapper::LvalNew,
|
||||
&PolicyArray::LvalNew },
|
||||
// createLvalPtr
|
||||
{ &HphpArray::CreateLvalPtrVec, &HphpArray::CreateLvalPtr,
|
||||
&ArrayData::CreateLvalPtr, // fatal
|
||||
&ArrayData::CreateLvalPtr, // fatal
|
||||
&PolicyArray::CreateLvalPtr },
|
||||
// getLvalPtr
|
||||
{ &HphpArray::GetLvalPtrVec, &HphpArray::GetLvalPtr,
|
||||
&ArrayData::GetLvalPtr, // fatal
|
||||
&ArrayData::GetLvalPtr, // fatal
|
||||
&PolicyArray::GetLvalPtr },
|
||||
// setRefInt
|
||||
{ &HphpArray::SetRefIntVec, &HphpArray::SetRefInt,
|
||||
&SharedMap::SetRefInt,
|
||||
&NameValueTableWrapper::SetRefInt,
|
||||
&PolicyArray::SetRefInt },
|
||||
// setRefStr
|
||||
{ &HphpArray::SetRefStrVec, &HphpArray::SetRefStr,
|
||||
&SharedMap::SetRefStr,
|
||||
&NameValueTableWrapper::SetRefStr,
|
||||
&PolicyArray::SetRefStr },
|
||||
// addInt
|
||||
{ &HphpArray::AddIntVec, &HphpArray::AddInt,
|
||||
&SharedMap::SetInt, // reuse set
|
||||
&NameValueTableWrapper::SetInt, // reuse set
|
||||
&PolicyArray::AddInt },
|
||||
// addStr
|
||||
{ &HphpArray::AddStrVec, &HphpArray::AddStr,
|
||||
&SharedMap::SetStr, // reuse set
|
||||
&NameValueTableWrapper::SetStr, // reuse set
|
||||
&PolicyArray::AddStr },
|
||||
// addLvalInt
|
||||
{ &HphpArray::AddLvalIntVec, &HphpArray::AddLvalInt,
|
||||
&SharedMap::AddLvalInt,
|
||||
&NameValueTableWrapper::AddLvalInt,
|
||||
&PolicyArray::AddLvalInt },
|
||||
// addLvalStr
|
||||
{ &HphpArray::AddLvalStrVec, &HphpArray::AddLvalStr,
|
||||
&SharedMap::AddLvalStr,
|
||||
&NameValueTableWrapper::AddLvalStr,
|
||||
&PolicyArray::AddLvalStr },
|
||||
// removeInt
|
||||
{ &HphpArray::RemoveIntVec, &HphpArray::RemoveInt,
|
||||
&SharedMap::RemoveInt,
|
||||
&NameValueTableWrapper::RemoveInt,
|
||||
&PolicyArray::RemoveInt },
|
||||
// removeStr
|
||||
{ &HphpArray::RemoveStrVec, &HphpArray::RemoveStr,
|
||||
&SharedMap::RemoveStr,
|
||||
&NameValueTableWrapper::RemoveStr,
|
||||
&PolicyArray::RemoveStr },
|
||||
// iterBegin
|
||||
{ &HphpArray::IterBegin, &HphpArray::IterBegin,
|
||||
&SharedMap::IterBegin,
|
||||
&NameValueTableWrapper::IterBegin,
|
||||
&PolicyArray::IterBegin },
|
||||
// iterEnd
|
||||
{ &HphpArray::IterEnd, &HphpArray::IterEnd,
|
||||
&SharedMap::IterEnd,
|
||||
&NameValueTableWrapper::IterEnd,
|
||||
&PolicyArray::IterEnd },
|
||||
// iterAdvance
|
||||
{ &HphpArray::IterAdvance, &HphpArray::IterAdvance,
|
||||
&SharedMap::IterAdvance,
|
||||
&NameValueTableWrapper::IterAdvance,
|
||||
&PolicyArray::IterAdvance },
|
||||
// iterRewind
|
||||
{ &HphpArray::IterRewind, &HphpArray::IterRewind,
|
||||
&SharedMap::IterRewind,
|
||||
&NameValueTableWrapper::IterRewind,
|
||||
&PolicyArray::IterRewind },
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -218,34 +338,16 @@ bool ArrayData::equal(const ArrayData *v2, bool strict) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
ArrayData *ArrayData::createLvalPtr(StringData* k, Variant *&ret, bool copy) {
|
||||
ArrayData *ArrayData::CreateLvalPtr(ArrayData* ad, StringData* k,
|
||||
Variant *&ret, bool copy) {
|
||||
throw FatalErrorException("Unimplemented ArrayData::createLvalPtr");
|
||||
}
|
||||
|
||||
ArrayData *ArrayData::getLvalPtr(StringData* k, Variant *&ret, bool copy) {
|
||||
ArrayData *ArrayData::GetLvalPtr(ArrayData* ad, StringData* k,
|
||||
Variant *&ret, bool copy) {
|
||||
throw FatalErrorException("Unimplemented ArrayData::getLvalPtr");
|
||||
}
|
||||
|
||||
ArrayData *ArrayData::add(int64_t k, CVarRef v, bool copy) {
|
||||
assert(!exists(k));
|
||||
return set(k, v, copy);
|
||||
}
|
||||
|
||||
ArrayData *ArrayData::add(StringData* k, CVarRef v, bool copy) {
|
||||
assert(!exists(k));
|
||||
return set(k, v, copy);
|
||||
}
|
||||
|
||||
ArrayData *ArrayData::addLval(int64_t k, Variant *&ret, bool copy) {
|
||||
assert(!exists(k));
|
||||
return lval(k, ret, copy);
|
||||
}
|
||||
|
||||
ArrayData *ArrayData::addLval(StringData* k, Variant *&ret, bool copy) {
|
||||
assert(!exists(k));
|
||||
return lval(k, ret, copy);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// stack and queue operations
|
||||
|
||||
|
||||
@@ -144,25 +144,32 @@ public:
|
||||
/**
|
||||
* Number of elements this array has.
|
||||
*/
|
||||
ssize_t size() const {
|
||||
size_t size() const {
|
||||
if (UNLIKELY((int)m_size) < 0) return vsize();
|
||||
return m_size;
|
||||
}
|
||||
|
||||
// unlike ArrayData::size(), this functions doesn't delegate
|
||||
// to the virtual Vsize() function, so its more efficient to
|
||||
// use this when you know you don't have a NameValueTableWrapper.
|
||||
size_t getSize() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of elements this array has.
|
||||
*/
|
||||
virtual ssize_t vsize() const = 0;
|
||||
size_t vsize() const;
|
||||
|
||||
/**
|
||||
* getValueRef() gets a reference to value at position "pos".
|
||||
*/
|
||||
virtual CVarRef getValueRef(ssize_t pos) const = 0;
|
||||
CVarRef getValueRef(ssize_t pos) const;
|
||||
|
||||
/*
|
||||
* Return true for array types that don't have COW semantics.
|
||||
*/
|
||||
virtual bool noCopyOnWrite() const { return false; }
|
||||
bool noCopyOnWrite() const;
|
||||
|
||||
/*
|
||||
* Specific derived class type querying operators.
|
||||
@@ -183,7 +190,7 @@ public:
|
||||
* Returns whether or not this array contains "vector-like" data.
|
||||
* I.e. all the keys are contiguous increasing integers.
|
||||
*/
|
||||
virtual bool isVectorData() const = 0;
|
||||
bool isVectorData() const;
|
||||
|
||||
/**
|
||||
* Whether or not this array has a referenced Variant or Object appearing
|
||||
@@ -213,8 +220,8 @@ public:
|
||||
/**
|
||||
* Testing whether a key exists.
|
||||
*/
|
||||
virtual bool exists(int64_t k) const = 0;
|
||||
virtual bool exists(const StringData* k) const = 0;
|
||||
bool exists(int64_t k) const;
|
||||
bool exists(const StringData* k) const;
|
||||
|
||||
/**
|
||||
* Interface for VM helpers. ArrayData implements generic versions
|
||||
@@ -236,8 +243,8 @@ public:
|
||||
* Getting l-value (that Variant pointer) at specified key. Return this if
|
||||
* escalation is not needed, or an escalated array data.
|
||||
*/
|
||||
virtual ArrayData *lval(int64_t k, Variant *&ret, bool copy) = 0;
|
||||
virtual ArrayData *lval(StringData* k, Variant *&ret, bool copy) = 0;
|
||||
ArrayData *lval(int64_t k, Variant *&ret, bool copy);
|
||||
ArrayData *lval(StringData* k, Variant *&ret, bool copy);
|
||||
|
||||
/**
|
||||
* Getting l-value (that Variant pointer) of a new element with the next
|
||||
@@ -246,15 +253,19 @@ public:
|
||||
* available integer key may fail, in which case ret is set to point to
|
||||
* the lval blackhole (see Variant::lvalBlackHole() for details).
|
||||
*/
|
||||
virtual ArrayData *lvalNew(Variant *&ret, bool copy) = 0;
|
||||
ArrayData *lvalNew(Variant *&ret, bool copy);
|
||||
|
||||
/**
|
||||
* Helper functions used for getting a reference to elements of
|
||||
* the dynamic property array in ObjectData or the local cache array
|
||||
* in ShardMap.
|
||||
*/
|
||||
virtual ArrayData *createLvalPtr(StringData* k, Variant *&ret, bool copy);
|
||||
virtual ArrayData *getLvalPtr(StringData* k, Variant *&ret, bool copy);
|
||||
ArrayData *createLvalPtr(StringData* k, Variant *&ret, bool copy);
|
||||
ArrayData *getLvalPtr(StringData* k, Variant *&ret, bool copy);
|
||||
static ArrayData *CreateLvalPtr(ArrayData* ad, StringData* k,
|
||||
Variant *&ret, bool copy);
|
||||
static ArrayData *GetLvalPtr(ArrayData* ad, StringData* k,
|
||||
Variant *&ret, bool copy);
|
||||
|
||||
/**
|
||||
* Setting a value at specified key. If "copy" is true, make a copy first
|
||||
@@ -264,31 +275,31 @@ public:
|
||||
ArrayData *set(int64_t k, CVarRef v, bool copy);
|
||||
ArrayData *set(StringData* k, CVarRef v, bool copy);
|
||||
|
||||
virtual ArrayData *setRef(int64_t k, CVarRef v, bool copy) = 0;
|
||||
virtual ArrayData *setRef(StringData* k, CVarRef v, bool copy) = 0;
|
||||
ArrayData *setRef(int64_t k, CVarRef v, bool copy);
|
||||
ArrayData *setRef(StringData* k, CVarRef v, bool copy);
|
||||
|
||||
/**
|
||||
* The same as set(), but with the precondition that the key does
|
||||
* not already exist in this array. (This is to allow more
|
||||
* efficient implementation of this case in some derived classes.)
|
||||
*/
|
||||
virtual ArrayData *add(int64_t k, CVarRef v, bool copy);
|
||||
virtual ArrayData *add(StringData* k, CVarRef v, bool copy);
|
||||
ArrayData *add(int64_t k, CVarRef v, bool copy);
|
||||
ArrayData *add(StringData* k, CVarRef v, bool copy);
|
||||
|
||||
/*
|
||||
* Same semantics as lval(), except with the precondition that the
|
||||
* key doesn't already exist in the array.
|
||||
*/
|
||||
virtual ArrayData *addLval(int64_t k, Variant *&ret, bool copy);
|
||||
virtual ArrayData *addLval(StringData* k, Variant *&ret, bool copy);
|
||||
ArrayData *addLval(int64_t k, Variant *&ret, bool copy);
|
||||
ArrayData *addLval(StringData* k, Variant *&ret, bool copy);
|
||||
|
||||
/**
|
||||
* Remove a value at specified key. If "copy" is true, make a copy first
|
||||
* then remove the value. Return this if escalation is not needed, or an
|
||||
* escalated array data.
|
||||
*/
|
||||
virtual ArrayData *remove(int64_t k, bool copy) = 0;
|
||||
virtual ArrayData *remove(const StringData* k, bool copy) = 0;
|
||||
ArrayData *remove(int64_t k, bool copy);
|
||||
ArrayData *remove(const StringData* k, bool copy);
|
||||
|
||||
/**
|
||||
* Inline accessors that convert keys to StringData* before delegating to
|
||||
@@ -317,10 +328,10 @@ public:
|
||||
ArrayData *remove(CStrRef k, bool copy);
|
||||
ArrayData *remove(CVarRef k, bool copy);
|
||||
|
||||
virtual ssize_t iter_begin() const = 0;
|
||||
virtual ssize_t iter_end() const = 0;
|
||||
virtual ssize_t iter_advance(ssize_t prev) const = 0;
|
||||
virtual ssize_t iter_rewind(ssize_t prev) const = 0;
|
||||
ssize_t iter_begin() const;
|
||||
ssize_t iter_end() const;
|
||||
ssize_t iter_advance(ssize_t prev) const;
|
||||
ssize_t iter_rewind(ssize_t prev) const;
|
||||
|
||||
/**
|
||||
* Mutable iteration APIs
|
||||
@@ -529,6 +540,35 @@ struct ArrayFunctions {
|
||||
void (*nvGetKey[NK])(const ArrayData*, TypedValue* out, ssize_t pos);
|
||||
ArrayData* (*setInt[NK])(ArrayData*, int64_t k, CVarRef v, bool copy);
|
||||
ArrayData* (*setStr[NK])(ArrayData*, StringData* k, CVarRef v, bool copy);
|
||||
size_t (*vsize[NK])(const ArrayData*);
|
||||
CVarRef (*getValueRef[NK])(const ArrayData*, ssize_t pos);
|
||||
bool noCopyOnWrite[NK];
|
||||
bool (*isVectorData[NK])(const ArrayData*);
|
||||
bool (*existsInt[NK])(const ArrayData*, int64_t k);
|
||||
bool (*existsStr[NK])(const ArrayData*, const StringData* k);
|
||||
ArrayData* (*lvalInt[NK])(ArrayData*, int64_t k, Variant*& ret,
|
||||
bool copy);
|
||||
ArrayData* (*lvalStr[NK])(ArrayData*, StringData* k, Variant*& ret,
|
||||
bool copy);
|
||||
ArrayData* (*lvalNew[NK])(ArrayData*, Variant *&ret, bool copy);
|
||||
ArrayData* (*createLvalPtr[NK])(ArrayData*, StringData* k, Variant *&ret,
|
||||
bool copy);
|
||||
ArrayData* (*getLvalPtr[NK])(ArrayData*, StringData* k, Variant *&ret,
|
||||
bool copy);
|
||||
ArrayData* (*setRefInt[NK])(ArrayData*, int64_t k, CVarRef v, bool copy);
|
||||
ArrayData* (*setRefStr[NK])(ArrayData*, StringData* k, CVarRef v, bool copy);
|
||||
ArrayData* (*addInt[NK])(ArrayData*, int64_t k, CVarRef v, bool copy);
|
||||
ArrayData* (*addStr[NK])(ArrayData*, StringData* k, CVarRef v, bool copy);
|
||||
ArrayData* (*addLvalInt[NK])(ArrayData*, int64_t k, Variant *&ret,
|
||||
bool copy);
|
||||
ArrayData* (*addLvalStr[NK])(ArrayData*, StringData* k, Variant *&ret,
|
||||
bool copy);
|
||||
ArrayData* (*removeInt[NK])(ArrayData*, int64_t k, bool copy);
|
||||
ArrayData* (*removeStr[NK])(ArrayData*, const StringData* k, bool copy);
|
||||
ssize_t (*iterBegin[NK])(const ArrayData*);
|
||||
ssize_t (*iterEnd[NK])(const ArrayData*);
|
||||
ssize_t (*iterAdvance[NK])(const ArrayData*, ssize_t pos);
|
||||
ssize_t (*iterRewind[NK])(const ArrayData*, ssize_t pos);
|
||||
};
|
||||
|
||||
extern const ArrayFunctions g_array_funcs;
|
||||
|
||||
@@ -103,6 +103,20 @@ void HphpArray::getArrayElm(ssize_t pos, TypedValue* valOut,
|
||||
}
|
||||
}
|
||||
|
||||
inline HphpArray* HphpArray::asHphpArray(ArrayData* ad) {
|
||||
assert(ad->isHphpArray());
|
||||
auto a = static_cast<HphpArray*>(ad);
|
||||
assert(a->checkInvariants());
|
||||
return a;
|
||||
}
|
||||
|
||||
inline const HphpArray* HphpArray::asHphpArray(const ArrayData* ad) {
|
||||
assert(ad->isHphpArray());
|
||||
auto a = static_cast<const HphpArray*>(ad);
|
||||
assert(a->checkInvariants());
|
||||
return a;
|
||||
}
|
||||
|
||||
inline HphpArray* HphpArray::asVector(ArrayData* ad) {
|
||||
assert(ad->kind() == kVectorKind);
|
||||
assert(dynamic_cast<HphpArray*>(ad));
|
||||
@@ -119,17 +133,15 @@ inline const HphpArray* HphpArray::asVector(const ArrayData* ad) {
|
||||
return a;
|
||||
}
|
||||
|
||||
inline HphpArray* HphpArray::asHphpArray(ArrayData* ad) {
|
||||
inline HphpArray* HphpArray::asGeneric(ArrayData* ad) {
|
||||
assert(ad->kind() == kMixedKind);
|
||||
assert(dynamic_cast<HphpArray*>(ad));
|
||||
auto a = static_cast<HphpArray*>(ad);
|
||||
assert(a->checkInvariants());
|
||||
return a;
|
||||
}
|
||||
|
||||
inline const HphpArray* HphpArray::asHphpArray(const ArrayData* ad) {
|
||||
inline const HphpArray* HphpArray::asGeneric(const ArrayData* ad) {
|
||||
assert(ad->kind() == kMixedKind);
|
||||
assert(dynamic_cast<const HphpArray*>(ad));
|
||||
auto a = static_cast<const HphpArray*>(ad);
|
||||
assert(a->checkInvariants());
|
||||
return a;
|
||||
|
||||
+260
-159
@@ -244,7 +244,7 @@ void HphpArray::ReleaseVec(ArrayData* ad) {
|
||||
|
||||
HOT_FUNC_VM
|
||||
void HphpArray::Release(ArrayData* ad) {
|
||||
auto a = asHphpArray(ad);
|
||||
auto a = asGeneric(ad);
|
||||
a->destroy();
|
||||
if (UNLIKELY(a->strongIterators() != nullptr)) a->freeStrongIterators();
|
||||
HphpArray::AllocatorType::getNoCheck()->dealloc(a);
|
||||
@@ -345,12 +345,6 @@ bool HphpArray::checkInvariants() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t HphpArray::vsize() const {
|
||||
assert(false && "vsize() called, but m_size should "
|
||||
"never be -1 in HphpArray");
|
||||
return m_size;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Iteration.
|
||||
|
||||
@@ -365,26 +359,26 @@ inline ssize_t HphpArray::prevElm(Elm* elms, ssize_t ei) const {
|
||||
return (ssize_t)ElmIndEmpty;
|
||||
}
|
||||
|
||||
ssize_t HphpArray::iter_begin() const {
|
||||
assert(checkInvariants());
|
||||
return nextElm(m_data, ElmIndEmpty);
|
||||
ssize_t HphpArray::IterBegin(const ArrayData* ad) {
|
||||
auto a = asHphpArray(ad);
|
||||
return a->nextElm(a->m_data, ElmIndEmpty);
|
||||
}
|
||||
|
||||
ssize_t HphpArray::iter_end() const {
|
||||
assert(checkInvariants());
|
||||
return prevElm(m_data, m_used);
|
||||
ssize_t HphpArray::IterEnd(const ArrayData* ad) {
|
||||
auto a = asHphpArray(ad);
|
||||
return a->prevElm(a->m_data, a->m_used);
|
||||
}
|
||||
|
||||
ssize_t HphpArray::iter_advance(ssize_t pos) const {
|
||||
assert(checkInvariants());
|
||||
assert(ArrayData::invalid_index == -1);
|
||||
ssize_t HphpArray::IterAdvance(const ArrayData* ad, ssize_t pos) {
|
||||
auto a = asHphpArray(ad);
|
||||
// Since m_used is always less than 2^32 and invalid_index == -1,
|
||||
// we can save a check by doing an unsigned comparison instead
|
||||
// of a signed comparison.
|
||||
if (size_t(++pos) < m_used && !isTombstone(m_data[pos].data.m_type)) {
|
||||
if (size_t(++pos) < a->m_used && !isTombstone(a->m_data[pos].data.m_type)) {
|
||||
return pos;
|
||||
}
|
||||
return iter_advance_helper(pos);
|
||||
return a->iter_advance_helper(pos);
|
||||
static_assert(invalid_index == -1, "");
|
||||
}
|
||||
|
||||
// caller has already incremented pos but encountered a tombstone
|
||||
@@ -398,40 +392,43 @@ ssize_t HphpArray::iter_advance_helper(ssize_t next_pos) const {
|
||||
return next_pos;
|
||||
}
|
||||
}
|
||||
return ArrayData::invalid_index;
|
||||
return invalid_index;
|
||||
}
|
||||
|
||||
ssize_t HphpArray::iter_rewind(ssize_t pos) const {
|
||||
assert(checkInvariants());
|
||||
if (pos == ArrayData::invalid_index) {
|
||||
return ArrayData::invalid_index;
|
||||
}
|
||||
return prevElm(m_data, pos);
|
||||
ssize_t HphpArray::IterRewind(const ArrayData* ad, ssize_t pos) {
|
||||
if (pos == invalid_index) return invalid_index;
|
||||
auto a = asHphpArray(ad);
|
||||
return a->prevElm(a->m_data, pos);
|
||||
}
|
||||
|
||||
CVarRef HphpArray::getValueRef(ssize_t pos) const {
|
||||
assert(checkInvariants());
|
||||
CVarRef HphpArray::GetValueRef(const ArrayData* ad, ssize_t pos) {
|
||||
auto a = asHphpArray(ad);
|
||||
assert(a->checkInvariants());
|
||||
assert(pos != ArrayData::invalid_index);
|
||||
Elm* e = &m_data[pos];
|
||||
Elm* e = &a->m_data[pos];
|
||||
assert(!isTombstone(e->data.m_type));
|
||||
return tvAsCVarRef(&e->data);
|
||||
}
|
||||
|
||||
bool HphpArray::isVectorData() const {
|
||||
assert(checkInvariants());
|
||||
if (m_size == 0 || isVector()) {
|
||||
bool HphpArray::IsVectorDataVec(const ArrayData*) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HphpArray::IsVectorData(const ArrayData* ad) {
|
||||
auto a = asGeneric(ad);
|
||||
if (a->m_size == 0) {
|
||||
// any 0-length array is "vector-like" for the sake of this
|
||||
// function, even if m_kind != kVector.
|
||||
return true;
|
||||
}
|
||||
Elm* elms = m_data;
|
||||
auto const elms = a->m_data;
|
||||
int64_t i = 0;
|
||||
for (uint32_t pos = 0, limit = m_used; pos < limit; ++pos) {
|
||||
Elm* e = &elms[pos];
|
||||
if (isTombstone(e->data.m_type)) {
|
||||
for (uint32_t pos = 0, limit = a->m_used; pos < limit; ++pos) {
|
||||
auto const& e = elms[pos];
|
||||
if (isTombstone(e.data.m_type)) {
|
||||
continue;
|
||||
}
|
||||
if (e->hasStrKey() || e->ikey != i) {
|
||||
if (e.hasStrKey() || e.ikey != i) {
|
||||
return false;
|
||||
}
|
||||
++i;
|
||||
@@ -606,16 +603,24 @@ HphpArray::findForNewInsertLoop(size_t tableMask, size_t h0) const {
|
||||
}
|
||||
}
|
||||
|
||||
bool HphpArray::exists(int64_t k) const {
|
||||
assert(checkInvariants());
|
||||
if (isVector()) return size_t(k) < m_size;
|
||||
return find(k) != ElmIndEmpty;
|
||||
bool HphpArray::ExistsIntVec(const ArrayData* ad, int64_t k) {
|
||||
auto a = asVector(ad);
|
||||
return size_t(k) < a->m_size;
|
||||
}
|
||||
|
||||
bool HphpArray::exists(const StringData* k) const {
|
||||
assert(checkInvariants());
|
||||
if (isVector()) return false;
|
||||
return find(k, k->hash()) != ElmIndEmpty;
|
||||
bool HphpArray::ExistsInt(const ArrayData* ad, int64_t k) {
|
||||
auto a = asGeneric(ad);
|
||||
return a->find(k) != ElmIndEmpty;
|
||||
}
|
||||
|
||||
bool HphpArray::ExistsStrVec(const ArrayData* ad, const StringData* k) {
|
||||
assert(asVector(ad));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HphpArray::ExistsStr(const ArrayData* ad, const StringData* k) {
|
||||
auto a = asGeneric(ad);
|
||||
return a->find(k, k->hash()) != ElmIndEmpty;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
@@ -1069,19 +1074,7 @@ ArrayData* HphpArray::update(StringData* key, CVarRef data) {
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::updateRef(int64_t ki, CVarRef data) {
|
||||
if (isVector()) {
|
||||
if (size_t(ki) < m_size) {
|
||||
tvAsVariant(&m_data[ki].data).assignRefHelper(data);
|
||||
return this;
|
||||
}
|
||||
if (size_t(ki) == m_size) {
|
||||
auto& tv = allocNextElm(ki);
|
||||
tvAsUninitializedVariant(&tv).constructRefHelper(data);
|
||||
return this;
|
||||
}
|
||||
vectorToGeneric();
|
||||
// todo t2606310: key can't exist. use add/findForNewInsert
|
||||
}
|
||||
assert(!isVector());
|
||||
ElmInd* ei = findForInsert(ki);
|
||||
if (validElmInd(*ei)) {
|
||||
Elm* e = &m_data[*ei];
|
||||
@@ -1096,10 +1089,7 @@ ArrayData* HphpArray::updateRef(int64_t ki, CVarRef data) {
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::updateRef(StringData* key, CVarRef data) {
|
||||
if (isVector()) {
|
||||
vectorToGeneric();
|
||||
// todo t2606310: key can't exist. use add/findForNewInsert
|
||||
}
|
||||
assert(!isVector());
|
||||
strhash_t h = key->hash();
|
||||
ElmInd* ei = findForInsert(key, h);
|
||||
if (validElmInd(*ei)) {
|
||||
@@ -1111,44 +1101,90 @@ ArrayData* HphpArray::updateRef(StringData* key, CVarRef data) {
|
||||
return this;
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::lval(int64_t k, Variant*& ret, bool copy) {
|
||||
assert(checkInvariants());
|
||||
return (!copy ? this : copyImpl())->addLvalImpl(k, &ret);
|
||||
// return true if Elm contains a Reference that won't be flattened
|
||||
// by a copy, or an object.
|
||||
static inline bool isContainer(const TypedValue& tv) {
|
||||
auto& v = tvAsCVarRef(&tv);
|
||||
return v.isReferenced() || v.isObject();
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::lval(StringData* key, Variant*& ret, bool copy) {
|
||||
assert(checkInvariants());
|
||||
return (!copy ? this : copyImpl())->addLvalImpl(key, key->hash(), &ret);
|
||||
ArrayData* HphpArray::LvalIntVec(ArrayData* ad, int64_t k, Variant*& ret,
|
||||
bool copy) {
|
||||
auto a = asVector(ad);
|
||||
return (!copy ? a : a->copyImpl())->addLvalImpl(k, &ret);
|
||||
}
|
||||
|
||||
ArrayData *HphpArray::createLvalPtr(StringData* key, Variant*& ret, bool copy) {
|
||||
assert(checkInvariants());
|
||||
HphpArray* a = !copy ? this : copyImpl();
|
||||
ArrayData* HphpArray::LvalInt(ArrayData* ad, int64_t k, Variant*& ret,
|
||||
bool copy) {
|
||||
auto a = asGeneric(ad);
|
||||
return (!copy ? a : a->copyImpl())->addLvalImpl(k, &ret);
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::LvalStrVec(ArrayData* ad, StringData* key, Variant*& ret,
|
||||
bool copy) {
|
||||
auto a = asVector(ad);
|
||||
return (!copy ? a : a->copyImpl())->addLvalImpl(key, key->hash(), &ret);
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::LvalStr(ArrayData* ad, StringData* key, Variant*& ret,
|
||||
bool copy) {
|
||||
auto a = asGeneric(ad);
|
||||
return (!copy ? a : a->copyImpl())->addLvalImpl(key, key->hash(), &ret);
|
||||
}
|
||||
|
||||
ArrayData *HphpArray::CreateLvalPtrVec(ArrayData* ad, StringData* key,
|
||||
Variant*& ret, bool copy) {
|
||||
auto a = asVector(ad);
|
||||
if (copy) a = a->copyVec();
|
||||
return a->vectorToGeneric()->addLvalImpl(key, key->hash(), &ret);
|
||||
// todo: we know the key can't exist; use specialized addLvalImpl
|
||||
}
|
||||
|
||||
ArrayData *HphpArray::CreateLvalPtr(ArrayData* ad, StringData* key,
|
||||
Variant*& ret, bool copy) {
|
||||
auto a = asGeneric(ad);
|
||||
if (copy) a = a->copyGeneric();
|
||||
return a->addLvalImpl(key, key->hash(), &ret);
|
||||
}
|
||||
|
||||
ArrayData *HphpArray::getLvalPtr(StringData* key, Variant*& ret, bool copy) {
|
||||
assert(checkInvariants());
|
||||
HphpArray* a = !copy ? this : copyImpl();
|
||||
auto pos = a->find(key, key->hash());
|
||||
if (pos != ElmIndEmpty) {
|
||||
Elm* e = &a->m_data[pos];
|
||||
ret = &tvAsVariant(&e->data);
|
||||
} else {
|
||||
ret = nullptr;
|
||||
}
|
||||
ArrayData *HphpArray::GetLvalPtrVec(ArrayData* ad, StringData* key,
|
||||
Variant*& ret, bool copy) {
|
||||
auto a = asVector(ad);
|
||||
if (copy) a = a->copyVec();
|
||||
// todo: we didn't have to copy since we didn't mutate. Or, should
|
||||
// we have just escalate to generic anyway? and, why isn't this
|
||||
// method const?
|
||||
ret = nullptr;
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::lvalNew(Variant*& ret, bool copy) {
|
||||
assert(checkInvariants());
|
||||
TypedValue* tv;
|
||||
ArrayData* a = nvNew(tv, copy);
|
||||
if (tv == nullptr) {
|
||||
ret = &(Variant::lvalBlackHole());
|
||||
} else {
|
||||
ret = &tvAsVariant(tv);
|
||||
ArrayData *HphpArray::GetLvalPtr(ArrayData* ad, StringData* key,
|
||||
Variant*& ret, bool copy) {
|
||||
auto a = asGeneric(ad);
|
||||
if (copy) a = a->copyGeneric();
|
||||
auto pos = a->find(key, key->hash());
|
||||
ret = pos != ElmIndEmpty ? &tvAsVariant(&a->m_data[pos].data) :
|
||||
nullptr;
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::LvalNewVec(ArrayData* ad, Variant*& ret, bool copy) {
|
||||
auto a = asVector(ad);
|
||||
if (copy) a = a->copyVec();
|
||||
auto& tv = a->allocNextElm(a->m_size);
|
||||
tvWriteUninit(&tv);
|
||||
ret = &tvAsVariant(&tv);
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::LvalNew(ArrayData* ad, Variant*& ret, bool copy) {
|
||||
auto a = asGeneric(ad);
|
||||
if (copy) a = a->copyGeneric();
|
||||
if (UNLIKELY(!a->nextInsert(uninit_null()))) {
|
||||
ret = &Variant::lvalBlackHole();
|
||||
return a;
|
||||
}
|
||||
ret = &tvAsVariant(&a->m_data[a->m_used - 1].data);
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -1170,7 +1206,7 @@ HphpArray::SetIntVec(ArrayData* ad, int64_t k, CVarRef v, bool copy) {
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::SetInt(ArrayData* ad, int64_t k, CVarRef v, bool copy) {
|
||||
auto a = asHphpArray(ad);
|
||||
auto a = asGeneric(ad);
|
||||
if (copy) a = a->copyGeneric();
|
||||
return a->update(k, v);
|
||||
}
|
||||
@@ -1185,58 +1221,127 @@ HphpArray::SetStrVec(ArrayData* ad, StringData* k, CVarRef v, bool copy) {
|
||||
|
||||
ArrayData*
|
||||
HphpArray::SetStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) {
|
||||
auto a = asHphpArray(ad);
|
||||
auto a = asGeneric(ad);
|
||||
if (copy) a = a->copyGeneric();
|
||||
return a->update(k, v);
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::setRef(int64_t k, CVarRef v, bool copy) {
|
||||
assert(checkInvariants());
|
||||
HphpArray* a = !copy ? this : copyImpl();
|
||||
return a->updateRef(k, v);
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::setRef(StringData* k, CVarRef v, bool copy) {
|
||||
assert(checkInvariants());
|
||||
HphpArray* a = !copy ? this : copyImpl();
|
||||
return a->updateRef(k, v);
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::add(int64_t k, CVarRef v, bool copy) {
|
||||
assert(checkInvariants());
|
||||
assert(!exists(k));
|
||||
HphpArray* a = !copy ? this : copyImpl();
|
||||
if (a->isVector()) {
|
||||
if (size_t(k) == a->m_size) {
|
||||
auto& tv = a->allocNextElm(k);
|
||||
elemConstruct((TypedValue*)&v, &tv);
|
||||
return a;
|
||||
}
|
||||
a->vectorToGeneric();
|
||||
ArrayData*
|
||||
HphpArray::SetRefIntVec(ArrayData* ad, int64_t k, CVarRef v, bool copy) {
|
||||
auto a = asVector(ad);
|
||||
if (copy) a = a->copyVec();
|
||||
if (size_t(k) < a->m_size) {
|
||||
tvAsVariant(&a->m_data[k].data).assignRefHelper(v);
|
||||
return a;
|
||||
}
|
||||
if (size_t(k) == a->m_size) {
|
||||
auto& tv = a->allocNextElm(k);
|
||||
tvAsUninitializedVariant(&tv).constructRefHelper(v);
|
||||
return a;
|
||||
}
|
||||
// todo t2606310: key can't exist. use add/findForNewInsert
|
||||
return a->vectorToGeneric()->updateRef(k, v);
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
HphpArray::SetRefInt(ArrayData* ad, int64_t k, CVarRef v, bool copy) {
|
||||
auto a = asGeneric(ad);
|
||||
if (copy) a = a->copyGeneric();
|
||||
return a->updateRef(k, v);
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
HphpArray::SetRefStrVec(ArrayData* ad, StringData* k, CVarRef v, bool copy) {
|
||||
auto a = asVector(ad);
|
||||
if (copy) a = a->copyVec();
|
||||
return a->vectorToGeneric()->updateRef(k, v);
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
HphpArray::SetRefStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) {
|
||||
auto a = asGeneric(ad);
|
||||
if (copy) a = a->copyVec();
|
||||
// todo t2606310: key can't exist. use add/findForNewInsert
|
||||
return a->updateRef(k, v);
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
HphpArray::AddIntVec(ArrayData* ad, int64_t k, CVarRef v, bool copy) {
|
||||
assert(!ad->exists(k));
|
||||
auto a = asVector(ad);
|
||||
if (copy) a = a->copyVec();
|
||||
if (size_t(k) == a->m_size) {
|
||||
auto& tv = a->allocNextElm(k);
|
||||
elemConstruct((TypedValue*)&v, &tv);
|
||||
return a;
|
||||
}
|
||||
return a->vectorToGeneric()->addVal(k, v);
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
HphpArray::AddInt(ArrayData* ad, int64_t k, CVarRef v, bool copy) {
|
||||
assert(!ad->exists(k));
|
||||
auto a = asGeneric(ad);
|
||||
if (copy) a = a->copyGeneric();
|
||||
return a->addVal(k, v);
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::add(StringData* k, CVarRef v, bool copy) {
|
||||
assert(checkInvariants());
|
||||
assert(!exists(k));
|
||||
HphpArray* a = !copy ? this : copyImpl();
|
||||
if (a->isVector()) a->vectorToGeneric();
|
||||
ArrayData*
|
||||
HphpArray::AddStrVec(ArrayData* ad, StringData* k, CVarRef v, bool copy) {
|
||||
assert(!ad->exists(k));
|
||||
auto a = asVector(ad);
|
||||
if (copy) a = a->copyVec();
|
||||
return a->vectorToGeneric()->addVal(k, v);
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
HphpArray::AddStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) {
|
||||
assert(!ad->exists(k));
|
||||
auto a = asGeneric(ad);
|
||||
if (copy) a = a->copyGeneric();
|
||||
return a->addVal(k, v);
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::addLval(int64_t k, Variant*& ret, bool copy) {
|
||||
assert(checkInvariants());
|
||||
assert(!exists(k));
|
||||
HphpArray* a = !copy ? this : copyImpl();
|
||||
ArrayData*
|
||||
HphpArray::AddLvalIntVec(ArrayData* ad, int64_t k, Variant*& ret, bool copy) {
|
||||
assert(!ad->exists(k));
|
||||
auto a = asVector(ad);
|
||||
if (copy) a = a->copyVec();
|
||||
if (size_t(k) < a->m_size) {
|
||||
ret = &tvAsVariant(&a->m_data[k].data);
|
||||
return a;
|
||||
}
|
||||
if (size_t(k) == a->m_size) {
|
||||
auto& tv = a->allocNextElm(k);
|
||||
tvWriteNull(&tv);
|
||||
ret = &(tvAsVariant(&tv));
|
||||
return a;
|
||||
}
|
||||
return a->vectorToGeneric()->addLvalImpl(k, &ret);
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
HphpArray::AddLvalInt(ArrayData* ad, int64_t k, Variant*& ret, bool copy) {
|
||||
assert(!ad->exists(k));
|
||||
auto a = asGeneric(ad);
|
||||
if (copy) a = a->copyGeneric();
|
||||
return a->addLvalImpl(k, &ret);
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::addLval(StringData* k, Variant*& ret, bool copy) {
|
||||
assert(checkInvariants());
|
||||
assert(!exists(k));
|
||||
HphpArray* a = !copy ? this : copyImpl();
|
||||
if (a->isVector()) a->vectorToGeneric();
|
||||
ArrayData*
|
||||
HphpArray::AddLvalStrVec(ArrayData* ad, StringData* k, Variant*& ret,
|
||||
bool copy) {
|
||||
assert(!ad->exists(k));
|
||||
auto a = asVector(ad);
|
||||
if (copy) a = a->copyVec();
|
||||
return a->vectorToGeneric()->addLvalImpl(k, k->hash(), &ret);
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
HphpArray::AddLvalStr(ArrayData* ad, StringData* k, Variant*& ret, bool copy) {
|
||||
assert(!ad->exists(k));
|
||||
auto a = asGeneric(ad);
|
||||
if (copy) a = a->copyVec();
|
||||
return a->addLvalImpl(k, k->hash(), &ret);
|
||||
}
|
||||
|
||||
@@ -1319,20 +1424,34 @@ ArrayData* HphpArray::erase(ElmInd* ei, bool updateNext /* = false */) {
|
||||
return this;
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::remove(int64_t k, bool copy) {
|
||||
assert(checkInvariants());
|
||||
HphpArray* a = !copy ? this : copyImpl();
|
||||
if (a->isVector()) {
|
||||
// todo t2606310: what is probability of (k == size-1)
|
||||
ArrayData* HphpArray::RemoveIntVec(ArrayData* ad, int64_t k, bool copy) {
|
||||
auto a = asVector(ad);
|
||||
if (copy) a = a->copyImpl();
|
||||
// todo t2606310: what is probability of (k == size-1)
|
||||
if (size_t(k) < a->m_size) {
|
||||
a->vectorToGeneric();
|
||||
return a->erase(a->findForInsert(k));
|
||||
}
|
||||
return a; // key didn't exist, so we're still vector
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::RemoveInt(ArrayData* ad, int64_t k, bool copy) {
|
||||
auto a = asGeneric(ad);
|
||||
if (copy) a = a->copyImpl();
|
||||
return a->erase(a->findForInsert(k));
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::remove(const StringData* key, bool copy) {
|
||||
assert(checkInvariants());
|
||||
HphpArray* a = !copy ? this : copyImpl();
|
||||
if (a->isVector()) return a; // since key cannot exist
|
||||
ArrayData*
|
||||
HphpArray::RemoveStrVec(ArrayData* ad, const StringData* key, bool copy) {
|
||||
auto a = asVector(ad);
|
||||
if (copy) a = a->copyImpl();
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
HphpArray::RemoveStr(ArrayData* ad, const StringData* key, bool copy) {
|
||||
auto a = asGeneric(ad);
|
||||
if (copy) a = a->copyImpl();
|
||||
return a->erase(a->findForInsert(key, key->hash()));
|
||||
}
|
||||
|
||||
@@ -1357,7 +1476,7 @@ TypedValue* HphpArray::NvGetIntVec(const ArrayData* ad, int64_t ki) {
|
||||
}
|
||||
|
||||
TypedValue* HphpArray::NvGetInt(const ArrayData* ad, int64_t ki) {
|
||||
auto a = asHphpArray(ad);
|
||||
auto a = asGeneric(ad);
|
||||
auto i = a->find(ki);
|
||||
return LIKELY(i != ElmIndEmpty) ? &a->m_data[i].data : nullptr;
|
||||
}
|
||||
@@ -1368,7 +1487,7 @@ TypedValue* HphpArray::NvGetStrVec(const ArrayData* ad, const StringData* k) {
|
||||
}
|
||||
|
||||
TypedValue* HphpArray::NvGetStr(const ArrayData* ad, const StringData* k) {
|
||||
auto a = asHphpArray(ad);
|
||||
auto a = asGeneric(ad);
|
||||
auto i = a->find(k, k->hash());
|
||||
if (LIKELY(i != ElmIndEmpty)) {
|
||||
return &a->m_data[i].data;
|
||||
@@ -1376,24 +1495,6 @@ TypedValue* HphpArray::NvGetStr(const ArrayData* ad, const StringData* k) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::nvNew(TypedValue*& ret, bool copy) {
|
||||
assert(checkInvariants());
|
||||
HphpArray* a = !copy ? this : copyImpl();
|
||||
if (a->isVector()) {
|
||||
auto& tv = a->allocNextElm(a->m_size);
|
||||
tv.m_type = KindOfUninit;
|
||||
ret = &tv;
|
||||
return a;
|
||||
}
|
||||
if (UNLIKELY(!a->nextInsert(uninit_null()))) {
|
||||
ret = nullptr;
|
||||
return a;
|
||||
}
|
||||
assert(a->m_used > 0);
|
||||
ret = &a->m_data[a->m_used - 1].data;
|
||||
return a;
|
||||
}
|
||||
|
||||
// nvGetKey does not touch out->_count, so can be used
|
||||
// for inner or outer cells.
|
||||
void HphpArray::NvGetKeyVec(const ArrayData* ad, TypedValue* out, ssize_t pos) {
|
||||
@@ -1405,7 +1506,7 @@ void HphpArray::NvGetKeyVec(const ArrayData* ad, TypedValue* out, ssize_t pos) {
|
||||
}
|
||||
|
||||
void HphpArray::NvGetKey(const ArrayData* ad, TypedValue* out, ssize_t pos) {
|
||||
auto a = asHphpArray(ad);
|
||||
auto a = asGeneric(ad);
|
||||
assert(pos != ArrayData::invalid_index);
|
||||
assert(!isTombstone(a->m_data[pos].data.m_type));
|
||||
getElmKey(a->m_data[pos], out);
|
||||
@@ -1444,7 +1545,7 @@ ArrayData* HphpArray::AppendVec(ArrayData* ad, CVarRef v, bool copy) {
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::Append(ArrayData* ad, CVarRef v, bool copy) {
|
||||
auto a = asHphpArray(ad);
|
||||
auto a = asGeneric(ad);
|
||||
if (copy) a = a->copyGeneric();
|
||||
a->nextInsert(v);
|
||||
return a;
|
||||
@@ -1557,7 +1658,7 @@ ArrayData* HphpArray::pop(Variant& value) {
|
||||
assert(checkInvariants());
|
||||
HphpArray* a = getCount() <= 1 ? this : copyImpl();
|
||||
Elm* elms = a->m_data;
|
||||
ElmInd pos = a->HphpArray::iter_end();
|
||||
ElmInd pos = IterEnd(a);
|
||||
if (validElmInd(pos)) {
|
||||
Elm* e = &elms[pos];
|
||||
assert(!isTombstone(e->data.m_type));
|
||||
|
||||
@@ -57,6 +57,8 @@ private:
|
||||
// Safe downcast helpers
|
||||
static HphpArray* asVector(ArrayData* ad);
|
||||
static const HphpArray* asVector(const ArrayData* ad);
|
||||
static HphpArray* asGeneric(ArrayData* ad);
|
||||
static const HphpArray* asGeneric(const ArrayData* ad);
|
||||
static HphpArray* asHphpArray(ArrayData* ad);
|
||||
static const HphpArray* asHphpArray(const ArrayData* ad);
|
||||
|
||||
@@ -72,13 +74,6 @@ public:
|
||||
void destroyVec();
|
||||
void destroy();
|
||||
|
||||
// unlike ArrayData::size(), this functions doesn't delegate
|
||||
// to the virtual vsize() functions, so its more efficient to
|
||||
// use this when you know you have an HphpArray.
|
||||
ssize_t getSize() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
// This behaves the same as iter_begin except that it assumes
|
||||
// this array is not empty and its not virtual.
|
||||
ssize_t getIterBegin() const {
|
||||
@@ -107,28 +102,43 @@ public:
|
||||
using ArrayData::nvGet;
|
||||
|
||||
// implements ArrayData
|
||||
ssize_t vsize() const;
|
||||
CVarRef getValueRef(ssize_t pos) const;
|
||||
static CVarRef GetValueRef(const ArrayData*, ssize_t pos);
|
||||
|
||||
// overrides ArrayData
|
||||
bool isVectorData() const;
|
||||
ssize_t iter_begin() const;
|
||||
ssize_t iter_end() const;
|
||||
ssize_t iter_advance(ssize_t prev) const;
|
||||
ssize_t iter_rewind(ssize_t prev) const;
|
||||
static bool IsVectorData(const ArrayData*);
|
||||
static bool IsVectorDataVec(const ArrayData*);
|
||||
static ssize_t IterBegin(const ArrayData*);
|
||||
static ssize_t IterEnd(const ArrayData*);
|
||||
static ssize_t IterAdvance(const ArrayData*, ssize_t pos);
|
||||
static ssize_t IterRewind(const ArrayData*, ssize_t pos);
|
||||
|
||||
// implements ArrayData
|
||||
bool exists(int64_t k) const;
|
||||
bool exists(const StringData* k) const;
|
||||
static bool ExistsInt(const ArrayData*, int64_t k);
|
||||
static bool ExistsStr(const ArrayData*, const StringData* k);
|
||||
static bool ExistsIntVec(const ArrayData*, int64_t k);
|
||||
static bool ExistsStrVec(const ArrayData*, const StringData* k);
|
||||
|
||||
// implements ArrayData
|
||||
ArrayData* lval(int64_t k, Variant*& ret, bool copy);
|
||||
ArrayData* lval(StringData* k, Variant*& ret, bool copy);
|
||||
ArrayData* lvalNew(Variant*& ret, bool copy);
|
||||
static ArrayData* LvalInt(ArrayData* ad, int64_t k, Variant*& ret,
|
||||
bool copy);
|
||||
static ArrayData* LvalStr(ArrayData* ad, StringData* k, Variant*& ret,
|
||||
bool copy);
|
||||
static ArrayData* LvalIntVec(ArrayData* ad, int64_t k, Variant*& ret,
|
||||
bool copy);
|
||||
static ArrayData* LvalStrVec(ArrayData* ad, StringData* k, Variant*& ret,
|
||||
bool copy);
|
||||
static ArrayData* LvalNew(ArrayData*, Variant*& ret, bool copy);
|
||||
static ArrayData* LvalNewVec(ArrayData*, Variant*& ret, bool copy);
|
||||
|
||||
// overrides ArrayData
|
||||
ArrayData* createLvalPtr(StringData* k, Variant*& ret, bool copy);
|
||||
ArrayData* getLvalPtr(StringData* k, Variant*& ret, bool copy);
|
||||
static ArrayData* CreateLvalPtr(ArrayData*, StringData* k, Variant*& ret,
|
||||
bool copy);
|
||||
static ArrayData* GetLvalPtr(ArrayData*, StringData* k, Variant*& ret,
|
||||
bool copy);
|
||||
static ArrayData* CreateLvalPtrVec(ArrayData*, StringData* k, Variant*& ret,
|
||||
bool copy);
|
||||
static ArrayData* GetLvalPtrVec(ArrayData*, StringData* k, Variant*& ret,
|
||||
bool copy);
|
||||
|
||||
// implements ArrayData
|
||||
static ArrayData* SetIntVec(ArrayData*, int64_t k, CVarRef v, bool copy);
|
||||
@@ -137,18 +147,35 @@ public:
|
||||
static ArrayData* SetStr(ArrayData*, StringData* k, CVarRef v, bool copy);
|
||||
|
||||
// implements ArrayData
|
||||
ArrayData* setRef(int64_t k, CVarRef v, bool copy);
|
||||
ArrayData* setRef(StringData* k, CVarRef v, bool copy);
|
||||
static ArrayData* SetRefInt(ArrayData* ad, int64_t k, CVarRef v,
|
||||
bool copy);
|
||||
static ArrayData* SetRefStr(ArrayData* ad, StringData* k, CVarRef v,
|
||||
bool copy);
|
||||
static ArrayData* SetRefIntVec(ArrayData* ad, int64_t k, CVarRef v,
|
||||
bool copy);
|
||||
static ArrayData* SetRefStrVec(ArrayData* ad, StringData* k, CVarRef v,
|
||||
bool copy);
|
||||
|
||||
// overrides ArrayData
|
||||
ArrayData *add(int64_t k, CVarRef v, bool copy);
|
||||
ArrayData *add(StringData* k, CVarRef v, bool copy);
|
||||
ArrayData *addLval(int64_t k, Variant*& ret, bool copy);
|
||||
ArrayData *addLval(StringData* k, Variant*& ret, bool copy);
|
||||
static ArrayData* AddInt(ArrayData*, int64_t k, CVarRef v, bool copy);
|
||||
static ArrayData* AddStr(ArrayData*, StringData* k, CVarRef v, bool copy);
|
||||
static ArrayData* AddIntVec(ArrayData*, int64_t k, CVarRef v, bool copy);
|
||||
static ArrayData* AddStrVec(ArrayData*, StringData* k, CVarRef v, bool copy);
|
||||
|
||||
static ArrayData* AddLvalInt(ArrayData*, int64_t k, Variant*& ret,
|
||||
bool copy);
|
||||
static ArrayData* AddLvalStr(ArrayData*, StringData* k, Variant*& ret,
|
||||
bool copy);
|
||||
static ArrayData* AddLvalIntVec(ArrayData*, int64_t k, Variant*& ret,
|
||||
bool copy);
|
||||
static ArrayData* AddLvalStrVec(ArrayData*, StringData* k, Variant*& ret,
|
||||
bool copy);
|
||||
|
||||
// implements ArrayData
|
||||
ArrayData* remove(int64_t k, bool copy);
|
||||
ArrayData* remove(const StringData* k, bool copy);
|
||||
static ArrayData* RemoveInt(ArrayData*, int64_t k, bool copy);
|
||||
static ArrayData* RemoveStr(ArrayData*, const StringData* k, bool copy);
|
||||
static ArrayData* RemoveIntVec(ArrayData*, int64_t k, bool copy);
|
||||
static ArrayData* RemoveStrVec(ArrayData*, const StringData* k, bool copy);
|
||||
|
||||
// overrides/implements ArrayData
|
||||
ArrayData* copy() const;
|
||||
@@ -189,16 +216,15 @@ public:
|
||||
static TypedValue* NvGetStrVec(const ArrayData*, const StringData* k);
|
||||
static TypedValue* NvGetStr(const ArrayData*, const StringData* k);
|
||||
|
||||
void nvBind(int64_t ki, const TypedValue* v) {
|
||||
updateRef(ki, tvAsCVarRef(v));
|
||||
void nvBind(int64_t k, const TypedValue* v) {
|
||||
ArrayData::setRef(k, tvAsCVarRef(v), false);
|
||||
}
|
||||
void nvBind(StringData* k, const TypedValue* v) {
|
||||
updateRef(k, tvAsCVarRef(v));
|
||||
ArrayData::setRef(k, tvAsCVarRef(v), false);
|
||||
}
|
||||
void nvAppend(const TypedValue* v) {
|
||||
nextInsertVec(tvAsCVarRef(v));
|
||||
}
|
||||
ArrayData* nvNew(TypedValue*& v, bool copy);
|
||||
static void NvGetKeyVec(const ArrayData*, TypedValue* out, ssize_t pos);
|
||||
static void NvGetKey(const ArrayData*, TypedValue* out, ssize_t pos);
|
||||
bool nvInsert(StringData* k, TypedValue *v);
|
||||
|
||||
@@ -227,20 +227,32 @@ inline const PolicyArray* PolicyArray::asPolicyArray(const ArrayData* ad) {
|
||||
return static_cast<const PolicyArray*>(ad);
|
||||
}
|
||||
|
||||
const Variant& PolicyArray::getValueRef(ssize_t pos) const {
|
||||
APILOG(this) << "(" << pos << ")";
|
||||
assert(size_t(pos) < m_size);
|
||||
return val(toPos(pos));
|
||||
const Variant& PolicyArray::GetValueRef(const ArrayData* ad, ssize_t pos) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "(" << pos << ")";
|
||||
assert(size_t(pos) < a->m_size);
|
||||
return a->val(toPos(pos));
|
||||
}
|
||||
|
||||
bool PolicyArray::isVectorData() const {
|
||||
APILOG(this) << "()";
|
||||
for (ssize_t i = 0; i < m_size; ++i) {
|
||||
if (Store::find(i, m_size) != toPos(i)) return false;
|
||||
bool PolicyArray::IsVectorData(const ArrayData* ad) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "()";
|
||||
for (ssize_t i = 0; i < a->m_size; ++i) {
|
||||
if (a->Store::find(i, a->m_size) != toPos(i)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PolicyArray::ExistsInt(const ArrayData* ad, int64_t k) {
|
||||
auto a = asPolicyArray(ad);
|
||||
return a->Store::find(k, a->m_size) < toPos(a->m_size);
|
||||
}
|
||||
|
||||
bool PolicyArray::ExistsStr(const ArrayData* ad, const StringData* k) {
|
||||
auto a = asPolicyArray(ad);
|
||||
return a->Store::find(k, a->m_size) < toPos(a->m_size);
|
||||
}
|
||||
|
||||
static_assert(ArrayData::invalid_index == size_t(-1), "ehm");
|
||||
|
||||
template <class K>
|
||||
@@ -295,41 +307,53 @@ ArrayData *PolicyArray::lvalImpl(K k, Variant*& ret, bool copy) {
|
||||
return this;
|
||||
}
|
||||
|
||||
ArrayData *PolicyArray::lvalNew(Variant *&ret, bool copy) {
|
||||
if (copy) {
|
||||
return PolicyArray::copy()->lvalNew(ret, false);
|
||||
}
|
||||
ArrayData* PolicyArray::LvalInt(ArrayData* ad, int64_t k, Variant *&ret,
|
||||
bool copy) {
|
||||
return asPolicyArray(ad)->lvalImpl(k, ret, copy);
|
||||
}
|
||||
|
||||
ArrayData* PolicyArray::LvalStr(ArrayData* ad, StringData* k, Variant*& ret,
|
||||
bool copy) {
|
||||
return asPolicyArray(ad)->lvalImpl(k, ret, copy);
|
||||
}
|
||||
|
||||
ArrayData *PolicyArray::LvalNew(ArrayData* ad, Variant *&ret, bool copy) {
|
||||
auto a = asPolicyArray(ad);
|
||||
if (copy) a = a->PolicyArray::copy();
|
||||
|
||||
// Andrei: TODO - append() currently never fails, probably it
|
||||
// should.
|
||||
auto oldSize = m_size;
|
||||
append(uninit_null(), false);
|
||||
assert(m_size == oldSize + 1);
|
||||
if (UNLIKELY(oldSize == m_size)) {
|
||||
auto oldSize = a->m_size;
|
||||
a->append(uninit_null(), false);
|
||||
assert(a->m_size == oldSize + 1);
|
||||
if (UNLIKELY(oldSize == a->m_size)) {
|
||||
ret = &Variant::lvalBlackHole();
|
||||
} else {
|
||||
assert(lastIndex(m_size) != PosType::invalid);
|
||||
ret = &lval(lastIndex(m_size));
|
||||
assert(a->lastIndex(a->m_size) != PosType::invalid);
|
||||
ret = &a->lval(a->lastIndex(a->m_size));
|
||||
}
|
||||
|
||||
return this;
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData *PolicyArray::createLvalPtr(StringData* k, Variant *&ret, bool copy) {
|
||||
APILOG(this) << "(" << keystr(k) << ", " << ret << ", " << copy << ")";
|
||||
return addLval(k, ret, copy);
|
||||
ArrayData *PolicyArray::CreateLvalPtr(ArrayData* ad, StringData* k,
|
||||
Variant *&ret, bool copy) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "(" << keystr(k) << ", " << ret << ", " << copy << ")";
|
||||
return a->addLval(k, ret, copy);
|
||||
}
|
||||
|
||||
ArrayData *PolicyArray::getLvalPtr(StringData* k, Variant *&ret, bool copy) {
|
||||
APILOG(this) << "(" << keystr(k) << ", " << ret << ", " << copy << ")";
|
||||
ArrayData *PolicyArray::GetLvalPtr(ArrayData* ad, StringData* k,
|
||||
Variant *&ret, bool copy) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "(" << keystr(k) << ", " << ret << ", " << copy << ")";
|
||||
if (copy) {
|
||||
return PolicyArray::copy()->getLvalPtr(k, ret, false);
|
||||
return a->PolicyArray::copy()->getLvalPtr(k, ret, false);
|
||||
}
|
||||
const auto pos = find(k, m_size);
|
||||
const auto pos = a->find(k, a->m_size);
|
||||
ret = pos != PosType::invalid
|
||||
? &Store::lval(pos)
|
||||
? &a->Store::lval(pos)
|
||||
: nullptr;
|
||||
return this;
|
||||
return a;
|
||||
}
|
||||
|
||||
template <class K>
|
||||
@@ -381,6 +405,16 @@ ArrayData *PolicyArray::setRefImpl(K k, CVarRef v, bool copy) {
|
||||
return this;
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
PolicyArray::SetRefInt(ArrayData* ad, int64_t k, CVarRef v, bool copy) {
|
||||
return asPolicyArray(ad)->setRefImpl(k, v, copy);
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
PolicyArray::SetRefStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) {
|
||||
return asPolicyArray(ad)->setRefImpl(k, v, copy);
|
||||
}
|
||||
|
||||
template <class K>
|
||||
ArrayData *PolicyArray::addImpl(K k, const Variant& v, bool copy) {
|
||||
APILOG(this) << "(" << keystr(k) << ", " << valstr(v) << ", " << copy << ");";
|
||||
@@ -398,8 +432,18 @@ ArrayData *PolicyArray::addImpl(K k, const Variant& v, bool copy) {
|
||||
return this;
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
PolicyArray::AddInt(ArrayData* ad, int64_t k, CVarRef v, bool copy) {
|
||||
return asPolicyArray(ad)->addImpl(k, v, copy);
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
PolicyArray::AddStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) {
|
||||
return asPolicyArray(ad)->addImpl(k, v, copy);
|
||||
}
|
||||
|
||||
template <class K>
|
||||
PolicyArray *PolicyArray::addLvalImpl(K k, Variant*& ret, bool copy) {
|
||||
ArrayData* PolicyArray::addLvalImpl(K k, Variant*& ret, bool copy) {
|
||||
APILOG(this) << "(" << k << ", " << ret << ", " << copy << ")";
|
||||
if (copy) {
|
||||
return PolicyArray::copy()->addLval(k, ret, false);
|
||||
@@ -413,6 +457,16 @@ PolicyArray *PolicyArray::addLvalImpl(K k, Variant*& ret, bool copy) {
|
||||
return this;
|
||||
}
|
||||
|
||||
ArrayData* PolicyArray::AddLvalInt(ArrayData* ad, int64_t k,
|
||||
Variant *&ret, bool copy) {
|
||||
return asPolicyArray(ad)->addLvalImpl(k, ret, copy);
|
||||
}
|
||||
|
||||
ArrayData* PolicyArray::AddLvalStr(ArrayData* ad, StringData* k,
|
||||
Variant *&ret, bool copy) {
|
||||
return asPolicyArray(ad)->addLvalImpl(k, ret, copy);
|
||||
}
|
||||
|
||||
template <class K>
|
||||
ArrayData *PolicyArray::removeImpl(K k, bool copy) {
|
||||
APILOG(this) << "(" << keystr(k) << ", " << copy << ")";
|
||||
@@ -451,26 +505,40 @@ ArrayData *PolicyArray::removeImpl(K k, bool copy) {
|
||||
return this;
|
||||
}
|
||||
|
||||
ssize_t PolicyArray::iter_begin() const {
|
||||
APILOG(this) << "()";
|
||||
return m_size ? toInt<int64_t>(firstIndex(m_size)) : invalid_index;
|
||||
ArrayData*
|
||||
PolicyArray::RemoveInt(ArrayData* ad, int64_t k, bool copy) {
|
||||
return asPolicyArray(ad)->removeImpl(k, copy);
|
||||
}
|
||||
|
||||
ssize_t PolicyArray::iter_end() const {
|
||||
APILOG(this) << "()";
|
||||
return ssize_t(lastIndex(m_size));
|
||||
ArrayData*
|
||||
PolicyArray::RemoveStr(ArrayData* ad, const StringData* k, bool copy) {
|
||||
return asPolicyArray(ad)->removeImpl(k, copy);
|
||||
}
|
||||
|
||||
ssize_t PolicyArray::iter_advance(ssize_t prev) const {
|
||||
APILOG(this) << "(" << prev << ")";
|
||||
auto const result = toInt<int64_t>(nextIndex(toPos(prev), m_size));
|
||||
ssize_t PolicyArray::IterBegin(const ArrayData* ad) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "()";
|
||||
return a->m_size ? toInt<int64_t>(a->firstIndex(a->m_size)) : invalid_index;
|
||||
}
|
||||
|
||||
ssize_t PolicyArray::IterEnd(const ArrayData* ad) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "()";
|
||||
return ssize_t(a->lastIndex(a->m_size));
|
||||
}
|
||||
|
||||
ssize_t PolicyArray::IterAdvance(const ArrayData* ad, ssize_t prev) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "(" << prev << ")";
|
||||
auto const result = toInt<int64_t>(a->nextIndex(toPos(prev), a->m_size));
|
||||
MYLOG << "returning " << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t PolicyArray::iter_rewind(ssize_t prev) const {
|
||||
APILOG(this) << "(" << prev << ")";
|
||||
return toInt<int64_t>(prevIndex(toPos(prev), m_size));
|
||||
ssize_t PolicyArray::IterRewind(const ArrayData* ad, ssize_t prev) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "(" << prev << ")";
|
||||
return toInt<int64_t>(a->prevIndex(toPos(prev), a->m_size));
|
||||
}
|
||||
|
||||
bool PolicyArray::validFullPos(const FullPos& fp) const {
|
||||
@@ -659,7 +727,7 @@ ArrayData *PolicyArray::merge(const ArrayData *elems, bool copy) {
|
||||
StringData *s = key.getStringData();
|
||||
Variant *p;
|
||||
// Andrei TODO: make sure this is the right semantics
|
||||
lval(s, p, false);
|
||||
LvalStr(this, s, p, false);
|
||||
p->setWithRef(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,35 +331,22 @@ public:
|
||||
|
||||
virtual ~PolicyArray() FOLLY_OVERRIDE;
|
||||
|
||||
/**
|
||||
* Number of elements this array has.
|
||||
*/
|
||||
virtual ssize_t vsize() const FOLLY_OVERRIDE {
|
||||
// vsize() called, but m_size should never be -1 in PolicyArray
|
||||
assert(false);
|
||||
return m_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* getValueRef() gets a reference to value at position "pos".
|
||||
*/
|
||||
virtual CVarRef getValueRef(ssize_t pos) const FOLLY_OVERRIDE;
|
||||
static CVarRef GetValueRef(const ArrayData*, ssize_t pos);
|
||||
|
||||
/*
|
||||
* Returns whether or not this array contains "vector-like" data.
|
||||
* I.e. all the keys are contiguous increasing integers.
|
||||
*/
|
||||
virtual bool isVectorData() const FOLLY_OVERRIDE;
|
||||
static bool IsVectorData(const ArrayData*);
|
||||
|
||||
/**
|
||||
* Testing whether a key exists.
|
||||
*/
|
||||
virtual bool exists(int64_t k) const FOLLY_OVERRIDE {
|
||||
return Store::find(k, m_size) < toPos(m_size);
|
||||
}
|
||||
virtual bool exists(const StringData* k) const FOLLY_OVERRIDE {
|
||||
return Store::find(k, m_size) < toPos(m_size);
|
||||
}
|
||||
static bool ExistsInt(const ArrayData*, int64_t k);
|
||||
static bool ExistsStr(const ArrayData*, const StringData* k);
|
||||
|
||||
private:
|
||||
template <class K> TypedValue* nvGetImpl(K k) const;
|
||||
@@ -384,16 +371,10 @@ public:
|
||||
* Getting l-value (that Variant pointer) at specified key. Return NULL if
|
||||
* escalation is not needed, or an escalated array data.
|
||||
*/
|
||||
virtual ArrayData *lval(int64_t k,
|
||||
Variant *&ret,
|
||||
bool copy) FOLLY_OVERRIDE {
|
||||
return lvalImpl(k, ret, copy);
|
||||
}
|
||||
virtual ArrayData *lval(StringData* k,
|
||||
Variant*& ret,
|
||||
bool copy) FOLLY_OVERRIDE {
|
||||
return lvalImpl(k, ret, copy);
|
||||
}
|
||||
static ArrayData* LvalInt(ArrayData* ad, int64_t k, Variant *&ret,
|
||||
bool copy);
|
||||
static ArrayData* LvalStr(ArrayData* ad, StringData* k, Variant*& ret,
|
||||
bool copy);
|
||||
|
||||
/**
|
||||
* Getting l-value (that Variant pointer) of a new element with the next
|
||||
@@ -402,17 +383,17 @@ public:
|
||||
* available integer key may fail, in which case ret is set to point to
|
||||
* the lval blackhole (see Variant::lvalBlackHole() for details).
|
||||
*/
|
||||
virtual ArrayData *lvalNew(Variant *&ret, bool copy) FOLLY_OVERRIDE;
|
||||
static ArrayData *LvalNew(ArrayData* ad, Variant *&ret, bool copy);
|
||||
|
||||
/**
|
||||
* Helper functions used for getting a reference to elements of
|
||||
* the dynamic property array in ObjectData or the local cache array
|
||||
* in ShardMap.
|
||||
*/
|
||||
virtual ArrayData *createLvalPtr(StringData* k, Variant *&ret, bool copy)
|
||||
FOLLY_OVERRIDE;
|
||||
virtual ArrayData *getLvalPtr(StringData* k, Variant *&ret, bool copy)
|
||||
FOLLY_OVERRIDE;
|
||||
static ArrayData *CreateLvalPtr(ArrayData*, StringData* k, Variant *&ret,
|
||||
bool copy);
|
||||
static ArrayData *GetLvalPtr(ArrayData*, StringData* k, Variant *&ret,
|
||||
bool copy);
|
||||
|
||||
/**
|
||||
* Setting a value at specified key. If "copy" is true, make a copy first
|
||||
@@ -432,12 +413,9 @@ private:
|
||||
ArrayData *setRefImpl(K k, CVarRef v, bool copy);
|
||||
|
||||
public:
|
||||
virtual ArrayData *setRef(int64_t k, CVarRef v, bool copy) FOLLY_OVERRIDE {
|
||||
return setRefImpl(k, v, copy);
|
||||
}
|
||||
virtual ArrayData *setRef(StringData* k, CVarRef v, bool cpy) FOLLY_OVERRIDE {
|
||||
return setRefImpl(k, v, cpy);
|
||||
}
|
||||
static ArrayData* SetRefInt(ArrayData* ad, int64_t k, CVarRef v, bool copy);
|
||||
static ArrayData* SetRefStr(ArrayData* ad, StringData* k, CVarRef v,
|
||||
bool cpy);
|
||||
|
||||
/**
|
||||
* The same as set(), but with the precondition that the key does
|
||||
@@ -446,15 +424,11 @@ public:
|
||||
*/
|
||||
private:
|
||||
template <class K>
|
||||
ArrayData *addImpl(K k, CVarRef v, bool copy);
|
||||
ArrayData* addImpl(K k, CVarRef v, bool copy);
|
||||
|
||||
public:
|
||||
virtual ArrayData *add(int64_t k, CVarRef v, bool copy) FOLLY_OVERRIDE {
|
||||
return addImpl(k, v, copy);
|
||||
}
|
||||
virtual ArrayData *add(StringData* k, CVarRef v, bool copy) FOLLY_OVERRIDE {
|
||||
return addImpl(k, v, copy);
|
||||
}
|
||||
static ArrayData* AddInt(ArrayData*, int64_t k, CVarRef v, bool copy);
|
||||
static ArrayData* AddStr(ArrayData*, StringData* k, CVarRef v, bool copy);
|
||||
|
||||
/*
|
||||
* Same semantics as lval(), except with the precondition that the
|
||||
@@ -462,17 +436,13 @@ public:
|
||||
*/
|
||||
private:
|
||||
template <class K>
|
||||
PolicyArray* addLvalImpl(K k, Variant*& ret, bool copy);
|
||||
ArrayData* addLvalImpl(K k, Variant*& ret, bool copy);
|
||||
|
||||
public:
|
||||
virtual PolicyArray *addLval(int64_t k, Variant *&ret, bool copy)
|
||||
FOLLY_OVERRIDE {
|
||||
return addLvalImpl(k, ret, copy);
|
||||
}
|
||||
virtual PolicyArray *addLval(StringData* k, Variant *&ret, bool copy)
|
||||
FOLLY_OVERRIDE {
|
||||
return addLvalImpl(k, ret, copy);
|
||||
}
|
||||
static ArrayData* AddLvalInt(ArrayData*, int64_t k, Variant *&ret,
|
||||
bool copy);
|
||||
static ArrayData* AddLvalStr(ArrayData*, StringData* k, Variant *&ret,
|
||||
bool copy);
|
||||
|
||||
/**
|
||||
* Remove a value at specified key. If "copy" is true, make a copy first
|
||||
@@ -483,17 +453,13 @@ private:
|
||||
template <class K> ArrayData *removeImpl(K k, bool copy);
|
||||
|
||||
public:
|
||||
virtual ArrayData *remove(int64_t k, bool copy) FOLLY_OVERRIDE {
|
||||
return removeImpl(k, copy);
|
||||
}
|
||||
virtual ArrayData *remove(const StringData* k, bool copy) FOLLY_OVERRIDE {
|
||||
return removeImpl(k, copy);
|
||||
}
|
||||
static ArrayData *RemoveInt(ArrayData*, int64_t k, bool copy);
|
||||
static ArrayData *RemoveStr(ArrayData*, const StringData* k, bool copy);
|
||||
|
||||
virtual ssize_t iter_begin() const FOLLY_OVERRIDE;
|
||||
virtual ssize_t iter_end() const FOLLY_OVERRIDE;
|
||||
virtual ssize_t iter_advance(ssize_t prev) const FOLLY_OVERRIDE;
|
||||
virtual ssize_t iter_rewind(ssize_t prev) const FOLLY_OVERRIDE;
|
||||
static ssize_t IterBegin(const ArrayData*);
|
||||
static ssize_t IterEnd(const ArrayData*);
|
||||
static ssize_t IterAdvance(const ArrayData*, ssize_t prev);
|
||||
static ssize_t IterRewind(const ArrayData*, ssize_t prev);
|
||||
|
||||
/**
|
||||
* Mutable iteration APIs
|
||||
|
||||
@@ -45,6 +45,10 @@ CVarRef SharedMap::getValueRef(ssize_t pos) const {
|
||||
return tvAsCVarRef(tv);
|
||||
}
|
||||
|
||||
CVarRef SharedMap::GetValueRef(const ArrayData* ad, ssize_t pos) {
|
||||
return asSharedMap(ad)->getValueRef(pos);
|
||||
}
|
||||
|
||||
HOT_FUNC
|
||||
SharedMap::~SharedMap() {
|
||||
if (m_localCache) {
|
||||
@@ -86,22 +90,24 @@ ssize_t SharedMap::getIndex(int64_t k) const {
|
||||
return m_map->indexOf(k);
|
||||
}
|
||||
|
||||
bool SharedMap::isVectorData() const {
|
||||
if (isVector()) return true;
|
||||
const auto n = size();
|
||||
bool SharedMap::IsVectorData(const ArrayData* ad) {
|
||||
auto a = asSharedMap(ad);
|
||||
if (a->isVector()) return true;
|
||||
const auto n = a->size();
|
||||
for (ssize_t i = 0; i < n; i++) {
|
||||
if (m_map->indexOf(i) != i) return false;
|
||||
if (a->m_map->indexOf(i) != i) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedMap::exists(const StringData* k) const {
|
||||
if (isVector()) return false;
|
||||
return m_map->indexOf(k) != -1;
|
||||
bool SharedMap::ExistsStr(const ArrayData* ad, const StringData* k) {
|
||||
auto a = asSharedMap(ad);
|
||||
if (a->isVector()) return false;
|
||||
return a->m_map->indexOf(k) != -1;
|
||||
}
|
||||
|
||||
bool SharedMap::exists(int64_t k) const {
|
||||
return getIndex(k) != -1;
|
||||
bool SharedMap::ExistsInt(const ArrayData* ad, int64_t k) {
|
||||
return asSharedMap(ad)->getIndex(k) != -1;
|
||||
}
|
||||
|
||||
/* if a2 is modified copy of a1 (i.e. != a1), then release a1 and return a2 */
|
||||
@@ -110,18 +116,20 @@ inline ArrayData* releaseIfCopied(ArrayData* a1, ArrayData* a2) {
|
||||
return a2;
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::lval(int64_t k, Variant *&ret, bool copy) {
|
||||
ArrayData *escalated = SharedMap::escalate();
|
||||
ArrayData *SharedMap::LvalInt(ArrayData* ad, int64_t k, Variant *&ret,
|
||||
bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
return releaseIfCopied(escalated, escalated->lval(k, ret, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::lval(StringData* k, Variant *&ret, bool copy) {
|
||||
ArrayData *escalated = SharedMap::escalate();
|
||||
ArrayData *SharedMap::LvalStr(ArrayData* ad, StringData* k, Variant *&ret,
|
||||
bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
return releaseIfCopied(escalated, escalated->lval(k, ret, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::lvalNew(Variant *&ret, bool copy) {
|
||||
ArrayData *escalated = SharedMap::escalate();
|
||||
ArrayData *SharedMap::LvalNew(ArrayData* ad, Variant *&ret, bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
return releaseIfCopied(escalated, escalated->lvalNew(ret, false));
|
||||
}
|
||||
|
||||
@@ -137,23 +145,37 @@ SharedMap::SetStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) {
|
||||
return releaseIfCopied(escalated, escalated->set(k, v, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::setRef(int64_t k, CVarRef v, bool copy) {
|
||||
ArrayData *escalated = SharedMap::escalate();
|
||||
ArrayData*
|
||||
SharedMap::SetRefInt(ArrayData* ad, int64_t k, CVarRef v, bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
return releaseIfCopied(escalated, escalated->setRef(k, v, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::setRef(StringData* k, CVarRef v, bool copy) {
|
||||
ArrayData *escalated = SharedMap::escalate();
|
||||
ArrayData*
|
||||
SharedMap::SetRefStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
return releaseIfCopied(escalated, escalated->setRef(k, v, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::remove(int64_t k, bool copy) {
|
||||
ArrayData *escalated = SharedMap::escalate();
|
||||
ArrayData *SharedMap::AddLvalInt(ArrayData* ad, int64_t k, Variant *&ret,
|
||||
bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
return releaseIfCopied(escalated, escalated->addLval(k, ret, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::AddLvalStr(ArrayData* ad, StringData* k, Variant *&ret,
|
||||
bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
return releaseIfCopied(escalated, escalated->addLval(k, ret, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::RemoveInt(ArrayData* ad, int64_t k, bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
return releaseIfCopied(escalated, escalated->remove(k, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::remove(const StringData* k, bool copy) {
|
||||
ArrayData *escalated = SharedMap::escalate();
|
||||
ArrayData *SharedMap::RemoveStr(ArrayData* ad, const StringData* k, bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
return releaseIfCopied(escalated, escalated->remove(k, false));
|
||||
}
|
||||
|
||||
@@ -233,28 +255,27 @@ ArrayData* SharedMap::escalateForSort() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t SharedMap::vsize() const {
|
||||
assert(false); // should never be called since we set size already.
|
||||
return m_size;
|
||||
ssize_t SharedMap::IterBegin(const ArrayData* ad) {
|
||||
auto a = asSharedMap(ad);
|
||||
return a->m_size > 0 ? 0 : invalid_index;
|
||||
}
|
||||
|
||||
ssize_t SharedMap::iter_begin() const {
|
||||
return !empty() ? 0 : invalid_index;
|
||||
}
|
||||
|
||||
ssize_t SharedMap::iter_end() const {
|
||||
auto n = size();
|
||||
ssize_t SharedMap::IterEnd(const ArrayData* ad) {
|
||||
auto a = asSharedMap(ad);
|
||||
auto n = a->m_size;
|
||||
return n > 0 ? ssize_t(n - 1) : invalid_index;
|
||||
}
|
||||
|
||||
ssize_t SharedMap::iter_advance(ssize_t prev) const {
|
||||
assert(prev >= 0 && prev < size());
|
||||
ssize_t SharedMap::IterAdvance(const ArrayData* ad, ssize_t prev) {
|
||||
auto a = asSharedMap(ad);
|
||||
assert(prev >= 0 && prev < a->m_size);
|
||||
ssize_t next = prev + 1;
|
||||
return next < size() ? next : invalid_index;
|
||||
return next < a->m_size ? next : invalid_index;
|
||||
}
|
||||
|
||||
ssize_t SharedMap::iter_rewind(ssize_t prev) const {
|
||||
assert(prev >= 0 && prev < size());
|
||||
ssize_t SharedMap::IterRewind(const ArrayData* ad, ssize_t prev) {
|
||||
auto a = asSharedMap(ad);
|
||||
assert(prev >= 0 && prev < a->m_size);
|
||||
ssize_t next = prev - 1;
|
||||
return next >= 0 ? next : invalid_index;
|
||||
}
|
||||
|
||||
@@ -56,28 +56,34 @@ public:
|
||||
using ArrayData::addLval;
|
||||
using ArrayData::remove;
|
||||
|
||||
ssize_t vsize() const;
|
||||
|
||||
SharedVariant* getValueImpl(ssize_t pos) const {
|
||||
return isVector() ? m_vec->getValue(pos) : m_map->getValue(pos);
|
||||
}
|
||||
|
||||
CVarRef getValueRef(ssize_t pos) const;
|
||||
static CVarRef GetValueRef(const ArrayData* ad, ssize_t pos);
|
||||
|
||||
bool exists(int64_t k) const;
|
||||
bool exists(const StringData* k) const;
|
||||
static bool ExistsInt(const ArrayData* ad, int64_t k);
|
||||
static bool ExistsStr(const ArrayData* ad, const StringData* k);
|
||||
|
||||
virtual ArrayData *lval(int64_t k, Variant *&ret, bool copy);
|
||||
virtual ArrayData *lval(StringData* k, Variant *&ret, bool copy);
|
||||
ArrayData *lvalNew(Variant *&ret, bool copy);
|
||||
static ArrayData* LvalInt(ArrayData*, int64_t k, Variant *&ret,
|
||||
bool copy);
|
||||
static ArrayData* LvalStr(ArrayData*, StringData* k, Variant *&ret,
|
||||
bool copy);
|
||||
static ArrayData* LvalNew(ArrayData*, Variant *&ret, bool copy);
|
||||
|
||||
static ArrayData *SetInt(ArrayData*, int64_t k, CVarRef v, bool copy);
|
||||
static ArrayData *SetStr(ArrayData*, StringData* k, CVarRef v, bool copy);
|
||||
ArrayData *setRef(int64_t k, CVarRef v, bool copy);
|
||||
ArrayData *setRef(StringData* k, CVarRef v, bool copy);
|
||||
static ArrayData* SetInt(ArrayData*, int64_t k, CVarRef v, bool copy);
|
||||
static ArrayData* SetStr(ArrayData*, StringData* k, CVarRef v, bool copy);
|
||||
static ArrayData* SetRefInt(ArrayData*, int64_t k, CVarRef v, bool copy);
|
||||
static ArrayData* SetRefStr(ArrayData*, StringData* k, CVarRef v, bool copy);
|
||||
|
||||
ArrayData *remove(int64_t k, bool copy);
|
||||
ArrayData *remove(const StringData* k, bool copy);
|
||||
static ArrayData* AddLvalInt(ArrayData*, int64_t k, Variant *&ret,
|
||||
bool copy);
|
||||
static ArrayData* AddLvalStr(ArrayData*, StringData* k, Variant *&ret,
|
||||
bool copy);
|
||||
|
||||
static ArrayData *RemoveInt(ArrayData* ad, int64_t k, bool copy);
|
||||
static ArrayData *RemoveStr(ArrayData* ad, const StringData* k, bool copy);
|
||||
|
||||
ArrayData *copy() const;
|
||||
/**
|
||||
@@ -98,12 +104,12 @@ public:
|
||||
static TypedValue* NvGetStr(const ArrayData*, const StringData* k);
|
||||
static void NvGetKey(const ArrayData*, TypedValue* out, ssize_t pos);
|
||||
|
||||
bool isVectorData() const;
|
||||
static bool IsVectorData(const ArrayData* ad);
|
||||
|
||||
ssize_t iter_begin() const;
|
||||
ssize_t iter_end() const;
|
||||
ssize_t iter_advance(ssize_t prev) const;
|
||||
ssize_t iter_rewind(ssize_t prev) const;
|
||||
static ssize_t IterBegin(const ArrayData*);
|
||||
static ssize_t IterEnd(const ArrayData*);
|
||||
static ssize_t IterAdvance(const ArrayData*, ssize_t prev);
|
||||
static ssize_t IterRewind(const ArrayData*, ssize_t prev);
|
||||
|
||||
bool validFullPos(const FullPos& fp) const;
|
||||
bool advanceFullPos(FullPos& fp);
|
||||
|
||||
@@ -36,14 +36,15 @@ NameValueTableWrapper::asNVTW(const ArrayData* ad) {
|
||||
return static_cast<const NameValueTableWrapper*>(ad);
|
||||
}
|
||||
|
||||
ssize_t NameValueTableWrapper::vsize() const {
|
||||
size_t NameValueTableWrapper::Vsize(const ArrayData* ad) {
|
||||
// We need to iterate to find out the actual size, since
|
||||
// KindOfIndirect elements in the array may have been set to
|
||||
// KindOfUninit.
|
||||
ssize_t count = 0;
|
||||
for (ssize_t iter = iter_begin();
|
||||
iter != ArrayData::invalid_index;
|
||||
iter = iter_advance(iter)) {
|
||||
auto a = asNVTW(ad);
|
||||
size_t count = 0;
|
||||
for (auto iter = IterBegin(a);
|
||||
iter != invalid_index;
|
||||
iter = IterAdvance(a, iter)) {
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
@@ -63,23 +64,20 @@ void NameValueTableWrapper::NvGetKey(const ArrayData* ad, TypedValue* out,
|
||||
}
|
||||
}
|
||||
|
||||
CVarRef NameValueTableWrapper::getValueRef(ssize_t pos) const {
|
||||
NameValueTable::Iterator iter(m_tab, pos);
|
||||
CVarRef NameValueTableWrapper::GetValueRef(const ArrayData* ad, ssize_t pos) {
|
||||
auto a = asNVTW(ad);
|
||||
NameValueTable::Iterator iter(a->m_tab, pos);
|
||||
return iter.valid() ? tvAsCVarRef(iter.curVal()) : null_variant;
|
||||
}
|
||||
|
||||
bool NameValueTableWrapper::noCopyOnWrite() const {
|
||||
// This just disables a few places that will call copy() on an array
|
||||
// if it has more than one reference.
|
||||
return true;
|
||||
bool
|
||||
NameValueTableWrapper::ExistsInt(const ArrayData* ad, int64_t k) {
|
||||
return ExistsStr(ad, String(k).get());
|
||||
}
|
||||
|
||||
bool NameValueTableWrapper::exists(int64_t k) const {
|
||||
return exists(String(k));
|
||||
}
|
||||
|
||||
bool NameValueTableWrapper::exists(const StringData* k) const {
|
||||
return m_tab->lookup(k);
|
||||
bool
|
||||
NameValueTableWrapper::ExistsStr(const ArrayData* ad, const StringData* k) {
|
||||
return asNVTW(ad)->m_tab->lookup(k) != nullptr;
|
||||
}
|
||||
|
||||
TypedValue*
|
||||
@@ -91,24 +89,42 @@ TypedValue* NameValueTableWrapper::NvGetInt(const ArrayData* ad, int64_t k) {
|
||||
return asNVTW(ad)->m_tab->lookup(String(k).get());
|
||||
}
|
||||
|
||||
ArrayData* NameValueTableWrapper::lval(int64_t k, Variant*& ret, bool) {
|
||||
return lval(String(k), ret, false);
|
||||
ArrayData*
|
||||
NameValueTableWrapper::LvalInt(ArrayData* ad, int64_t k, Variant*& ret,
|
||||
bool copy) {
|
||||
return LvalStr(ad, String(k).get(), ret, copy);
|
||||
}
|
||||
|
||||
ArrayData* NameValueTableWrapper::lval(StringData* k, Variant*& ret, bool) {
|
||||
TypedValue* tv = m_tab->lookup(k);
|
||||
ArrayData*
|
||||
NameValueTableWrapper::LvalStr(ArrayData* ad, StringData* k, Variant*& ret,
|
||||
bool copy) {
|
||||
auto a = asNVTW(ad);
|
||||
TypedValue* tv = a->m_tab->lookup(k);
|
||||
if (!tv) {
|
||||
TypedValue nulVal;
|
||||
tvWriteNull(&nulVal);
|
||||
tv = m_tab->set(k, &nulVal);
|
||||
tv = a->m_tab->set(k, &nulVal);
|
||||
}
|
||||
ret = &tvAsVariant(tv);
|
||||
return this;
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData* NameValueTableWrapper::lvalNew(Variant*& ret, bool copy) {
|
||||
ArrayData*
|
||||
NameValueTableWrapper::AddLvalInt(ArrayData* ad, int64_t k, Variant*& ret,
|
||||
bool copy) {
|
||||
return LvalStr(ad, String(k).get(), ret, copy);
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
NameValueTableWrapper::AddLvalStr(ArrayData* ad, StringData* k, Variant*& ret,
|
||||
bool copy) {
|
||||
return LvalStr(ad, k, ret, copy);
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
NameValueTableWrapper::LvalNew(ArrayData* ad, Variant*& ret, bool copy) {
|
||||
ret = &Variant::lvalBlackHole();
|
||||
return this;
|
||||
return ad;
|
||||
}
|
||||
|
||||
ArrayData* NameValueTableWrapper::SetInt(ArrayData* ad, int64_t k,
|
||||
@@ -123,22 +139,29 @@ ArrayData* NameValueTableWrapper::SetStr(ArrayData* ad, StringData* k,
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData* NameValueTableWrapper::setRef(int64_t k, CVarRef v, bool copy) {
|
||||
return setRef(String(k), v, copy);
|
||||
ArrayData* NameValueTableWrapper::SetRefInt(ArrayData* ad, int64_t k,
|
||||
CVarRef v, bool copy) {
|
||||
return asNVTW(ad)->setRef(String(k).get(), v, copy);
|
||||
}
|
||||
|
||||
ArrayData* NameValueTableWrapper::setRef(StringData* k, CVarRef v, bool copy) {
|
||||
tvAsVariant(m_tab->lookupAdd(k)).assignRef(v);
|
||||
return this;
|
||||
ArrayData* NameValueTableWrapper::SetRefStr(ArrayData* ad, StringData* k,
|
||||
CVarRef v, bool copy) {
|
||||
auto a = asNVTW(ad);
|
||||
tvAsVariant(a->m_tab->lookupAdd(k)).assignRef(v);
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData* NameValueTableWrapper::remove(int64_t k, bool copy) {
|
||||
return remove(String(k), copy);
|
||||
ArrayData*
|
||||
NameValueTableWrapper::RemoveInt(ArrayData* ad, int64_t k, bool copy) {
|
||||
return RemoveStr(ad, String(k).get(), copy);
|
||||
}
|
||||
|
||||
ArrayData* NameValueTableWrapper::remove(const StringData* k, bool copy) {
|
||||
m_tab->unset(k);
|
||||
return this;
|
||||
ArrayData*
|
||||
NameValueTableWrapper::RemoveStr(ArrayData* ad, const StringData* k,
|
||||
bool copy) {
|
||||
auto a = asNVTW(ad);
|
||||
a->m_tab->unset(k);
|
||||
return a;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -171,23 +194,27 @@ ArrayData* NameValueTableWrapper::prepend(CVarRef v, bool copy) {
|
||||
throw NotImplementedException("prepend on $GLOBALS");
|
||||
}
|
||||
|
||||
ssize_t NameValueTableWrapper::iter_begin() const {
|
||||
NameValueTable::Iterator iter(m_tab);
|
||||
ssize_t NameValueTableWrapper::IterBegin(const ArrayData* ad) {
|
||||
auto a = asNVTW(ad);
|
||||
NameValueTable::Iterator iter(a->m_tab);
|
||||
return iter.toInteger();
|
||||
}
|
||||
|
||||
ssize_t NameValueTableWrapper::iter_end() const {
|
||||
return NameValueTable::Iterator::getEnd(m_tab).toInteger();
|
||||
ssize_t NameValueTableWrapper::IterEnd(const ArrayData* ad) {
|
||||
auto a = asNVTW(ad);
|
||||
return NameValueTable::Iterator::getEnd(a->m_tab).toInteger();
|
||||
}
|
||||
|
||||
ssize_t NameValueTableWrapper::iter_advance(ssize_t prev) const {
|
||||
NameValueTable::Iterator iter(m_tab, prev);
|
||||
ssize_t NameValueTableWrapper::IterAdvance(const ArrayData* ad, ssize_t prev) {
|
||||
auto a = asNVTW(ad);
|
||||
NameValueTable::Iterator iter(a->m_tab, prev);
|
||||
iter.next();
|
||||
return iter.toInteger();
|
||||
}
|
||||
|
||||
ssize_t NameValueTableWrapper::iter_rewind(ssize_t prev) const {
|
||||
NameValueTable::Iterator iter(m_tab, prev);
|
||||
ssize_t NameValueTableWrapper::IterRewind(const ArrayData* ad, ssize_t prev) {
|
||||
auto a = asNVTW(ad);
|
||||
NameValueTable::Iterator iter(a->m_tab, prev);
|
||||
iter.prev();
|
||||
return iter.toInteger();
|
||||
}
|
||||
@@ -233,7 +260,7 @@ void NameValueTableWrapper::uksort(CVarRef cmp_function) {}
|
||||
void NameValueTableWrapper::usort(CVarRef cmp_function) {}
|
||||
void NameValueTableWrapper::uasort(CVarRef cmp_function) {}
|
||||
|
||||
bool NameValueTableWrapper::isVectorData() const {
|
||||
bool NameValueTableWrapper::IsVectorData(const ArrayData*) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,27 +77,31 @@ public: // ArrayData implementation
|
||||
return tvAsVariant(nvGet(k.get()));
|
||||
}
|
||||
|
||||
virtual ssize_t vsize() const;
|
||||
static size_t Vsize(const ArrayData*);
|
||||
static void NvGetKey(const ArrayData* ad, TypedValue* out, ssize_t pos);
|
||||
virtual CVarRef getValueRef(ssize_t pos) const;
|
||||
virtual bool noCopyOnWrite() const;
|
||||
static CVarRef GetValueRef(const ArrayData*, ssize_t pos);
|
||||
|
||||
virtual bool exists(int64_t k) const;
|
||||
virtual bool exists(const StringData* k) const;
|
||||
static bool ExistsInt(const ArrayData* ad, int64_t k);
|
||||
static bool ExistsStr(const ArrayData* ad, const StringData* k);
|
||||
|
||||
static TypedValue* NvGetInt(const ArrayData*, int64_t k);
|
||||
static TypedValue* NvGetStr(const ArrayData*, const StringData* k);
|
||||
|
||||
virtual ArrayData* lval(int64_t k, Variant*& ret, bool copy);
|
||||
virtual ArrayData* lval(StringData* k, Variant*& ret, bool copy);
|
||||
virtual ArrayData* lvalNew(Variant*& ret, bool copy);
|
||||
static ArrayData* LvalInt(ArrayData*, int64_t k, Variant*& ret, bool copy);
|
||||
static ArrayData* LvalStr(ArrayData*, StringData* k, Variant*& ret,
|
||||
bool copy);
|
||||
static ArrayData* LvalNew(ArrayData*, Variant*& ret, bool copy);
|
||||
|
||||
static ArrayData* SetInt(ArrayData*, int64_t k, CVarRef v, bool copy);
|
||||
static ArrayData* SetStr(ArrayData*, StringData* k, CVarRef v, bool copy);
|
||||
virtual ArrayData* setRef(int64_t k, CVarRef v, bool copy);
|
||||
virtual ArrayData* setRef(StringData* k, CVarRef v, bool copy);
|
||||
virtual ArrayData* remove(int64_t k, bool copy);
|
||||
virtual ArrayData* remove(const StringData* k, bool copy);
|
||||
static ArrayData* SetRefInt(ArrayData*, int64_t k, CVarRef v, bool copy);
|
||||
static ArrayData* SetRefStr(ArrayData*, StringData* k, CVarRef v, bool copy);
|
||||
static ArrayData* AddLvalInt(ArrayData*, int64_t k, Variant*& ret,
|
||||
bool copy);
|
||||
static ArrayData* AddLvalStr(ArrayData*, StringData* k, Variant*& ret,
|
||||
bool copy);
|
||||
static ArrayData* RemoveInt(ArrayData*, int64_t k, bool copy);
|
||||
static ArrayData* RemoveStr(ArrayData*, const StringData* k, bool copy);
|
||||
|
||||
virtual ArrayData* copy() const { return 0; }
|
||||
|
||||
@@ -110,14 +114,14 @@ public: // ArrayData implementation
|
||||
|
||||
virtual ArrayData* prepend(CVarRef v, bool copy);
|
||||
|
||||
virtual ssize_t iter_begin() const;
|
||||
virtual ssize_t iter_end() const;
|
||||
virtual ssize_t iter_advance(ssize_t prev) const;
|
||||
virtual ssize_t iter_rewind(ssize_t prev) const;
|
||||
static ssize_t IterBegin(const ArrayData*);
|
||||
static ssize_t IterEnd(const ArrayData*);
|
||||
static ssize_t IterAdvance(const ArrayData*, ssize_t prev);
|
||||
static ssize_t IterRewind(const ArrayData*, ssize_t prev);
|
||||
|
||||
virtual bool validFullPos(const FullPos & fp) const;
|
||||
virtual bool advanceFullPos(FullPos&);
|
||||
virtual bool isVectorData() const;
|
||||
static bool IsVectorData(const ArrayData*);
|
||||
|
||||
virtual ArrayData* escalateForSort();
|
||||
virtual void ksort(int sort_flags, bool ascending);
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário