示例#1
0
Object BaseMap::php_retain(const Variant& callback) {
  CallCtx ctx;
  vm_decode_function(callback, nullptr, false, ctx);
  if (!ctx.func) {
    SystemLib::throwInvalidArgumentExceptionObject(
               "Parameter must be a valid callback");
  }
  auto size = m_size;
  if (!size) { return Object{this}; }
  constexpr int64_t argc = useKey ? 2 : 1;
  TypedValue argv[argc];
  for (ssize_t pos = iter_begin(); iter_valid(pos); pos = iter_next(pos)) {
    auto* e = iter_elm(pos);
    if (useKey) {
      if (e->hasIntKey()) {
        argv[0].m_type = KindOfInt64;
        argv[0].m_data.num = e->ikey;
      } else {
        argv[0].m_type = KindOfString;
        argv[0].m_data.pstr = e->skey;
      }
    }
    argv[argc-1] = e->data;
    int32_t version = m_version;
    bool b = invokeAndCastToBool(ctx, argc, argv);
    if (UNLIKELY(version != m_version)) {
      throw_collection_modified();
    }
    if (b) {
      continue;
    }
    mutateAndBump();
    version = m_version;
    e = iter_elm(pos);
    ssize_t pp = (e->hasIntKey()
                   ? findForRemove(e->ikey)
                   : findForRemove(e->skey, e->skey->hash()));
    eraseNoCompact(pp);
    if (UNLIKELY(version != m_version)) {
      throw_collection_modified();
    }
  }

  assert(m_size <= size);
  compactOrShrinkIfDensityTooLow();
  return Object{this};
}
示例#2
0
NEVER_INLINE
void HashCollection::reserve(int64_t sz) {
  assert(m_size <= posLimit() && posLimit() <= cap());
  auto cap = static_cast<int64_t>(this->cap());
  if (LIKELY(sz > cap)) {
    if (UNLIKELY(sz > int64_t(MaxReserveSize))) {
      throwReserveTooLarge();
    }
    // Fast path: The requested capacity is greater than the current capacity.
    // Grow to the smallest allowed capacity that is sufficient.
    grow(MixedArray::computeScaleFromSize(sz));
    assert(canMutateBuffer());
    return;
  }
  if (LIKELY(!hasTombstones())) {
    // Fast path: There are no tombstones and the requested capacity is less
    // than or equal to the current capacity.
    mutate();
    return;
  }
  if (sz + int64_t(posLimit() - m_size) <= cap || isDensityTooLow()) {
    // If we reach this case, then either (1) density is too low (this is
    // possible because of methods like retain()), in which case we compact
    // to make room and return, OR (2) density is not too low and either
    // sz < m_size or there's enough room to add sz-m_size elements, in
    // which case we do nothing and return.
    compactOrShrinkIfDensityTooLow();
    assert(sz + int64_t(posLimit() - m_size) <= cap);
    mutate();
    return;
  }
  // If we reach this case, then density is not too low and sz > m_size and
  // there is not enough room to add sz-m_size elements. While would could
  // compact to make room, it's better for Hysteresis if we grow capacity
  // by 2x instead.
  assert(!isDensityTooLow());
  assert(sz + int64_t(posLimit() - m_size) > cap);
  assert(cap < MaxSize && tableMask() != 0);
  auto newScale = scale() * 2;
  assert(sz > 0 && MixedArray::Capacity(newScale) >= sz);
  grow(newScale);
  assert(canMutateBuffer());
}