ZEND_API void zend_llist_sort(zend_llist *l, llist_compare_func_t comp_func TSRMLS_DC) { size_t i; zend_llist_element **elements; zend_llist_element *element, **ptr; if (l->count <= 0) { return; } elements = (zend_llist_element **) emalloc(l->count * sizeof(zend_llist_element *)); ptr = &elements[0]; for (element=l->head; element; element=element->next) { *ptr++ = element; } zend_qsort(elements, l->count, sizeof(zend_llist_element *), (compare_func_t) comp_func TSRMLS_CC); l->head = elements[0]; elements[0]->prev = NULL; for (i = 1; i < l->count; i++) { elements[i]->prev = elements[i-1]; elements[i-1]->next = elements[i]; } elements[i-1]->next = NULL; l->tail = elements[i-1]; efree(elements); }
void Array::SortImpl(vector<int> &indices, CArrRef source, Array::SortData &opaque, Array::PFUNC_CMP cmp_func, bool by_key, const void *data /* = NULL */) { ASSERT(cmp_func); int count = source.size(); if (count == 0) { return; } indices.reserve(count); for (int i = 0; i < count; i++) { indices.push_back(i); } opaque.array = &source; opaque.by_key = by_key; opaque.cmp_func = cmp_func; opaque.data = data; opaque.positions.reserve(count); for (ssize_t pos = source->iter_begin(); pos != ArrayData::invalid_index; pos = source->iter_advance(pos)) { opaque.positions.push_back(pos); } zend_qsort(&indices[0], count, sizeof(int), array_compare_func, &opaque); }
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; }
bool c_Collator::t_sortwithsortkeys(VRefParam arr) { INSTANCE_METHOD_INJECTION_BUILTIN(Collator, Collator::sortwithsortkeys); char* sortKeyBuf = NULL; /* buffer to store sort keys */ int32_t sortKeyBufSize = DEF_SORT_KEYS_BUF_SIZE; /* buffer size */ ptrdiff_t sortKeyBufOffset = 0; /* pos in buffer to store sort key */ int32_t sortKeyLen = 0; /* the length of currently processing key */ int32_t bufLeft = 0; int32_t bufIncrement = 0; /* buffer to store 'indexes' which will be passed to 'qsort' */ collator_sort_key_index_t* sortKeyIndxBuf = NULL; int32_t sortKeyIndxBufSize = DEF_SORT_KEYS_INDX_BUF_SIZE; int32_t sortKeyIndxSize = sizeof( collator_sort_key_index_t ); int32_t sortKeyCount = 0; int32_t j = 0; /* tmp buffer to hold current processing string in utf-16 */ UChar* utf16_buf = NULL; /* the length of utf16_buf */ int utf16_buf_size = DEF_UTF16_BUF_SIZE; /* length of converted string */ int utf16_len = 0; m_errcode.clear(); s_intl_error->m_error.clear(); /* * Sort specified array. */ if (!arr.isArray()) { return true; } Array hash = arr.toArray(); if (hash.size() == 0) { return true; } /* Create bufers */ sortKeyBuf = (char*)calloc(sortKeyBufSize, sizeof(char)); sortKeyIndxBuf = (collator_sort_key_index_t*)malloc(sortKeyIndxBufSize); utf16_buf = (UChar*)malloc(utf16_buf_size); /* Iterate through input hash and create a sort key for each value. */ for (ssize_t pos = hash->iter_begin(); pos != ArrayData::invalid_index; pos = hash->iter_advance(pos)) { /* Convert current hash item from UTF-8 to UTF-16LE and save the result * to utf16_buf. */ utf16_len = utf16_buf_size; /* Process string values only. */ Variant val(hash->getValue(pos)); if (val.isString()) { String str = val.toString(); intl_convert_utf8_to_utf16(&utf16_buf, &utf16_len, str.data(), str.size(), &(m_errcode.code)); if (U_FAILURE(m_errcode.code)) { m_errcode.custom_error_message = "Sort with sort keys failed"; if (utf16_buf) { free(utf16_buf); } free(sortKeyIndxBuf); free(sortKeyBuf); return false; } } else { /* Set empty string */ utf16_len = 0; utf16_buf[utf16_len] = 0; } if ((utf16_len + 1) > utf16_buf_size) { utf16_buf_size = utf16_len + 1; } /* Get sort key, reallocating the buffer if needed. */ bufLeft = sortKeyBufSize - sortKeyBufOffset; sortKeyLen = ucol_getSortKey(m_ucoll, utf16_buf, utf16_len, (uint8_t*)sortKeyBuf + sortKeyBufOffset, bufLeft); /* check for sortKeyBuf overflow, increasing its size of the buffer if needed */ if (sortKeyLen > bufLeft) { bufIncrement = ( sortKeyLen > DEF_SORT_KEYS_BUF_INCREMENT ) ? sortKeyLen : DEF_SORT_KEYS_BUF_INCREMENT; sortKeyBufSize += bufIncrement; bufLeft += bufIncrement; sortKeyBuf = (char*)realloc(sortKeyBuf, sortKeyBufSize); sortKeyLen = ucol_getSortKey(m_ucoll, utf16_buf, utf16_len, (uint8_t*)sortKeyBuf + sortKeyBufOffset, bufLeft); } /* check sortKeyIndxBuf overflow, increasing its size of the buffer if needed */ if ((sortKeyCount + 1) * sortKeyIndxSize > sortKeyIndxBufSize) { bufIncrement = (sortKeyIndxSize > DEF_SORT_KEYS_INDX_BUF_INCREMENT) ? sortKeyIndxSize : DEF_SORT_KEYS_INDX_BUF_INCREMENT; sortKeyIndxBufSize += bufIncrement; sortKeyIndxBuf = (collator_sort_key_index_t*)realloc(sortKeyIndxBuf, sortKeyIndxBufSize); } sortKeyIndxBuf[sortKeyCount].key = (char*)sortKeyBufOffset; sortKeyIndxBuf[sortKeyCount].valPos = pos; sortKeyBufOffset += sortKeyLen; ++sortKeyCount; } /* update ptrs to point to valid keys. */ for( j = 0; j < sortKeyCount; j++ ) sortKeyIndxBuf[j].key = sortKeyBuf + (ptrdiff_t)sortKeyIndxBuf[j].key; /* sort it */ zend_qsort(sortKeyIndxBuf, sortKeyCount, sortKeyIndxSize, collator_cmp_sort_keys, NULL); /* for resulting hash we'll assign new hash keys rather then reordering */ Array sortedHash = Array::Create(); for (j = 0; j < sortKeyCount; j++) { sortedHash.append(hash->getValue(sortKeyIndxBuf[j].valPos)); } /* Save sorted hash into return variable. */ arr = sortedHash; if (utf16_buf) free(utf16_buf); free(sortKeyIndxBuf); free(sortKeyBuf); return true; }
static bool HHVM_METHOD(Collator, sortWithSortKeys, VRefParam arr) { FETCH_COL(data, this_, false); data->clearError(); if (!arr.isArray()) { return true; } Array hash = arr.toArray(); if (hash.size() == 0) { return true; } // Preallocate sort keys buffer size_t sortKeysOffset = 0; size_t sortKeysLength = DEF_SORT_KEYS_BUF_SIZE; char* sortKeys = (char*)smart_malloc(sortKeysLength); if (!sortKeys) { throw Exception("Out of memory"); } SCOPE_EXIT{ smart_free(sortKeys); }; // Preallocate index buffer size_t sortIndexPos = 0; size_t sortIndexLength = DEF_SORT_KEYS_INDX_BUF_SIZE; auto sortIndex = (collator_sort_key_index_t*)smart_malloc( sortIndexLength * sizeof(collator_sort_key_index_t)); if (!sortIndex) { throw Exception("Out of memory"); } SCOPE_EXIT{ smart_free(sortIndex); }; // Translate input hash to sortable index auto pos_limit = hash->iter_end(); for (ssize_t pos = hash->iter_begin(); pos != pos_limit; pos = hash->iter_advance(pos)) { Variant val(hash->getValue(pos)); // Convert to UTF16 icu::UnicodeString strval; if (val.isString()) { UErrorCode error = U_ZERO_ERROR; strval = u16(val.toString(), error); if (U_FAILURE(error)) { return false; } } // Generate sort key int sortkey_len = ucol_getSortKey(data->collator(), strval.getBuffer(), strval.length(), (uint8_t*)(sortKeys + sortKeysOffset), sortKeysLength - sortKeysOffset); // Check for key buffer overflow if (sortkey_len > (sortKeysLength - sortKeysOffset)) { int32_t inc = (sortkey_len > DEF_SORT_KEYS_BUF_INCREMENT) ? sortkey_len : DEF_SORT_KEYS_BUF_INCREMENT; sortKeysLength += inc; sortKeys = (char*)smart_realloc(sortKeys, sortKeysLength); if (!sortKeys) { throw Exception("Out of memory"); } sortkey_len = ucol_getSortKey(data->collator(), strval.getBuffer(), strval.length(), (uint8_t*)(sortKeys + sortKeysOffset), sortKeysLength - sortKeysOffset); assert(sortkey_len <= (sortKeysLength - sortKeysOffset)); } // Check for index buffer overflow if ((sortIndexPos + 1) > sortIndexLength) { sortIndexLength += DEF_SORT_KEYS_INDX_BUF_INCREMENT; sortIndex = (collator_sort_key_index_t*)smart_realloc(sortIndex, sortIndexLength * sizeof(collator_sort_key_index_t)); if (!sortIndex) { throw Exception("Out of memory"); } } // Initially store offset into buffer, update later to deal with reallocs sortIndex[sortIndexPos].key = (char*)sortKeysOffset; sortKeysOffset += sortkey_len; sortIndex[sortIndexPos].valPos = pos; ++sortIndexPos; } // Update keys to location in realloc'd buffer for (int i = 0; i < sortIndexPos; ++i) { sortIndex[i].key = sortKeys + (ptrdiff_t)sortIndex[i].key; } zend_qsort(sortIndex, sortIndexPos, sizeof(collator_sort_key_index_t), collator_cmp_sort_keys, nullptr); Array ret = Array::Create(); for (int i = 0; i < sortIndexPos; ++i) { ret.append(hash->getValue(sortIndex[i].valPos)); } arr = ret; return true; }