Browse Source
This is needed to create a merged view multiple reftables Signed-off-by: Han-Wen Nienhuys <hanwen@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
![hanwen@google.com](/assets/img/avatar_default.png)
![Junio C Hamano](/assets/img/avatar_default.png)
6 changed files with 224 additions and 0 deletions
@ -0,0 +1,105 @@
@@ -0,0 +1,105 @@
|
||||
/* |
||||
Copyright 2020 Google LLC |
||||
|
||||
Use of this source code is governed by a BSD-style |
||||
license that can be found in the LICENSE file or at |
||||
https://developers.google.com/open-source/licenses/bsd |
||||
*/ |
||||
|
||||
#include "pq.h" |
||||
|
||||
#include "reftable-record.h" |
||||
#include "system.h" |
||||
#include "basics.h" |
||||
|
||||
int pq_less(struct pq_entry *a, struct pq_entry *b) |
||||
{ |
||||
struct strbuf ak = STRBUF_INIT; |
||||
struct strbuf bk = STRBUF_INIT; |
||||
int cmp = 0; |
||||
reftable_record_key(&a->rec, &ak); |
||||
reftable_record_key(&b->rec, &bk); |
||||
|
||||
cmp = strbuf_cmp(&ak, &bk); |
||||
|
||||
strbuf_release(&ak); |
||||
strbuf_release(&bk); |
||||
|
||||
if (cmp == 0) |
||||
return a->index > b->index; |
||||
|
||||
return cmp < 0; |
||||
} |
||||
|
||||
struct pq_entry merged_iter_pqueue_top(struct merged_iter_pqueue pq) |
||||
{ |
||||
return pq.heap[0]; |
||||
} |
||||
|
||||
int merged_iter_pqueue_is_empty(struct merged_iter_pqueue pq) |
||||
{ |
||||
return pq.len == 0; |
||||
} |
||||
|
||||
struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq) |
||||
{ |
||||
int i = 0; |
||||
struct pq_entry e = pq->heap[0]; |
||||
pq->heap[0] = pq->heap[pq->len - 1]; |
||||
pq->len--; |
||||
|
||||
i = 0; |
||||
while (i < pq->len) { |
||||
int min = i; |
||||
int j = 2 * i + 1; |
||||
int k = 2 * i + 2; |
||||
if (j < pq->len && pq_less(&pq->heap[j], &pq->heap[i])) { |
||||
min = j; |
||||
} |
||||
if (k < pq->len && pq_less(&pq->heap[k], &pq->heap[min])) { |
||||
min = k; |
||||
} |
||||
|
||||
if (min == i) { |
||||
break; |
||||
} |
||||
|
||||
SWAP(pq->heap[i], pq->heap[min]); |
||||
i = min; |
||||
} |
||||
|
||||
return e; |
||||
} |
||||
|
||||
void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, struct pq_entry e) |
||||
{ |
||||
int i = 0; |
||||
if (pq->len == pq->cap) { |
||||
pq->cap = 2 * pq->cap + 1; |
||||
pq->heap = reftable_realloc(pq->heap, |
||||
pq->cap * sizeof(struct pq_entry)); |
||||
} |
||||
|
||||
pq->heap[pq->len++] = e; |
||||
i = pq->len - 1; |
||||
while (i > 0) { |
||||
int j = (i - 1) / 2; |
||||
if (pq_less(&pq->heap[j], &pq->heap[i])) { |
||||
break; |
||||
} |
||||
|
||||
SWAP(pq->heap[j], pq->heap[i]); |
||||
|
||||
i = j; |
||||
} |
||||
} |
||||
|
||||
void merged_iter_pqueue_release(struct merged_iter_pqueue *pq) |
||||
{ |
||||
int i = 0; |
||||
for (i = 0; i < pq->len; i++) { |
||||
reftable_record_destroy(&pq->heap[i].rec); |
||||
} |
||||
FREE_AND_NULL(pq->heap); |
||||
pq->len = pq->cap = 0; |
||||
} |
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
/* |
||||
Copyright 2020 Google LLC |
||||
|
||||
Use of this source code is governed by a BSD-style |
||||
license that can be found in the LICENSE file or at |
||||
https://developers.google.com/open-source/licenses/bsd |
||||
*/ |
||||
|
||||
#ifndef PQ_H |
||||
#define PQ_H |
||||
|
||||
#include "record.h" |
||||
|
||||
struct pq_entry { |
||||
int index; |
||||
struct reftable_record rec; |
||||
}; |
||||
|
||||
struct merged_iter_pqueue { |
||||
struct pq_entry *heap; |
||||
size_t len; |
||||
size_t cap; |
||||
}; |
||||
|
||||
struct pq_entry merged_iter_pqueue_top(struct merged_iter_pqueue pq); |
||||
int merged_iter_pqueue_is_empty(struct merged_iter_pqueue pq); |
||||
void merged_iter_pqueue_check(struct merged_iter_pqueue pq); |
||||
struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq); |
||||
void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, struct pq_entry e); |
||||
void merged_iter_pqueue_release(struct merged_iter_pqueue *pq); |
||||
int pq_less(struct pq_entry *a, struct pq_entry *b); |
||||
|
||||
#endif |
@ -0,0 +1,82 @@
@@ -0,0 +1,82 @@
|
||||
/* |
||||
Copyright 2020 Google LLC |
||||
|
||||
Use of this source code is governed by a BSD-style |
||||
license that can be found in the LICENSE file or at |
||||
https://developers.google.com/open-source/licenses/bsd |
||||
*/ |
||||
|
||||
#include "system.h" |
||||
|
||||
#include "basics.h" |
||||
#include "constants.h" |
||||
#include "pq.h" |
||||
#include "record.h" |
||||
#include "reftable-tests.h" |
||||
#include "test_framework.h" |
||||
|
||||
void merged_iter_pqueue_check(struct merged_iter_pqueue pq) |
||||
{ |
||||
int i; |
||||
for (i = 1; i < pq.len; i++) { |
||||
int parent = (i - 1) / 2; |
||||
|
||||
EXPECT(pq_less(&pq.heap[parent], &pq.heap[i])); |
||||
} |
||||
} |
||||
|
||||
static void test_pq(void) |
||||
{ |
||||
char *names[54] = { NULL }; |
||||
int N = ARRAY_SIZE(names) - 1; |
||||
|
||||
struct merged_iter_pqueue pq = { NULL }; |
||||
const char *last = NULL; |
||||
|
||||
int i = 0; |
||||
for (i = 0; i < N; i++) { |
||||
char name[100]; |
||||
snprintf(name, sizeof(name), "%02d", i); |
||||
names[i] = xstrdup(name); |
||||
} |
||||
|
||||
i = 1; |
||||
do { |
||||
struct reftable_record rec = |
||||
reftable_new_record(BLOCK_TYPE_REF); |
||||
struct pq_entry e = { 0 }; |
||||
|
||||
reftable_record_as_ref(&rec)->refname = names[i]; |
||||
e.rec = rec; |
||||
merged_iter_pqueue_add(&pq, e); |
||||
merged_iter_pqueue_check(pq); |
||||
i = (i * 7) % N; |
||||
} while (i != 1); |
||||
|
||||
while (!merged_iter_pqueue_is_empty(pq)) { |
||||
struct pq_entry e = merged_iter_pqueue_remove(&pq); |
||||
struct reftable_ref_record *ref = |
||||
reftable_record_as_ref(&e.rec); |
||||
|
||||
merged_iter_pqueue_check(pq); |
||||
|
||||
if (last) { |
||||
EXPECT(strcmp(last, ref->refname) < 0); |
||||
} |
||||
last = ref->refname; |
||||
ref->refname = NULL; |
||||
reftable_free(ref); |
||||
} |
||||
|
||||
for (i = 0; i < N; i++) { |
||||
reftable_free(names[i]); |
||||
} |
||||
|
||||
merged_iter_pqueue_release(&pq); |
||||
} |
||||
|
||||
int pq_test_main(int argc, const char *argv[]) |
||||
{ |
||||
RUN_TEST(test_pq); |
||||
return 0; |
||||
} |
Loading…
Reference in new issue