bool Array::MultiSort(std::vector<SortData> &data, bool renumber) { ASSERT(!data.empty()); 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_invalid_argument("arrays: (inconsistent sizes)"); return false; } 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 true; } 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->getValueRef(pos)); } else { sorted.set(k, arr->getValueRef(pos)); } } *opaque.original = sorted; } free(indices); return true; }
Variant ArrayUtil::RandomValues(CArrRef input, int num_req /* = 1 */) { int count = input.size(); if (num_req <= 0 || num_req > count) { return uninit_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); } php_array_data_shuffle(indices); 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->getValueRef(pos)); } return ret; }
Variant 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.setWithRef(key, input->getValueRef(pos), true); } else { ret.appendWithRef(input->getValueRef(pos)); } } return ret; }
int64_t f_array_unshift(int _argc, VRefParam array, CVarRef var, CArrRef _argv /* = null_array */) { if (array.toArray()->isVectorData()) { if (!_argv.empty()) { for (ssize_t pos = _argv->iter_end(); pos != ArrayData::invalid_index; pos = _argv->iter_rewind(pos)) { array.prepend(_argv->getValueRef(pos)); } } array.prepend(var); } else { { Array newArray; newArray.append(var); if (!_argv.empty()) { for (ssize_t pos = _argv->iter_begin(); pos != ArrayData::invalid_index; pos = _argv->iter_advance(pos)) { newArray.append(_argv->getValueRef(pos)); } } for (ArrayIter iter(array); iter; ++iter) { Variant key(iter.first()); CVarRef value(iter.secondRef()); if (key.isInteger()) { newArray.appendWithRef(value); } else { newArray.lvalAt(key, AccessFlags::Key).setWithRef(value); } } array = newArray; } // Reset the array's internal pointer if (array.is(KindOfArray)) { array.array_iter_reset(); } } return array.toArray().size(); }
Variant 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); } php_array_data_shuffle(indices); Array ret = Array::Create(); for (int i = 0; i < count; i++) { ssize_t pos = indices[i]; ret.appendWithRef(input->getValueRef(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); PFUNC_CMP value_cmp_as_string_function = value_cmp_function; if (!value_cmp_function) { value_cmp_function = SortStringAscending; value_cmp_as_string_function = CompareAsStrings; } Array ret = Array::Create(); if (by_key && !key_cmp_function) { // Fast case for (ArrayIter iter(*this); iter; ++iter) { Variant key(iter.first()); CVarRef value(iter.secondRef()); bool found = false; if (array->exists(key)) { if (by_value) { found = value_cmp_as_string_function( value, array.rvalAt(key, AccessFlags::Key), value_data) == 0; } else { found = true; } } if (found == match) { ret.addLval(key, true).setWithRef(value); } } 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; } SortImpl(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->getValueRef(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) { CVarRef val(iter.secondRef()); // 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_as_string_function(val, array->getValueRef(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_as_string_function(val, array->getValueRef(pos), value_data) == 0) { found = true; break; } } } } else { // found at mid found = true; } } if (found == match) { ret.addLval(iter.first(), true).setWithRef(iter.secondRef()); } } return ret; }