Ejemplo n.º 1
0
/**
 * postSort() runs after the sort has been performed. For HphpArray, postSort()
 * handles rebuilding the hash. Also, if resetKeys is true, postSort() will
 * renumber the keys 0 thru n-1.
 */
void HphpArray::postSort(bool resetKeys) {
    assert(m_size > 0);
    auto const ht = hashTab();
    initHash(ht, hashSize());
    m_hLoad = 0;
    if (resetKeys) {
        for (uint32_t pos = 0; pos < m_used; ++pos) {
            auto& e = data()[pos];
            if (e.hasStrKey()) decRefStr(e.key);
            e.setIntKey(pos);
            ht[pos] = pos;
        }
        m_nextKI = m_size;
    } else {
        auto mask = m_tableMask;
        auto data = this->data();
        for (uint32_t pos = 0; pos < m_used; ++pos) {
            auto& e = data[pos];
            auto ei = findForNewInsert(ht, mask,
                                       e.hasIntKey() ? e.ikey : e.hash());
            *ei = pos;
        }
    }
    m_hLoad = m_size;
}
Ejemplo n.º 2
0
void HashCollection::shrink(uint32_t oldCap /* = 0 */) {
  assert(isCapacityTooHigh() && (oldCap == 0 || oldCap < cap()));
  assert(m_size <= posLimit() && posLimit() <= cap());
  dropImmCopy();
  uint32_t newCap;
  if (oldCap != 0) {
    // If an old capacity was specified, use that
    newCap = oldCap;
    // .. unless the old capacity is too small, in which case we use the
    // smallest capacity that is large enough to hold the current number
    // of elements.
    for (; newCap < m_size; newCap <<= 1) {}
    assert(newCap == computeMaxElms(folly::nextPowTwo<uint64_t>(newCap) - 1));
  } else {
    if (m_size == 0 && nextKI() == 0) {
      decRefArr(m_arr);
      m_arr = staticEmptyDictArrayAsMixed();
      return;
    }
    // If no old capacity was provided, we compute the largest capacity
    // where m_size/cap() is less than or equal to 0.5 for good hysteresis
    size_t doubleSz = size_t(m_size) * 2;
    uint32_t capThreshold = (doubleSz < size_t(MaxSize)) ? doubleSz : MaxSize;
    for (newCap = SmallSize * 2; newCap < capThreshold; newCap <<= 1) {}
  }
  assert(SmallSize <= newCap && newCap <= MaxSize);
  assert(m_size <= newCap);
  auto* oldAd = arrayData();
  if (!oldAd->cowCheck()) {
    // If the buffer's refcount is 1, we can teleport the elements
    // to a new buffer
    auto oldBuf = data();
    auto oldUsed = posLimit();
    auto oldNextKI = nextKI();
    auto arr = MixedArray::asMixed(MixedArray::MakeReserveDict(newCap));
    auto data = mixedData(arr);
    m_arr = arr;
    auto table = (int32_t*)(data + size_t(newCap));
    auto table_mask = tableMask();
    arr->m_size = m_size;
    setPosLimit(m_size);
    setNextKI(oldNextKI);
    for (uint32_t frPos = 0, toPos = 0; toPos < m_size; ++toPos, ++frPos) {
      frPos = skipTombstonesNoBoundsCheck(frPos, oldUsed, oldBuf);
      copyElm(oldBuf[frPos], data[toPos]);
      *findForNewInsert(table, table_mask, data[toPos].probe()) = toPos;
    }
    oldAd->setZombie();
    decRefArr(oldAd);
  } else {
    // For cases where the buffer's refcount is greater than 1, call
    // resizeHelper()
    resizeHelper(newCap);
  }
  assert(canMutateBuffer());
  assert(m_immCopy.isNull());
  assert(!isCapacityTooHigh() || newCap == oldCap);
}
Ejemplo n.º 3
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)};
}
Ejemplo n.º 4
0
/**
 * postSort() runs after the sort has been performed. For MixedArray, postSort()
 * handles rebuilding the hash. Also, if resetKeys is true, postSort() will
 * renumber the keys 0 thru n-1.
 */
void MixedArray::postSort(bool resetKeys) {   // nothrow guarantee
  assert(m_size > 0);
  auto const ht = hashTab();
  initHash(ht, m_scale);
  if (resetKeys) {
    for (uint32_t pos = 0; pos < m_used; ++pos) {
      auto& e = data()[pos];
      if (e.hasStrKey()) decRefStr(e.skey);
      e.setIntKey(pos);
      ht[pos] = pos;
    }
    m_nextKI = m_size;
  } else {
    auto mask = this->mask();
    auto data = this->data();
    for (uint32_t pos = 0; pos < m_used; ++pos) {
      auto& e = data[pos];
      *findForNewInsert(ht, mask, e.probe()) = pos;
    }
  }
}
Ejemplo n.º 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)};
}
Ejemplo n.º 6
0
/**
 * postSort() runs after the sort has been performed. For HphpArray, postSort()
 * handles rebuilding the hash. Also, if resetKeys is true, postSort() will
 * renumber the keys 0 thru n-1.
 */
void HphpArray::postSort(bool resetKeys) {
  assert(m_size > 0);
  size_t tableSize = computeTableSize(m_tableMask);
  initHash(m_hash, tableSize);
  m_hLoad = 0;
  if (resetKeys) {
    for (uint32_t pos = 0; pos < m_used; ++pos) {
      Elm* e = &m_data[pos];
      if (e->hasStrKey()) decRefStr(e->key);
      e->setIntKey(pos);
      m_hash[pos] = pos;
    }
    m_nextKI = m_size;
  } else {
    for (uint32_t pos = 0; pos < m_used; ++pos) {
      Elm* e = &m_data[pos];
      ElmInd* ei = findForNewInsert(e->hasIntKey() ? e->ikey : e->hash());
      *ei = pos;
    }
  }
  m_hLoad = m_size;
}
Ejemplo n.º 7
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)};
}
Ejemplo n.º 8
0
/**
 * postSort() runs after the sort has been performed. For HphpArray, postSort()
 * handles rebuilding the hash. Also, if resetKeys is true, postSort() will
 * renumber the keys 0 thru n-1.
 */
void HphpArray::postSort(bool resetKeys) {
  ASSERT(m_size > 0);
  size_t tableSize = computeTableSize(m_tableMask);
  initHash(m_hash, tableSize);
  m_hLoad = 0;
  if (resetKeys) {
    for (ElmInd pos = 0; pos <= m_lastE; ++pos) {
      Elm* e = &m_data[pos];
      if (e->hasStrKey() && e->key->decRefCount() == 0) {
        e->key->release();
      }
      e->setIntKey(pos);
      m_hash[pos] = pos;
    }
    m_nextKI = m_size;
  } else {
    for (ElmInd pos = 0; pos <= m_lastE; ++pos) {
      Elm* e = &m_data[pos];
      ElmInd* ei = findForNewInsert(e->hasIntKey() ? e->ikey : e->hash);
      *ei = pos;
    }
  }
  m_hLoad = m_size;
}