Introduce a hash iterator for iterating in sorted order, to save having to
declare an array and sort the hash into it. Use it in a few places.

### The calls to svn_sort_compare_items_*() in the mergeinfo functions now
  give compiler warnings because the comparison function expects
  svn_sort__item_t not svn_sort__hash_index_t.

* subversion/include/svn_sorts.h,
  subversion/libsvn_subr/sorts.c
  (svn_sort__hash_index_t, svn_sort__hash_first, svn_sort__hash_next): New.

* subversion/libsvn_client/list.c
  (get_dir_contents): Use it.

* subversion/libsvn_subr/mergeinfo.c
  (svn_mergeinfo_merge2, svn_mergeinfo_catalog_merge): Same.

* subversion/svn/log-cmd.c
  (log_entry_receiver): Same.
--This line, and those below, will be ignored--

Index: subversion/include/svn_sorts.h
===================================================================
--- subversion/include/svn_sorts.h	(revision 1189146)
+++ subversion/include/svn_sorts.h	(working copy)
@@ -164,6 +164,41 @@ svn_sort__hash(apr_hash_t *ht,
                                       const svn_sort__item_t *),
                apr_pool_t *pool);
 
+/** A hash iterator for iterating over a hash table in sorted order. The
+ * @c key member always holds the hash key and @c value holds the hash value
+ * of the hash item at index @c i in the sorted array @c array. */
+typedef struct svn_sort__hash_index_t
+{
+  /** pointer to the key */
+  const void *key;
+
+  /** size of the key */
+  apr_ssize_t klen;
+
+  /** pointer to the value */
+  void *value;
+
+  /** this item's index into the array */
+  int i;
+
+  /** the sorted array of svn_sort__item_t elements */
+  apr_array_header_t *array;
+} svn_sort__hash_index_t;
+
+/** Start iterating over the hash table @a ht, in sorted order according to
+ * @a comparison_func. Similar to apr_hash_first(). */
+svn_sort__hash_index_t *
+svn_sort__hash_first(apr_hash_t *ht,
+                     int (*comparison_func)(const svn_sort__item_t *,
+                                            const svn_sort__item_t *),
+                     apr_pool_t *pool);
+
+/* Access the next element of the hash table being iterated, or return NULL
+ * if there are no more items. Similar to apr_hash_next(). */
+svn_sort__hash_index_t *
+svn_sort__hash_next(svn_sort__hash_index_t *hi);
+
+
 /* Return the lowest index at which the element @a *key should be inserted into
  * the array @a array, according to the ordering defined by @a compare_func.
  * The array must already be sorted in the ordering defined by @a compare_func.
Index: subversion/libsvn_client/list.c
===================================================================
--- subversion/libsvn_client/list.c	(revision 1189146)
+++ subversion/libsvn_client/list.c	(working copy)
@@ -63,9 +63,8 @@ get_dir_contents(apr_uint32_t dirent_fie
 {
   apr_hash_t *tmpdirents;
   apr_pool_t *iterpool = svn_pool_create(pool);
-  apr_array_header_t *array;
   svn_error_t *err;
-  int i;
+  svn_sort__hash_index_t *item;
 
   if (depth == svn_depth_empty)
     return SVN_NO_ERROR;
@@ -86,10 +85,10 @@ get_dir_contents(apr_uint32_t dirent_fie
     SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
 
   /* Sort the hash, so we can call the callback in a "deterministic" order. */
