Devirtualize ArrayData part 2
Convert remaining virtual methods to static methods dispatched by kind. This makes ArrayData a non-virtual class, so shuffle fields and adjust static_asserts.
Esse commit está contido em:
@@ -173,6 +173,14 @@ inline ArrayData* ArrayData::append(CVarRef v, bool copy) {
|
||||
return g_array_funcs.append[m_kind](this, v, copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::appendRef(CVarRef v, bool copy) {
|
||||
return g_array_funcs.appendRef[m_kind](this, v, copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::appendWithRef(CVarRef v, bool copy) {
|
||||
return g_array_funcs.appendWithRef[m_kind](this, v, copy);
|
||||
}
|
||||
|
||||
inline TypedValue* ArrayData::nvGet(int64_t ikey) const {
|
||||
return g_array_funcs.nvGetInt[m_kind](this, ikey);
|
||||
}
|
||||
@@ -287,6 +295,86 @@ inline ssize_t ArrayData::iter_rewind(ssize_t pos) const {
|
||||
return g_array_funcs.iterRewind[m_kind](this, pos);
|
||||
}
|
||||
|
||||
inline bool ArrayData::validFullPos(const FullPos& fp) const {
|
||||
return g_array_funcs.validFullPos[m_kind](this, fp);
|
||||
}
|
||||
|
||||
inline bool ArrayData::advanceFullPos(FullPos& fp) {
|
||||
return g_array_funcs.advanceFullPos[m_kind](this, fp);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::escalateForSort() {
|
||||
return g_array_funcs.escalateForSort[m_kind](this);
|
||||
}
|
||||
|
||||
inline void ArrayData::ksort(int sort_flags, bool ascending) {
|
||||
return g_array_funcs.ksort[m_kind](this, sort_flags, ascending);
|
||||
}
|
||||
|
||||
inline void ArrayData::sort(int sort_flags, bool ascending) {
|
||||
return g_array_funcs.sort[m_kind](this, sort_flags, ascending);
|
||||
}
|
||||
|
||||
inline void ArrayData::asort(int sort_flags, bool ascending) {
|
||||
return g_array_funcs.asort[m_kind](this, sort_flags, ascending);
|
||||
}
|
||||
|
||||
inline void ArrayData::uksort(CVarRef compare) {
|
||||
return g_array_funcs.uksort[m_kind](this, compare);
|
||||
}
|
||||
|
||||
inline void ArrayData::usort(CVarRef compare) {
|
||||
return g_array_funcs.usort[m_kind](this, compare);
|
||||
}
|
||||
|
||||
inline void ArrayData::uasort(CVarRef compare) {
|
||||
return g_array_funcs.uasort[m_kind](this, compare);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::copy() const {
|
||||
return g_array_funcs.copy[m_kind](this);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::copyWithStrongIterators() const {
|
||||
return g_array_funcs.copyWithStrongIterators[m_kind](this);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::nonSmartCopy() const {
|
||||
return g_array_funcs.nonSmartCopy[m_kind](this);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::pop(Variant& value) {
|
||||
return g_array_funcs.pop[m_kind](this, value);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::dequeue(Variant& value) {
|
||||
return g_array_funcs.dequeue[m_kind](this, value);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::prepend(CVarRef value, bool copy) {
|
||||
return g_array_funcs.prepend[m_kind](this, value, copy);
|
||||
}
|
||||
|
||||
inline void ArrayData::renumber() {
|
||||
return g_array_funcs.renumber[m_kind](this);
|
||||
}
|
||||
|
||||
inline void ArrayData::onSetEvalScalar() {
|
||||
return g_array_funcs.onSetEvalScalar[m_kind](this);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::escalate() const {
|
||||
return g_array_funcs.escalate[m_kind](this);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::plus(const ArrayData* elms, bool copy) {
|
||||
return g_array_funcs.plus[m_kind](this, elms, copy);
|
||||
}
|
||||
|
||||
inline ArrayData* ArrayData::merge(const ArrayData* elms, bool copy) {
|
||||
return g_array_funcs.merge[m_kind](this, elms, copy);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static_assert(
|
||||
sizeof(ArrayData) == 32,
|
||||
sizeof(ArrayData) == 24,
|
||||
"Performance is sensitive to sizeof(ArrayData)."
|
||||
" Make sure you changed it with good reason and then update this assert.");
|
||||
|
||||
@@ -76,11 +76,6 @@ extern const ArrayFunctions g_array_funcs = {
|
||||
&SharedMap::Release,
|
||||
&NameValueTableWrapper::Release,
|
||||
&PolicyArray::Release },
|
||||
// append
|
||||
{ &HphpArray::AppendVec, &HphpArray::Append,
|
||||
&SharedMap::Append,
|
||||
&NameValueTableWrapper::Append,
|
||||
&PolicyArray::Append },
|
||||
// nvGetInt
|
||||
{ &HphpArray::NvGetIntVec, &HphpArray::NvGetInt,
|
||||
&SharedMap::NvGetInt,
|
||||
@@ -221,6 +216,121 @@ extern const ArrayFunctions g_array_funcs = {
|
||||
&SharedMap::IterRewind,
|
||||
&NameValueTableWrapper::IterRewind,
|
||||
&PolicyArray::IterRewind },
|
||||
// validFullPos
|
||||
{ &HphpArray::ValidFullPos, &HphpArray::ValidFullPos,
|
||||
&SharedMap::ValidFullPos,
|
||||
&NameValueTableWrapper::ValidFullPos,
|
||||
&PolicyArray::ValidFullPos },
|
||||
// advanceFullPos
|
||||
{ &HphpArray::AdvanceFullPos, &HphpArray::AdvanceFullPos,
|
||||
&SharedMap::AdvanceFullPos,
|
||||
&NameValueTableWrapper::AdvanceFullPos,
|
||||
&PolicyArray::AdvanceFullPos },
|
||||
// escalateForSort
|
||||
{ &HphpArray::EscalateForSort, &HphpArray::EscalateForSort,
|
||||
&SharedMap::EscalateForSort,
|
||||
&NameValueTableWrapper::EscalateForSort,
|
||||
&PolicyArray::EscalateForSort },
|
||||
// ksort
|
||||
{ &HphpArray::Ksort, &HphpArray::Ksort,
|
||||
&ArrayData::Ksort,
|
||||
&NameValueTableWrapper::Ksort,
|
||||
&ArrayData::Ksort },
|
||||
// sort
|
||||
{ &HphpArray::Sort, &HphpArray::Sort,
|
||||
&ArrayData::Sort,
|
||||
&NameValueTableWrapper::Sort,
|
||||
&ArrayData::Sort },
|
||||
// asort
|
||||
{ &HphpArray::Asort, &HphpArray::Asort,
|
||||
&ArrayData::Asort,
|
||||
&NameValueTableWrapper::Asort,
|
||||
&ArrayData::Asort },
|
||||
// uksort
|
||||
{ &HphpArray::Uksort, &HphpArray::Uksort,
|
||||
&ArrayData::Uksort,
|
||||
&NameValueTableWrapper::Uksort,
|
||||
&ArrayData::Uksort },
|
||||
// usort
|
||||
{ &HphpArray::Usort, &HphpArray::Usort,
|
||||
&ArrayData::Usort,
|
||||
&NameValueTableWrapper::Usort,
|
||||
&ArrayData::Usort },
|
||||
// uasort
|
||||
{ &HphpArray::Uasort, &HphpArray::Uasort,
|
||||
&ArrayData::Uasort,
|
||||
&NameValueTableWrapper::Uasort,
|
||||
&ArrayData::Uasort },
|
||||
// copy
|
||||
{ &HphpArray::CopyVec, &HphpArray::Copy,
|
||||
&SharedMap::Copy,
|
||||
&NameValueTableWrapper::Copy,
|
||||
&PolicyArray::Copy },
|
||||
// copyWithStrongIterators
|
||||
{ &HphpArray::CopyWithStrongIterators, &HphpArray::CopyWithStrongIterators,
|
||||
&SharedMap::CopyWithStrongIterators,
|
||||
&NameValueTableWrapper::CopyWithStrongIterators,
|
||||
&PolicyArray::CopyWithStrongIterators },
|
||||
// nonSmartCopy
|
||||
{ &HphpArray::NonSmartCopy, &HphpArray::NonSmartCopy,
|
||||
&ArrayData::NonSmartCopy,
|
||||
&ArrayData::NonSmartCopy,
|
||||
&PolicyArray::NonSmartCopy },
|
||||
// append
|
||||
{ &HphpArray::AppendVec, &HphpArray::Append,
|
||||
&SharedMap::Append,
|
||||
&NameValueTableWrapper::Append,
|
||||
&PolicyArray::Append },
|
||||
// appendRef
|
||||
{ &HphpArray::AppendRefVec, &HphpArray::AppendRef,
|
||||
&SharedMap::AppendRef,
|
||||
&NameValueTableWrapper::AppendRef,
|
||||
&PolicyArray::AppendRef },
|
||||
// appendWithRef
|
||||
{ &HphpArray::AppendWithRefVec, &HphpArray::AppendWithRef,
|
||||
&SharedMap::AppendRef,
|
||||
&NameValueTableWrapper::AppendRef,
|
||||
&PolicyArray::AppendRef },
|
||||
// plus
|
||||
{ &HphpArray::Plus, &HphpArray::Plus,
|
||||
&SharedMap::Plus,
|
||||
&NameValueTableWrapper::Plus,
|
||||
&PolicyArray::Plus },
|
||||
// merge
|
||||
{ &HphpArray::Merge, &HphpArray::Merge,
|
||||
&SharedMap::Merge,
|
||||
&NameValueTableWrapper::Merge,
|
||||
&PolicyArray::Merge },
|
||||
// pop
|
||||
{ &HphpArray::PopVec, &HphpArray::Pop,
|
||||
&SharedMap::Pop,
|
||||
&NameValueTableWrapper::Pop,
|
||||
&PolicyArray::Pop },
|
||||
// dequeue
|
||||
{ &HphpArray::Dequeue, &HphpArray::Dequeue,
|
||||
&SharedMap::Dequeue,
|
||||
&NameValueTableWrapper::Dequeue,
|
||||
&PolicyArray::Dequeue },
|
||||
// prepend
|
||||
{ &HphpArray::Prepend, &HphpArray::Prepend,
|
||||
&SharedMap::Prepend,
|
||||
&NameValueTableWrapper::Prepend,
|
||||
&PolicyArray::Prepend },
|
||||
// renumber
|
||||
{ &HphpArray::RenumberVec, &HphpArray::Renumber,
|
||||
&SharedMap::Renumber,
|
||||
&NameValueTableWrapper::Renumber,
|
||||
&PolicyArray::Renumber },
|
||||
// onSetEvalScalar
|
||||
{ &HphpArray::OnSetEvalScalarVec, &HphpArray::OnSetEvalScalar,
|
||||
&SharedMap::OnSetEvalScalar,
|
||||
&NameValueTableWrapper::OnSetEvalScalar,
|
||||
&PolicyArray::OnSetEvalScalar },
|
||||
// escalate
|
||||
{ &ArrayData::Escalate, &ArrayData::Escalate,
|
||||
&SharedMap::Escalate,
|
||||
&ArrayData::Escalate,
|
||||
&PolicyArray::Escalate },
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -272,7 +382,7 @@ ArrayData *ArrayData::CreateRef(CVarRef name, CVarRef value) {
|
||||
return init.create();
|
||||
}
|
||||
|
||||
ArrayData *ArrayData::nonSmartCopy() const {
|
||||
ArrayData *ArrayData::NonSmartCopy(const ArrayData*) {
|
||||
throw FatalErrorException("nonSmartCopy not implemented.");
|
||||
}
|
||||
|
||||
@@ -351,28 +461,28 @@ ArrayData *ArrayData::GetLvalPtr(ArrayData* ad, StringData* k,
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// stack and queue operations
|
||||
|
||||
ArrayData *ArrayData::pop(Variant &value) {
|
||||
if (!empty()) {
|
||||
ssize_t pos = iter_end();
|
||||
value = getValue(pos);
|
||||
return remove(getKey(pos), getCount() > 1);
|
||||
ArrayData *ArrayData::Pop(ArrayData* a, Variant &value) {
|
||||
if (!a->empty()) {
|
||||
ssize_t pos = a->iter_end();
|
||||
value = a->getValue(pos);
|
||||
return a->remove(a->getKey(pos), a->getCount() > 1);
|
||||
}
|
||||
value = uninit_null();
|
||||
return this;
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData *ArrayData::dequeue(Variant &value) {
|
||||
if (!empty()) {
|
||||
auto const pos = iter_begin();
|
||||
value = getValue(pos);
|
||||
ArrayData *ret = remove(getKey(pos), getCount() > 1);
|
||||
ArrayData *ArrayData::Dequeue(ArrayData* a, Variant &value) {
|
||||
if (!a->empty()) {
|
||||
auto const pos = a->iter_begin();
|
||||
value = a->getValue(pos);
|
||||
ArrayData *ret = a->remove(a->getKey(pos), a->getCount() > 1);
|
||||
|
||||
// In PHP, array_shift() will cause all numerically key-ed values re-keyed
|
||||
ret->renumber();
|
||||
return ret;
|
||||
}
|
||||
value = uninit_null();
|
||||
return this;
|
||||
return a;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -430,31 +540,31 @@ CVarRef ArrayData::endRef() {
|
||||
throw FatalErrorException("invalid ArrayData::m_pos");
|
||||
}
|
||||
|
||||
ArrayData* ArrayData::escalateForSort() {
|
||||
if (getCount() > 1) {
|
||||
return copy();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
void ArrayData::ksort(int sort_flags, bool ascending) {
|
||||
void ArrayData::Ksort(ArrayData*, int sort_flags, bool ascending) {
|
||||
throw FatalErrorException("Unimplemented ArrayData::ksort");
|
||||
}
|
||||
void ArrayData::sort(int sort_flags, bool ascending) {
|
||||
|
||||
void ArrayData::Sort(ArrayData*, int sort_flags, bool ascending) {
|
||||
throw FatalErrorException("Unimplemented ArrayData::sort");
|
||||
}
|
||||
void ArrayData::asort(int sort_flags, bool ascending) {
|
||||
|
||||
void ArrayData::Asort(ArrayData*, int sort_flags, bool ascending) {
|
||||
throw FatalErrorException("Unimplemented ArrayData::asort");
|
||||
}
|
||||
void ArrayData::uksort(CVarRef cmp_function) {
|
||||
|
||||
void ArrayData::Uksort(ArrayData*, CVarRef cmp_function) {
|
||||
throw FatalErrorException("Unimplemented ArrayData::uksort");
|
||||
}
|
||||
void ArrayData::usort(CVarRef cmp_function) {
|
||||
|
||||
void ArrayData::Usort(ArrayData*, CVarRef cmp_function) {
|
||||
throw FatalErrorException("Unimplemented ArrayData::usort");
|
||||
}
|
||||
void ArrayData::uasort(CVarRef cmp_function) {
|
||||
|
||||
void ArrayData::Uasort(ArrayData*, CVarRef cmp_function) {
|
||||
throw FatalErrorException("Unimplemented ArrayData::uasort");
|
||||
}
|
||||
ArrayData* ArrayData::copyWithStrongIterators() const {
|
||||
|
||||
ArrayData* ArrayData::CopyWithStrongIterators(const ArrayData* ad) {
|
||||
throw FatalErrorException("Unimplemented ArrayData::copyWithStrongIterators");
|
||||
}
|
||||
|
||||
@@ -624,6 +734,17 @@ CVarRef ArrayData::getNotFound(CVarRef k) {
|
||||
return null_variant;
|
||||
}
|
||||
|
||||
void ArrayData::Renumber(ArrayData*) {
|
||||
}
|
||||
|
||||
void ArrayData::OnSetEvalScalar(ArrayData*) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
ArrayData* ArrayData::Escalate(const ArrayData* ad) {
|
||||
return const_cast<ArrayData*>(ad);
|
||||
}
|
||||
|
||||
void ArrayData::dump() {
|
||||
string out; dump(out); fwrite(out.c_str(), out.size(), 1, stdout);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ class HphpArray;
|
||||
/**
|
||||
* Base class/interface for all types of specialized array data.
|
||||
*/
|
||||
class ArrayData : public Countable {
|
||||
class ArrayData {
|
||||
public:
|
||||
enum class AllocationMode : bool { smart, nonSmart };
|
||||
|
||||
@@ -56,46 +56,54 @@ public:
|
||||
static const ssize_t invalid_index = -1;
|
||||
|
||||
explicit ArrayData(ArrayKind kind)
|
||||
: m_size(-1)
|
||||
, m_strongIterators(nullptr)
|
||||
, m_pos(0)
|
||||
, m_kind(kind)
|
||||
: m_kind(kind)
|
||||
, m_allocMode(AllocationMode::smart)
|
||||
, m_size(-1)
|
||||
, _count(0)
|
||||
, m_pos(0)
|
||||
, m_strongIterators(nullptr)
|
||||
{}
|
||||
|
||||
explicit ArrayData(ArrayKind kind, AllocationMode m)
|
||||
: m_size(-1)
|
||||
, m_strongIterators(nullptr)
|
||||
, m_pos(0)
|
||||
, m_kind(kind)
|
||||
, m_allocMode(m)
|
||||
: m_kind(kind)
|
||||
, m_allocMode(m)
|
||||
, m_size(-1)
|
||||
, _count(0)
|
||||
, m_pos(0)
|
||||
, m_strongIterators(nullptr)
|
||||
{}
|
||||
|
||||
ArrayData(ArrayKind kind, AllocationMode m, uint size)
|
||||
: m_size(size)
|
||||
, m_strongIterators(nullptr)
|
||||
, m_pos(size ? 0 : ArrayData::invalid_index)
|
||||
, m_kind(kind)
|
||||
, m_allocMode(m)
|
||||
: m_kind(kind)
|
||||
, m_allocMode(m)
|
||||
, m_size(size)
|
||||
, _count(0)
|
||||
, m_pos(size ? 0 : ArrayData::invalid_index)
|
||||
, m_strongIterators(nullptr)
|
||||
{}
|
||||
|
||||
ArrayData(const ArrayData *src, ArrayKind kind,
|
||||
AllocationMode m = AllocationMode::smart)
|
||||
: m_strongIterators(nullptr)
|
||||
, m_pos(src->m_pos)
|
||||
, m_kind(src->m_kind)
|
||||
: m_kind(src->m_kind)
|
||||
, m_allocMode(m)
|
||||
, _count(0)
|
||||
, m_pos(src->m_pos)
|
||||
, m_strongIterators(nullptr)
|
||||
{}
|
||||
|
||||
static HphpArray* Make(uint capacity);
|
||||
static HphpArray* Make(uint size, const TypedValue*);
|
||||
|
||||
virtual ~ArrayData() {
|
||||
void destroy() {
|
||||
// If there are any strong iterators pointing to this array, they need
|
||||
// to be invalidated.
|
||||
freeStrongIterators();
|
||||
if (UNLIKELY(m_strongIterators != nullptr)) freeStrongIterators();
|
||||
}
|
||||
|
||||
~ArrayData() { destroy(); }
|
||||
|
||||
IMPLEMENT_COUNTABLE_METHODS
|
||||
|
||||
/**
|
||||
* Create a new ArrayData with specified array element(s).
|
||||
*/
|
||||
@@ -150,8 +158,8 @@ public:
|
||||
}
|
||||
|
||||
// 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.
|
||||
// to the 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;
|
||||
}
|
||||
@@ -185,10 +193,9 @@ public:
|
||||
return m_kind == kNvtwKind;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns whether or not this array contains "vector-like" data.
|
||||
* I.e. all the keys are contiguous increasing integers.
|
||||
* I.e. iteration order produces int keys 0 to m_size-1 in sequence.
|
||||
*/
|
||||
bool isVectorData() const;
|
||||
|
||||
@@ -201,8 +208,8 @@ public:
|
||||
bool detectSerializable = false) const;
|
||||
|
||||
/**
|
||||
* non-virtual Position-based iterations, implemented using iter_begin,
|
||||
* iter_advance, iter_prev, iter_rewind pure virtual methods.
|
||||
* Position-based iterations, implemented using iter_begin,
|
||||
* iter_advance, iter_prev, iter_rewind.
|
||||
*/
|
||||
Variant reset();
|
||||
Variant prev();
|
||||
@@ -226,15 +233,13 @@ public:
|
||||
/**
|
||||
* Interface for VM helpers. ArrayData implements generic versions
|
||||
* using the other ArrayData api; subclasses may customize methods either
|
||||
* by overriding a virtual method or providing a custom static method,
|
||||
* depending on how the method is dispatched.
|
||||
* todo: t2608483 eliminate the remaining virtual methods.
|
||||
* by providing a custom static method in g_array_funcs.
|
||||
*/
|
||||
TypedValue* nvGet(int64_t k) const;
|
||||
TypedValue* nvGet(const StringData* k) const;
|
||||
void nvGetKey(TypedValue* out, ssize_t pos) const;
|
||||
|
||||
// nonvirtual wrappers that call virtual getValueRef()
|
||||
// wrappers that call getValueRef()
|
||||
TypedValue* nvGetValueRef(ssize_t pos);
|
||||
Variant getValue(ssize_t pos) const;
|
||||
Variant getKey(ssize_t pos) const;
|
||||
@@ -303,7 +308,8 @@ public:
|
||||
|
||||
/**
|
||||
* Inline accessors that convert keys to StringData* before delegating to
|
||||
* the virtual method.
|
||||
* the virtual method. Helpers that take a CVarRef key dispatch to either
|
||||
* the StringData* or int64_t key-type helpers.
|
||||
*/
|
||||
bool exists(CStrRef k) const;
|
||||
bool exists(CVarRef k) const;
|
||||
@@ -368,24 +374,32 @@ public:
|
||||
* This will return false if the iterator points past the last element, or
|
||||
* if the iterator points before the first element.
|
||||
*/
|
||||
virtual bool validFullPos(const FullPos& fp) const = 0;
|
||||
bool validFullPos(const FullPos& fp) const;
|
||||
|
||||
/**
|
||||
* Advances the mutable iterator to the next element in the array. Returns
|
||||
* false if the iterator has moved past the last element, otherwise returns
|
||||
* true.
|
||||
*/
|
||||
virtual bool advanceFullPos(FullPos& fp) = 0;
|
||||
bool advanceFullPos(FullPos& fp);
|
||||
|
||||
CVarRef endRef();
|
||||
|
||||
virtual ArrayData* escalateForSort();
|
||||
virtual void ksort(int sort_flags, bool ascending);
|
||||
virtual void sort(int sort_flags, bool ascending);
|
||||
virtual void asort(int sort_flags, bool ascending);
|
||||
virtual void uksort(CVarRef cmp_function);
|
||||
virtual void usort(CVarRef cmp_function);
|
||||
virtual void uasort(CVarRef cmp_function);
|
||||
ArrayData* escalateForSort();
|
||||
void ksort(int sort_flags, bool ascending);
|
||||
void sort(int sort_flags, bool ascending);
|
||||
void asort(int sort_flags, bool ascending);
|
||||
void uksort(CVarRef cmp_function);
|
||||
void usort(CVarRef cmp_function);
|
||||
void uasort(CVarRef cmp_function);
|
||||
|
||||
// default sort implementations
|
||||
static void Ksort(ArrayData*, int sort_flags, bool ascending);
|
||||
static void Sort(ArrayData*, int sort_flags, bool ascending);
|
||||
static void Asort(ArrayData*, int sort_flags, bool ascending);
|
||||
static void Uksort(ArrayData*, CVarRef cmp_function);
|
||||
static void Usort(ArrayData*, CVarRef cmp_function);
|
||||
static void Uasort(ArrayData*, CVarRef cmp_function);
|
||||
|
||||
/**
|
||||
* Make a copy of myself.
|
||||
@@ -394,9 +408,11 @@ public:
|
||||
* Is only implemented for array types that need to be able to go
|
||||
* into the static array list.
|
||||
*/
|
||||
virtual ArrayData *copy() const = 0;
|
||||
virtual ArrayData *copyWithStrongIterators() const;
|
||||
virtual ArrayData *nonSmartCopy() const;
|
||||
ArrayData* copy() const;
|
||||
ArrayData* copyWithStrongIterators() const;
|
||||
ArrayData* nonSmartCopy() const;
|
||||
static ArrayData* CopyWithStrongIterators(const ArrayData*);
|
||||
static ArrayData* NonSmartCopy(const ArrayData*);
|
||||
|
||||
/**
|
||||
* Append a value to the array. If "copy" is true, make a copy first
|
||||
@@ -404,42 +420,42 @@ public:
|
||||
* escalated array data.
|
||||
*/
|
||||
ArrayData* append(CVarRef v, bool copy);
|
||||
virtual ArrayData* appendRef(CVarRef v, bool copy) = 0;
|
||||
ArrayData* appendRef(CVarRef v, bool copy);
|
||||
|
||||
/**
|
||||
* Similar to append(v, copy), with reference in v preserved.
|
||||
*/
|
||||
virtual ArrayData *appendWithRef(CVarRef v, bool copy) = 0;
|
||||
ArrayData* appendWithRef(CVarRef v, bool copy);
|
||||
|
||||
/**
|
||||
* Implementing array appending and merging. If "copy" is true, make a copy
|
||||
* first then append/merge arrays. Return NULL if escalation is not needed,
|
||||
* or an escalated array data.
|
||||
*/
|
||||
virtual ArrayData *plus(const ArrayData *elems, bool copy) = 0;
|
||||
virtual ArrayData *merge(const ArrayData *elems, bool copy) = 0;
|
||||
ArrayData* plus(const ArrayData *elems, bool copy);
|
||||
ArrayData* merge(const ArrayData *elems, bool copy);
|
||||
|
||||
/**
|
||||
* Stack function: pop the last item and return it.
|
||||
*/
|
||||
virtual ArrayData *pop(Variant &value);
|
||||
ArrayData* pop(Variant &value);
|
||||
|
||||
/**
|
||||
* Queue function: remove the 1st item and return it.
|
||||
*/
|
||||
virtual ArrayData *dequeue(Variant &value);
|
||||
ArrayData* dequeue(Variant &value);
|
||||
|
||||
/**
|
||||
* Array function: prepend a new item.
|
||||
*/
|
||||
virtual ArrayData *prepend(CVarRef v, bool copy) = 0;
|
||||
ArrayData* prepend(CVarRef v, bool copy);
|
||||
|
||||
/**
|
||||
* Only map classes need this. Re-index all numeric keys to start from 0.
|
||||
*/
|
||||
virtual void renumber() {}
|
||||
void renumber();
|
||||
|
||||
virtual void onSetEvalScalar() { assert(false);}
|
||||
void onSetEvalScalar();
|
||||
|
||||
/**
|
||||
* Serialize this array. We could have made this virtual function to ask
|
||||
@@ -452,9 +468,9 @@ public:
|
||||
void serialize(VariableSerializer *serializer,
|
||||
bool skipNestCheck = false) const;
|
||||
|
||||
virtual void dump();
|
||||
virtual void dump(std::string &out);
|
||||
virtual void dump(std::ostream &os);
|
||||
void dump();
|
||||
void dump(std::string &out);
|
||||
void dump(std::ostream &os);
|
||||
|
||||
/**
|
||||
* Comparisons.
|
||||
@@ -464,9 +480,17 @@ public:
|
||||
|
||||
void setPosition(ssize_t p) { m_pos = p; }
|
||||
|
||||
virtual ArrayData *escalate() const {
|
||||
return const_cast<ArrayData *>(this);
|
||||
}
|
||||
ArrayData *escalate() const;
|
||||
|
||||
// default implementations
|
||||
static ArrayData* Plus(ArrayData*, const ArrayData *elems, bool copy);
|
||||
static ArrayData* Merge(ArrayData*, const ArrayData *elems, bool copy);
|
||||
static ArrayData* Pop(ArrayData*, Variant &value);
|
||||
static ArrayData* Dequeue(ArrayData*, Variant &value);
|
||||
static ArrayData* Prepend(ArrayData*, CVarRef v, bool copy);
|
||||
static void Renumber(ArrayData*);
|
||||
static void OnSetEvalScalar(ArrayData*);
|
||||
static ArrayData* Escalate(const ArrayData* ad);
|
||||
|
||||
static ArrayData *GetScalarArray(ArrayData *arr,
|
||||
const StringData *key = nullptr);
|
||||
@@ -505,22 +529,20 @@ public:
|
||||
void modeFree(void* ptr) const;
|
||||
|
||||
protected:
|
||||
// Layout starts with 64 bits for vtable, then 32 bits for m_count
|
||||
// from Countable base, then...
|
||||
uint m_size;
|
||||
private:
|
||||
FullPos* m_strongIterators; // head of linked list
|
||||
protected:
|
||||
int32_t m_pos;
|
||||
ArrayKind m_kind;
|
||||
const AllocationMode m_allocMode;
|
||||
uint32_t m_size;
|
||||
mutable int32_t _count;
|
||||
int32_t m_pos;
|
||||
private:
|
||||
FullPos* m_strongIterators; // head of linked list
|
||||
|
||||
public: // for the JIT
|
||||
static uint32_t getKindOff() {
|
||||
return (uintptr_t)&((ArrayData*)0)->m_kind;
|
||||
}
|
||||
|
||||
public:
|
||||
public: // for heap profiler
|
||||
void getChildren(std::vector<TypedValue *> &out);
|
||||
};
|
||||
|
||||
@@ -534,7 +556,6 @@ struct ArrayFunctions {
|
||||
// NK stands for number of array kinds; here just for shorthand.
|
||||
static auto const NK = size_t(ArrayData::ArrayKind::kNumKinds);
|
||||
void (*release[NK])(ArrayData*);
|
||||
ArrayData* (*append[NK])(ArrayData*, CVarRef v, bool copy);
|
||||
TypedValue* (*nvGetInt[NK])(const ArrayData*, int64_t k);
|
||||
TypedValue* (*nvGetStr[NK])(const ArrayData*, const StringData* k);
|
||||
void (*nvGetKey[NK])(const ArrayData*, TypedValue* out, ssize_t pos);
|
||||
@@ -569,6 +590,29 @@ struct ArrayFunctions {
|
||||
ssize_t (*iterEnd[NK])(const ArrayData*);
|
||||
ssize_t (*iterAdvance[NK])(const ArrayData*, ssize_t pos);
|
||||
ssize_t (*iterRewind[NK])(const ArrayData*, ssize_t pos);
|
||||
bool (*validFullPos[NK])(const ArrayData*, const FullPos&);
|
||||
bool (*advanceFullPos[NK])(ArrayData*, FullPos&);
|
||||
ArrayData* (*escalateForSort[NK])(ArrayData*);
|
||||
void (*ksort[NK])(ArrayData* ad, int sort_flags, bool ascending);
|
||||
void (*sort[NK])(ArrayData* ad, int sort_flags, bool ascending);
|
||||
void (*asort[NK])(ArrayData* ad, int sort_flags, bool ascending);
|
||||
void (*uksort[NK])(ArrayData* ad, CVarRef cmp_function);
|
||||
void (*usort[NK])(ArrayData* ad, CVarRef cmp_function);
|
||||
void (*uasort[NK])(ArrayData* ad, CVarRef cmp_function);
|
||||
ArrayData* (*copy[NK])(const ArrayData*);
|
||||
ArrayData* (*copyWithStrongIterators[NK])(const ArrayData*);
|
||||
ArrayData* (*nonSmartCopy[NK])(const ArrayData*);
|
||||
ArrayData* (*append[NK])(ArrayData*, CVarRef v, bool copy);
|
||||
ArrayData* (*appendRef[NK])(ArrayData*, CVarRef v, bool copy);
|
||||
ArrayData* (*appendWithRef[NK])(ArrayData*, CVarRef v, bool copy);
|
||||
ArrayData* (*plus[NK])(ArrayData*, const ArrayData* elems, bool copy);
|
||||
ArrayData* (*merge[NK])(ArrayData*, const ArrayData* elems, bool copy);
|
||||
ArrayData* (*pop[NK])(ArrayData*, Variant& value);
|
||||
ArrayData* (*dequeue[NK])(ArrayData*, Variant& value);
|
||||
ArrayData* (*prepend[NK])(ArrayData*, CVarRef value, bool copy);
|
||||
void (*renumber[NK])(ArrayData*);
|
||||
void (*onSetEvalScalar[NK])(ArrayData*);
|
||||
ArrayData* (*escalate[NK])(const ArrayData*);
|
||||
};
|
||||
|
||||
extern const ArrayFunctions g_array_funcs;
|
||||
|
||||
@@ -78,7 +78,7 @@ inline DEBUG_ONLY bool is_refcount_realistic(int32_t count) {
|
||||
} \
|
||||
bool isStatic() const { \
|
||||
assert(is_refcount_realistic(_count)); \
|
||||
return _count == STATIC_FLAG; \
|
||||
return _count == RefCountStaticValue; \
|
||||
} \
|
||||
IMPLEMENT_COUNTABLE_METHODS_NO_STATIC
|
||||
|
||||
@@ -89,7 +89,6 @@ inline DEBUG_ONLY bool is_refcount_realistic(int32_t count) {
|
||||
*/
|
||||
class Countable {
|
||||
public:
|
||||
static const int32_t STATIC_FLAG = RefCountStaticValue;
|
||||
Countable() : _count(0) {}
|
||||
IMPLEMENT_COUNTABLE_METHODS
|
||||
protected:
|
||||
|
||||
@@ -119,7 +119,6 @@ inline const HphpArray* HphpArray::asHphpArray(const ArrayData* ad) {
|
||||
|
||||
inline HphpArray* HphpArray::asVector(ArrayData* ad) {
|
||||
assert(ad->kind() == kVectorKind);
|
||||
assert(dynamic_cast<HphpArray*>(ad));
|
||||
auto a = static_cast<HphpArray*>(ad);
|
||||
assert(a->checkInvariants());
|
||||
return a;
|
||||
@@ -127,7 +126,6 @@ inline HphpArray* HphpArray::asVector(ArrayData* ad) {
|
||||
|
||||
inline const HphpArray* HphpArray::asVector(const ArrayData* ad) {
|
||||
assert(ad->kind() == kVectorKind);
|
||||
assert(dynamic_cast<const HphpArray*>(ad));
|
||||
auto a = static_cast<const HphpArray*>(ad);
|
||||
assert(a->checkInvariants());
|
||||
return a;
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
namespace HPHP {
|
||||
|
||||
static_assert(
|
||||
sizeof(HphpArray) == 160,
|
||||
sizeof(HphpArray) == 152,
|
||||
"Performance is sensitive to sizeof(HphpArray)."
|
||||
" Make sure you changed it with good reason and then update this assert.");
|
||||
|
||||
@@ -238,7 +238,7 @@ HOT_FUNC_VM
|
||||
void HphpArray::ReleaseVec(ArrayData* ad) {
|
||||
auto a = asVector(ad);
|
||||
a->destroyVec();
|
||||
if (UNLIKELY(a->strongIterators() != nullptr)) a->freeStrongIterators();
|
||||
a->ArrayData::destroy();
|
||||
HphpArray::AllocatorType::getNoCheck()->dealloc(a);
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ HOT_FUNC_VM
|
||||
void HphpArray::Release(ArrayData* ad) {
|
||||
auto a = asGeneric(ad);
|
||||
a->destroy();
|
||||
if (UNLIKELY(a->strongIterators() != nullptr)) a->freeStrongIterators();
|
||||
a->ArrayData::destroy();
|
||||
HphpArray::AllocatorType::getNoCheck()->dealloc(a);
|
||||
}
|
||||
|
||||
@@ -1455,15 +1455,18 @@ HphpArray::RemoveStr(ArrayData* ad, const StringData* key, bool copy) {
|
||||
return a->erase(a->findForInsert(key, key->hash()));
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::copy() const {
|
||||
assert(checkInvariants());
|
||||
return copyImpl();
|
||||
ArrayData* HphpArray::CopyVec(const ArrayData* ad) {
|
||||
return asVector(ad)->copyVec();
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::copyWithStrongIterators() const {
|
||||
assert(checkInvariants());
|
||||
HphpArray* copied = copyImpl();
|
||||
moveStrongIterators(copied, const_cast<HphpArray*>(this));
|
||||
ArrayData* HphpArray::Copy(const ArrayData* ad) {
|
||||
return asGeneric(ad)->copyGeneric();
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::CopyWithStrongIterators(const ArrayData* ad) {
|
||||
auto a = asHphpArray(ad);
|
||||
auto copied = a->copyImpl();
|
||||
moveStrongIterators(copied, const_cast<HphpArray*>(a));
|
||||
return copied;
|
||||
}
|
||||
|
||||
@@ -1590,32 +1593,38 @@ ArrayData* HphpArray::AddNewElemC(ArrayData* a, TypedValue value) {
|
||||
return genericAddNewElemC(a, value);
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::appendRef(CVarRef v, bool copy) {
|
||||
assert(checkInvariants());
|
||||
HphpArray *a = !copy ? this : copyImpl();
|
||||
if (a->isVector()) {
|
||||
auto &tv = a->allocNextElm(a->m_size);
|
||||
tvAsUninitializedVariant(&tv).constructRefHelper(v);
|
||||
return a;
|
||||
}
|
||||
ArrayData* HphpArray::AppendRefVec(ArrayData* ad, CVarRef v, bool copy) {
|
||||
auto a = asVector(ad);
|
||||
if (copy) a = a->copyVec();
|
||||
auto &tv = a->allocNextElm(a->m_size);
|
||||
tvAsUninitializedVariant(&tv).constructRefHelper(v);
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::AppendRef(ArrayData* ad, CVarRef v, bool copy) {
|
||||
auto a = asGeneric(ad);
|
||||
if (copy) a = a->copyGeneric();
|
||||
return a->nextInsertRef(v);
|
||||
}
|
||||
|
||||
ArrayData *HphpArray::appendWithRef(CVarRef v, bool copy) {
|
||||
assert(checkInvariants());
|
||||
HphpArray *a = !copy ? this : copyImpl();
|
||||
if (a->isVector()) {
|
||||
auto& tv = a->allocNextElm(a->m_size);
|
||||
tvWriteNull(&tv);
|
||||
tvAsVariant(&tv).setWithRef(v);
|
||||
return a;
|
||||
}
|
||||
ArrayData *HphpArray::AppendWithRefVec(ArrayData* ad, CVarRef v, bool copy) {
|
||||
auto a = asVector(ad);
|
||||
if (copy) a = a->copyVec();
|
||||
auto& tv = a->allocNextElm(a->m_size);
|
||||
tvWriteNull(&tv);
|
||||
tvAsVariant(&tv).setWithRef(v);
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData *HphpArray::AppendWithRef(ArrayData* ad, CVarRef v, bool copy) {
|
||||
auto a = asGeneric(ad);
|
||||
if (copy) a = a->copyGeneric();
|
||||
return a->nextInsertWithRef(v);
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::plus(const ArrayData* elems, bool copy) {
|
||||
assert(checkInvariants());
|
||||
HphpArray* a = !copy ? this : copyImpl();
|
||||
ArrayData* HphpArray::Plus(ArrayData* ad, const ArrayData* elems, bool copy) {
|
||||
auto a = asHphpArray(ad);
|
||||
if (copy) a = a->copyImpl();
|
||||
if (a->isVector()) {
|
||||
// todo t2606310: is there a fast path if elems is also a vector?
|
||||
a->vectorToGeneric();
|
||||
@@ -1632,9 +1641,9 @@ ArrayData* HphpArray::plus(const ArrayData* elems, bool copy) {
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::merge(const ArrayData* elems, bool copy) {
|
||||
assert(checkInvariants());
|
||||
HphpArray* a = !copy ? this : copyImpl();
|
||||
ArrayData* HphpArray::Merge(ArrayData* ad, const ArrayData* elems, bool copy) {
|
||||
auto a = asHphpArray(ad);
|
||||
if (copy) a = a->copyImpl();
|
||||
if (a->isVector()) {
|
||||
// todo t2606310: is there a fast path if elems is also a vector?
|
||||
a->vectorToGeneric();
|
||||
@@ -1654,22 +1663,30 @@ ArrayData* HphpArray::merge(const ArrayData* elems, bool copy) {
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::pop(Variant& value) {
|
||||
assert(checkInvariants());
|
||||
HphpArray* a = getCount() <= 1 ? this : copyImpl();
|
||||
ArrayData* HphpArray::PopVec(ArrayData* ad, Variant& value) {
|
||||
auto a = asVector(ad);
|
||||
if (a->getCount() > 1) a = a->copyImpl();
|
||||
if (a->m_size > 0) {
|
||||
auto i = a->m_size - 1;
|
||||
value = tvAsCVarRef(&a->m_data[i].data);
|
||||
a->m_size = a->m_used = i;
|
||||
a->m_pos = i > 0 ? 0 : invalid_index; // reset internal iterator
|
||||
} else {
|
||||
value = uninit_null();
|
||||
a->m_pos = invalid_index; // reset internal iterator
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::Pop(ArrayData* ad, Variant& value) {
|
||||
auto a = asGeneric(ad);
|
||||
if (a->getCount() > 1) a = a->copyImpl();
|
||||
Elm* elms = a->m_data;
|
||||
ElmInd pos = IterEnd(a);
|
||||
if (validElmInd(pos)) {
|
||||
Elm* e = &elms[pos];
|
||||
assert(!isTombstone(e->data.m_type));
|
||||
value = tvAsCVarRef(&e->data);
|
||||
if (a->isVector()) {
|
||||
assert(pos == a->m_size - 1);
|
||||
a->m_size = a->m_used = pos;
|
||||
a->m_pos = pos ? 0 : invalid_index;
|
||||
tvRefcountedDecRef(&e->data);
|
||||
return a;
|
||||
}
|
||||
ElmInd* ei = e->hasStrKey()
|
||||
? a->findForInsert(e->key, e->hash())
|
||||
: a->findForInsert(e->ikey);
|
||||
@@ -1683,9 +1700,9 @@ ArrayData* HphpArray::pop(Variant& value) {
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::dequeue(Variant& value) {
|
||||
assert(checkInvariants());
|
||||
HphpArray* a = getCount() <= 1 ? this : copyImpl();
|
||||
ArrayData* HphpArray::Dequeue(ArrayData* ad, Variant& value) {
|
||||
auto a = asHphpArray(ad);
|
||||
if (a->getCount() > 1) a = a->copyImpl();
|
||||
// To conform to PHP behavior, we invalidate all strong iterators when an
|
||||
// element is removed from the beginning of the array.
|
||||
a->freeStrongIterators();
|
||||
@@ -1717,9 +1734,9 @@ ArrayData* HphpArray::dequeue(Variant& value) {
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::prepend(CVarRef v, bool copy) {
|
||||
assert(checkInvariants());
|
||||
HphpArray* a = getCount() <= 1 ? this : copyImpl();
|
||||
ArrayData* HphpArray::Prepend(ArrayData* ad, CVarRef v, bool copy) {
|
||||
auto a = asHphpArray(ad);
|
||||
if (a->getCount() > 1) a = a->copyImpl();
|
||||
if (a->isVector()) {
|
||||
// todo t2606310: fast path - same as add for empty vectors
|
||||
a->vectorToGeneric();
|
||||
@@ -1757,69 +1774,71 @@ ArrayData* HphpArray::prepend(CVarRef v, bool copy) {
|
||||
return a;
|
||||
}
|
||||
|
||||
void HphpArray::renumber() {
|
||||
assert(checkInvariants());
|
||||
if (isVector()) {
|
||||
// iterators don't move and nothing else happens.
|
||||
return;
|
||||
}
|
||||
compact(true);
|
||||
void HphpArray::RenumberVec(ArrayData* ad) {
|
||||
assert(asVector(ad)); // for the checkInvariants() call
|
||||
// renumber has no effect on Vector and doesn't move internal pos
|
||||
}
|
||||
|
||||
void HphpArray::onSetEvalScalar() {
|
||||
assert(checkInvariants());
|
||||
Elm* elms = m_data;
|
||||
if (isVector()) {
|
||||
for (uint32_t i = 0, limit = m_used; i < limit; ++i) {
|
||||
tvAsVariant(&elms[i].data).setEvalScalar();
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0, limit = m_used; i < limit; ++i) {
|
||||
Elm* e = &elms[i];
|
||||
if (!isTombstone(e->data.m_type)) {
|
||||
StringData *key = e->key;
|
||||
if (e->hasStrKey() && !key->isStatic()) {
|
||||
e->key = StringData::GetStaticString(key);
|
||||
decRefStr(key);
|
||||
}
|
||||
tvAsVariant(&e->data).setEvalScalar();
|
||||
void HphpArray::Renumber(ArrayData* ad) {
|
||||
asGeneric(ad)->compact(true);
|
||||
}
|
||||
|
||||
void HphpArray::OnSetEvalScalarVec(ArrayData* ad) {
|
||||
auto a = asVector(ad);
|
||||
Elm* elms = a->m_data;
|
||||
for (uint32_t i = 0, limit = a->m_size; i < limit; ++i) {
|
||||
tvAsVariant(&elms[i].data).setEvalScalar();
|
||||
}
|
||||
}
|
||||
|
||||
void HphpArray::OnSetEvalScalar(ArrayData* ad) {
|
||||
auto a = asGeneric(ad);
|
||||
Elm* elms = a->m_data;
|
||||
for (uint32_t i = 0, limit = a->m_used; i < limit; ++i) {
|
||||
Elm* e = &elms[i];
|
||||
if (!isTombstone(e->data.m_type)) {
|
||||
StringData *key = e->key;
|
||||
if (e->hasStrKey() && !key->isStatic()) {
|
||||
e->key = StringData::GetStaticString(key);
|
||||
decRefStr(key);
|
||||
}
|
||||
tvAsVariant(&e->data).setEvalScalar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool HphpArray::validFullPos(const FullPos &fp) const {
|
||||
assert(checkInvariants());
|
||||
assert(fp.getContainer() == (ArrayData*)this);
|
||||
bool HphpArray::ValidFullPos(const ArrayData* ad, const FullPos &fp) {
|
||||
assert(fp.getContainer() == asHphpArray(ad));
|
||||
if (fp.getResetFlag()) return false;
|
||||
return (fp.m_pos != ssize_t(ElmIndEmpty));
|
||||
}
|
||||
|
||||
bool HphpArray::advanceFullPos(FullPos& fp) {
|
||||
assert(checkInvariants());
|
||||
Elm* elms = m_data;
|
||||
bool HphpArray::AdvanceFullPos(ArrayData* ad, FullPos& fp) {
|
||||
auto a = asHphpArray(ad);
|
||||
Elm* elms = a->m_data;
|
||||
if (fp.getResetFlag()) {
|
||||
fp.setResetFlag(false);
|
||||
fp.m_pos = ElmIndEmpty;
|
||||
} else if (fp.m_pos == ssize_t(ElmIndEmpty)) {
|
||||
return false;
|
||||
}
|
||||
fp.m_pos = nextElm(elms, fp.m_pos);
|
||||
fp.m_pos = a->nextElm(elms, fp.m_pos);
|
||||
if (fp.m_pos == ssize_t(ElmIndEmpty)) {
|
||||
return false;
|
||||
}
|
||||
// To conform to PHP behavior, we need to set the internal
|
||||
// cursor to point to the next element.
|
||||
m_pos = nextElm(elms, fp.m_pos);
|
||||
a->m_pos = a->nextElm(elms, fp.m_pos);
|
||||
return true;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
NEVER_INLINE ArrayData* HphpArray::nonSmartCopy() const {
|
||||
return isVector() ?
|
||||
new HphpArray(*this, AllocationMode::nonSmart, CopyVector()) :
|
||||
new HphpArray(*this, AllocationMode::nonSmart, CopyGeneric());
|
||||
NEVER_INLINE ArrayData* HphpArray::NonSmartCopy(const ArrayData* ad) {
|
||||
auto a = asHphpArray(ad);
|
||||
return a->isVector() ?
|
||||
new HphpArray(*a, AllocationMode::nonSmart, CopyVector()) :
|
||||
new HphpArray(*a, AllocationMode::nonSmart, CopyGeneric());
|
||||
}
|
||||
|
||||
NEVER_INLINE HphpArray* HphpArray::copyVec() const {
|
||||
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
// moving (without refcounting) and reversing vals.
|
||||
HphpArray(uint size, const TypedValue* vals); // make tuple
|
||||
|
||||
virtual ~HphpArray();
|
||||
~HphpArray();
|
||||
void destroyVec();
|
||||
void destroy();
|
||||
|
||||
@@ -177,30 +177,36 @@ public:
|
||||
static ArrayData* RemoveIntVec(ArrayData*, int64_t k, bool copy);
|
||||
static ArrayData* RemoveStrVec(ArrayData*, const StringData* k, bool copy);
|
||||
|
||||
// overrides/implements ArrayData
|
||||
ArrayData* copy() const;
|
||||
ArrayData* copyWithStrongIterators() const;
|
||||
// overrides ArrayData
|
||||
static ArrayData* Copy(const ArrayData*);
|
||||
static ArrayData* CopyVec(const ArrayData*);
|
||||
static ArrayData* CopyWithStrongIterators(const ArrayData*);
|
||||
static ArrayData* NonSmartCopy(const ArrayData*);
|
||||
|
||||
ArrayData* nonSmartCopy() const;
|
||||
HphpArray* copyImpl() const;
|
||||
HphpArray* copyVec() const;
|
||||
HphpArray* copyGeneric() const;
|
||||
|
||||
static ArrayData* AppendVec(ArrayData*, CVarRef v, bool copy);
|
||||
static ArrayData* Append(ArrayData*, CVarRef v, bool copy);
|
||||
ArrayData* appendRef(CVarRef v, bool copy);
|
||||
ArrayData* appendWithRef(CVarRef v, bool copy);
|
||||
ArrayData* plus(const ArrayData* elems, bool copy);
|
||||
ArrayData* merge(const ArrayData* elems, bool copy);
|
||||
ArrayData* pop(Variant& value);
|
||||
ArrayData* dequeue(Variant& value);
|
||||
ArrayData* prepend(CVarRef v, bool copy);
|
||||
void renumber();
|
||||
void onSetEvalScalar();
|
||||
static ArrayData* AppendRef(ArrayData*, CVarRef v, bool copy);
|
||||
static ArrayData* AppendRefVec(ArrayData*, CVarRef v, bool copy);
|
||||
static ArrayData* AppendWithRef(ArrayData*, CVarRef v, bool copy);
|
||||
static ArrayData* AppendWithRefVec(ArrayData*, CVarRef v, bool copy);
|
||||
static ArrayData* Plus(ArrayData*, const ArrayData* elems, bool copy);
|
||||
static ArrayData* Merge(ArrayData*, const ArrayData* elems, bool copy);
|
||||
static ArrayData* Pop(ArrayData*, Variant& value);
|
||||
static ArrayData* PopVec(ArrayData*, Variant& value);
|
||||
static ArrayData* Dequeue(ArrayData*, Variant& value);
|
||||
static ArrayData* Prepend(ArrayData*, CVarRef v, bool copy);
|
||||
static void Renumber(ArrayData*);
|
||||
static void RenumberVec(ArrayData*);
|
||||
static void OnSetEvalScalar(ArrayData*);
|
||||
static void OnSetEvalScalarVec(ArrayData*);
|
||||
|
||||
// overrides ArrayData
|
||||
bool validFullPos(const FullPos &fp) const;
|
||||
bool advanceFullPos(FullPos& fp);
|
||||
static bool ValidFullPos(const ArrayData*, const FullPos &fp);
|
||||
static bool AdvanceFullPos(ArrayData*, FullPos& fp);
|
||||
|
||||
// END overide/implements section
|
||||
|
||||
@@ -245,13 +251,13 @@ private:
|
||||
void postSort(bool resetKeys);
|
||||
|
||||
public:
|
||||
ArrayData* escalateForSort();
|
||||
void ksort(int sort_flags, bool ascending);
|
||||
void sort(int sort_flags, bool ascending);
|
||||
void asort(int sort_flags, bool ascending);
|
||||
void uksort(CVarRef cmp_function);
|
||||
void usort(CVarRef cmp_function);
|
||||
void uasort(CVarRef cmp_function);
|
||||
static ArrayData* EscalateForSort(ArrayData* ad);
|
||||
static void Ksort(ArrayData*, int sort_flags, bool ascending);
|
||||
static void Sort(ArrayData*, int sort_flags, bool ascending);
|
||||
static void Asort(ArrayData*, int sort_flags, bool ascending);
|
||||
static void Uksort(ArrayData*, CVarRef cmp_function);
|
||||
static void Usort(ArrayData*, CVarRef cmp_function);
|
||||
static void Uasort(ArrayData*, CVarRef cmp_function);
|
||||
|
||||
// Elm's data.m_type == KindOfInvalid for deleted slots.
|
||||
static bool isTombstone(DataType t) {
|
||||
|
||||
@@ -143,19 +143,19 @@ void HphpArray::postSort(bool resetKeys) {
|
||||
m_hLoad = m_size;
|
||||
}
|
||||
|
||||
ArrayData* HphpArray::escalateForSort() {
|
||||
ArrayData* HphpArray::EscalateForSort(ArrayData* ad) {
|
||||
// task #1910931 only do this for refCount() > 1
|
||||
return copyImpl();
|
||||
return asHphpArray(ad)->copyImpl();
|
||||
}
|
||||
|
||||
#define SORT_CASE(flag, cmp_type, acc_type) \
|
||||
case flag: { \
|
||||
if (ascending) { \
|
||||
cmp_type##Compare<acc_type, flag, true> comp; \
|
||||
HPHP::Sort::sort(m_data, m_data + m_size, comp); \
|
||||
HPHP::Sort::sort(a->m_data, a->m_data + a->m_size, comp); \
|
||||
} else { \
|
||||
cmp_type##Compare<acc_type, flag, false> comp; \
|
||||
HPHP::Sort::sort(m_data, m_data + m_size, comp); \
|
||||
HPHP::Sort::sort(a->m_data, a->m_data + a->m_size, comp); \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
@@ -179,34 +179,37 @@ ArrayData* HphpArray::escalateForSort() {
|
||||
}
|
||||
#define SORT_BODY(acc_type, resetKeys) \
|
||||
do { \
|
||||
freeStrongIterators(); \
|
||||
if (!m_size) { \
|
||||
a->freeStrongIterators(); \
|
||||
if (!a->m_size) { \
|
||||
if (resetKeys) { \
|
||||
m_nextKI = 0; \
|
||||
a->m_nextKI = 0; \
|
||||
} \
|
||||
return; \
|
||||
} \
|
||||
SortFlavor flav = preSort<acc_type>(acc_type(), true); \
|
||||
m_pos = ssize_t(0); \
|
||||
SortFlavor flav = a->preSort<acc_type>(acc_type(), true); \
|
||||
a->m_pos = ssize_t(0); \
|
||||
try { \
|
||||
CALL_SORT(acc_type); \
|
||||
} catch (...) { \
|
||||
/* Make sure we leave the array in a consistent state */ \
|
||||
postSort(resetKeys); \
|
||||
a->postSort(resetKeys); \
|
||||
throw; \
|
||||
} \
|
||||
postSort(resetKeys); \
|
||||
a->postSort(resetKeys); \
|
||||
} while (0)
|
||||
|
||||
void HphpArray::ksort(int sort_flags, bool ascending) {
|
||||
void HphpArray::Ksort(ArrayData* ad, int sort_flags, bool ascending) {
|
||||
auto a = asHphpArray(ad);
|
||||
SORT_BODY(KeyAccessor, false);
|
||||
}
|
||||
|
||||
void HphpArray::sort(int sort_flags, bool ascending) {
|
||||
void HphpArray::Sort(ArrayData* ad, int sort_flags, bool ascending) {
|
||||
auto a = asHphpArray(ad);
|
||||
SORT_BODY(ValAccessor, true);
|
||||
}
|
||||
|
||||
void HphpArray::asort(int sort_flags, bool ascending) {
|
||||
void HphpArray::Asort(ArrayData* ad, int sort_flags, bool ascending) {
|
||||
auto a = asHphpArray(ad);
|
||||
SORT_BODY(ValAccessor, false);
|
||||
}
|
||||
|
||||
@@ -216,39 +219,42 @@ void HphpArray::asort(int sort_flags, bool ascending) {
|
||||
|
||||
#define USER_SORT_BODY(acc_type, resetKeys) \
|
||||
do { \
|
||||
freeStrongIterators(); \
|
||||
if (!m_size) { \
|
||||
a->freeStrongIterators(); \
|
||||
if (!a->m_size) { \
|
||||
if (resetKeys) { \
|
||||
m_nextKI = 0; \
|
||||
a->m_nextKI = 0; \
|
||||
} \
|
||||
return; \
|
||||
} \
|
||||
preSort<acc_type>(acc_type(), false); \
|
||||
m_pos = ssize_t(0); \
|
||||
a->preSort<acc_type>(acc_type(), false); \
|
||||
a->m_pos = ssize_t(0); \
|
||||
try { \
|
||||
ElmUCompare<acc_type> comp; \
|
||||
Transl::CallerFrame cf; \
|
||||
Transl::CallerFrame cf; \
|
||||
CallCtx ctx; \
|
||||
vm_decode_function(cmp_function, cf(), false, ctx); \
|
||||
comp.ctx = &ctx; \
|
||||
HPHP::Sort::sort(m_data, m_data + m_size, comp); \
|
||||
HPHP::Sort::sort(a->m_data, a->m_data + a->m_size, comp); \
|
||||
} catch (...) { \
|
||||
/* Make sure we leave the array in a consistent state */ \
|
||||
postSort(resetKeys); \
|
||||
a->postSort(resetKeys); \
|
||||
throw; \
|
||||
} \
|
||||
postSort(resetKeys); \
|
||||
a->postSort(resetKeys); \
|
||||
} while (0)
|
||||
|
||||
void HphpArray::uksort(CVarRef cmp_function) {
|
||||
void HphpArray::Uksort(ArrayData* ad, CVarRef cmp_function) {
|
||||
auto a = asHphpArray(ad);
|
||||
USER_SORT_BODY(KeyAccessor, false);
|
||||
}
|
||||
|
||||
void HphpArray::usort(CVarRef cmp_function) {
|
||||
void HphpArray::Usort(ArrayData* ad, CVarRef cmp_function) {
|
||||
auto a = asHphpArray(ad);
|
||||
USER_SORT_BODY(ValAccessor, true);
|
||||
}
|
||||
|
||||
void HphpArray::uasort(CVarRef cmp_function) {
|
||||
void HphpArray::Uasort(ArrayData* ad, CVarRef cmp_function) {
|
||||
auto a = asHphpArray(ad);
|
||||
USER_SORT_BODY(ValAccessor, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ PolicyArray::PolicyArray(const PolicyArray& rhs, uint capacity,
|
||||
|
||||
PolicyArray::~PolicyArray() {
|
||||
APILOG(this) << "()";
|
||||
destroy(m_size, m_allocMode);
|
||||
SimpleArrayStore::destroy(m_size, m_allocMode);
|
||||
}
|
||||
|
||||
void PolicyArray::Release(ArrayData* ad) {
|
||||
@@ -217,13 +217,11 @@ void PolicyArray::Release(ArrayData* ad) {
|
||||
|
||||
inline PolicyArray* PolicyArray::asPolicyArray(ArrayData* ad) {
|
||||
assert(ad->kind() == kPolicyKind);
|
||||
assert(dynamic_cast<PolicyArray*>(ad));
|
||||
return static_cast<PolicyArray*>(ad);
|
||||
}
|
||||
|
||||
inline const PolicyArray* PolicyArray::asPolicyArray(const ArrayData* ad) {
|
||||
assert(ad->kind() == kPolicyKind);
|
||||
assert(dynamic_cast<const PolicyArray*>(ad));
|
||||
return static_cast<const PolicyArray*>(ad);
|
||||
}
|
||||
|
||||
@@ -285,7 +283,7 @@ ArrayData *PolicyArray::lvalImpl(K k, Variant*& ret, bool copy) {
|
||||
<< copy << ", " << ")";
|
||||
|
||||
if (copy) {
|
||||
return PolicyArray::copy()->lvalImpl(k, ret, false);
|
||||
return asPolicyArray(Copy(this))->lvalImpl(k, ret, false);
|
||||
}
|
||||
|
||||
PosType pos = find(k, m_size);
|
||||
@@ -319,7 +317,7 @@ ArrayData* PolicyArray::LvalStr(ArrayData* ad, StringData* k, Variant*& ret,
|
||||
|
||||
ArrayData *PolicyArray::LvalNew(ArrayData* ad, Variant *&ret, bool copy) {
|
||||
auto a = asPolicyArray(ad);
|
||||
if (copy) a = a->PolicyArray::copy();
|
||||
if (copy) a = asPolicyArray(Copy(a));
|
||||
|
||||
// Andrei: TODO - append() currently never fails, probably it
|
||||
// should.
|
||||
@@ -346,9 +344,7 @@ ArrayData *PolicyArray::GetLvalPtr(ArrayData* ad, StringData* k,
|
||||
Variant *&ret, bool copy) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "(" << keystr(k) << ", " << ret << ", " << copy << ")";
|
||||
if (copy) {
|
||||
return a->PolicyArray::copy()->getLvalPtr(k, ret, false);
|
||||
}
|
||||
if (copy) a = asPolicyArray(Copy(a));
|
||||
const auto pos = a->find(k, a->m_size);
|
||||
ret = pos != PosType::invalid
|
||||
? &a->Store::lval(pos)
|
||||
@@ -361,7 +357,7 @@ PolicyArray* PolicyArray::setImpl(K k, const Variant& v, bool copy) {
|
||||
APILOG(this) << "(" << keystr(k) << ", " << valstr(v) << ", " << copy
|
||||
<< ")";
|
||||
PolicyArray* result = this;
|
||||
if (copy) result = PolicyArray::copy();
|
||||
if (copy) result = asPolicyArray(Copy(this));
|
||||
if (result->update(k, v, result->m_size, result->m_allocMode)) {
|
||||
// Added a new element, must update size and possibly m_pos
|
||||
if (m_pos == invalid_index) m_pos = result->m_size;
|
||||
@@ -385,7 +381,7 @@ ArrayData *PolicyArray::setRefImpl(K k, CVarRef v, bool copy) {
|
||||
APILOG(this) << "(" << keystr(k) << ", " << valstr(v) << ", " << copy << ")";
|
||||
|
||||
if (copy) {
|
||||
return PolicyArray::copy()->setRef(k, v, false);
|
||||
return asPolicyArray(Copy(this))->setRef(k, v, false);
|
||||
}
|
||||
|
||||
auto const pos = find(k, m_size);
|
||||
@@ -446,7 +442,7 @@ template <class K>
|
||||
ArrayData* PolicyArray::addLvalImpl(K k, Variant*& ret, bool copy) {
|
||||
APILOG(this) << "(" << k << ", " << ret << ", " << copy << ")";
|
||||
if (copy) {
|
||||
return PolicyArray::copy()->addLval(k, ret, false);
|
||||
return asPolicyArray(Copy(this))->addLval(k, ret, false);
|
||||
}
|
||||
assert(!exists(k) && m_size <= capacity());
|
||||
if (m_size == capacity()) {
|
||||
@@ -472,7 +468,7 @@ ArrayData *PolicyArray::removeImpl(K k, bool copy) {
|
||||
APILOG(this) << "(" << keystr(k) << ", " << copy << ")";
|
||||
|
||||
if (copy) {
|
||||
return PolicyArray::copy()->remove(k, false);
|
||||
return asPolicyArray(Copy(this))->remove(k, false);
|
||||
}
|
||||
|
||||
auto const pos = find(k, m_size);
|
||||
@@ -541,28 +537,30 @@ ssize_t PolicyArray::IterRewind(const ArrayData* ad, ssize_t prev) {
|
||||
return toInt<int64_t>(a->prevIndex(toPos(prev), a->m_size));
|
||||
}
|
||||
|
||||
bool PolicyArray::validFullPos(const FullPos& fp) const {
|
||||
APILOG(this) << "(" << fp.m_pos << ";" << fp.getResetFlag() << ")";
|
||||
assert(fp.getContainer() == this);
|
||||
bool PolicyArray::ValidFullPos(const ArrayData* ad, const FullPos& fp) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "(" << fp.m_pos << ";" << fp.getResetFlag() << ")";
|
||||
assert(fp.getContainer() == a);
|
||||
return fp.m_pos != invalid_index;
|
||||
}
|
||||
|
||||
bool PolicyArray::advanceFullPos(FullPos &fp) {
|
||||
APILOG(this) << "(" << fp.m_pos << ";" << fp.getResetFlag() << ")";
|
||||
assert(fp.getContainer() == this);
|
||||
bool PolicyArray::AdvanceFullPos(ArrayData* ad, FullPos &fp) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "(" << fp.m_pos << ";" << fp.getResetFlag() << ")";
|
||||
assert(fp.getContainer() == a);
|
||||
if (fp.getResetFlag()) {
|
||||
fp.setResetFlag(false);
|
||||
fp.m_pos = invalid_index;
|
||||
} else if (fp.m_pos == invalid_index) {
|
||||
return false;
|
||||
}
|
||||
fp.m_pos = toInt<int64_t>(nextIndex(toPos(fp.m_pos), m_size));
|
||||
fp.m_pos = toInt<int64_t>(a->nextIndex(toPos(fp.m_pos), a->m_size));
|
||||
if (fp.m_pos == invalid_index) {
|
||||
return false;
|
||||
}
|
||||
// To conform to PHP behavior, we need to set the internal
|
||||
// cursor to point to the next element.
|
||||
m_pos = toInt<int64_t>(nextIndex(toPos(fp.m_pos), m_size));
|
||||
a->m_pos = toInt<int64_t>(a->nextIndex(toPos(fp.m_pos), a->m_size));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -578,17 +576,17 @@ HphpArray* PolicyArray::toHphpArray() const {
|
||||
return result;
|
||||
}
|
||||
|
||||
ArrayData* PolicyArray::escalateForSort() {
|
||||
APILOG(this) << "()";
|
||||
return toHphpArray();
|
||||
ArrayData* PolicyArray::EscalateForSort(ArrayData* ad) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "()";
|
||||
return a->toHphpArray();
|
||||
}
|
||||
|
||||
PolicyArray *PolicyArray::copy() const {
|
||||
APILOG(this) << "()";
|
||||
auto result = NEW(PolicyArray)(
|
||||
*this,
|
||||
capacity() + (m_size == capacity()),
|
||||
m_allocMode);
|
||||
ArrayData* PolicyArray::Copy(const ArrayData* ad) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "()";
|
||||
auto result = NEW(PolicyArray)(*a,
|
||||
a->capacity() + (a->m_size == a->capacity()), a->m_allocMode);
|
||||
assert(result->getCount() == 0);
|
||||
return result;
|
||||
}
|
||||
@@ -598,58 +596,56 @@ PolicyArray* PolicyArray::copy(uint capacity) {
|
||||
return NEW(PolicyArray)(*this, capacity, m_allocMode);
|
||||
}
|
||||
|
||||
PolicyArray *PolicyArray::copyWithStrongIterators() const {
|
||||
APILOG(this) << "()";
|
||||
auto result = PolicyArray::copy();
|
||||
moveStrongIterators(result, const_cast<PolicyArray*>(this));
|
||||
ArrayData* PolicyArray::CopyWithStrongIterators(const ArrayData* ad) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "()";
|
||||
auto result = Copy(a);
|
||||
moveStrongIterators(result, const_cast<PolicyArray*>(a));
|
||||
assert(result->getCount() == 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
ArrayData *PolicyArray::nonSmartCopy() const {
|
||||
APILOG(this) << "()";
|
||||
//return NEW(PolicyArray)(*this, capacity(), true);
|
||||
return toHphpArray()->nonSmartCopy();
|
||||
ArrayData* PolicyArray::NonSmartCopy(const ArrayData* ad) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "()";
|
||||
return a->toHphpArray()->nonSmartCopy();
|
||||
}
|
||||
|
||||
ArrayData *PolicyArray::Append(ArrayData* ad, const Variant& v, bool copy) {
|
||||
auto a = static_cast<PolicyArray*>(ad);
|
||||
ArrayData* PolicyArray::Append(ArrayData* ad, const Variant& v, bool copy) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "(" << valstr(v) << ", " << copy << ")";
|
||||
if (copy) a = a->PolicyArray::copy();
|
||||
if (copy) a = asPolicyArray(Copy(a));
|
||||
a->grow(a->m_size, a->m_size + 1, a->m_size * 2 + 1, a->m_allocMode);
|
||||
a->appendNoGrow(a->nextKeyBump(), v);
|
||||
return a;
|
||||
}
|
||||
|
||||
PolicyArray *PolicyArray::appendRef(const Variant& v, bool copy) {
|
||||
APILOG(this) << "(" << valstr(v) << ", " << copy << ")";
|
||||
if (copy) {
|
||||
return PolicyArray::copy()->appendRef(v, false);
|
||||
ArrayData* PolicyArray::AppendRef(ArrayData* ad, const Variant& v, bool copy) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "(" << valstr(v) << ", " << copy << ")";
|
||||
if (copy) a = asPolicyArray(Copy(a));
|
||||
auto const k = a->nextKeyBump();
|
||||
if (a->m_size == a->capacity()) {
|
||||
a->grow(a->m_size, a->m_size + 1, a->m_size * 2 + 1, a->m_allocMode);
|
||||
}
|
||||
//addValWithRef(nextKeyBump(), v);
|
||||
auto const k = nextKeyBump();
|
||||
if (m_size == capacity()) {
|
||||
grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode);
|
||||
}
|
||||
assert(m_size < capacity());
|
||||
appendNoGrow(k, Variant::NoInit())->constructRefHelper(v);
|
||||
return this;
|
||||
assert(a->m_size < a->capacity());
|
||||
a->appendNoGrow(k, Variant::NoInit())->constructRefHelper(v);
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to append(v, copy), with reference in v preserved.
|
||||
*/
|
||||
ArrayData *PolicyArray::appendWithRef(CVarRef v, bool copy) {
|
||||
APILOG(this) << "(" << valstr(v) << ", " << copy << ")";
|
||||
if (copy) {
|
||||
return PolicyArray::copy()->appendWithRef(v, false);
|
||||
ArrayData* PolicyArray::AppendWithRef(ArrayData* ad, CVarRef v, bool copy) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "(" << valstr(v) << ", " << copy << ")";
|
||||
if (copy) a = asPolicyArray(Copy(a));
|
||||
if (a->m_size == a->capacity()) {
|
||||
a->grow(a->m_size, a->m_size + 1, a->m_size * 2 + 1, a->m_allocMode);
|
||||
}
|
||||
if (m_size == capacity()) {
|
||||
grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode);
|
||||
}
|
||||
assert(m_size < capacity());
|
||||
appendNoGrow(nextKeyBump(), Variant::NullInit())->setWithRef(v);
|
||||
return this;
|
||||
assert(a->m_size < a->capacity());
|
||||
a->appendNoGrow(a->nextKeyBump(), Variant::NullInit())->setWithRef(v);
|
||||
return a;
|
||||
}
|
||||
|
||||
template <class K>
|
||||
@@ -688,127 +684,125 @@ void PolicyArray::nextInsertWithRef(const Variant& v) {
|
||||
appendNoGrow(k, Variant::NullInit())->setWithRef(v);
|
||||
}
|
||||
|
||||
ArrayData *PolicyArray::plus(const ArrayData *elems, bool copy) {
|
||||
APILOG(this) << "(" << elems << ", " << copy << ")";
|
||||
if (copy) {
|
||||
return PolicyArray::copy()->plus(elems, false);
|
||||
}
|
||||
ArrayData*
|
||||
PolicyArray::Plus(ArrayData* ad, const ArrayData *elems, bool copy) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "(" << elems << ", " << copy << ")";
|
||||
if (copy) a = asPolicyArray(Copy(a));
|
||||
|
||||
assert(elems);
|
||||
grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode);
|
||||
a->grow(a->m_size, a->m_size + 1, a->m_size * 2 + 1, a->m_allocMode);
|
||||
|
||||
for (ArrayIter it(elems); !it.end(); it.next()) {
|
||||
Variant key = it.first();
|
||||
const Variant& value = it.secondRef();
|
||||
if (key.isNumeric()) {
|
||||
addValWithRef(key.toInt64(), value);
|
||||
a->addValWithRef(key.toInt64(), value);
|
||||
} else {
|
||||
addValWithRef(key.getStringData(), value);
|
||||
a->addValWithRef(key.getStringData(), value);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData *PolicyArray::merge(const ArrayData *elems, bool copy) {
|
||||
APILOG(this) << "(" << elems << ", " << copy << ")";
|
||||
if (copy) {
|
||||
return PolicyArray::copy()->merge(elems, false);
|
||||
}
|
||||
ArrayData*
|
||||
PolicyArray::Merge(ArrayData* ad, const ArrayData *elems, bool copy) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "(" << elems << ", " << copy << ")";
|
||||
if (copy) a = asPolicyArray(Copy(a));
|
||||
|
||||
assert(elems);
|
||||
grow(m_size, m_size + 1, m_size * 2 + 1, m_allocMode);
|
||||
a->grow(a->m_size, a->m_size + 1, a->m_size * 2 + 1, a->m_allocMode);
|
||||
|
||||
for (ArrayIter it(elems); !it.end(); it.next()) {
|
||||
Variant key = it.first();
|
||||
const Variant& value = it.secondRef();
|
||||
if (key.isNumeric()) {
|
||||
nextInsertWithRef(value);
|
||||
a->nextInsertWithRef(value);
|
||||
} else {
|
||||
StringData *s = key.getStringData();
|
||||
Variant *p;
|
||||
// Andrei TODO: make sure this is the right semantics
|
||||
LvalStr(this, s, p, false);
|
||||
LvalStr(a, s, p, false);
|
||||
p->setWithRef(value);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stack function: pop the last item and return it.
|
||||
*/
|
||||
ArrayData* PolicyArray::pop(Variant &value) {
|
||||
APILOG(this) << "(" << &value << ")";
|
||||
if (getCount() > 1) {
|
||||
return PolicyArray::copy()->pop(value);
|
||||
}
|
||||
if (!m_size) {
|
||||
/**
|
||||
* Stack function: pop the last item and return it.
|
||||
*/
|
||||
ArrayData* PolicyArray::Pop(ArrayData* ad, Variant &value) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "(" << &value << ")";
|
||||
if (a->getCount() > 1) a = asPolicyArray(Copy(a));
|
||||
if (!a->m_size) {
|
||||
value = uninit_null();
|
||||
return this;
|
||||
return a;
|
||||
}
|
||||
auto pos = lastIndex(m_size);
|
||||
assert(size_t(pos) < m_size);
|
||||
value = val(pos);
|
||||
auto pos = a->lastIndex(a->m_size);
|
||||
assert(size_t(pos) < a->m_size);
|
||||
value = a->val(pos);
|
||||
|
||||
// Match PHP 5.3.1 semantics
|
||||
if (!hasStrKey(pos)
|
||||
&& Store::nextKey() == 1 + key(pos).toInt64()) {
|
||||
nextKeyPop();
|
||||
if (!a->hasStrKey(pos)
|
||||
&& a->Store::nextKey() == 1 + a->key(pos).toInt64()) {
|
||||
a->nextKeyPop();
|
||||
}
|
||||
|
||||
Store::erase(pos, m_size);
|
||||
--m_size;
|
||||
a->Store::erase(pos, a->m_size);
|
||||
--a->m_size;
|
||||
// To match PHP-like semantics, the pop operation resets the array's
|
||||
// internal iterator.
|
||||
m_pos = m_size ? toInt<int64_t>(firstIndex(m_size)) : invalid_index;
|
||||
return this;
|
||||
a->m_pos = a->m_size ? toInt<int64_t>(a->firstIndex(a->m_size)) :
|
||||
invalid_index;
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData *PolicyArray::dequeue(Variant &value) {
|
||||
APILOG(this) << "(" << &value << ")";
|
||||
if (getCount() > 1) {
|
||||
return PolicyArray::copy()->dequeue(value);
|
||||
}
|
||||
ArrayData* PolicyArray::Dequeue(ArrayData* ad, Variant &value) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "(" << &value << ")";
|
||||
if (a->getCount() > 1) a = asPolicyArray(Copy(ad));
|
||||
|
||||
// To match PHP-like semantics, we invalidate all strong iterators when an
|
||||
// element is removed from the beginning of the array.
|
||||
freeStrongIterators();
|
||||
if (!m_size) {
|
||||
a->freeStrongIterators();
|
||||
if (!a->m_size) {
|
||||
value = uninit_null();
|
||||
return this;
|
||||
return a;
|
||||
}
|
||||
|
||||
auto& front = lval(firstIndex(m_size));
|
||||
auto& front = a->lval(a->firstIndex(a->m_size));
|
||||
value = std::move(front);
|
||||
new(&front) Variant;
|
||||
erase(firstIndex(m_size), m_size);
|
||||
--m_size;
|
||||
renumber();
|
||||
a->erase(a->firstIndex(a->m_size), a->m_size);
|
||||
--a->m_size;
|
||||
a->renumber();
|
||||
|
||||
// To match PHP-like semantics, the dequeue operation resets the array's
|
||||
// internal iterator
|
||||
m_pos = m_size ? toInt<int64_t>(firstIndex(m_size)) : invalid_index;
|
||||
return this;
|
||||
a->m_pos = a->m_size ? toInt<int64_t>(a->firstIndex(a->m_size)) :
|
||||
invalid_index;
|
||||
return a;
|
||||
}
|
||||
|
||||
ArrayData* PolicyArray::prepend(CVarRef v, bool copy) {
|
||||
APILOG(this) << "(" << valstr(v) << ", " << copy << ")";
|
||||
if (copy) {
|
||||
return PolicyArray::copy()->prepend(v, false);
|
||||
}
|
||||
ArrayData* PolicyArray::Prepend(ArrayData* ad, CVarRef v, bool copy) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "(" << valstr(v) << ", " << copy << ")";
|
||||
if (copy) a = asPolicyArray(Copy(a));
|
||||
// To match PHP-like semantics, we invalidate all strong iterators when an
|
||||
// element is added to the beginning of the array.
|
||||
freeStrongIterators();
|
||||
Store::prepend(v, m_size, m_allocMode);
|
||||
++m_size;
|
||||
auto first = firstIndex(m_size);
|
||||
setKey(first, int64_t(0));
|
||||
// Renumber.
|
||||
renumber();
|
||||
a->freeStrongIterators();
|
||||
a->Store::prepend(v, a->m_size, a->m_allocMode);
|
||||
++a->m_size;
|
||||
auto first = a->firstIndex(a->m_size);
|
||||
a->setKey(first, int64_t(0));
|
||||
a->renumber();
|
||||
// To match PHP-like semantics, the prepend operation resets the array's
|
||||
// internal iterator
|
||||
m_pos = toInt<int64_t>(first);
|
||||
return this;
|
||||
a->m_pos = toInt<int64_t>(first);
|
||||
return a;
|
||||
}
|
||||
|
||||
void PolicyArray::renumber() {
|
||||
@@ -867,30 +861,36 @@ void PolicyArray::renumber() {
|
||||
assert(i == siKeys.cend());
|
||||
}
|
||||
|
||||
void PolicyArray::onSetEvalScalar() {
|
||||
APILOG(this) << "()";
|
||||
void PolicyArray::Renumber(ArrayData* ad) {
|
||||
return asPolicyArray(ad)->renumber();
|
||||
}
|
||||
|
||||
void PolicyArray::OnSetEvalScalar(ArrayData* ad) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "()";
|
||||
//FOR_EACH_RANGE (pos, 0, m_size) {
|
||||
for (auto pos = firstIndex(m_size); pos != PosType::invalid;
|
||||
pos = nextIndex(pos, m_size)) {
|
||||
if (hasStrKey(pos)) {
|
||||
auto k = key(pos).getStringData();
|
||||
for (auto pos = a->firstIndex(a->m_size); pos != PosType::invalid;
|
||||
pos = a->nextIndex(pos, a->m_size)) {
|
||||
if (a->hasStrKey(pos)) {
|
||||
auto k = a->key(pos).getStringData();
|
||||
if (!k->isStatic()) {
|
||||
auto sk = StringData::GetStaticString(k);
|
||||
if (k->decRefCount() == 0) {
|
||||
DELETE(StringData)(k);
|
||||
}
|
||||
// Andrei TODO: inefficient, does one incref and then decref
|
||||
setKey(pos, sk);
|
||||
a->setKey(pos, sk);
|
||||
sk->decRefCount();
|
||||
}
|
||||
}
|
||||
lval(pos).setEvalScalar();
|
||||
a->lval(pos).setEvalScalar();
|
||||
}
|
||||
}
|
||||
|
||||
ArrayData *PolicyArray::escalate() const {
|
||||
APILOG(this) << "()";
|
||||
return ArrayData::escalate();
|
||||
ArrayData *PolicyArray::Escalate(const ArrayData* ad) {
|
||||
auto a = asPolicyArray(ad);
|
||||
APILOG(a) << "()";
|
||||
return ArrayData::Escalate(a);
|
||||
}
|
||||
|
||||
} // namespace HPHP
|
||||
|
||||
@@ -329,7 +329,7 @@ public:
|
||||
|
||||
explicit PolicyArray(uint size);
|
||||
|
||||
virtual ~PolicyArray() FOLLY_OVERRIDE;
|
||||
~PolicyArray();
|
||||
|
||||
/**
|
||||
* getValueRef() gets a reference to value at position "pos".
|
||||
@@ -475,16 +475,16 @@ public:
|
||||
* This will return false if the iterator points past the last element, or
|
||||
* if the iterator points before the first element.
|
||||
*/
|
||||
virtual bool validFullPos(const FullPos& fp) const FOLLY_OVERRIDE;
|
||||
static bool ValidFullPos(const ArrayData*, const FullPos& fp);
|
||||
|
||||
/**
|
||||
* Advances the mutable iterator to the next element in the array. Returns
|
||||
* false if the iterator has moved past the last element, otherwise returns
|
||||
* true.
|
||||
*/
|
||||
virtual bool advanceFullPos(FullPos& fp) FOLLY_OVERRIDE;
|
||||
static bool AdvanceFullPos(ArrayData* ad, FullPos& fp);
|
||||
|
||||
virtual ArrayData* escalateForSort() FOLLY_OVERRIDE;
|
||||
static ArrayData* EscalateForSort(ArrayData* ad);
|
||||
|
||||
/**
|
||||
* Make a copy of myself.
|
||||
@@ -494,9 +494,9 @@ public:
|
||||
* into the static array list.
|
||||
*/
|
||||
PolicyArray* copy(uint minCapacity);
|
||||
virtual PolicyArray *copy() const FOLLY_OVERRIDE;
|
||||
virtual PolicyArray *copyWithStrongIterators() const FOLLY_OVERRIDE;
|
||||
virtual ArrayData *nonSmartCopy() const FOLLY_OVERRIDE;
|
||||
static ArrayData* Copy(const ArrayData* ad);
|
||||
static ArrayData* CopyWithStrongIterators(const ArrayData* ad);
|
||||
static ArrayData* NonSmartCopy(const ArrayData* ad);
|
||||
|
||||
private:
|
||||
template <class K, class V>
|
||||
@@ -520,44 +520,45 @@ public:
|
||||
* escalated array data.
|
||||
*/
|
||||
static ArrayData* Append(ArrayData*, CVarRef v, bool copy);
|
||||
virtual PolicyArray *appendRef(CVarRef v, bool copy) FOLLY_OVERRIDE;
|
||||
static ArrayData* AppendRef(ArrayData*, CVarRef v, bool copy);
|
||||
|
||||
/**
|
||||
* Similar to append(v, copy), with reference in v preserved.
|
||||
*/
|
||||
virtual ArrayData *appendWithRef(CVarRef v, bool copy) FOLLY_OVERRIDE;
|
||||
static ArrayData* AppendWithRef(ArrayData*, CVarRef v, bool copy);
|
||||
|
||||
/**
|
||||
* Implementing array appending and merging. If "copy" is true, make a copy
|
||||
* first then append/merge arrays. Return NULL if escalation is not needed,
|
||||
* or an escalated array data.
|
||||
*/
|
||||
virtual ArrayData *plus(const ArrayData *elems, bool copy) FOLLY_OVERRIDE;
|
||||
virtual ArrayData *merge(const ArrayData *elems, bool copy) FOLLY_OVERRIDE;
|
||||
static ArrayData* Plus(ArrayData* ad, const ArrayData *elems, bool copy);
|
||||
static ArrayData* Merge(ArrayData* ad, const ArrayData *elems, bool copy);
|
||||
|
||||
/**
|
||||
* Stack function: pop the last item and return it.
|
||||
*/
|
||||
virtual ArrayData *pop(Variant &value) FOLLY_OVERRIDE;
|
||||
static ArrayData* Pop(ArrayData*, Variant &value);
|
||||
|
||||
/**
|
||||
* Queue function: remove the 1st item and return it.
|
||||
*/
|
||||
virtual ArrayData *dequeue(Variant &value) FOLLY_OVERRIDE;
|
||||
static ArrayData* Dequeue(ArrayData*, Variant &value);
|
||||
|
||||
/**
|
||||
* Array function: prepend a new item.
|
||||
*/
|
||||
virtual ArrayData *prepend(CVarRef v, bool copy) FOLLY_OVERRIDE;
|
||||
static ArrayData* Prepend(ArrayData*, CVarRef v, bool copy);
|
||||
|
||||
/**
|
||||
* Only map classes need this. Re-index all numeric keys to start from 0.
|
||||
*/
|
||||
virtual void renumber() FOLLY_OVERRIDE;
|
||||
void renumber();
|
||||
static void Renumber(ArrayData*);
|
||||
|
||||
virtual void onSetEvalScalar() FOLLY_OVERRIDE;
|
||||
static void OnSetEvalScalar(ArrayData*);
|
||||
|
||||
virtual ArrayData *escalate() const FOLLY_OVERRIDE;
|
||||
static ArrayData* Escalate(const ArrayData*);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -67,13 +67,11 @@ void SharedMap::Release(ArrayData* ad) {
|
||||
|
||||
inline SharedMap* SharedMap::asSharedMap(ArrayData* ad) {
|
||||
assert(ad->kind() == kSharedKind);
|
||||
assert(dynamic_cast<SharedMap*>(ad));
|
||||
return static_cast<SharedMap*>(ad);
|
||||
}
|
||||
|
||||
inline const SharedMap* SharedMap::asSharedMap(const ArrayData* ad) {
|
||||
assert(ad->kind() == kSharedKind);
|
||||
assert(dynamic_cast<const SharedMap*>(ad));
|
||||
return static_cast<const SharedMap*>(ad);
|
||||
}
|
||||
|
||||
@@ -118,104 +116,103 @@ inline ArrayData* releaseIfCopied(ArrayData* a1, ArrayData* a2) {
|
||||
|
||||
ArrayData *SharedMap::LvalInt(ArrayData* ad, int64_t k, Variant *&ret,
|
||||
bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
ArrayData *escalated = Escalate(ad);
|
||||
return releaseIfCopied(escalated, escalated->lval(k, ret, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::LvalStr(ArrayData* ad, StringData* k, Variant *&ret,
|
||||
bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
ArrayData *escalated = Escalate(ad);
|
||||
return releaseIfCopied(escalated, escalated->lval(k, ret, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::LvalNew(ArrayData* ad, Variant *&ret, bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
ArrayData *escalated = Escalate(ad);
|
||||
return releaseIfCopied(escalated, escalated->lvalNew(ret, false));
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
SharedMap::SetInt(ArrayData* ad, int64_t k, CVarRef v, bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
ArrayData *escalated = Escalate(ad);
|
||||
return releaseIfCopied(escalated, escalated->set(k, v, false));
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
SharedMap::SetStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
ArrayData *escalated = Escalate(ad);
|
||||
return releaseIfCopied(escalated, escalated->set(k, v, false));
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
SharedMap::SetRefInt(ArrayData* ad, int64_t k, CVarRef v, bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
ArrayData *escalated = Escalate(ad);
|
||||
return releaseIfCopied(escalated, escalated->setRef(k, v, false));
|
||||
}
|
||||
|
||||
ArrayData*
|
||||
SharedMap::SetRefStr(ArrayData* ad, StringData* k, CVarRef v, bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
ArrayData *escalated = Escalate(ad);
|
||||
return releaseIfCopied(escalated, escalated->setRef(k, v, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::AddLvalInt(ArrayData* ad, int64_t k, Variant *&ret,
|
||||
bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
ArrayData *escalated = Escalate(ad);
|
||||
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();
|
||||
ArrayData *escalated = Escalate(ad);
|
||||
return releaseIfCopied(escalated, escalated->addLval(k, ret, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::RemoveInt(ArrayData* ad, int64_t k, bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
ArrayData *escalated = Escalate(ad);
|
||||
return releaseIfCopied(escalated, escalated->remove(k, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::RemoveStr(ArrayData* ad, const StringData* k, bool copy) {
|
||||
ArrayData *escalated = asSharedMap(ad)->SharedMap::escalate();
|
||||
ArrayData *escalated = Escalate(ad);
|
||||
return releaseIfCopied(escalated, escalated->remove(k, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::copy() const {
|
||||
return SharedMap::escalate();
|
||||
ArrayData* SharedMap::Copy(const ArrayData* ad) {
|
||||
return Escalate(ad);
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::Append(ArrayData* ad, CVarRef v, bool copy) {
|
||||
auto a = asSharedMap(ad);
|
||||
ArrayData *escalated = a->SharedMap::escalate();
|
||||
ArrayData *escalated = Escalate(ad);
|
||||
return releaseIfCopied(escalated, escalated->append(v, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::appendRef(CVarRef v, bool copy) {
|
||||
ArrayData *escalated = SharedMap::escalate();
|
||||
ArrayData *SharedMap::AppendRef(ArrayData* ad, CVarRef v, bool copy) {
|
||||
ArrayData *escalated = Escalate(ad);
|
||||
return releaseIfCopied(escalated, escalated->appendRef(v, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::appendWithRef(CVarRef v, bool copy) {
|
||||
ArrayData *escalated = SharedMap::escalate();
|
||||
ArrayData *SharedMap::AppendWithRef(ArrayData* ad, CVarRef v, bool copy) {
|
||||
ArrayData *escalated = Escalate(ad);
|
||||
return releaseIfCopied(escalated, escalated->appendWithRef(v, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::plus(const ArrayData *elems, bool copy) {
|
||||
ArrayData *escalated = SharedMap::escalate();
|
||||
ArrayData *SharedMap::Plus(ArrayData* ad, const ArrayData *elems, bool copy) {
|
||||
ArrayData *escalated = Escalate(ad);
|
||||
return releaseIfCopied(escalated, escalated->plus(elems, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::merge(const ArrayData *elems, bool copy) {
|
||||
ArrayData *escalated = SharedMap::escalate();
|
||||
ArrayData *SharedMap::Merge(ArrayData* ad, const ArrayData *elems, bool copy) {
|
||||
ArrayData *escalated = Escalate(ad);
|
||||
return releaseIfCopied(escalated, escalated->merge(elems, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::prepend(CVarRef v, bool copy) {
|
||||
ArrayData *escalated = SharedMap::escalate();
|
||||
ArrayData *SharedMap::Prepend(ArrayData* ad, CVarRef v, bool copy) {
|
||||
ArrayData *escalated = Escalate(ad);
|
||||
return releaseIfCopied(escalated, escalated->prepend(v, false));
|
||||
}
|
||||
|
||||
ArrayData *SharedMap::escalate() const {
|
||||
ArrayData *ret = loadElems();
|
||||
ArrayData *SharedMap::Escalate(const ArrayData* ad) {
|
||||
auto ret = asSharedMap(ad)->loadElems();
|
||||
assert(!ret->isStatic());
|
||||
return ret;
|
||||
}
|
||||
@@ -249,8 +246,9 @@ void SharedMap::NvGetKey(const ArrayData* ad, TypedValue* out, ssize_t pos) {
|
||||
}
|
||||
}
|
||||
|
||||
ArrayData* SharedMap::escalateForSort() {
|
||||
ArrayData *ret = loadElems(true /* mapInit */);
|
||||
ArrayData* SharedMap::EscalateForSort(ArrayData* ad) {
|
||||
auto a = asSharedMap(ad);
|
||||
auto ret = a->loadElems(true /* mapInit */);
|
||||
assert(!ret->isStatic());
|
||||
return ret;
|
||||
}
|
||||
@@ -279,12 +277,12 @@ ssize_t SharedMap::IterRewind(const ArrayData* ad, ssize_t prev) {
|
||||
return next >= 0 ? next : invalid_index;
|
||||
}
|
||||
|
||||
bool SharedMap::validFullPos(const FullPos& fp) const {
|
||||
assert(fp.getContainer() == (ArrayData*)this);
|
||||
bool SharedMap::ValidFullPos(const ArrayData* ad, const FullPos& fp) {
|
||||
assert(fp.getContainer() == ad);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SharedMap::advanceFullPos(FullPos& fp) {
|
||||
bool SharedMap::AdvanceFullPos(ArrayData* ad, FullPos& fp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,8 +42,6 @@ public:
|
||||
|
||||
~SharedMap();
|
||||
|
||||
virtual bool isSharedMap() const { return true; }
|
||||
|
||||
// these using directives ensure the full set of overloaded functions
|
||||
// are visible in this class, to avoid triggering implicit conversions
|
||||
// from a CVarRef key to int64.
|
||||
@@ -85,20 +83,19 @@ public:
|
||||
static ArrayData *RemoveInt(ArrayData* ad, int64_t k, bool copy);
|
||||
static ArrayData *RemoveStr(ArrayData* ad, const StringData* k, bool copy);
|
||||
|
||||
ArrayData *copy() const;
|
||||
static ArrayData* Copy(const ArrayData*);
|
||||
/**
|
||||
* Copy (escalate) the SharedMap without triggering local cache.
|
||||
*/
|
||||
static ArrayData *Append(ArrayData* a, CVarRef v, bool copy);
|
||||
ArrayData *appendRef(CVarRef v, bool copy);
|
||||
ArrayData *appendWithRef(CVarRef v, bool copy);
|
||||
ArrayData *plus(const ArrayData *elems, bool copy);
|
||||
ArrayData *merge(const ArrayData *elems, bool copy);
|
||||
|
||||
ArrayData *prepend(CVarRef v, bool copy);
|
||||
static ArrayData* Append(ArrayData* a, CVarRef v, bool copy);
|
||||
static ArrayData* AppendRef(ArrayData*, CVarRef v, bool copy);
|
||||
static ArrayData* AppendWithRef(ArrayData*, CVarRef v, bool copy);
|
||||
static ArrayData* Plus(ArrayData*, const ArrayData *elems, bool copy);
|
||||
static ArrayData* Merge(ArrayData*, const ArrayData *elems, bool copy);
|
||||
static ArrayData* Prepend(ArrayData*, CVarRef v, bool copy);
|
||||
|
||||
/**
|
||||
* Non-Variant virtual methods that override ArrayData
|
||||
* Non-Variant methods that override ArrayData
|
||||
*/
|
||||
static TypedValue* NvGetInt(const ArrayData*, int64_t k);
|
||||
static TypedValue* NvGetStr(const ArrayData*, const StringData* k);
|
||||
@@ -111,8 +108,8 @@ public:
|
||||
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);
|
||||
static bool ValidFullPos(const ArrayData*, const FullPos& fp);
|
||||
static bool AdvanceFullPos(ArrayData*, FullPos& fp);
|
||||
|
||||
/**
|
||||
* Memory allocator methods.
|
||||
@@ -120,8 +117,8 @@ public:
|
||||
DECLARE_SMART_ALLOCATION(SharedMap);
|
||||
static void Release(ArrayData*);
|
||||
|
||||
virtual ArrayData *escalate() const;
|
||||
virtual ArrayData* escalateForSort();
|
||||
static ArrayData* Escalate(const ArrayData*);
|
||||
static ArrayData* EscalateForSort(ArrayData*);
|
||||
|
||||
ArrayData* loadElems(bool mapInit = false) const;
|
||||
|
||||
|
||||
@@ -378,10 +378,6 @@ struct GarbageCollector {
|
||||
}
|
||||
|
||||
void dealloc(SmartAllocatorImpl* sa, ArrayData* ar) const {
|
||||
if (Sweepable* s = dynamic_cast<Sweepable*>(ar)) {
|
||||
s->sweep();
|
||||
s->unregister();
|
||||
}
|
||||
sa->dealloc(ar);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,14 +25,12 @@ namespace HPHP {
|
||||
|
||||
inline NameValueTableWrapper* NameValueTableWrapper::asNVTW(ArrayData* ad) {
|
||||
assert(ad->kind() == kNvtwKind);
|
||||
assert(dynamic_cast<NameValueTableWrapper*>(ad));
|
||||
return static_cast<NameValueTableWrapper*>(ad);
|
||||
}
|
||||
|
||||
inline const NameValueTableWrapper*
|
||||
NameValueTableWrapper::asNVTW(const ArrayData* ad) {
|
||||
assert(ad->kind() == kNvtwKind);
|
||||
assert(dynamic_cast<const NameValueTableWrapper*>(ad));
|
||||
return static_cast<const NameValueTableWrapper*>(ad);
|
||||
}
|
||||
|
||||
@@ -170,27 +168,33 @@ NameValueTableWrapper::RemoveStr(ArrayData* ad, const StringData* k,
|
||||
* is currently $GLOBALS.
|
||||
*/
|
||||
|
||||
ArrayData* NameValueTableWrapper::Append(ArrayData*, CVarRef v, bool copy) {
|
||||
ArrayData*
|
||||
NameValueTableWrapper::Append(ArrayData*, CVarRef v, bool copy) {
|
||||
throw NotImplementedException("append on $GLOBALS");
|
||||
}
|
||||
|
||||
ArrayData* NameValueTableWrapper::appendRef(CVarRef v, bool copy) {
|
||||
ArrayData*
|
||||
NameValueTableWrapper::AppendRef(ArrayData*, CVarRef v, bool copy) {
|
||||
throw NotImplementedException("appendRef on $GLOBALS");
|
||||
}
|
||||
|
||||
ArrayData* NameValueTableWrapper::appendWithRef(CVarRef v, bool copy) {
|
||||
ArrayData*
|
||||
NameValueTableWrapper::AppendWithRef(ArrayData*, CVarRef v, bool copy) {
|
||||
throw NotImplementedException("appendWithRef on $GLOBALS");
|
||||
}
|
||||
|
||||
ArrayData* NameValueTableWrapper::plus(const ArrayData* elems, bool copy) {
|
||||
ArrayData*
|
||||
NameValueTableWrapper::Plus(ArrayData*, const ArrayData* elems, bool copy) {
|
||||
throw NotImplementedException("plus on $GLOBALS");
|
||||
}
|
||||
|
||||
ArrayData* NameValueTableWrapper::merge(const ArrayData* elems, bool copy) {
|
||||
ArrayData*
|
||||
NameValueTableWrapper::Merge(ArrayData*, const ArrayData* elems, bool copy) {
|
||||
throw NotImplementedException("merge on $GLOBALS");
|
||||
}
|
||||
|
||||
ArrayData* NameValueTableWrapper::prepend(CVarRef v, bool copy) {
|
||||
ArrayData*
|
||||
NameValueTableWrapper::Prepend(ArrayData*, CVarRef v, bool copy) {
|
||||
throw NotImplementedException("prepend on $GLOBALS");
|
||||
}
|
||||
|
||||
@@ -219,19 +223,22 @@ ssize_t NameValueTableWrapper::IterRewind(const ArrayData* ad, ssize_t prev) {
|
||||
return iter.toInteger();
|
||||
}
|
||||
|
||||
bool NameValueTableWrapper::validFullPos(const FullPos & fp) const {
|
||||
assert(fp.getContainer() == (ArrayData*)this);
|
||||
bool
|
||||
NameValueTableWrapper::ValidFullPos(const ArrayData* ad, const FullPos & fp) {
|
||||
assert(fp.getContainer() == ad);
|
||||
auto a = asNVTW(ad);
|
||||
if (fp.getResetFlag()) return false;
|
||||
if (fp.m_pos == ArrayData::invalid_index) return false;
|
||||
NameValueTable::Iterator iter(m_tab, fp.m_pos);
|
||||
return (iter.valid());
|
||||
if (fp.m_pos == invalid_index) return false;
|
||||
NameValueTable::Iterator iter(a->m_tab, fp.m_pos);
|
||||
return iter.valid();
|
||||
}
|
||||
|
||||
bool NameValueTableWrapper::advanceFullPos(FullPos& fp) {
|
||||
bool NameValueTableWrapper::AdvanceFullPos(ArrayData* ad, FullPos& fp) {
|
||||
auto a = asNVTW(ad);
|
||||
bool reset = fp.getResetFlag();
|
||||
NameValueTable::Iterator iter = reset ?
|
||||
NameValueTable::Iterator(m_tab) :
|
||||
NameValueTable::Iterator(m_tab, fp.m_pos);
|
||||
NameValueTable::Iterator(a->m_tab) :
|
||||
NameValueTable::Iterator(a->m_tab, fp.m_pos);
|
||||
if (reset) {
|
||||
fp.setResetFlag(false);
|
||||
} else {
|
||||
@@ -245,20 +252,20 @@ bool NameValueTableWrapper::advanceFullPos(FullPos& fp) {
|
||||
// To conform to PHP behavior, we need to set the internal
|
||||
// cursor to point to the next element.
|
||||
iter.next();
|
||||
m_pos = iter.toInteger();
|
||||
a->m_pos = iter.toInteger();
|
||||
return true;
|
||||
}
|
||||
|
||||
ArrayData* NameValueTableWrapper::escalateForSort() {
|
||||
ArrayData* NameValueTableWrapper::EscalateForSort(ArrayData* ad) {
|
||||
raise_warning("Sorting the $GLOBALS array is not supported");
|
||||
return this;
|
||||
return ad;
|
||||
}
|
||||
void NameValueTableWrapper::ksort(int sort_flags, bool ascending) {}
|
||||
void NameValueTableWrapper::sort(int sort_flags, bool ascending) {}
|
||||
void NameValueTableWrapper::asort(int sort_flags, bool ascending) {}
|
||||
void NameValueTableWrapper::uksort(CVarRef cmp_function) {}
|
||||
void NameValueTableWrapper::usort(CVarRef cmp_function) {}
|
||||
void NameValueTableWrapper::uasort(CVarRef cmp_function) {}
|
||||
void NameValueTableWrapper::Ksort(ArrayData*, int sort_flags, bool ascending) {}
|
||||
void NameValueTableWrapper::Sort(ArrayData*, int sort_flags, bool ascending) {}
|
||||
void NameValueTableWrapper::Asort(ArrayData*, int sort_flags, bool ascending) {}
|
||||
void NameValueTableWrapper::Uksort(ArrayData*, CVarRef cmp_function) {}
|
||||
void NameValueTableWrapper::Usort(ArrayData*, CVarRef cmp_function) {}
|
||||
void NameValueTableWrapper::Uasort(ArrayData*, CVarRef cmp_function) {}
|
||||
|
||||
bool NameValueTableWrapper::IsVectorData(const ArrayData*) {
|
||||
return false;
|
||||
|
||||
@@ -103,33 +103,34 @@ public: // ArrayData implementation
|
||||
static ArrayData* RemoveInt(ArrayData*, int64_t k, bool copy);
|
||||
static ArrayData* RemoveStr(ArrayData*, const StringData* k, bool copy);
|
||||
|
||||
virtual ArrayData* copy() const { return 0; }
|
||||
static ArrayData* Copy(const ArrayData* ad) {
|
||||
return const_cast<ArrayData*>(ad);
|
||||
}
|
||||
|
||||
static ArrayData* Append(ArrayData*, CVarRef v, bool copy);
|
||||
virtual ArrayData* appendRef(CVarRef v, bool copy);
|
||||
virtual ArrayData* appendWithRef(CVarRef v, bool copy);
|
||||
static ArrayData* AppendRef(ArrayData*, CVarRef v, bool copy);
|
||||
static ArrayData* AppendWithRef(ArrayData*, CVarRef v, bool copy);
|
||||
|
||||
virtual ArrayData* plus(const ArrayData* elems, bool copy);
|
||||
virtual ArrayData* merge(const ArrayData* elems, bool copy);
|
||||
|
||||
virtual ArrayData* prepend(CVarRef v, bool copy);
|
||||
static ArrayData* Plus(ArrayData*, const ArrayData* elems, bool copy);
|
||||
static ArrayData* Merge(ArrayData*, const ArrayData* elems, bool copy);
|
||||
static ArrayData* Prepend(ArrayData*, CVarRef v, bool copy);
|
||||
|
||||
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&);
|
||||
static bool ValidFullPos(const ArrayData*, const FullPos & fp);
|
||||
static bool AdvanceFullPos(ArrayData*, FullPos&);
|
||||
static bool IsVectorData(const ArrayData*);
|
||||
|
||||
virtual ArrayData* escalateForSort();
|
||||
virtual void ksort(int sort_flags, bool ascending);
|
||||
virtual void sort(int sort_flags, bool ascending);
|
||||
virtual void asort(int sort_flags, bool ascending);
|
||||
virtual void uksort(CVarRef cmp_function);
|
||||
virtual void usort(CVarRef cmp_function);
|
||||
virtual void uasort(CVarRef cmp_function);
|
||||
static ArrayData* EscalateForSort(ArrayData*);
|
||||
static void Ksort(ArrayData*, int sort_flags, bool ascending);
|
||||
static void Sort(ArrayData*, int sort_flags, bool ascending);
|
||||
static void Asort(ArrayData*, int sort_flags, bool ascending);
|
||||
static void Uksort(ArrayData*, CVarRef cmp_function);
|
||||
static void Usort(ArrayData*, CVarRef cmp_function);
|
||||
static void Uasort(ArrayData*, CVarRef cmp_function);
|
||||
|
||||
private:
|
||||
static NameValueTableWrapper* asNVTW(ArrayData* ad);
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário