コード例 #1
0
ALWAYS_INLINE
void BaseSet::addImpl(StringData *key) {
  if (!raw) {
    mutate();
  }
  strhash_t h = key->hash();
  auto p = findForInsert(key, h);
  assert(p);
  if (validPos(*p)) {
    return;
  }
  if (UNLIKELY(isFull())) {
    makeRoom();
    p = findForInsert(key, h);
  }
  auto& e = allocElm(p);
  // This increments the string's refcount twice, once for
  // the key and once for the value
  e.setStrKey(key, h);
  cellDup(make_tv<KindOfString>(key), e.data);
  updateIntLikeStrKeys(key);
  if (!raw) {
    ++m_version;
  }
}
コード例 #2
0
ALWAYS_INLINE
void BaseMap::setImpl(StringData* key, const TypedValue* val) {
  if (!raw) {
    mutate();
  }
  assert(val->m_type != KindOfRef);
  assert(canMutateBuffer());
retry:
  strhash_t h = key->hash();
  auto* p = findForInsert(key, h);
  assert(p);
  if (validPos(*p)) {
    auto& e = data()[*p];
    TypedValue old = e.data;
    cellDup(*val, e.data);
    tvRefcountedDecRef(old);
    return;
  }
  if (UNLIKELY(isFull())) {
    makeRoom();
    goto retry;
  }
  if (!raw) {
    ++m_version;
  }
  auto& e = allocElm(p);
  cellDup(*val, e.data);
  e.setStrKey(key, h);
  updateIntLikeStrKeys(key);
}
コード例 #3
0
void BaseMap::addAllImpl(const Variant& iterable) {
  if (iterable.isNull()) return;
  VMRegGuard _;

  decltype(cap()) oldCap = 0;
  bool ok = IterateKV(
    *iterable.asTypedValue(),
    [&](ArrayData* adata) {
      auto sz = adata->size();
      if (!sz) return true;
      if (!m_size) {
        if (adata->isMixed()) {
          replaceArray(adata);
          updateIntLikeStrKeys();
          return true;
        }
      } else {
        oldCap = cap(); // assume minimal collisions
      }
      reserve(m_size + sz);
      mutateAndBump();
      return false;
    },
    [this](const TypedValue* key, const TypedValue* value) {
      setRaw(tvAsCVarRef(key), tvAsCVarRef(value));
    },
    [this](ObjectData* coll) {
      switch (coll->collectionType()) {
        case CollectionType::Map:
        case CollectionType::Set:
        {
          if (m_size) break;
          auto hc = static_cast<HashCollection*>(coll);
          replaceArray(hc->arrayData());
          setIntLikeStrKeys(BaseMap::intLikeStrKeys(hc));
          return true;
        }
        case CollectionType::Pair:
          mutateAndBump();
          break;
        default:
          break;
      }
      return false;
    },
    [this](const TypedValue* key, const TypedValue* value) {
      set(tvAsCVarRef(key), tvAsCVarRef(value));
    });

  if (UNLIKELY(!ok)) {
    throw_invalid_collection_parameter();
  }
  // ... and shrink back if that was incorrect
  if (oldCap) shrinkIfCapacityTooHigh(oldCap);
}
コード例 #4
0
typename std::enable_if<
  std::is_base_of<BaseSet, TSet>::value, Object>::type
