Example #1
0
Variant ArrayUtil::RandomValues(CArrRef input, int num_req /* = 1 */) {
  int count = input.size();
  if (num_req <= 0 || num_req > count) {
    return null;
  }

  std::vector<ssize_t> indices;
  indices.reserve(count);
  for (ssize_t pos = input->iter_begin(); pos != ArrayData::invalid_index;
       pos = input->iter_advance(pos)) {
    indices.push_back(pos);
  }
  random_shuffle(indices.begin(), indices.end());

  if (num_req == 1) {
    return input->getValue(indices[0]);
  }

  Array ret = Array::Create();
  for (int i = 0; i < num_req; i++) {
    ssize_t pos = indices[i];
    ret.append(input->getValue(pos));
  }
  return ret;
}
Example #2
0
void Array::MultiSort(std::vector<SortData> &data, bool renumber) {
  if (data.empty()) {
    return;
  }

  int count = -1;
  for (unsigned int k = 0; k < data.size(); k++) {
    SortData &opaque = data[k];

    ASSERT(opaque.array);
    ASSERT(opaque.cmp_func);
    int size = opaque.array->size();
    if (count == -1) {
      count = size;
    } else if (count != size) {
      throw InvalidArgumentException("arrays", "(inconsistent sizes)");
    }

    opaque.positions.reserve(size);
    CArrRef arr = *opaque.array;
    if (!arr.empty()) {
      for (ssize_t pos = arr->iter_begin(); pos != ArrayData::invalid_index;
           pos = arr->iter_advance(pos)) {
        opaque.positions.push_back(pos);
      }
    }
  }
  if (count == 0) {
    return;
  }

  int *indices = (int *)malloc(sizeof(int) * count);
  for (int i = 0; i < count; i++) {
    indices[i] = i;
  }

  zend_qsort(indices, count, sizeof(int), multi_compare_func, (void *)&data);

  for (unsigned int k = 0; k < data.size(); k++) {
    SortData &opaque = data[k];
    CArrRef arr = *opaque.array;

    Array sorted;
    for (int i = 0; i < count; i++) {
      ssize_t pos = opaque.positions[indices[i]];
      Variant k = arr->getKey(pos);
      if (renumber && k.isInteger()) {
        sorted.append(arr->getValue(pos));
      } else {
        sorted.set(k, arr->getValue(pos));
      }
    }
    *opaque.original = sorted;
  }

  free(indices);
}
Example #3
0
Variant f_max(int _argc, CVarRef value, CArrRef _argv /* = null_array */) {
  Variant ret;
  if (_argv.empty() && value.is(KindOfArray)) {
    Array v = value.toArray();
    if (!v.empty()) {
      ssize_t pos = v->iter_begin();
      if (pos != ArrayData::invalid_index) {
        ret = v->getValue(pos);
        while (true) {
          pos = v->iter_advance(pos);
          if (pos == ArrayData::invalid_index) break;
          Variant tmp = v->getValue(pos);
          if (more(tmp, ret)) {
            ret = tmp;
          }
        }
      }
    }
  } else {
    ret = value;
    if (!_argv.empty()) {
      for (ssize_t pos = _argv->iter_begin(); pos != ArrayData::invalid_index;
           pos = _argv->iter_advance(pos)) {
        Variant tmp = _argv->getValue(pos);
        if (more(tmp, ret)) {
          ret = tmp;
        }
      }
    }
  }
  return ret;
}
Example #4
0
Array ArrayUtil::Reverse(CArrRef input, bool preserve_keys /* = false */) {
  if (input.empty()) {
    return input;
  }

  Array ret = Array::Create();
  for (ssize_t pos = input->iter_end(); pos != ArrayData::invalid_index;
       pos = input->iter_rewind(pos)) {
    Variant key = input->getKey(pos);
    if (preserve_keys || key.isString()) {
      ret.set(key, input->getValue(pos));
    } else {
      ret.append(input->getValue(pos));
    }
  }
  return ret;
}
Example #5
0
Variant ArrayUtil::RegularSortUnique(CArrRef input) {
  /* The output of this function in PHP strictly depends on the implementation
   * of the sort function and on whether values that compare as equal end
   * up in contiguous positions in the sorted array (which is not really
   * well-defined in case of mixed strings/numbers). To get the same result
   * as in PHP we thus need to replicate the PHP algorithm more closely than
   * in the other versions of array_unique.
   */
  if (input.size() <= 1) return input;

  Array::SortData opaque;
  std::vector<int> indices;
  Array::SortImpl(indices, input, opaque, Array::SortRegularAscending, false);

  std::vector<bool> duplicates(indices.size(), false);
  int lastIdx = indices[0];
  Variant last = input->getValue(opaque.positions[lastIdx]);
  for (unsigned int i = 1; i < indices.size(); ++i) {
    int currentIdx = indices[i];
    Variant current = input->getValue(opaque.positions[currentIdx]);
    if (equal(current, last)) {
      if (currentIdx > lastIdx) {
        duplicates[currentIdx] = true;
        continue;
      }
      duplicates[lastIdx] = true;
    }
    lastIdx = currentIdx;
    last = current;
  }

  Array ret = Array::Create();
  int i = 0;
  for (ArrayIter iter(input); iter; ++iter, ++i) {
    if (!duplicates[i]) ret.set(iter.first(), iter.secondRef());
  }
  return ret;
}
Example #6
0
Array ArrayUtil::Shuffle(CArrRef input) {
  int count = input.size();
  if (count == 0) {
    return input;
  }

  std::vector<ssize_t> indices;
  indices.reserve(count);
  for (ssize_t pos = input->iter_begin(); pos != ArrayData::invalid_index;
       pos = input->iter_advance(pos)) {
    indices.push_back(pos);
  }
  random_shuffle(indices.begin(), indices.end());

  Array ret = Array::Create();
  for (int i = 0; i < count; i++) {
    ssize_t pos = indices[i];
    ret.append(input->getValue(pos));
  }
  return ret;
}
Example #7
0
Array Array::diffImpl(CArrRef array, bool by_key, bool by_value, bool match,
                      PFUNC_CMP key_cmp_function,
                      const void *key_data,
                      PFUNC_CMP value_cmp_function,
                      const void *value_data) const {
  ASSERT(by_key || by_value);
  ASSERT(by_key || key_cmp_function == NULL);
  ASSERT(by_value || value_cmp_function == NULL);

  if (!value_cmp_function) {
    value_cmp_function = SortStringAscending;
  }

  Array ret = Array::Create();
  if (by_key && !key_cmp_function) {
    // Fast case
    for (ArrayIter iter(*this); iter; ++iter) {
      Variant key = iter.first();
      bool found = false;
      if (array.exists(key)) {
        if (by_value) {
          found = value_cmp_function(iter.second(),
                                     array.rvalAt(key), value_data) == 0;
        } else {
          found = true;
        }
      }
      if (found == match) {
        ret.set(key, iter.second());
      }
    }
    return ret;
  }

  if (!key_cmp_function) {
    key_cmp_function = SortRegularAscending;
  }

  vector<int> perm1;
  SortData opaque1;
  int bottom = 0;
  int top = array.size();
  PFUNC_CMP cmp;
  const void *cmp_data;
  if (by_key) {
    cmp = key_cmp_function;
    cmp_data = key_data;
  } else {
    cmp = value_cmp_function;
    cmp_data = value_data;
  }
  _sort(perm1, array, opaque1, cmp, by_key, cmp_data);

  for (ArrayIter iter(*this); iter; ++iter) {
    Variant target;
    if (by_key) {
      target = iter.first();
    } else {
      target = iter.second();
    }

    int mid = -1;
    int min = bottom;
    int max = top;
    while (min < max) {
      mid = (max + min) / 2;
      ssize_t pos = opaque1.positions[perm1[mid]];
      int cmp_res =  cmp(target,
                         by_key ? array->getKey(pos) : array->getValue(pos),
                         cmp_data);
      if (cmp_res > 0) { // outer is bigger
        min = mid + 1;
      } else if (cmp_res == 0) {
        break;
      } else {
        max = mid;
      }
    }
    bool found = false;
    if (min < max) { // found
      // if checking both, check value
      if (by_key && by_value) {
        Variant val = iter.second();
        // Have to look up and down for matches
        for (int i = mid; i < max; i++) {
          ssize_t pos = opaque1.positions[perm1[i]];
          if (key_cmp_function(target, array->getKey(pos), key_data) != 0) {
            break;
          }
          if (value_cmp_function(val, array->getValue(pos), value_data) == 0) {
            found = true;
            break;
          }
        }
        if (!found) {
          for (int i = mid-1; i >= min; i--) {
            ssize_t pos = opaque1.positions[perm1[i]];
            if (key_cmp_function(target, array->getKey(pos), key_data) != 0) {
              break;
            }
            if (value_cmp_function(val, array->getValue(pos),
                                   value_data) == 0) {
              found = true;
              break;
            }
          }
        }
      } else {
        // found at mid
        found = true;
      }
    }

    if (found == match) {
      ret.set(iter.first(), iter.second());
    }
  }
  return ret;
}