Esempio n. 1
0
TypedValue HHVM_FUNCTION(serialize_memoize_param, TypedValue param) {
  // Memoize throws in the emitter if any function parameters are references, so
  // we can just assert that the param is cell here
  assertx(param.m_type != KindOfRef);
  auto const type = param.m_type;

  if (isStringType(type)) {
    auto const str = param.m_data.pstr;
    if (str->empty()) {
      return make_tv<KindOfPersistentString>(s_emptyStrMemoKey.get());
    } else if ((unsigned char)str->data()[0] < '~') {
      // fb_compact_serialize always returns a string with the high-bit set in
      // the first character. Furthermore, we use ~ to begin all our special
      // constants, so anything less than ~ can't collide. There's no worry
      // about int-like strings because we use dicts (which don't perform key
      // coercion) to store the memoized values.
      str->incRefCount();
      return param;
    }
  } else if (isContainer(param) && getContainerSize(param) == 0) {
    return make_tv<KindOfPersistentString>(s_emptyArrMemoKey.get());
  } else if (type == KindOfUninit || type == KindOfNull) {
    return make_tv<KindOfPersistentString>(s_nullMemoKey.get());
  } else if (type == KindOfBoolean) {
    return make_tv<KindOfPersistentString>(
      param.m_data.num ? s_trueMemoKey.get() : s_falseMemoKey.get()
    );
  } else if (type == KindOfInt64) {
    return param;
  }

  return tvReturn(
    fb_compact_serialize(tvAsCVarRef(&param),
                         FBCompactSerializeBehavior::MemoizeParam));
}
Esempio n. 2
0
Variant HHVM_FUNCTION(serialize_memoize_param, const Variant& param) {
  // Memoize throws in the emitter if any function parameters are references, so
  // we can just assert that the param is cell here
  const auto& cell_param = *tvAssertCell(param.asTypedValue());
  auto type = param.getType();

  if (type == KindOfInt64) {
    return param;
  } else if (type == KindOfUninit || type == KindOfNull) {
    return s_empty;
  } else if (type == KindOfBoolean) {
    return param.asBooleanVal() ? s_true : s_false;
  } else if (type == KindOfString) {
    auto str = param.asCStrRef();
    if (str.empty()) {
      return s_emptyStr;
    } else if (str.charAt(0) > '9') {
      // If it doesn't start with a number, then we know it can never collide
      // with an int or any of our constants, so it's fine as is
      return param;
    }
  } else if (isContainer(cell_param) && getContainerSize(cell_param) == 0) {
    return s_emptyArr;
  }

  return fb_compact_serialize(param, FBCompactSerializeBehavior::MemoizeParam);
}
Esempio n. 3
0
Variant f_array_combine(CVarRef keys, CVarRef values) {
  const auto& cell_keys = *keys.asCell();
  const auto& cell_values = *values.asCell();
  if (UNLIKELY(!isContainer(cell_keys) || !isContainer(cell_values))) {
    raise_warning("Invalid operand type was used: array_combine expects "
                  "arrays or collections");
    return uninit_null();
  }
  if (UNLIKELY(getContainerSize(cell_keys) != getContainerSize(cell_values))) {
    raise_warning("array_combine(): Both parameters should have an equal "
                  "number of elements");
    return false;
  }
  Array ret = ArrayData::Create();
  for (ArrayIter iter1(cell_keys), iter2(cell_values);
       iter1; ++iter1, ++iter2) {
    ret.lvalAt(iter1.secondRefPlus()).setWithRef(iter2.secondRefPlus());
  }
  return ret;
}
Esempio n. 4
0
Variant f_array_values(CVarRef input) {
  const auto& cell_input = *input.asCell();
  if (!isContainer(cell_input)) {
    raise_warning("array_values() expects parameter 1 to be an array "
                  "or collection");
    return uninit_null();
  }
  PackedArrayInit ai(getContainerSize(cell_input));
  for (ArrayIter iter(cell_input); iter; ++iter) {
    ai.appendWithRef(iter.secondRefPlus());
  }
  return ai.toArray();
}
Esempio n. 5
0
static Variant
arrayKeysSetHelper(const Cell& cell_input, CVarRef search_value, bool strict) {
  ArrayIter iter(cell_input);
  if (LIKELY(!search_value.isInitialized())) {
    PackedArrayInit ai(getContainerSize(cell_input));
    for (; iter; ++iter) {
      ai.append(iter.second());
    }
    return ai.toArray();
  }

  Array ai = HphpArray::MakeReserve(0);
  for (; iter; ++iter) {
    if ((strict && HPHP::same(iter.secondRefPlus(), search_value)) ||
        (!strict && HPHP::equal(iter.secondRefPlus(), search_value))) {
      ai.append(iter.second());
    }
  }
  return ai;
}
Esempio n. 6
0
String StringUtil::Implode(const Variant& items, const String& delim) {
  if (!isContainer(items)) {
    throw_param_is_not_container();
  }
  int size = getContainerSize(items);
  if (size == 0) return "";

  String* sitems = (String*)smart_malloc(size * sizeof(String));
  int len = 0;
  int lenDelim = delim.size();
  int i = 0;
  for (ArrayIter iter(items); iter; ++iter) {
    new (&sitems[i]) String(iter.second().toString());
    len += sitems[i].size() + lenDelim;
    i++;
  }
  len -= lenDelim; // always one delimiter less than count of items
  assert(i == size);

  String s = String(len, ReserveString);
  char *buffer = s.bufferSlice().ptr;
  const char *sdelim = delim.data();
  char *p = buffer;
  for (int i = 0; i < size; i++) {
    String &item = sitems[i];
    if (i && lenDelim) {
      memcpy(p, sdelim, lenDelim);
      p += lenDelim;
    }
    int lenItem = item.size();
    if (lenItem) {
      memcpy(p, item.data(), lenItem);
      p += lenItem;
    }
    sitems[i].~String();
  }
  smart_free(sitems);
  assert(p - buffer == len);
  s.setSize(len);
  return s;
}
Esempio n. 7
0
String StringUtil::Implode(const Variant& items, const String& delim,
                           const bool checkIsContainer /* = true */) {
  if (checkIsContainer && !isContainer(items)) {
    throw_param_is_not_container();
  }
  int size = getContainerSize(items);
  if (size == 0) return empty_string();

  req::vector<String> sitems;
  sitems.reserve(size);
  size_t len = 0;
  size_t lenDelim = delim.size();
  for (ArrayIter iter(items); iter; ++iter) {
    sitems.emplace_back(iter.second().toString());
    len += sitems.back().size() + lenDelim;
  }
  len -= lenDelim; // always one delimiter less than count of items
  assert(sitems.size() == size);

  String s = String(len, ReserveString);
  char *buffer = s.mutableData();
  const char *sdelim = delim.data();
  char *p = buffer;
  String &init_str = sitems[0];
  int init_len = init_str.size();
  memcpy(p, init_str.data(), init_len);
  p += init_len;
  for (int i = 1; i < size; i++) {
    String &item = sitems[i];
    memcpy(p, sdelim, lenDelim);
    p += lenDelim;
    int lenItem = item.size();
    memcpy(p, item.data(), lenItem);
    p += lenItem;
  }
  assert(p - buffer == len);
  s.setSize(len);
  return s;
}
Esempio n. 8
0
Variant f_array_keys(CVarRef input, CVarRef search_value /* = null_variant */,
                     bool strict /* = false */) {
  const auto& cell_input = *input.asCell();
  if (UNLIKELY(!isContainer(cell_input))) {
    goto warn;
  }
  {
    // We treat Sets differently. For Sets, we pretend the values are
    // also the keys (similar to how Set::toArray() behaves).
    bool isSetType =
      cell_input.m_type == KindOfObject &&
      cell_input.m_data.pobj->getCollectionType() == Collection::SetType;
    if (UNLIKELY(isSetType)) {
      return arrayKeysSetHelper(cell_input, search_value, strict);
    }
    ArrayIter iter(cell_input);
    if (LIKELY(!search_value.isInitialized())) {
      PackedArrayInit ai(getContainerSize(cell_input));
      for (; iter; ++iter) {
        ai.append(iter.first());
      }
      return ai.toArray();
    }

    Array ai = Array::attach(HphpArray::MakeReserve(0));
    for (; iter; ++iter) {
      if ((strict && HPHP::same(iter.secondRefPlus(), search_value)) ||
          (!strict && HPHP::equal(iter.secondRefPlus(), search_value))) {
        ai.append(iter.first());
      }
    }
    return ai;
  }
warn:
  raise_warning("array_keys() expects parameter 1 to be an array "
                "or collection");
  return uninit_null();
}