2 * sorts.c: all sorts of sorts
4 * ====================================================================
5 * Copyright (c) 2000-2006 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
21 #include <apr_pools.h>
23 #include <apr_tables.h>
24 #include <stdlib.h> /* for qsort() */
27 #include "svn_sorts.h"
28 #include "svn_error.h"
32 /*** svn_sort__hash() ***/
34 /* (Should this be a permanent part of APR?)
36 OK, folks, here's what's going on. APR hash tables hash on
37 key/klen objects, and store associated generic values. They work
38 great, but they have no ordering.
40 The point of this exercise is to somehow arrange a hash's keys into
41 an "ordered list" of some kind -- in this case, a nicely sorted
44 We're using APR arrays, therefore, because that's what they are:
45 ordered lists. However, what "keys" should we put in the array?
46 Clearly, (const char *) objects aren't general enough. Or rather,
47 they're not as general as APR's hash implementation, which stores
48 (void *)/length as keys. We don't want to lose this information.
50 Therefore, it makes sense to store pointers to {void *, size_t}
51 structures in our array. No such apr object exists... BUT... if we
52 can use a new type svn_sort__item_t which contains {char *, size_t, void
53 *}. If store these objects in our array, we get the hash value
54 *for free*. When looping over the final array, we don't need to
55 call apr_hash_get(). Major bonus!
60 svn_sort_compare_items_as_paths(const svn_sort__item_t
*a
,
61 const svn_sort__item_t
*b
)
63 const char *astr
, *bstr
;
67 assert(astr
[a
->klen
] == '\0');
68 assert(bstr
[b
->klen
] == '\0');
69 return svn_path_compare_paths(astr
, bstr
);
74 svn_sort_compare_items_lexically(const svn_sort__item_t
*a
,
75 const svn_sort__item_t
*b
)
80 /* Compare bytes of a's key and b's key up to the common length. */
81 len
= (a
->klen
< b
->klen
) ? a
->klen
: b
->klen
;
82 val
= memcmp(a
->key
, b
->key
, len
);
86 /* They match up until one of them ends; whichever is longer is greater. */
87 return (a
->klen
< b
->klen
) ? -1 : (a
->klen
> b
->klen
) ? 1 : 0;
92 svn_sort_compare_revisions(const void *a
, const void *b
)
94 svn_revnum_t a_rev
= *(const svn_revnum_t
*)a
;
95 svn_revnum_t b_rev
= *(const svn_revnum_t
*)b
;
100 return a_rev
< b_rev
? 1 : -1;
105 svn_sort_compare_paths(const void *a
, const void *b
)
107 const char *item1
= *((const char * const *) a
);
108 const char *item2
= *((const char * const *) b
);
110 return svn_path_compare_paths(item1
, item2
);
115 svn_sort_compare_ranges(const void *a
, const void *b
)
117 const svn_merge_range_t
*item1
= *((const svn_merge_range_t
* const *) a
);
118 const svn_merge_range_t
*item2
= *((const svn_merge_range_t
* const *) b
);
120 if (item1
->start
== item2
->start
121 && item1
->end
== item2
->end
)
124 if (item1
->start
== item2
->start
)
125 return item1
->end
< item2
->end
? -1 : 1;
127 return item1
->start
< item2
->start
? -1 : 1;
131 svn_sort__hash(apr_hash_t
*ht
,
132 int (*comparison_func
)(const svn_sort__item_t
*,
133 const svn_sort__item_t
*),
136 apr_hash_index_t
*hi
;
137 apr_array_header_t
*ary
;
139 /* allocate an array with enough elements to hold all the keys. */
140 ary
= apr_array_make(pool
, apr_hash_count(ht
), sizeof(svn_sort__item_t
));
142 /* loop over hash table and push all keys into the array */
143 for (hi
= apr_hash_first(pool
, ht
); hi
; hi
= apr_hash_next(hi
))
145 svn_sort__item_t
*item
= apr_array_push(ary
);
147 apr_hash_this(hi
, &item
->key
, &item
->klen
, &item
->value
);
150 /* now quicksort the array. */
151 qsort(ary
->elts
, ary
->nelts
, ary
->elt_size
,
152 (int (*)(const void *, const void *))comparison_func
);