You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/03/25 11:06:49 UTC

svn commit: r1460579 - in /subversion/branches/fsfs-format7/subversion: include/svn_sorts.h libsvn_subr/sorts.c

Author: stefan2
Date: Mon Mar 25 10:06:48 2013
New Revision: 1460579

URL: http://svn.apache.org/r1460579
Log:
On the fsfs-format7 branch: Introduce a libsvn_subr API for priority queues.
We will soon use it in the new FSFS pack code.

* subversion/include/svn_sorts.h
  (svn__priority_queue_t): declare new data type
  (svn__priority_queue_create,
   svn__priority_queue_size,
   svn__priority_queue_peek,
   svn__priority_queue_pop,
   svn__priority_queue_push): declare new API functions

* subversion/libsvn_subr/sorts.c
  (svn__priority_queue_t): define data type
  (heap_is_less,
   heap_swap,
   heap_bubble_down,
   heap_bubble_up): new utility functions
  (svn__priority_queue_create,
   svn__priority_queue_size,
   svn__priority_queue_peek,
   svn__priority_queue_pop,
   svn__priority_queue_push): implement new API

Modified:
    subversion/branches/fsfs-format7/subversion/include/svn_sorts.h
    subversion/branches/fsfs-format7/subversion/libsvn_subr/sorts.c

Modified: subversion/branches/fsfs-format7/subversion/include/svn_sorts.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/include/svn_sorts.h?rev=1460579&r1=1460578&r2=1460579&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/include/svn_sorts.h (original)
+++ subversion/branches/fsfs-format7/subversion/include/svn_sorts.h Mon Mar 25 10:06:48 2013
@@ -214,6 +214,71 @@ void
 svn_sort__array_reverse(apr_array_header_t *array,
                         apr_pool_t *scratch_pool);
 
+/** Priority queues.
+ *
+ * @defgroup svn__priority_queue_t Priority Queues
+ * @{
+ */
+
+/**
+ * We implement priority queues on top of existing ELEMENTS arrays.  They
+ * provide us with memory management and very basic element type information.
+ *
+ * The extraction order is being defined by a comparison function similar
+ * to the ones used with qsort.  The first element in the queue is always
+ * on with COMPARISON_FUNC(first,element) <= 0, for all elements in the
+ * queue.
+ */
+
+/**
+ * Opaque data type for priority queues.
+ */
+typedef struct svn__priority_queue_t svn__priority_queue_t;
+
+/**
+ * Return a priority queue containing all provided @a elements and prioritize
+ * them according to @a compare_func.
+ *
+ * @note The priority queue will use the existing @a elements array for data
+ * storage.  So, you must not manipulate that array while using the queue.
+ * Also, the lifetime of the queue is bound to that of the array.
+ */
+svn__priority_queue_t *
+svn__priority_queue_create(apr_array_header_t *elements,
+                           int (*compare_func)(const void *, const void *));
+
+/**
+ * Returns the number of elements in the @a queue.
+ */
+apr_size_t
+svn__priority_queue_size(svn__priority_queue_t *queue);
+
+/**
+ * Returns a reference to the first element in the @a queue.  The queue
+ * contents remains unchanged.  If the @a queue is empty, #NULL will be
+ * returned.
+ */
+void *
+svn__priority_queue_peek(svn__priority_queue_t *queue);
+
+/**
+ * Remove the first element from the @a queue.  This is a no-op for empty
+ * queues.
+ */
+void
+svn__priority_queue_pop(svn__priority_queue_t *queue);
+
+/**
+ * Append the new @a element to the @a queue.  @a element must neither be
+ * #NULL nor the first element as returned by #svn__priority_queue_peek.
+ */
+void
+svn__priority_queue_push(svn__priority_queue_t *queue,
+                         void *element);
+
+/** @} */
+
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/branches/fsfs-format7/subversion/libsvn_subr/sorts.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_subr/sorts.c?rev=1460579&r1=1460578&r2=1460579&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_subr/sorts.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_subr/sorts.c Mon Mar 25 10:06:48 2013
@@ -306,3 +306,142 @@ svn_sort__array_reverse(apr_array_header
         }
     }
 }
