1251881Speter/* 2251881Speter * sorts.c: all sorts of sorts 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter 25251881Speter 26251881Speter#include <apr_pools.h> 27251881Speter#include <apr_hash.h> 28251881Speter#include <apr_tables.h> 29251881Speter#include <stdlib.h> /* for qsort() */ 30251881Speter#include <assert.h> 31251881Speter#include "svn_hash.h" 32251881Speter#include "svn_path.h" 33251881Speter#include "svn_sorts.h" 34251881Speter#include "svn_error.h" 35251881Speter 36251881Speter 37251881Speter 38251881Speter/*** svn_sort__hash() ***/ 39251881Speter 40251881Speter/* (Should this be a permanent part of APR?) 41251881Speter 42251881Speter OK, folks, here's what's going on. APR hash tables hash on 43251881Speter key/klen objects, and store associated generic values. They work 44251881Speter great, but they have no ordering. 45251881Speter 46251881Speter The point of this exercise is to somehow arrange a hash's keys into 47251881Speter an "ordered list" of some kind -- in this case, a nicely sorted 48251881Speter one. 49251881Speter 50251881Speter We're using APR arrays, therefore, because that's what they are: 51251881Speter ordered lists. However, what "keys" should we put in the array? 52251881Speter Clearly, (const char *) objects aren't general enough. Or rather, 53251881Speter they're not as general as APR's hash implementation, which stores 54251881Speter (void *)/length as keys. We don't want to lose this information. 55251881Speter 56251881Speter Therefore, it makes sense to store pointers to {void *, size_t} 57251881Speter structures in our array. No such apr object exists... BUT... if we 58251881Speter can use a new type svn_sort__item_t which contains {char *, size_t, void 59251881Speter *}. If store these objects in our array, we get the hash value 60251881Speter *for free*. When looping over the final array, we don't need to 61251881Speter call apr_hash_get(). Major bonus! 62251881Speter */ 63251881Speter 64251881Speter 65251881Speterint 66251881Spetersvn_sort_compare_items_as_paths(const svn_sort__item_t *a, 67251881Speter const svn_sort__item_t *b) 68251881Speter{ 69251881Speter const char *astr, *bstr; 70251881Speter 71251881Speter astr = a->key; 72251881Speter bstr = b->key; 73251881Speter assert(astr[a->klen] == '\0'); 74251881Speter assert(bstr[b->klen] == '\0'); 75251881Speter return svn_path_compare_paths(astr, bstr); 76251881Speter} 77251881Speter 78251881Speter 79251881Speterint 80251881Spetersvn_sort_compare_items_lexically(const svn_sort__item_t *a, 81251881Speter const svn_sort__item_t *b) 82251881Speter{ 83251881Speter int val; 84251881Speter apr_size_t len; 85251881Speter 86251881Speter /* Compare bytes of a's key and b's key up to the common length. */ 87251881Speter len = (a->klen < b->klen) ? a->klen : b->klen; 88251881Speter val = memcmp(a->key, b->key, len); 89251881Speter if (val != 0) 90251881Speter return val; 91251881Speter 92251881Speter /* They match up until one of them ends; whichever is longer is greater. */ 93251881Speter return (a->klen < b->klen) ? -1 : (a->klen > b->klen) ? 1 : 0; 94251881Speter} 95251881Speter 96251881Speter 97251881Speterint 98251881Spetersvn_sort_compare_revisions(const void *a, const void *b) 99251881Speter{ 100251881Speter svn_revnum_t a_rev = *(const svn_revnum_t *)a; 101251881Speter svn_revnum_t b_rev = *(const svn_revnum_t *)b; 102251881Speter 103251881Speter if (a_rev == b_rev) 104251881Speter return 0; 105251881Speter 106251881Speter return a_rev < b_rev ? 1 : -1; 107251881Speter} 108251881Speter 109251881Speter 110251881Speterint 111251881Spetersvn_sort_compare_paths(const void *a, const void *b) 112251881Speter{ 113251881Speter const char *item1 = *((const char * const *) a); 114251881Speter const char *item2 = *((const char * const *) b); 115251881Speter 116251881Speter return svn_path_compare_paths(item1, item2); 117251881Speter} 118251881Speter 119251881Speter 120251881Speterint 121251881Spetersvn_sort_compare_ranges(const void *a, const void *b) 122251881Speter{ 123251881Speter const svn_merge_range_t *item1 = *((const svn_merge_range_t * const *) a); 124251881Speter const svn_merge_range_t *item2 = *((const svn_merge_range_t * const *) b); 125251881Speter 126251881Speter if (item1->start == item2->start 127251881Speter && item1->end == item2->end) 128251881Speter return 0; 129251881Speter 130251881Speter if (item1->start == item2->start) 131251881Speter return item1->end < item2->end ? -1 : 1; 132251881Speter 133251881Speter return item1->start < item2->start ? -1 : 1; 134251881Speter} 135251881Speter 136251881Speterapr_array_header_t * 137251881Spetersvn_sort__hash(apr_hash_t *ht, 138251881Speter int (*comparison_func)(const svn_sort__item_t *, 139251881Speter const svn_sort__item_t *), 140251881Speter apr_pool_t *pool) 141251881Speter{ 142251881Speter apr_hash_index_t *hi; 143251881Speter apr_array_header_t *ary; 144251881Speter svn_boolean_t sorted; 145251881Speter svn_sort__item_t *prev_item; 146251881Speter 147251881Speter /* allocate an array with enough elements to hold all the keys. */ 148251881Speter ary = apr_array_make(pool, apr_hash_count(ht), sizeof(svn_sort__item_t)); 149251881Speter 150251881Speter /* loop over hash table and push all keys into the array */ 151251881Speter sorted = TRUE; 152251881Speter prev_item = NULL; 153251881Speter for (hi = apr_hash_first(pool, ht); hi; hi = apr_hash_next(hi)) 154251881Speter { 155251881Speter svn_sort__item_t *item = apr_array_push(ary); 156251881Speter 157251881Speter apr_hash_this(hi, &item->key, &item->klen, &item->value); 158251881Speter 159251881Speter if (prev_item == NULL) 160251881Speter { 161251881Speter prev_item = item; 162251881Speter continue; 163251881Speter } 164251881Speter 165251881Speter if (sorted) 166251881Speter { 167251881Speter sorted = (comparison_func(prev_item, item) < 0); 168251881Speter prev_item = item; 169251881Speter } 170251881Speter } 171251881Speter 172251881Speter /* quicksort the array if it isn't already sorted. */ 173251881Speter if (!sorted) 174251881Speter qsort(ary->elts, ary->nelts, ary->elt_size, 175251881Speter (int (*)(const void *, const void *))comparison_func); 176251881Speter 177251881Speter return ary; 178251881Speter} 179251881Speter 180251881Speter/* Return the lowest index at which the element *KEY should be inserted into 181251881Speter the array at BASE which has NELTS elements of size ELT_SIZE bytes each, 182251881Speter according to the ordering defined by COMPARE_FUNC. 183251881Speter 0 <= NELTS <= INT_MAX, 1 <= ELT_SIZE <= INT_MAX. 184251881Speter The array must already be sorted in the ordering defined by COMPARE_FUNC. 185251881Speter COMPARE_FUNC is defined as for the C stdlib function bsearch(). 186251881Speter Note: This function is modeled on bsearch() and on lower_bound() in the 187251881Speter C++ STL. 188251881Speter */ 189251881Speterstatic int 190251881Speterbsearch_lower_bound(const void *key, 191251881Speter const void *base, 192251881Speter int nelts, 193251881Speter int elt_size, 194251881Speter int (*compare_func)(const void *, const void *)) 195251881Speter{ 196251881Speter int lower = 0; 197251881Speter int upper = nelts - 1; 198251881Speter 199251881Speter /* Binary search for the lowest position at which to insert KEY. */ 200251881Speter while (lower <= upper) 201251881Speter { 202251881Speter int try = lower + (upper - lower) / 2; /* careful to avoid overflow */ 203251881Speter int cmp = compare_func((const char *)base + try * elt_size, key); 204251881Speter 205251881Speter if (cmp < 0) 206251881Speter lower = try + 1; 207251881Speter else 208251881Speter upper = try - 1; 209251881Speter } 210251881Speter assert(lower == upper + 1); 211251881Speter 212251881Speter return lower; 213251881Speter} 214251881Speter 215251881Speterint 216251881Spetersvn_sort__bsearch_lower_bound(const void *key, 217251881Speter const apr_array_header_t *array, 218251881Speter int (*compare_func)(const void *, const void *)) 219251881Speter{ 220251881Speter return bsearch_lower_bound(key, 221251881Speter array->elts, array->nelts, array->elt_size, 222251881Speter compare_func); 223251881Speter} 224251881Speter 225251881Spetervoid 226251881Spetersvn_sort__array_insert(const void *new_element, 227251881Speter apr_array_header_t *array, 228251881Speter int insert_index) 229251881Speter{ 230251881Speter int elements_to_move; 231251881Speter char *new_position; 232251881Speter 233251881Speter assert(0 <= insert_index && insert_index <= array->nelts); 234251881Speter elements_to_move = array->nelts - insert_index; /* before bumping nelts */ 235251881Speter 236251881Speter /* Grow the array, allocating a new space at the end. Note: this can 237251881Speter reallocate the array's "elts" at a different address. */ 238251881Speter apr_array_push(array); 239251881Speter 240251881Speter /* Move the elements after INSERT_INDEX along. (When elements_to_move == 0, 241251881Speter this is a no-op.) */ 242251881Speter new_position = (char *)array->elts + insert_index * array->elt_size; 243251881Speter memmove(new_position + array->elt_size, new_position, 244251881Speter array->elt_size * elements_to_move); 245251881Speter 246251881Speter /* Copy in the new element */ 247251881Speter memcpy(new_position, new_element, array->elt_size); 248251881Speter} 249251881Speter 250251881Spetervoid 251251881Spetersvn_sort__array_delete(apr_array_header_t *arr, 252251881Speter int delete_index, 253251881Speter int elements_to_delete) 254251881Speter{ 255251881Speter /* Do we have a valid index and are there enough elements? */ 256251881Speter if (delete_index >= 0 257251881Speter && delete_index < arr->nelts 258251881Speter && elements_to_delete > 0 259251881Speter && (elements_to_delete + delete_index) <= arr->nelts) 260251881Speter { 261251881Speter /* If we are not deleting a block of elements that extends to the end 262251881Speter of the array, then we need to move the remaining elements to keep 263251881Speter the array contiguous. */ 264251881Speter if ((elements_to_delete + delete_index) < arr->nelts) 265251881Speter memmove( 266251881Speter arr->elts + arr->elt_size * delete_index, 267251881Speter arr->elts + (arr->elt_size * (delete_index + elements_to_delete)), 268251881Speter arr->elt_size * (arr->nelts - elements_to_delete - delete_index)); 269251881Speter 270251881Speter /* Delete the last ELEMENTS_TO_DELETE elements. */ 271251881Speter arr->nelts -= elements_to_delete; 272251881Speter } 273251881Speter} 274251881Speter 275251881Spetervoid 276251881Spetersvn_sort__array_reverse(apr_array_header_t *array, 277251881Speter apr_pool_t *scratch_pool) 278251881Speter{ 279251881Speter int i; 280251881Speter 281251881Speter if (array->elt_size == sizeof(void *)) 282251881Speter { 283251881Speter for (i = 0; i < array->nelts / 2; i++) 284251881Speter { 285251881Speter int swap_index = array->nelts - i - 1; 286251881Speter void *tmp = APR_ARRAY_IDX(array, i, void *); 287251881Speter 288251881Speter APR_ARRAY_IDX(array, i, void *) = 289251881Speter APR_ARRAY_IDX(array, swap_index, void *); 290251881Speter APR_ARRAY_IDX(array, swap_index, void *) = tmp; 291251881Speter } 292251881Speter } 293251881Speter else 294251881Speter { 295251881Speter apr_size_t sz = array->elt_size; 296251881Speter char *tmp = apr_palloc(scratch_pool, sz); 297251881Speter 298251881Speter for (i = 0; i < array->nelts / 2; i++) 299251881Speter { 300251881Speter int swap_index = array->nelts - i - 1; 301251881Speter char *x = array->elts + (sz * i); 302251881Speter char *y = array->elts + (sz * swap_index); 303251881Speter 304251881Speter memcpy(tmp, x, sz); 305251881Speter memcpy(x, y, sz); 306251881Speter memcpy(y, tmp, sz); 307251881Speter } 308251881Speter } 309251881Speter} 310