-  array = svn_sort__hash(tmpdirents, svn_sort_compare_items_lexically, pool);
-  for (i = 0; i < array->nelts; ++i)
+  for (item = svn_sort__hash_first(tmpdirents, svn_sort_compare_items_lexically,
+                                   pool);
+       item; item = svn_sort__hash_next(item))
     {
-      svn_sort__item_t *item = &APR_ARRAY_IDX(array, i, svn_sort__item_t);
       const char *path;
       svn_dirent_t *the_ent = apr_hash_get(tmpdirents, item->key, item->klen);
       svn_lock_t *lock;
Index: subversion/libsvn_subr/mergeinfo.c
===================================================================
--- subversion/libsvn_subr/mergeinfo.c	(revision 1189146)
+++ subversion/libsvn_subr/mergeinfo.c	(working copy)
@@ -1668,61 +1668,54 @@ svn_mergeinfo_merge2(svn_mergeinfo_t mer
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool)
 {
-  apr_array_header_t *sorted1, *sorted2;
-  int i, j;
+  svn_sort__hash_index_t *elt1, *elt2;
   apr_pool_t *iterpool;
 
   if (!apr_hash_count(changes))
     return SVN_NO_ERROR;
 
-  sorted1 = svn_sort__hash(mergeinfo, svn_sort_compare_items_as_paths,
-                           scratch_pool);
-  sorted2 = svn_sort__hash(changes, svn_sort_compare_items_as_paths,
-                           scratch_pool);
+  elt1 = svn_sort__hash_first(mergeinfo, svn_sort_compare_items_as_paths,
+                              scratch_pool);
+  elt2 = svn_sort__hash_first(changes, svn_sort_compare_items_as_paths,
+                              scratch_pool);
 
-  i = 0;
-  j = 0;
   iterpool = svn_pool_create(scratch_pool);
-  while (i < sorted1->nelts && j < sorted2->nelts)
+  while (elt1 && elt2)
     {
-      svn_sort__item_t elt1, elt2;
       int res;
 
       svn_pool_clear(iterpool);
 
-      elt1 = APR_ARRAY_IDX(sorted1, i, svn_sort__item_t);
-      elt2 = APR_ARRAY_IDX(sorted2, j, svn_sort__item_t);
-      res = svn_sort_compare_items_as_paths(&elt1, &elt2);
+      res = svn_sort_compare_items_as_paths(elt1, elt2);
 
       if (res == 0)
         {
           apr_array_header_t *rl1, *rl2;
 
-          rl1 = elt1.value;
-          rl2 = elt2.value;
+          rl1 = elt1->value;
+          rl2 = elt2->value;
 
           SVN_ERR(svn_rangelist_merge2(rl1, rl2, result_pool, iterpool));
-          apr_hash_set(mergeinfo, elt1.key, elt1.klen, rl1);
-          i++;
-          j++;
+          apr_hash_set(mergeinfo, elt1->key, elt1->klen, rl1);
+          elt1 = svn_sort__hash_next(elt1);
+          elt2 = svn_sort__hash_next(elt2);
         }
       else if (res < 0)
         {
-          i++;
+          elt1 = svn_sort__hash_next(elt1);
         }
       else
         {
-          apr_hash_set(mergeinfo, elt2.key, elt2.klen, elt2.value);
-          j++;
+          apr_hash_set(mergeinfo, elt2->key, elt2->klen, elt2->value);
+          elt2 = svn_sort__hash_next(elt2);
         }
     }
   svn_pool_destroy(iterpool);
 
   /* Copy back any remaining elements from the second hash. */
-  for (; j < sorted2->nelts; j++)
+  for (; elt2; elt2 = svn_sort__hash_next(elt2))
     {
-      svn_sort__item_t elt = APR_ARRAY_IDX(sorted2, j, svn_sort__item_t);
-      apr_hash_set(mergeinfo, elt.key, elt.klen, elt.value);
+      apr_hash_set(mergeinfo, elt2->key, elt2->klen, elt2->value);
     }
 
   return SVN_NO_ERROR;
@@ -1734,58 +1727,51 @@ svn_mergeinfo_catalog_merge(svn_mergeinf
                             apr_pool_t *result_pool,
                             apr_pool_t *scratch_pool)
 {
-  int i = 0;
-  int j = 0;
-  apr_array_header_t *sorted_cat =
-    svn_sort__hash(mergeinfo_cat, svn_sort_compare_items_as_paths,
-                   scratch_pool);
-  apr_array_header_t *sorted_changes =
-    svn_sort__hash(changes_cat, svn_sort_compare_items_as_paths,
-                   scratch_pool);
+  svn_sort__hash_index_t *cat_elt
+    = svn_sort__hash_first(mergeinfo_cat, svn_sort_compare_items_as_paths,
+                           scratch_pool);
+  svn_sort__hash_index_t *change_elt
+    = svn_sort__hash_first(changes_cat, svn_sort_compare_items_as_paths,
+                           scratch_pool);
 
-  while (i < sorted_cat->nelts && j < sorted_changes->nelts)
+  while (cat_elt && change_elt)
     {
-      svn_sort__item_t cat_elt, change_elt;
       int res;
 
-      cat_elt = APR_ARRAY_IDX(sorted_cat, i, svn_sort__item_t);
-      change_elt = APR_ARRAY_IDX(sorted_changes, j, svn_sort__item_t);
-      res = svn_sort_compare_items_as_paths(&cat_elt, &change_elt);
+      res = svn_sort_compare_items_as_paths(cat_elt, change_elt);
 
       if (res == 0) /* Both catalogs have mergeinfo for a given path. */
         {
-          svn_mergeinfo_t mergeinfo = cat_elt.value;
-          svn_mergeinfo_t changes_mergeinfo = change_elt.value;
+          svn_mergeinfo_t mergeinfo = cat_elt->value;
+          svn_mergeinfo_t changes_mergeinfo = change_elt->value;
 
           SVN_ERR(svn_mergeinfo_merge2(mergeinfo, changes_mergeinfo,
                                        result_pool, scratch_pool));
-          apr_hash_set(mergeinfo_cat, cat_elt.key, cat_elt.klen, mergeinfo);
-          i++;
-          j++;
+          apr_hash_set(mergeinfo_cat, cat_elt->key, cat_elt->klen, mergeinfo);
+          cat_elt = svn_sort__hash_next(cat_elt);
+          change_elt = svn_sort__hash_next(change_elt);
         }
       else if (res < 0) /* Only MERGEINFO_CAT has mergeinfo for this path. */
         {
-          i++;
+          cat_elt = svn_sort__hash_next(cat_elt);
         }
       else /* Only CHANGES_CAT has mergeinfo for this path. */
         {
           apr_hash_set(mergeinfo_cat,
-                       apr_pstrdup(result_pool, change_elt.key),
-                       change_elt.klen,
-                       svn_mergeinfo_dup(change_elt.value, result_pool));
-          j++;
+                       apr_pstrdup(result_pool, change_elt->key),
+                       change_elt->klen,
+                       svn_mergeinfo_dup(change_elt->value, result_pool));
+          change_elt = svn_sort__hash_next(change_elt);
         }
     }
 
   /* Copy back any remaining elements from the CHANGES_CAT catalog. */
-  for (; j < sorted_changes->nelts; j++)
+  for (; change_elt; change_elt = svn_sort__hash_next(change_elt))
     {
-      svn_sort__item_t elt = APR_ARRAY_IDX(sorted_changes, j,
-                                           svn_sort__item_t);
       apr_hash_set(mergeinfo_cat,
-                   apr_pstrdup(result_pool, elt.key),
-                   elt.klen,
-                   svn_mergeinfo_dup(elt.value, result_pool));
+                   apr_pstrdup(result_pool, change_elt->key),
+                   change_elt->klen,
+                   svn_mergeinfo_dup(change_elt->value, result_pool));
     }
 
   return SVN_NO_ERROR;
Index: subversion/libsvn_subr/sorts.c
===================================================================
--- subversion/libsvn_subr/sorts.c	(revision 1189146)
+++ subversion/libsvn_subr/sorts.c	(working copy)
@@ -30,6 +30,7 @@
 #include <assert.h>
 #include "svn_path.h"
 #include "svn_sorts.h"
+#include "private/svn_subr_private.h"
 #include "svn_error.h"
 
 
@@ -176,6 +177,38 @@ svn_sort__hash(apr_hash_t *ht,
   return ary;
 }
 
+svn_sort__hash_index_t *
+svn_sort__hash_first(apr_hash_t *ht,
+                     int (*comparison_func)(const svn_sort__item_t *,
+                                            const svn_sort__item_t *),
+                     apr_pool_t *pool)
+{
+  svn_sort__hash_index_t *hi = apr_palloc(pool, sizeof(*hi));
+
+  if (apr_hash_count(ht) == 0)
+    return NULL;
+
+  hi->array = svn_sort__hash(ht, comparison_func, pool);
+  hi->i = 0;
+  hi->key = APR_ARRAY_IDX(hi->array, hi->i, svn_sort__item_t).key;
+  hi->klen = APR_ARRAY_IDX(hi->array, hi->i, svn_sort__item_t).klen;
+  hi->value = APR_ARRAY_IDX(hi->array, hi->i, svn_sort__item_t).value;
+  return hi;
+}
+
+svn_sort__hash_index_t *
+svn_sort__hash_next(svn_sort__hash_index_t *hi)
+{
+  hi->i++;
+  if (hi->i >= hi->array->nelts)
+    return NULL;
+
+  hi->key = APR_ARRAY_IDX(hi->array, hi->i, svn_sort__item_t).key;
+  hi->klen = APR_ARRAY_IDX(hi->array, hi->i, svn_sort__item_t).klen;
+  hi->value = APR_ARRAY_IDX(hi->array, hi->i, svn_sort__item_t).value;
+  return hi;
+}
+
 /* Return the lowest index at which the element *KEY should be inserted into
    the array at BASE which has NELTS elements of size ELT_SIZE bytes each,
    according to the ordering defined by COMPARE_FUNC.
Index: subversion/svn/log-cmd.c
===================================================================
--- subversion/svn/log-cmd.c	(revision 1189146)
+++ subversion/svn/log-cmd.c	(working copy)
@@ -213,19 +213,15 @@ log_entry_receiver(void *baton,
 
   if (log_entry->changed_paths2)
     {
-      apr_array_header_t *sorted_paths;
-      int i;
-
-      /* Get an array of sorted hash keys. */
-      sorted_paths = svn_sort__hash(log_entry->changed_paths2,
-                                    svn_sort_compare_items_as_paths, pool);
+      svn_sort__hash_index_t *item;
 
       SVN_ERR(svn_cmdline_printf(pool,
                                  _("Changed paths:\n")));
-      for (i = 0; i < sorted_paths->nelts; i++)
+      /* Iterate in sorted order. */
+      for (item = svn_sort__hash(log_entry->changed_paths2,
+                                 svn_sort_compare_items_as_paths, pool);
+           item; item = svn_sort__hash_next(item))
         {
-          svn_sort__item_t *item = &(APR_ARRAY_IDX(sorted_paths, i,
-                                                   svn_sort__item_t));
           const char *path = item->key;
           svn_log_changed_path2_t *log_item
             = apr_hash_get(log_entry->changed_paths2, item->key, item->klen);
