Example #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);
}
Example #2
0
void BaseMap::addAllPairs(const Variant& iterable) {
  if (iterable.isNull()) return;
  VMRegGuard _;
  size_t sz;
  ArrayIter iter = getArrayIterHelper(iterable, sz);
  auto oldCap = cap();
  reserve(m_size + sz); // presume minimum key collisions ...
  for (; iter; ++iter) {
    add(iter.second());
  }
  // ... and shrink back if that was incorrect
  shrinkIfCapacityTooHigh(oldCap);
}
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);
}
typename std::enable_if<
  std::is_base_of<BaseSet, TSet>::value, Object>::type
BaseSet::php_map(const Variant& callback) const {
  VMRegGuard _;
  CallCtx ctx;
  vm_decode_function(callback, nullptr, false, ctx);
  if (!ctx.func) {
    SystemLib::throwInvalidArgumentExceptionObject(
      "Parameter must be a valid callback");
  }
  auto set = req::make<TSet>();
  if (!m_size) return Object{std::move(set)};
  assert(posLimit() != 0);
  assert(hashSize() > 0);
  assert(set->arrayData() == staticEmptyMixedArray());
  auto oldCap = set->cap();
  set->reserve(posLimit()); // presume minimum collisions ...
  assert(set->canMutateBuffer());
  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);
    TypedValue tvCbRet;
    int32_t pVer = m_version;
    if (useKey) {
      argv[0] = e->data;
    }
    argv[argc-1] = e->data;
    g_context->invokeFuncFew(&tvCbRet, ctx, argc, argv);
    // Now that tvCbRet is live, make sure to decref even if we throw.
    SCOPE_EXIT { tvRefcountedDecRef(&tvCbRet); };
    if (UNLIKELY(m_version != pVer)) throw_collection_modified();
    set->addRaw(&tvCbRet);
  }
  // ... and shrink back if that was incorrect
  set->shrinkIfCapacityTooHigh(oldCap);
  return Object{std::move(set)};
}