Example #1
0
MixedArray* StructArray::ToMixed(StructArray* old) {
  auto const oldSize = old->size();
  auto const ad      = ToMixedHeader(oldSize + 1);
  auto const srcData = old->data();
  auto shape         = old->shape();

  memset(ad->hashTab(), static_cast<uint8_t>(MixedArray::Empty),
    sizeof(int32_t) * ad->hashSize());

  for (auto i = 0; i < oldSize; ++i) {
    auto key = const_cast<StringData*>(shape->keyForOffset(i));
    auto& e = ad->addKeyAndGetElem(key);
    tvCopy(srcData[i], e.data);
  }

  old->m_size = 0;
  ad->m_pos = old->m_pos;
  if (debug) {
    // For debug builds, set m_pos to 0 as well to make the
    // asserts in checkInvariants() happy.
    old->m_pos = 0;
  }
  assert(ad->checkInvariants());
  assert(!ad->isFull());
  assert(ad->hasExactlyOneRef());
  return ad;
}
Example #2
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;
}
Example #3
0
/*
 * Creating a single-element mixed array with a integer key.  The
 * value is already incref'd.
 */
std::pair<ArrayData*,TypedValue*>
EmptyArray::MakeMixed(int64_t key, TypedValue val) {
  auto const ad = smartAllocArray(MixedArray::SmallScale);
  InitMixed(ad, 0/*count*/, 1/*size*/, (key >= 0) ? key + 1 : 0);
  auto const data = ad->data();
  auto const hash = reinterpret_cast<int32_t*>(data + MixedArray::SmallSize);
  assert(ad->hashSize() == MixedArray::SmallHashSize);
  auto const emptyVal = int64_t{MixedArray::Empty};
  reinterpret_cast<int64_t*>(hash)[0] = emptyVal;
  reinterpret_cast<int64_t*>(hash)[1] = emptyVal;

  auto const mask = MixedArray::SmallMask;
  hash[key & mask] = 0;
  data[0].setIntKey(key);

  auto& lval  = data[0].data;
  lval.m_data = val.m_data;
  lval.m_type = val.m_type;

  assert(ad->kind() == ArrayData::kMixedKind);
  assert(ad->m_size == 1);
  assert(ad->m_pos == 0);
  assert(ad->getCount() == 0);
  assert(ad->m_scale == MixedArray::SmallScale);
  assert(ad->m_used == 1);
  assert(ad->checkInvariants());
  return { ad, &lval };
}
Example #4
0
STORAGE_SET *aliasAuxDataStore(ALIAS_AUX_DATA *data) {
  // if we have no hashtable, return an empty set
  if(data->aliases == NULL || hashSize(data->aliases) == 0)
    return new_storage_set();

  STORAGE_SET *set       = new_storage_set();
  STORAGE_SET_LIST *list = new_storage_list();
  HASH_ITERATOR  *hash_i = newHashIterator(data->aliases);
  const char       *name = NULL;
  const char        *cmd = NULL;

  store_list(set, "aliases", list);
  ITERATE_HASH(name, cmd, hash_i) {
    STORAGE_SET *alias_set = new_storage_set();
    store_string(alias_set, "key", name);
    store_string(alias_set, "val", hashIteratorCurrentVal(hash_i));
    storage_list_put(list, alias_set);
  }
Example #5
0
MixedArray* StructArray::ToMixedCopy(const StructArray* old) {
  auto const oldSize = old->size();
  auto const ad      = ToMixedHeader(oldSize + 1);
  auto const srcData = old->data();
  auto shape         = old->shape();

  memset(ad->hashTab(), static_cast<uint8_t>(MixedArray::Empty),
    sizeof(int32_t) * ad->hashSize());

  for (auto i = 0; i < oldSize; ++i) {
    auto key = const_cast<StringData*>(shape->keyForOffset(i));
    auto& e = ad->addKeyAndGetElem(key);
    tvDupFlattenVars(&srcData[i], &e.data, old);
  }

  ad->m_pos = old->m_pos;
  assert(ad->checkInvariants());
  assert(!ad->isFull());
  assert(ad->hasExactlyOneRef());
  return ad;
}
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)};
}
Example #7
0
        /** Set the extra info (if any) */
        virtual void    finalizeWithExtraInfo(uint8 * outBuffer, const uint8 * extra, const uint32 extraLen)
        {
            uint8 hashArray[OutputSize + 64] = {0};
            uint32 tmpSize = InputSize + 4 + extraLen;
            uint8 hashTmpArray[InputSize + 4 + BaseHasher::DigestSize] = {0};
            uint8 * hashTmp = hashTmpArray;
            if ((extraLen && extra) || hasher.hashSize() > sizeof(hashTmpArray))
            {
                hashTmp = new uint8[max(tmpSize, hasher.hashSize())];
                if (!hashTmp)
                {
                    if (outBuffer) memset(outBuffer, 0, hashSize());
                    return; // Far more error to expect when stack or heap is exhausted
                }
                memset(hashTmp, 0, tmpSize);
            }
            uint32 d = (OutputSize + hasher.hashSize() - 1) / hasher.hashSize();
            for (uint32 i = 0; i < d; i++)
            {
                // Computing the inner hash
                memcpy(hashTmp, hashInput, InputSize);
                uint32 swappedI = Swap32(i);
                memcpy(&hashTmp[InputSize], &swappedI, sizeof(swappedI)); // Big endian
                if (extra && extraLen)
                    memcpy(&hashTmp[InputSize + 4], extra, extraLen);
                // Hash such string now
                hasher.Start();
                hasher.Hash(hashTmp, tmpSize);
                // Overwrite the data with the hash
                hasher.Finalize(hashTmp);

                memcpy(&hashArray[i * hasher.hashSize()], hashTmp, hasher.hashSize());
                memset(hashTmp, 0, tmpSize);
            }
            if ((extraLen && extra) || hasher.hashSize() > sizeof(hashTmpArray)) delete[] hashTmp;
            if (outBuffer) memcpy(outBuffer, hashArray, OutputSize);
        }
