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; }
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); }
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; }
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; }
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; }
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; }
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; }