decorate: clean up and document API
authorJonathan Tan <jonathantanmy@google.com>
Fri, 8 Dec 2017 00:14:24 +0000 (16:14 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 8 Dec 2017 17:16:27 +0000 (09:16 -0800)
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>
Documentation/technical/api-decorate.txt [deleted file]
Makefile
builtin/fast-export.c
decorate.c
decorate.h
t/helper/.gitignore
t/helper/test-example-decorate.c [new file with mode: 0644]
t/t9004-example.sh [new file with mode: 0755]
diff --git a/Documentation/technical/api-decorate.txt b/Documentation/technical/api-decorate.txt
deleted file mode 100644 (file)
index 1d52a6c..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-decorate API
-============
-
-Talk about <decorate.h>
-
-(Linus)
index fef9c8d2725d6806d9ef4516de64c6d68bd7a7fe..df52cc1c3907ad33c23aed9eae508ac84488a659 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -651,6 +651,7 @@ TEST_PROGRAMS_NEED_X += test-dump-cache-tree
 TEST_PROGRAMS_NEED_X += test-dump-fsmonitor
 TEST_PROGRAMS_NEED_X += test-dump-split-index
 TEST_PROGRAMS_NEED_X += test-dump-untracked-cache
+TEST_PROGRAMS_NEED_X += test-example-decorate
 TEST_PROGRAMS_NEED_X += test-fake-ssh
 TEST_PROGRAMS_NEED_X += test-genrandom
 TEST_PROGRAMS_NEED_X += test-hashmap
index f8fe04ca5332541213dc059dd02fdf09e0c6cf85..796d0cd66c7750a20613dea77cd75b1b8e7665a4 100644 (file)
@@ -895,7 +895,7 @@ static void export_marks(char *file)
 {
        unsigned int i;
        uint32_t mark;
-       struct object_decoration *deco = idnums.hash;
+       struct decoration_entry *deco = idnums.entries;
        FILE *f;
        int e = 0;
 
index 270eb2519764f1378fe53352021cd7afb3ea306a..de31331fa425429cf3c05078761b9bcf52fb0a45 100644 (file)
@@ -14,20 +14,20 @@ static unsigned int hash_obj(const struct object *obj, unsigned int n)
 static void *insert_decoration(struct decoration *n, const struct object *base, void *decoration)
 {
        int size = n->size;
-       struct object_decoration *hash = n->hash;
+       struct decoration_entry *entries = n->entries;
        unsigned int j = hash_obj(base, size);
 
-       while (hash[j].base) {
-               if (hash[j].base == base) {
-                       void *old = hash[j].decoration;
-                       hash[j].decoration = decoration;
+       while (entries[j].base) {
+               if (entries[j].base == base) {
+                       void *old = entries[j].decoration;
+                       entries[j].decoration = decoration;
                        return old;
                }
                if (++j >= size)
                        j = 0;
        }
-       hash[j].base = base;
-       hash[j].decoration = decoration;
+       entries[j].base = base;
+       entries[j].decoration = decoration;
        n->nr++;
        return NULL;
 }
@@ -36,24 +36,23 @@ static void grow_decoration(struct decoration *n)
 {
        int i;
        int old_size = n->size;
-       struct object_decoration *old_hash = n->hash;
+       struct decoration_entry *old_entries = n->entries;
 
        n->size = (old_size + 1000) * 3 / 2;
-       n->hash = xcalloc(n->size, sizeof(struct object_decoration));
+       n->entries = xcalloc(n->size, sizeof(struct decoration_entry));
        n->nr = 0;
 
        for (i = 0; i < old_size; i++) {
-               const struct object *base = old_hash[i].base;
-               void *decoration = old_hash[i].decoration;
+               const struct object *base = old_entries[i].base;
+               void *decoration = old_entries[i].decoration;
 
                if (!decoration)
                        continue;
                insert_decoration(n, base, decoration);
        }
-       free(old_hash);
+       free(old_entries);
 }
 
-/* Add a decoration pointer, return any old one */
 void *add_decoration(struct decoration *n, const struct object *obj,
                void *decoration)
 {
@@ -64,7 +63,6 @@ void *add_decoration(struct decoration *n, const struct object *obj,
        return insert_decoration(n, obj, decoration);
 }
 
-/* Lookup a decoration pointer */
 void *lookup_decoration(struct decoration *n, const struct object *obj)
 {
        unsigned int j;
@@ -74,7 +72,7 @@ void *lookup_decoration(struct decoration *n, const struct object *obj)
                return NULL;
        j = hash_obj(obj, n->size);
        for (;;) {
-               struct object_decoration *ref = n->hash + j;
+               struct decoration_entry *ref = n->entries + j;
                if (ref->base == obj)
                        return ref->decoration;
                if (!ref->base)
index e7328044ff84a4acaaa7f5f4bc5f85375dc7a07a..9014c1e996c60d9b3e1bd27ffa01b9c2d0c8ae80 100644 (file)
@@ -1,18 +1,61 @@
 #ifndef DECORATE_H
 #define DECORATE_H
 
-struct object_decoration {
+/*
+ * A data structure that associates Git objects to void pointers. See
+ * t/helper/test-example-decorate.c for a demonstration of how to use these
+ * functions.
+ */
+
+/*
+ * An entry in the data structure.
+ */
+struct decoration_entry {
        const struct object *base;
        void *decoration;
 };
 
+/*
+ * The data structure.
+ *
+ * This data structure must be zero-initialized.
+ */
 struct decoration {
+       /*
+        * Not used by the decoration mechanism. Clients may use this for
+        * whatever they want.
+        */
        const char *name;
-       unsigned int size, nr;
-       struct object_decoration *hash;
+
+       /*
+        * The capacity of "entries".
+        */
+       unsigned int size;
+
+       /*
+        * The number of real Git objects (that is, entries with non-NULL
+        * "base").
+        */
+       unsigned int nr;
+
+       /*
+        * The entries. This is an array of size "size", containing nr entries
+        * with non-NULL "base" and (size - nr) entries with NULL "base".
+        */
+       struct decoration_entry *entries;
 };
 
+/*
+ * Add an association from the given object to the given pointer (which may be
+ * NULL), returning the previously associated pointer. If there is no previous
+ * association, this function returns NULL.
+ */
 extern void *add_decoration(struct decoration *n, const struct object *obj, void *decoration);
+
+/*
+ * Return the pointer associated to the given object. If there is no
+ * association, this function returns NULL.
+ */
 extern void *lookup_decoration(struct decoration *n, const struct object *obj);
 
 #endif
index d02f9b39ac3630ab6ebfc1ee0f7f266c19f93a0c..fff6aef226f4fe5bbb138c77b81bc22300783cd4 100644 (file)
@@ -8,6 +8,7 @@
 /test-dump-fsmonitor
 /test-dump-split-index
 /test-dump-untracked-cache
+/test-example-decorate
 /test-fake-ssh
 /test-scrap-cache-tree
 /test-genrandom
diff --git a/t/helper/test-example-decorate.c b/t/helper/test-example-decorate.c
new file mode 100644 (file)
index 0000000..90dc97a
--- /dev/null
@@ -0,0 +1,74 @@
+#include "cache.h"
+#include "object.h"
+#include "decorate.h"
+
+int cmd_main(int argc, const char **argv)
+{
+       struct decoration n;
+       struct object_id one_oid = { {1} };
+       struct object_id two_oid = { {2} };
+       struct object_id three_oid = { {3} };
+       struct object *one, *two, *three;
+
+       int decoration_a, decoration_b;
+
+       void *ret;
+
+       int i, objects_noticed = 0;
+
+       /*
+        * The struct must be zero-initialized.
+        */
+       memset(&n, 0, sizeof(n));
+
+       /*
+        * Add 2 objects, one with a non-NULL decoration and one with a NULL
+        * decoration.
+        */
+       one = lookup_unknown_object(one_oid.hash);
+       two = lookup_unknown_object(two_oid.hash);
+       ret = add_decoration(&n, one, &decoration_a);
+       if (ret)
+               die("BUG: when adding a brand-new object, NULL should be returned");
+       ret = add_decoration(&n, two, NULL);
+       if (ret)
+               die("BUG: when adding a brand-new object, NULL should be returned");
+
+       /*
+        * When re-adding an already existing object, the old decoration is
+        * returned.
+        */
+       ret = add_decoration(&n, one, NULL);
+       if (ret != &decoration_a)
+               die("BUG: when readding an already existing object, existing decoration should be returned");
+       ret = add_decoration(&n, two, &decoration_b);
+       if (ret)
+               die("BUG: when readding an already existing object, existing decoration should be returned");
+
+       /*
+        * Lookup returns the added declarations, or NULL if the object was
+        * never added.
+        */
+       ret = lookup_decoration(&n, one);
+       if (ret)
+               die("BUG: lookup should return added declaration");
+       ret = lookup_decoration(&n, two);
+       if (ret != &decoration_b)
+               die("BUG: lookup should return added declaration");
+       three = lookup_unknown_object(three_oid.hash);
+       ret = lookup_decoration(&n, three);
+       if (ret)
+               die("BUG: lookup for unknown object should return NULL");
+
+       /*
+        * The user can also loop through all entries.
+        */
+       for (i = 0; i < n.size; i++) {
+               if (n.entries[i].base)
+                       objects_noticed++;
+       }
+       if (objects_noticed != 2)
+               die("BUG: should have 2 objects");
+
+       return 0;
+}
diff --git a/t/t9004-example.sh b/t/t9004-example.sh
new file mode 100755 (executable)
index 0000000..b28a028
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+test_description='check that example code compiles and runs'
+. ./test-lib.sh
+
+test_expect_success 'decorate' '
+       test-example-decorate
+'
+
+test_done