decorate: clean up and document API

Improve the names of the identifiers in decorate.h, document them, and add an example of how to use these functions. The example is compiled and run as part of the test suite. Signed-off-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jonathan Tan committed Dec 7, 2017 at 16:14 UTC ddd3e3124276133d0c7e902287ab4113f660f6d7
8 files changed +146 -25
Documentation/technical/api-decorate.txt deleted
-6
@@ -1,6 +0,0 @@
1 -decorate API
2 -============
3 -
4 -Talk about <decorate.h>
5 -
6 -(Linus)
Makefile
+1
@@ -651,6 +651,7 @@ TEST_PROGRAMS_NEED_X += test-dump-cache-tree
651 TEST_PROGRAMS_NEED_X += test-dump-fsmonitor
652 TEST_PROGRAMS_NEED_X += test-dump-split-index
653 TEST_PROGRAMS_NEED_X += test-dump-untracked-cache
654 +TEST_PROGRAMS_NEED_X += test-example-decorate
655 TEST_PROGRAMS_NEED_X += test-fake-ssh
656 TEST_PROGRAMS_NEED_X += test-genrandom
657 TEST_PROGRAMS_NEED_X += test-hashmap
builtin/fast-export.c
+1 -1
@@ -895,7 +895,7 @@ static void export_marks(char *file)
895 {
896 unsigned int i;
897 uint32_t mark;
898 - struct object_decoration *deco = idnums.hash;
898 + struct decoration_entry *deco = idnums.entries;
899 FILE *f;
900 int e = 0;
901
decorate.c
+13 -15
@@ -14,20 +14,20 @@ static unsigned int hash_obj(const struct object *obj, unsigned int n)
14 static void *insert_decoration(struct decoration *n, const struct object *base, void *decoration)
15 {
16 int size = n->size;
17 - struct object_decoration *hash = n->hash;
17 + struct decoration_entry *entries = n->entries;
18 unsigned int j = hash_obj(base, size);
19
20 - while (hash[j].base) {
21 - if (hash[j].base == base) {
22 - void *old = hash[j].decoration;
23 - hash[j].decoration = decoration;
20 + while (entries[j].base) {
21 + if (entries[j].base == base) {
22 + void *old = entries[j].decoration;
23 + entries[j].decoration = decoration;
24 return old;
25 }
26 if (++j >= size)
27 j = 0;
28 }
29 - hash[j].base = base;
30 - hash[j].decoration = decoration;
29 + entries[j].base = base;
30 + entries[j].decoration = decoration;
31 n->nr++;
32 return NULL;
33 }
@@ -36,24 +36,23 @@ static void grow_decoration(struct decoration *n)
36 {
37 int i;
38 int old_size = n->size;
39 - struct object_decoration *old_hash = n->hash;
39 + struct decoration_entry *old_entries = n->entries;
40
41 n->size = (old_size + 1000) * 3 / 2;
42 - n->hash = xcalloc(n->size, sizeof(struct object_decoration));
42 + n->entries = xcalloc(n->size, sizeof(struct decoration_entry));
43 n->nr = 0;
44
45 for (i = 0; i < old_size; i++) {
46 - const struct object *base = old_hash[i].base;
47 - void *decoration = old_hash[i].decoration;
46 + const struct object *base = old_entries[i].base;
47 + void *decoration = old_entries[i].decoration;
48
49 if (!decoration)
50 continue;
51 insert_decoration(n, base, decoration);
52 }
53 - free(old_hash);
53 + free(old_entries);
54 }
55
56 -/* Add a decoration pointer, return any old one */
56 void *add_decoration(struct decoration *n, const struct object *obj,
57 void *decoration)
58 {
@@ -64,7 +63,6 @@ void *add_decoration(struct decoration *n, const struct object *obj,
63 return insert_decoration(n, obj, decoration);
64 }
65
67 -/* Lookup a decoration pointer */
66 void *lookup_decoration(struct decoration *n, const struct object *obj)
67 {
68 unsigned int j;
@@ -74,7 +72,7 @@ void *lookup_decoration(struct decoration *n, const struct object *obj)
72 return NULL;
73 j = hash_obj(obj, n->size);
74 for (;;) {
77 - struct object_decoration *ref = n->hash + j;
75 + struct decoration_entry *ref = n->entries + j;
76 if (ref->base == obj)
77 return ref->decoration;
78 if (!ref->base)
decorate.h
+46 -3
@@ -1,18 +1,61 @@
1 #ifndef DECORATE_H
2 #define DECORATE_H
3
4 -struct object_decoration {
4 +/*
5 + * A data structure that associates Git objects to void pointers. See
6 + * t/helper/test-example-decorate.c for a demonstration of how to use these
7 + * functions.
8 + */
9 +
10 +/*
11 + * An entry in the data structure.
12 + */
13 +struct decoration_entry {
14 const struct object *base;
15 void *decoration;
16 };
17
18 +/*
19 + * The data structure.
20 + *
21 + * This data structure must be zero-initialized.
22 + */
23 struct decoration {
24 + /*
25 + * Not used by the decoration mechanism. Clients may use this for
26 + * whatever they want.
27 + */
28 const char *name;
11 - unsigned int size, nr;
12 - struct object_decoration *hash;
29 +
30 + /*
31 + * The capacity of "entries".
32 + */
33 + unsigned int size;
34 +
35 + /*
36 + * The number of real Git objects (that is, entries with non-NULL
37 + * "base").
38 + */
39 + unsigned int nr;
40 +
41 + /*
42 + * The entries. This is an array of size "size", containing nr entries
43 + * with non-NULL "base" and (size - nr) entries with NULL "base".
44 + */
45 + struct decoration_entry *entries;
46 };
47
48 +/*
49 + * Add an association from the given object to the given pointer (which may be
50 + * NULL), returning the previously associated pointer. If there is no previous
51 + * association, this function returns NULL.
52 + */
53 extern void *add_decoration(struct decoration *n, const struct object *obj, void *decoration);
54 +
55 +/*
56 + * Return the pointer associated to the given object. If there is no
57 + * association, this function returns NULL.
58 + */
59 extern void *lookup_decoration(struct decoration *n, const struct object *obj);
60
61 #endif
t/helper/.gitignore
+1
@@ -8,6 +8,7 @@
8 /test-dump-fsmonitor
9 /test-dump-split-index
10 /test-dump-untracked-cache
11 +/test-example-decorate
12 /test-fake-ssh
13 /test-scrap-cache-tree
14 /test-genrandom
t/helper/test-example-decorate.c new
+74
@@ -0,0 +1,74 @@
1 +#include "cache.h"
2 +#include "object.h"
3 +#include "decorate.h"
4 +
5 +int cmd_main(int argc, const char **argv)
6 +{
7 + struct decoration n;
8 + struct object_id one_oid = { {1} };
9 + struct object_id two_oid = { {2} };
10 + struct object_id three_oid = { {3} };
11 + struct object *one, *two, *three;
12 +
13 + int decoration_a, decoration_b;
14 +
15 + void *ret;
16 +
17 + int i, objects_noticed = 0;
18 +
19 + /*
20 + * The struct must be zero-initialized.
21 + */
22 + memset(&n, 0, sizeof(n));
23 +
24 + /*
25 + * Add 2 objects, one with a non-NULL decoration and one with a NULL
26 + * decoration.
27 + */
28 + one = lookup_unknown_object(one_oid.hash);
29 + two = lookup_unknown_object(two_oid.hash);
30 + ret = add_decoration(&n, one, &decoration_a);
31 + if (ret)
32 + die("BUG: when adding a brand-new object, NULL should be returned");
33 + ret = add_decoration(&n, two, NULL);
34 + if (ret)
35 + die("BUG: when adding a brand-new object, NULL should be returned");
36 +
37 + /*
38 + * When re-adding an already existing object, the old decoration is
39 + * returned.
40 + */
41 + ret = add_decoration(&n, one, NULL);
42 + if (ret != &decoration_a)
43 + die("BUG: when readding an already existing object, existing decoration should be returned");
44 + ret = add_decoration(&n, two, &decoration_b);
45 + if (ret)
46 + die("BUG: when readding an already existing object, existing decoration should be returned");
47 +
48 + /*
49 + * Lookup returns the added declarations, or NULL if the object was
50 + * never added.
51 + */
52 + ret = lookup_decoration(&n, one);
53 + if (ret)
54 + die("BUG: lookup should return added declaration");
55 + ret = lookup_decoration(&n, two);
56 + if (ret != &decoration_b)
57 + die("BUG: lookup should return added declaration");
58 + three = lookup_unknown_object(three_oid.hash);
59 + ret = lookup_decoration(&n, three);
60 + if (ret)
61 + die("BUG: lookup for unknown object should return NULL");
62 +
63 + /*
64 + * The user can also loop through all entries.
65 + */
66 + for (i = 0; i < n.size; i++) {
67 + if (n.entries[i].base)
68 + objects_noticed++;
69 + }
70 + if (objects_noticed != 2)
71 + die("BUG: should have 2 objects");
72 +
73 + return 0;
74 +}
t/t9004-example.sh new
+10
@@ -0,0 +1,10 @@
1 +#!/bin/sh
2 +
3 +test_description='check that example code compiles and runs'
4 +. ./test-lib.sh
5 +
6 +test_expect_success 'decorate' '
7 + test-example-decorate
8 +'
9 +
10 +test_done