47d8ee5298
The AddLval methods were fairly cold, so reimplement them in terms of lval(), but preserve the assert that ensures the keys being added do not already exist. This reduces the number of kind-specific methods we need to implement. Added Array::setWithRef(key,value) to capture a common use case for lvalAt(). Later this can implemented more efficiently as a virtual method in ArrayData subclasses. Differential Revision: D937227
265 linhas
8.2 KiB
C++
265 linhas
8.2 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include "hphp/runtime/vm/name-value-table-wrapper.h"
|
|
#include "hphp/runtime/base/runtime-error.h"
|
|
#include "hphp/runtime/base/array-iterator.h"
|
|
#include "hphp/runtime/base/array-init.h"
|
|
|
|
namespace HPHP {
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
inline NameValueTableWrapper* NameValueTableWrapper::asNVTW(ArrayData* ad) {
|
|
assert(ad->kind() == kNvtwKind);
|
|
return static_cast<NameValueTableWrapper*>(ad);
|
|
}
|
|
|
|
inline const NameValueTableWrapper*
|
|
NameValueTableWrapper::asNVTW(const ArrayData* ad) {
|
|
assert(ad->kind() == kNvtwKind);
|
|
return static_cast<const NameValueTableWrapper*>(ad);
|
|
}
|
|
|
|
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.
|
|
auto a = asNVTW(ad);
|
|
size_t count = 0;
|
|
for (auto iter = IterBegin(a);
|
|
iter != invalid_index;
|
|
iter = IterAdvance(a, iter)) {
|
|
++count;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
void NameValueTableWrapper::NvGetKey(const ArrayData* ad, TypedValue* out,
|
|
ssize_t pos) {
|
|
auto a = asNVTW(ad);
|
|
NameValueTable::Iterator iter(a->m_tab, pos);
|
|
if (iter.valid()) {
|
|
auto k = iter.curKey();
|
|
out->m_data.pstr = const_cast<StringData*>(k);
|
|
out->m_type = KindOfString;
|
|
k->incRefCount();
|
|
} else {
|
|
out->m_type = KindOfUninit;
|
|
}
|
|
}
|
|
|
|
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::ExistsInt(const ArrayData* ad, int64_t k) {
|
|
return ExistsStr(ad, String(k).get());
|
|
}
|
|
|
|
bool
|
|
NameValueTableWrapper::ExistsStr(const ArrayData* ad, const StringData* k) {
|
|
return asNVTW(ad)->m_tab->lookup(k) != nullptr;
|
|
}
|
|
|
|
TypedValue*
|
|
NameValueTableWrapper::NvGetStr(const ArrayData* ad, const StringData* k) {
|
|
return asNVTW(ad)->m_tab->lookup(k);
|
|
}
|
|
|
|
TypedValue* NameValueTableWrapper::NvGetInt(const ArrayData* ad, int64_t k) {
|
|
return asNVTW(ad)->m_tab->lookup(String(k).get());
|
|
}
|
|
|
|
ArrayData*
|
|
NameValueTableWrapper::LvalInt(ArrayData* ad, int64_t k, Variant*& ret,
|
|
bool copy) {
|
|
return LvalStr(ad, String(k).get(), ret, copy);
|
|
}
|
|
|
|
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 = a->m_tab->set(k, &nulVal);
|
|
}
|
|
ret = &tvAsVariant(tv);
|
|
return a;
|
|
}
|
|
|
|
ArrayData*
|
|
NameValueTableWrapper::LvalNew(ArrayData* ad, Variant*& ret, bool copy) {
|
|
ret = &Variant::lvalBlackHole();
|
|
return ad;
|
|
}
|
|
|
|
ArrayData* NameValueTableWrapper::SetInt(ArrayData* ad, int64_t k,
|
|
CVarRef v, bool copy) {
|
|
return SetStr(ad, String(k).get(), v, copy);
|
|
}
|
|
|
|
ArrayData* NameValueTableWrapper::SetStr(ArrayData* ad, StringData* k,
|
|
CVarRef v, bool copy) {
|
|
auto a = asNVTW(ad);
|
|
tvAsVariant(a->m_tab->lookupAdd(k)).assignVal(v);
|
|
return a;
|
|
}
|
|
|
|
ArrayData* NameValueTableWrapper::SetRefInt(ArrayData* ad, int64_t k,
|
|
CVarRef v, bool copy) {
|
|
return asNVTW(ad)->setRef(String(k).get(), v, copy);
|
|
}
|
|
|
|
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::RemoveInt(ArrayData* ad, int64_t k, bool copy) {
|
|
return RemoveStr(ad, String(k).get(), copy);
|
|
}
|
|
|
|
ArrayData*
|
|
NameValueTableWrapper::RemoveStr(ArrayData* ad, const StringData* k,
|
|
bool copy) {
|
|
auto a = asNVTW(ad);
|
|
a->m_tab->unset(k);
|
|
return a;
|
|
}
|
|
|
|
/*
|
|
* The messages in the user-visible exceptions below claim we are
|
|
* $GLOBALS, because the only user-visible NameValueTableWrapper array
|
|
* is currently $GLOBALS.
|
|
*/
|
|
|
|
ArrayData*
|
|
NameValueTableWrapper::Append(ArrayData*, CVarRef v, bool copy) {
|
|
throw NotImplementedException("append on $GLOBALS");
|
|
}
|
|
|
|
ArrayData*
|
|
NameValueTableWrapper::AppendRef(ArrayData*, CVarRef v, bool copy) {
|
|
throw NotImplementedException("appendRef on $GLOBALS");
|
|
}
|
|
|
|
ArrayData*
|
|
NameValueTableWrapper::AppendWithRef(ArrayData*, CVarRef v, bool copy) {
|
|
throw NotImplementedException("appendWithRef on $GLOBALS");
|
|
}
|
|
|
|
ArrayData*
|
|
NameValueTableWrapper::Plus(ArrayData*, const ArrayData* elems, bool copy) {
|
|
throw NotImplementedException("plus on $GLOBALS");
|
|
}
|
|
|
|
ArrayData*
|
|
NameValueTableWrapper::Merge(ArrayData*, const ArrayData* elems, bool copy) {
|
|
throw NotImplementedException("merge on $GLOBALS");
|
|
}
|
|
|
|
ArrayData*
|
|
NameValueTableWrapper::Prepend(ArrayData*, CVarRef v, bool copy) {
|
|
throw NotImplementedException("prepend on $GLOBALS");
|
|
}
|
|
|
|
ssize_t NameValueTableWrapper::IterBegin(const ArrayData* ad) {
|
|
auto a = asNVTW(ad);
|
|
NameValueTable::Iterator iter(a->m_tab);
|
|
return iter.toInteger();
|
|
}
|
|
|
|
ssize_t NameValueTableWrapper::IterEnd(const ArrayData* ad) {
|
|
auto a = asNVTW(ad);
|
|
return NameValueTable::Iterator::getEnd(a->m_tab).toInteger();
|
|
}
|
|
|
|
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::IterRewind(const ArrayData* ad, ssize_t prev) {
|
|
auto a = asNVTW(ad);
|
|
NameValueTable::Iterator iter(a->m_tab, prev);
|
|
iter.prev();
|
|
return iter.toInteger();
|
|
}
|
|
|
|
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 == invalid_index) return false;
|
|
NameValueTable::Iterator iter(a->m_tab, fp.m_pos);
|
|
return iter.valid();
|
|
}
|
|
|
|
bool NameValueTableWrapper::AdvanceFullPos(ArrayData* ad, FullPos& fp) {
|
|
auto a = asNVTW(ad);
|
|
bool reset = fp.getResetFlag();
|
|
NameValueTable::Iterator iter = reset ?
|
|
NameValueTable::Iterator(a->m_tab) :
|
|
NameValueTable::Iterator(a->m_tab, fp.m_pos);
|
|
if (reset) {
|
|
fp.setResetFlag(false);
|
|
} else {
|
|
if (!iter.valid()) {
|
|
return false;
|
|
}
|
|
iter.next();
|
|
}
|
|
fp.m_pos = iter.toInteger();
|
|
if (!iter.valid()) return false;
|
|
// To conform to PHP behavior, we need to set the internal
|
|
// cursor to point to the next element.
|
|
iter.next();
|
|
a->m_pos = iter.toInteger();
|
|
return true;
|
|
}
|
|
|
|
ArrayData* NameValueTableWrapper::EscalateForSort(ArrayData* ad) {
|
|
raise_warning("Sorting the $GLOBALS array is not supported");
|
|
return ad;
|
|
}
|
|
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;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
}
|