From: Thiago Farina <tfransosi@gmail.com>
To: Jeff King <peff@peff.net>
Cc: git@vger.kernel.org
Subject: Re: [PATCH 2/4] basic priority queue implementation
Date: Thu, 19 May 2011 21:47:38 -0300 [thread overview]
Message-ID: <BANLkTikLSwWanxUksf3Ezx7uhaTR4mMiWw@mail.gmail.com> (raw)
In-Reply-To: <20110519212448.GB29584@sigill.intra.peff.net>
On Thu, May 19, 2011 at 6:24 PM, Jeff King <peff@peff.net> wrote:
> This can provide better algorithmic complexity for some of
> the date-sorted commit list uses, among other things.
>
> The queue is stored as a heap, allowing O(log) insertion and
> top-element removal, and O(1) peeking at the top element.
> Current commit lists are sorted linked lists, giving O(1)
> peeking and top-element removal, but O(n^2) insertion.
>
> Signed-off-by: Jeff King <peff@peff.net>
> ---
> .gitignore | 1 +
> Makefile | 3 ++
> queue.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> queue.h | 17 +++++++++++++
> t/t0007-queue.sh | 50 ++++++++++++++++++++++++++++++++++++++
> test-queue.c | 39 ++++++++++++++++++++++++++++++
> 6 files changed, 180 insertions(+), 0 deletions(-)
> create mode 100644 queue.c
> create mode 100644 queue.h
> create mode 100755 t/t0007-queue.sh
> create mode 100644 test-queue.c
>
> diff --git a/.gitignore b/.gitignore
> index 711fce7..179483a 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -174,6 +174,7 @@
> /test-obj-pool
> /test-parse-options
> /test-path-utils
> +/test-queue
> /test-run-command
> /test-sha1
> /test-sigchain
> diff --git a/Makefile b/Makefile
> index d09ee70..737b2d5 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -422,6 +422,7 @@ TEST_PROGRAMS_NEED_X += test-mktemp
> TEST_PROGRAMS_NEED_X += test-obj-pool
> TEST_PROGRAMS_NEED_X += test-parse-options
> TEST_PROGRAMS_NEED_X += test-path-utils
> +TEST_PROGRAMS_NEED_X += test-queue
> TEST_PROGRAMS_NEED_X += test-run-command
> TEST_PROGRAMS_NEED_X += test-sha1
> TEST_PROGRAMS_NEED_X += test-sigchain
> @@ -532,6 +533,7 @@ LIB_H += parse-options.h
> LIB_H += patch-ids.h
> LIB_H += pkt-line.h
> LIB_H += progress.h
> +LIB_H += queue.h
> LIB_H += quote.h
> LIB_H += reflog-walk.h
> LIB_H += refs.h
> @@ -629,6 +631,7 @@ LIB_OBJS += pkt-line.o
> LIB_OBJS += preload-index.o
> LIB_OBJS += pretty.o
> LIB_OBJS += progress.o
> +LIB_OBJS += queue.o
> LIB_OBJS += quote.o
> LIB_OBJS += reachable.o
> LIB_OBJS += read-cache.o
> diff --git a/queue.c b/queue.c
> new file mode 100644
> index 0000000..068b559
> --- /dev/null
> +++ b/queue.c
> @@ -0,0 +1,70 @@
> +#include "queue.h"
> +#include "cache.h"
> +
> +static inline void queue_swap(struct queue *pq, unsigned i, unsigned j)
> +{
> + void *tmp = pq->items[i];
> + pq->items[i] = pq->items[j];
> + pq->items[j] = tmp;
> +}
> +
> +static void queue_heapify_up(struct queue *pq)
> +{
> + unsigned i = pq->nr - 1;
> + while (i > 0) {
> + int parent = (i-1)/2;
> +
> + if (pq->cmp(pq->items[i], pq->items[parent]) <= 0)
> + return;
> +
> + queue_swap(pq, i, parent);
> + i = parent;
> + }
> +}
> +
> +void queue_insert(struct queue *pq, void *item)
> +{
> + ALLOC_GROW(pq->items, pq->nr + 1, pq->alloc);
> + pq->items[pq->nr++] = item;
> + queue_heapify_up(pq);
> +}
> +
> +static void queue_heapify_down(struct queue *pq)
> +{
> + unsigned i = 0;
> + while (1) {
> + int largest = i, left = 2*i + 1, right = 2*i + 2;
> +
> + if (left < pq->nr &&
> + pq->cmp(pq->items[left], pq->items[largest]) > 0)
> + largest = left;
> + if (right < pq->nr &&
> + pq->cmp(pq->items[right], pq->items[largest]) > 0)
> + largest = right;
> +
> + if (largest == i)
> + return;
> +
> + queue_swap(pq, i, largest);
> + i = largest;
> + }
> +}
> +
> +void *queue_peek(struct queue *pq)
> +{
> + return pq->nr ? pq->items[0] : NULL;
> +}
> +
> +void *queue_pop(struct queue *pq)
> +{
> + void *ret;
> +
> + if (!pq->nr)
> + return NULL;
> + ret = pq->items[0];
> +
> + pq->items[0] = pq->items[--pq->nr];
> + queue_heapify_down(pq);
> +
> + return ret;
> +}
> diff --git a/queue.h b/queue.h
> new file mode 100644
> index 0000000..fee5a51
> --- /dev/null
> +++ b/queue.h
> @@ -0,0 +1,17 @@
> +#ifndef QUEUE_H
> +#define QUEUE_H
> +
> +typedef int (*queue_comparison_func_t)(const void *, const void *);
> +
> +struct queue {
> + queue_comparison_func_t cmp;
> + void **items;
> + unsigned nr;
> + unsigned alloc;
> +};
> +
> +void queue_insert(struct queue *pq, void *item);
I'd rename this to queue_append as we add |item| to the end of the
array (like you did for sha1_array_append), opposed of inserting it at
some position/index.
> +void *queue_peek(struct queue *pq);
> +void *queue_pop(struct queue *pq);
> +
> +#endif /* QUEUE_H */
> diff --git a/t/t0007-queue.sh b/t/t0007-queue.sh
> new file mode 100755
> index 0000000..ee357bb
> --- /dev/null
> +++ b/t/t0007-queue.sh
> @@ -0,0 +1,50 @@
> +#!/bin/sh
> +
> +test_description='basic tests for priority queue implementation'
> +. ./test-lib.sh
> +
> +cat >expect <<'EOF'
> +10
> +9
> +8
> +7
> +6
> +5
> +5
> +4
> +3
> +2
> +1
> +EOF
> +test_expect_success 'basic ordering' '
> + test-queue 2 6 3 10 9 5 7 4 5 8 1 dump >actual &&
> + test_cmp expect actual
> +'
> +
> +cat >expect <<'EOF'
> +3
> +5
> +4
> +6
> +2
> +1
> +EOF
> +test_expect_success 'mixed insert and pop' '
> + test-queue 1 2 3 pop 4 5 pop pop 6 dump >actual &&
> + test_cmp expect actual
> +'
> +
> +cat >expect <<'EOF'
> +2
> +1
> +NULL
> +2
> +1
> +NULL
> +EOF
> +test_expect_success 'notice empty queue' '
> + test-queue 1 2 pop pop pop 1 2 pop pop pop >actual &&
> + test_cmp expect actual
> +'
> +
> +test_done
> diff --git a/test-queue.c b/test-queue.c
> new file mode 100644
> index 0000000..a1e92e2
> --- /dev/null
> +++ b/test-queue.c
> @@ -0,0 +1,39 @@
> +#include "cache.h"
> +#include "queue.h"
> +
> +static int intcmp(const void *va, const void *vb)
> +{
> + const int *a = va, *b = vb;
> + return *a - *b;
> +}
> +
> +static void show(int *v)
> +{
> + if (!v)
> + printf("NULL\n");
> + else
> + printf("%d\n", *v);
> + free(v);
> +}
> +
> +int main(int argc, char **argv)
> +{
> + struct queue pq = { intcmp };
> +
> + while (*++argv) {
> + if (!strcmp(*argv, "pop"))
> + show(queue_pop(&pq));
> + else if (!strcmp(*argv, "dump")) {
> + int *v;
> + while ((v = queue_pop(&pq)))
> + show(v);
> + }
> + else {
> + int *v = malloc(sizeof(*v));
> + *v = atoi(*argv);
> + queue_insert(&pq, v);
> + }
> + }
> +
> + return 0;
> +}
> --
> 1.7.5.8.ga95ab
>
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
next prev parent reply other threads:[~2011-05-20 0:47 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-05-19 20:48 [PATCH] fetch: avoid repeated commits in mark_complete Jeff King
2011-05-19 21:23 ` [RFC/PATCH 0/4] commit lists as priority queues Jeff King
2011-05-19 21:24 ` [PATCH 1/4] Makefile: sort TEST_PROGRAMS list Jeff King
2011-05-19 21:24 ` [PATCH 2/4] basic priority queue implementation Jeff King
2011-05-20 0:47 ` Thiago Farina [this message]
2011-05-20 7:38 ` Jeff King
2011-05-20 13:13 ` Thiago Farina
2011-05-20 13:23 ` Jeff King
2011-05-19 21:25 ` [PATCH 3/4] commit: add infrastructure for priority queues of commits Jeff King
2011-05-19 21:26 ` [PATCH 4/4] fetch-pack: use priority queue for mark_complete Jeff King
2011-05-20 22:03 ` [RFC/PATCH 0/4] commit lists as priority queues Junio C Hamano
2011-05-20 1:42 ` [PATCH] fetch: avoid repeated commits in mark_complete Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=BANLkTikLSwWanxUksf3Ezx7uhaTR4mMiWw@mail.gmail.com \
--to=tfransosi@gmail.com \
--cc=git@vger.kernel.org \
--cc=peff@peff.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).