Example #8
0
HashCollection::Elm& HashCollection::allocElmFront(MixedArray::Inserter ei) {
  assert(MixedArray::isValidIns(ei) && !MixedArray::isValidPos(*ei));
  assert(m_size <= posLimit() && posLimit() < cap());
  // Move the existing elements to make element slot 0 available.
  memmove(data() + 1, data(), posLimit() * sizeof(Elm));
  incPosLimit();
  // Update the hashtable to reflect the fact that everything was
  // moved over one position
  auto* hash = hashTab();
  auto* hashEnd = hash + hashSize();
  for (; hash != hashEnd; ++hash) {
    if (validPos(*hash)) {
      ++(*hash);
    }
  }
  // Set the hash entry we found to point to element slot 0.
  (*ei) = 0;
  // Adjust m_pos so that is points at this new first element.
  arrayData()->m_pos = 0;
  // Adjust size to reflect that we're adding a new element.
  incSize();
  // Store the value into element slot 0.
  return data()[0];
}
Example #9
0
int raceCount() {
  return hashSize(race_table);
}
Example #10
0
ALWAYS_INLINE
typename std::enable_if<
  std::is_base_of<BaseMap, TMap>::value, Object>::type
BaseMap::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 map = req::make<TMap>();
  if (!m_size) return Object{std::move(map)};
  assert(posLimit() != 0);
  assert(hashSize() > 0);
  assert(map->arrayData() == staticEmptyMixedArray());
  map->m_arr = MixedArray::asMixed(MixedArray::MakeReserveMixed(cap()));
  map->setIntLikeStrKeys(intLikeStrKeys());
  wordcpy(map->hashTab(), hashTab(), hashSize());
  {
    uint32_t used = posLimit();
    int32_t version = m_version;
    uint32_t i = 0;
    // When the loop below finishes or when an exception is thrown,
    // make sure that posLimit() get set to the correct value and
    // that m_pos gets set to point to the first element.
    SCOPE_EXIT {
      map->setPosLimit(i);
      map->arrayData()->m_pos = map->nthElmPos(0);
    };
    constexpr int64_t argc = useKey ? 2 : 1;
    TypedValue argv[argc];
    for (; i < used; ++i) {
      const Elm& e = data()[i];
      Elm& ne = map->data()[i];
      if (isTombstone(i)) {
        ne.data.m_type = e.data.m_type;
        continue;
      }
      TypedValue* tv = &ne.data;
      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;
      g_context->invokeFuncFew(tv, ctx, argc, argv);
      if (UNLIKELY(version != m_version)) {
        tvRefcountedDecRef(tv);
        throw_collection_modified();
      }
      if (e.hasStrKey()) {
        e.skey->incRefCount();
      }
      ne.ikey = e.ikey;
      ne.data.hash() = e.data.hash();
      map->incSize();
      // Needed so that the new elements are accounted for when GC scanning.
      map->incPosLimit();
    }
  }
  return Object{std::move(map)};
}