BaseSet::php_skip(const Variant& n) {
  if (!n.isInteger()) {
    SystemLib::throwInvalidArgumentExceptionObject(
      "Parameter n must be an integer");
  }
  int64_t len = n.toInt64();
  if (len <= 0) {
    // We know the resulting Set will simply be a copy of this Set,
    // so we can just call Clone() and return early here.
    return Object::attach(TSet::Clone(this));
  }
  auto set = req::make<TSet>();
  if (len >= m_size) {
    // We know the resulting Set will be empty, so we can return
    // early here.
    return Object{std::move(set)};
  }
  size_t sz = size_t(m_size) - size_t(len);
  assert(sz);
  set->reserve(sz);
  set->setSize(sz);
  set->setPosLimit(sz);
  uint32_t frPos = nthElmPos(len);
  auto table = set->hashTab();
  auto mask = set->tableMask();
  for (uint32_t toPos = 0; toPos < sz; ++toPos, ++frPos) {
    while (isTombstone(frPos)) {
      assert(frPos + 1 < posLimit());
      ++frPos;
    }
    auto& toE = set->data()[toPos];
    dupElm(data()[frPos], toE);
    *findForNewInsert(table, mask, toE.probe()) = toPos;
    if (toE.hasIntKey()) {
      set->updateNextKI(toE.ikey);
    } else {
      assert(toE.hasStrKey());
      set->updateIntLikeStrKeys(toE.skey);
    }
  }
  return Object{std::move(set)};
}
コード例 #5
0
ALWAYS_INLINE
typename std::enable_if<
  std::is_base_of<BaseMap, TMap>::value, Object>::type
BaseMap::php_take(const Variant& n) {
  if (!n.isInteger()) {
    SystemLib::throwInvalidArgumentExceptionObject(
      "Parameter n must be an integer");
  }
  int64_t len = n.toInt64();
  if (len >= int64_t(m_size)) {
    // We know the resulting Map will simply be a copy of this Map,
    // so we can just call Clone() and return early here.
    return Object::attach(TMap::Clone(this));
  }
  auto map = req::make<TMap>();
  if (len <= 0) {
    // We know the resulting Map will be empty, so we can return
    // early here.
    return Object{std::move(map)};
  }
  size_t sz = size_t(len);
  map->reserve(sz);
  map->setSize(sz);
  map->setPosLimit(sz);
  auto table = map->hashTab();
  auto mask = map->tableMask();
  for (uint32_t frPos = 0, toPos = 0; toPos < sz; ++toPos, ++frPos) {
    frPos = skipTombstonesNoBoundsCheck(frPos);
    auto& toE = map->data()[toPos];
    dupElm(data()[frPos], toE);
    *findForNewInsert(table, mask, toE.probe()) = toPos;
    if (toE.hasIntKey()) {
      map->updateNextKI(toE.ikey);
    } else {
      assert(toE.hasStrKey());
      map->updateIntLikeStrKeys(toE.skey);
    }
  }
  return Object{std::move(map)};
}
コード例 #6
0
ALWAYS_INLINE
typename std::enable_if<
  std::is_base_of<BaseMap, TMap>::value, Object>::type
BaseMap::php_slice(const Variant& start, const Variant& len) {
  int64_t istart;
  int64_t ilen;
  if (!start.isInteger() || (istart = start.toInt64()) < 0) {
    SystemLib::throwInvalidArgumentExceptionObject(
      "Parameter start must be a non-negative integer");
  }
  if (!len.isInteger() || (ilen = len.toInt64()) < 0) {
    SystemLib::throwInvalidArgumentExceptionObject(
      "Parameter len must be a non-negative integer");
  }
  size_t skipAmt = std::min<size_t>(istart, m_size);
  size_t sz = std::min<size_t>(ilen, size_t(m_size) - skipAmt);
  auto map = req::make<TMap>();
  map->reserve(sz);
  map->setSize(sz);
  map->setPosLimit(sz);
  uint32_t frPos = nthElmPos(skipAmt);
  auto table = map->hashTab();
  auto mask = map->tableMask();
  for (uint32_t toPos = 0; toPos < sz; ++toPos, ++frPos) {
    frPos = skipTombstonesNoBoundsCheck(frPos);
    auto& toE = map->data()[toPos];
    dupElm(data()[frPos], toE);
    *findForNewInsert(table, mask, toE.probe()) = toPos;
    if (toE.hasIntKey()) {
      map->updateNextKI(toE.ikey);
    } else {
      assert(toE.hasStrKey());
      map->updateIntLikeStrKeys(toE.skey);
    }
  }
  return Object{std::move(map)};
}