ArrayData*
NameValueTableWrapper::RemoveStr(ArrayData* ad, const StringData* k,
                                 bool copy) {
  auto a = asNVTW(ad);
  a->m_tab->unset(k);
  return a;
}
ArrayData* NameValueTableWrapper::SetRefStr(ArrayData* ad,
                                            StringData* k,
                                            Variant& v,
                                            bool copy) {
  auto a = asNVTW(ad);
  tvAsVariant(a->m_tab->lookupAdd(k)).assignRef(v);
  return a;
}
ArrayData* NameValueTableWrapper::SetStr(ArrayData* ad,
                                         StringData* k,
                                         Cell v,
                                         bool copy) {
  auto a = asNVTW(ad);
  cellSet(v, *tvToCell(a->m_tab->lookupAdd(k)));
  return a;
}
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::ValidMArrayIter(const ArrayData* ad,
                                       const MArrayIter & fp) {
  assert(fp.getContainer() == ad);
  auto a = asNVTW(ad);
  if (fp.getResetFlag()) return false;
  if (fp.m_pos == IterEnd(a)) return false;
  NameValueTable::Iterator iter(a->m_tab, fp.m_pos);
  return iter.valid();
}
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;
}
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;
  }
}
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;
}
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;
}
TypedValue* NameValueTableWrapper::NvGetInt(const ArrayData* ad, int64_t k) {
  return asNVTW(ad)->m_tab->lookup(String(k).get());
}
TypedValue*
NameValueTableWrapper::NvGetStr(const ArrayData* ad, const StringData* k) {
  return asNVTW(ad)->m_tab->lookup(k);
}
bool
NameValueTableWrapper::ExistsStr(const ArrayData* ad, const StringData* k) {
  return asNVTW(ad)->m_tab->lookup(k) != nullptr;
}
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;
}
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();
}
ssize_t NameValueTableWrapper::IterEnd(const ArrayData* ad) {
  auto a = asNVTW(ad);
  return NameValueTable::Iterator::getEnd(a->m_tab).toInteger();
}
ssize_t NameValueTableWrapper::IterBegin(const ArrayData* ad) {
  auto a = asNVTW(ad);
  NameValueTable::Iterator iter(a->m_tab);
  return iter.toInteger();
}
ArrayData* NameValueTableWrapper::SetRefInt(ArrayData* ad, int64_t k,
                                            CVarRef v, bool copy) {
  return asNVTW(ad)->setRef(String(k).get(), v, copy);
}