+
+/* Our priority queue data structure:
+ * Simply remember the constructor parameters.
+ */
+struct svn__priority_queue_t
+{
+  /* the queue elements, ordered as a heap according to COMPARE_FUNC */
+  apr_array_header_t *elements;
+
+  /* predicate used to order the heap */
+  int (*compare_func)(const void *, const void *);
+};
+
+/* Return TRUE, if heap element number LHS in QUEUE is smaller than element
+ * number RHS according to QUEUE->COMPARE_FUNC
+ */
+static int
+heap_is_less(svn__priority_queue_t *queue,
+             apr_size_t lhs,
+             apr_size_t rhs)
+{
+  char *lhs_value = queue->elements->elts + lhs * queue->elements->elt_size;
+  char *rhs_value = queue->elements->elts + rhs * queue->elements->elt_size;
+
+  assert(lhs < queue->elements->nelts);
+  assert(rhs < queue->elements->nelts);
+  return queue->compare_func((void *)lhs_value, (void *)rhs_value) < 0;
+}
+
+/* Exchange elements number LHS and RHS in QUEUE.
+ */
+static void
+heap_swap(svn__priority_queue_t *queue,
+          apr_size_t lhs,
+          apr_size_t rhs)
+{
+  int i;
+  char *lhs_value = queue->elements->elts + lhs * queue->elements->elt_size;
+  char *rhs_value = queue->elements->elts + rhs * queue->elements->elt_size;
+
+  for (i = 0; i < queue->elements->elt_size; ++i)
+    {
+      char temp = lhs_value[i];
+      lhs_value[i] = rhs_value[i];
+      rhs_value[i] = temp;
+    }
+}
+
+/* Move element number IDX to lower indexes until the heap criterion is
+ * fulfilled again.
+ */
+static void
+heap_bubble_down(svn__priority_queue_t *queue,
+                 int idx)
+{
+  while (idx > 0 && heap_is_less(queue, idx, (idx - 1) / 2))
+    {
+      heap_swap(queue, idx, (idx - 1) / 2);
+      idx = (idx - 1) / 2;
+    }
+}
+
+/* Move element number IDX to higher indexes until the heap criterion is
+ * fulfilled again.
+ */
+static void
+heap_bubble_up(svn__priority_queue_t *queue,
+               int idx)
+{
+  while (2 * idx + 2 < queue->elements->nelts)
+    {
+      int child = heap_is_less(queue, 2 * idx + 1, 2 * idx + 2)
+                ? 2 * idx + 1
+                : 2 * idx + 2;
+
+      if (heap_is_less(queue, idx, child))
+        return;
+
+      heap_swap(queue, idx, child);
+      idx = child;
+    }
+
+  if (   2 * idx + 1 < queue->elements->nelts
+      && heap_is_less(queue, 2 * idx + 1, idx))
+    heap_swap(queue, 2 * idx + 1, idx);
+}
+
+svn__priority_queue_t *
+svn__priority_queue_create(apr_array_header_t *elements,
+                           int (*compare_func)(const void *, const void *))
+{
+  int i;
+
+  svn__priority_queue_t *queue = apr_pcalloc(elements->pool, sizeof(*queue));
+  queue->elements = elements;
+  queue->compare_func = compare_func;
+
+  for (i = elements->nelts - 1; i > 0; --i)
+    heap_bubble_down(queue, i);
+  
+  return queue;
+}
+
+apr_size_t
+svn__priority_queue_size(svn__priority_queue_t *queue)
+{
+  return queue->elements->nelts;
+}
+
+void *
+svn__priority_queue_peek(svn__priority_queue_t *queue)
+{
+  return queue->elements->nelts ? queue->elements->elts : NULL;
+}
+
+void
+svn__priority_queue_pop(svn__priority_queue_t *queue)
+{
+  if (queue->elements->nelts)
+    {
+      memcpy(queue->elements->elts,
+             queue->elements->elts + (queue->elements->nelts - 1)
+                                   * queue->elements->elt_size,
+             queue->elements->elt_size);
+      --queue->elements->nelts;
+      heap_bubble_up(queue, 0);
+    }
+}
+
+void
+svn__priority_queue_push(svn__priority_queue_t *queue,
+                         void *element)
+{
+  /* we cannot duplicate elements due to potential array re-allocs */
+  assert(element && element != queue->elements->elts);
+
+  memcpy(apr_array_push(queue->elements), element, queue->elements->elt_size);
+  heap_bubble_down(queue, queue->elements->nelts - 1);
+}
\ No newline at end of file