示例#1
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);
}
示例#2
0
void HashCollection::remove(StringData* key) {
  mutateAndBump();
  auto p = findForRemove(key, key->hash());
  if (validPos(p)) {
    erase(p);
  }
}
示例#3
0
void HashCollection::remove(int64_t key) {
  mutateAndBump();
  auto p = findForRemove(key, hash_int64(key));
  if (validPos(p)) {
    erase(p);
  }
}
void BaseSet::addAll(const Variant& t) {
  if (t.isNull()) { return; } // nothing to do

  decltype(cap()) oldCap = 0;
  bool ok = IterateV(
    *t.asTypedValue(),
    [&](ArrayData* adata) {
      auto sz = adata->size();
      if (!sz) return true;
      if (m_size) {
        oldCap = cap(); // assume minimal collisions
      }
      reserve(m_size + sz);
      mutateAndBump();
      return false;
    },
    [this](const TypedValue* value) {
      addRaw(tvAsCVarRef(value));
    },
    [this](ObjectData* coll) {
      if (!m_size && coll->collectionType() == CollectionType::Set) {
        auto hc = static_cast<HashCollection*>(coll);
        replaceArray(hc->arrayData());
        setIntLikeStrKeys(BaseSet::intLikeStrKeys(hc));
        return true;
      }
      if (coll->collectionType() == CollectionType::Pair) {
        mutateAndBump();
      }
      return false;
    },
    [this](const TypedValue* value) {
      add(tvAsCVarRef(value));
    });

  if (UNLIKELY(!ok)) {
    throw_invalid_collection_parameter();
  }
  // ... and shrink back if that was incorrect
  if (oldCap) shrinkIfCapacityTooHigh(oldCap);
}
示例#5
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};
}
Variant BaseSet::popFront() {
  if (UNLIKELY(m_size == 0)) {
    SystemLib::throwInvalidOperationExceptionObject("Cannot pop empty Set");
  }
  mutateAndBump();
  auto e = data();
  for (;; ++e) {
    assert(e != elmLimit());
    if (!isTombstone(e)) break;
  }
  Variant ret = tvAsCVarRef(&e->data);
  auto h = e->hash();
  auto ei = e->hasIntKey() ? findForRemove(e->ikey, h) :
            findForRemove(e->skey, h);
  erase(ei);
  return ret;
}
示例#7
0
Variant BaseMap::popFront() {
  if (m_size) {
    mutateAndBump();
    auto* e = data();
    for (;; ++e) {
      assert(e != elmLimit());
      if (!isTombstone(e)) break;
    }
    Variant ret = tvAsCVarRef(&e->data);
    ssize_t ei;
    if (e->hasIntKey()) {
      ei = findForRemove(e->ikey);
    } else {
      assert(e->hasStrKey());
      ei = findForRemove(e->skey, e->skey->hash());
    }
    erase(ei);
    return ret;
  } else {
    SystemLib::throwInvalidOperationExceptionObject(
      "Cannot pop empty Map");
  }
}
示例#8
0
bool HashCollection::uksort(const Variant& cmp_function) {
  if (m_size <= 1) return true;
  mutateAndBump();
  USER_SORT_BODY(AssocKeyAccessor<HashCollection::Elm>);
}
示例#9
0
void HashCollection::ksort(int sort_flags, bool ascending) {
  if (m_size <= 1) return;
  mutateAndBump();
  SORT_BODY(AssocKeyAccessor<HashCollection::Elm>);
}