{"thread":{"id":"7701","subject":"[PATCH 1/2] Add a generic \"object decorator\" interface, and make object refs use it","startedAt":"2007-04-16T23:03:15Z","lastAt":"2007-04-16T23:05:10Z","messageCount":2,"participants":["Linus Torvalds"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"39578","messageId":"Pine.LNX.4.64.0704161600470.5473@woody.linux-foundation.org","threadId":"7701","inReplyTo":null,"subject":"[PATCH 1/2] Add a generic \"object decorator\" interface, and make object refs use it","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2007-04-16T23:03:15Z","receivedAt":"2007-04-16T23:03:15Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nThis allows you to add an arbitrary \"decoration\" of your choice to any\nobject.  It's a space- and time-efficient way to add information to\narbitrary objects, especially if most objects probably do not have the\ndecoration.\n\nSigned-off-by: Linus Torvalds <torvalds@linux-foundation.org>\n---\n\nThis shouldn't change any behaviour, just re-implements the object-refs \nhashing as a new generic \"decorator\".\n\n Makefile      |    4 +-\n decorate.c    |   89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n decorate.h    |   18 +++++++++++\n object-refs.c |   69 ++++---------------------------------------\n object.h      |    1 -\n 5 files changed, 116 insertions(+), 65 deletions(-)\n create mode 100644 decorate.c\n create mode 100644 decorate.h\n\ndiff --git a/Makefile b/Makefile\nindex b8e6030..251fc31 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -283,7 +283,7 @@ LIB_H = \\\n \tdiff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \\\n \trun-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \\\n \ttree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \\\n-\tutf8.h reflog-walk.h patch-ids.h\n+\tutf8.h reflog-walk.h patch-ids.h decorate.h\n \n DIFF_OBJS = \\\n \tdiff.o diff-lib.o diffcore-break.o diffcore-order.o \\\n@@ -305,7 +305,7 @@ LIB_OBJS = \\\n \twrite_or_die.o trace.o list-objects.o grep.o match-trees.o \\\n \talloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \\\n \tcolor.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \\\n-\tconvert.o\n+\tconvert.o decorate.o\n \n BUILTIN_OBJS = \\\n \tbuiltin-add.o \\\ndiff --git a/decorate.c b/decorate.c\nnew file mode 100644\nindex 0000000..721bcd1\n--- /dev/null\n+++ b/decorate.c\n@@ -0,0 +1,89 @@\n+/*\n+ * decorate.c - decorate a git object with some arbitrary\n+ * data.\n+ */\n+#include \"cache.h\"\n+#include \"object.h\"\n+#include \"decorate.h\"\n+\n+static unsigned int hash_obj(struct object *obj, unsigned int n)\n+{\n+\tunsigned int hash = *(unsigned int *)obj->sha1;\n+\treturn hash % n;\n+}\n+\n+static void *insert_decoration(struct decoration *n, struct object *base, void *decoration)\n+{\n+\tint size = n->size;\n+\tstruct object_decoration *hash = n->hash;\n+\tint j = hash_obj(base, size);\n+\n+\twhile (hash[j].base) {\n+\t\tif (hash[j].base == base) {\n+\t\t\tvoid *old = hash[j].decoration;\n+\t\t\thash[j].decoration = decoration;\n+\t\t\treturn old;\n+\t\t}\n+\t\tj++;\n+\t\tif (++j >= size)\n+\t\t\tj = 0;\n+\t}\n+\thash[j].base = base;\n+\thash[j].decoration = decoration;\n+\tn->nr++;\n+\treturn NULL;\n+}\n+\n+static void grow_decoration(struct decoration *n)\n+{\n+\tint i;\n+\tint old_size = n->size;\n+\tstruct object_decoration *old_hash;\n+\n+\told_size = n->size;\n+\told_hash = n->hash;\n+\t\n+\tn->size = (old_size + 1000) * 3 / 2;\n+\tn->hash = xcalloc(n->size, sizeof(struct object_decoration));\n+\tn->nr = 0;\n+\t\n+\tfor (i = 0; i < old_size; i++) {\n+\t\tstruct object *base = old_hash[i].base;\n+\t\tvoid *decoration = old_hash[i].decoration;\n+\n+\t\tif (!base)\n+\t\t\tcontinue;\n+\t\tinsert_decoration(n, base, decoration);\n+\t}\n+\tfree(old_hash);\n+}\n+\n+/* Add a decoration pointer, return any old one */\n+void *add_decoration(struct decoration *n, struct object *obj, void *decoration)\n+{\n+\tint nr = n->nr + 1;\n+\n+\tif (nr > n->size * 2 / 3)\n+\t\tgrow_decoration(n);\n+\treturn insert_decoration(n, obj, decoration);\n+}\n+\n+/* Lookup a decoration pointer */\n+void *lookup_decoration(struct decoration *n, struct object *obj)\n+{\n+\tint j;\n+\n+\t/* nothing to lookup */\n+\tif (!n->size)\n+\t\treturn NULL;\n+\tj = hash_obj(obj, n->size);\n+\tfor (;;) {\n+\t\tstruct object_decoration *ref = n->hash + j;\n+\t\tif (ref->base == obj)\n+\t\t\treturn ref->decoration;\n+\t\tif (!ref->base)\n+\t\t\treturn NULL;\n+\t\tif (++j == n->size)\n+\t\t\tj = 0;\n+\t}\n+}\ndiff --git a/decorate.h b/decorate.h\nnew file mode 100644\nindex 0000000..1fa4ad9\n--- /dev/null\n+++ b/decorate.h\n@@ -0,0 +1,18 @@\n+#ifndef DECORATE_H\n+#define DECORATE_H\n+\n+struct object_decoration {\n+\tstruct object *base;\n+\tvoid *decoration;\n+};\n+\n+struct decoration {\n+\tconst char *name;\n+\tunsigned int size, nr;\n+\tstruct object_decoration *hash;\n+};\n+\n+extern void *add_decoration(struct decoration *n, struct object *obj, void *decoration);\n+extern void *lookup_decoration(struct decoration *n, struct object *obj);\n+\n+#endif\ndiff --git a/object-refs.c b/object-refs.c\nindex 98ea100..022e8d8 100644\n--- a/object-refs.c\n+++ b/object-refs.c\n@@ -1,75 +1,20 @@\n #include \"cache.h\"\n #include \"object.h\"\n+#include \"decorate.h\"\n \n int track_object_refs = 0;\n \n-static unsigned int refs_hash_size, nr_object_refs;\n-static struct object_refs **refs_hash;\n+static struct decoration ref_decorate;\n \n-static unsigned int hash_obj(struct object *obj, unsigned int n)\n+struct object_refs *lookup_object_refs(struct object *base)\n {\n-\tunsigned int hash = *(unsigned int *)obj->sha1;\n-\treturn hash % n;\n+\treturn lookup_decoration(&ref_decorate, base);\n }\n \n-static void insert_ref_hash(struct object_refs *ref, struct object_refs **hash, unsigned int size)\n+static void add_object_refs(struct object *obj, struct object_refs *refs)\n {\n-\tint j = hash_obj(ref->base, size);\n-\n-\twhile (hash[j]) {\n-\t\tj++;\n-\t\tif (j >= size)\n-\t\t\tj = 0;\n-\t}\n-\thash[j] = ref;\n-}\n-\n-static void grow_refs_hash(void)\n-{\n-\tint i;\n-\tint new_hash_size = (refs_hash_size + 1000) * 3 / 2;\n-\tstruct object_refs **new_hash;\n-\n-\tnew_hash = xcalloc(new_hash_size, sizeof(struct object_refs *));\n-\tfor (i = 0; i < refs_hash_size; i++) {\n-\t\tstruct object_refs *ref = refs_hash[i];\n-\t\tif (!ref)\n-\t\t\tcontinue;\n-\t\tinsert_ref_hash(ref, new_hash, new_hash_size);\n-\t}\n-\tfree(refs_hash);\n-\trefs_hash = new_hash;\n-\trefs_hash_size = new_hash_size;\n-}\n-\n-static void add_object_refs(struct object *obj, struct object_refs *ref)\n-{\n-\tint nr = nr_object_refs + 1;\n-\n-\tif (nr > refs_hash_size * 2 / 3)\n-\t\tgrow_refs_hash();\n-\tref->base = obj;\n-\tinsert_ref_hash(ref, refs_hash, refs_hash_size);\n-\tnr_object_refs = nr;\n-}\n-\n-struct object_refs *lookup_object_refs(struct object *obj)\n-{\n-\tstruct object_refs *ref;\n-\tint j;\n-\n-\t/* nothing to lookup */\n-\tif (!refs_hash_size)\n-\t\treturn NULL;\n-\tj = hash_obj(obj, refs_hash_size);\n-\twhile ((ref = refs_hash[j]) != NULL) {\n-\t\tif (ref->base == obj)\n-\t\t\tbreak;\n-\t\tj++;\n-\t\tif (j >= refs_hash_size)\n-\t\t\tj = 0;\n-\t}\n-\treturn ref;\n+\tif (add_decoration(&ref_decorate, obj, refs))\n+\t\tdie(\"object %s tried to add refs twice!\", sha1_to_hex(obj->sha1));\n }\n \n struct object_refs *alloc_object_refs(unsigned count)\ndiff --git a/object.h b/object.h\nindex bdbf0fa..bdbbc18 100644\n--- a/object.h\n+++ b/object.h\n@@ -8,7 +8,6 @@ struct object_list {\n \n struct object_refs {\n \tunsigned count;\n-\tstruct object *base;\n \tstruct object *ref[FLEX_ARRAY]; /* more */\n };\n \n-- \n1.5.1.1.107.g7a15\n"},{"id":"39579","messageId":"Pine.LNX.4.64.0704161603220.5473@woody.linux-foundation.org","threadId":"7701","inReplyTo":"Pine.LNX.4.64.0704161600470.5473@woody.linux-foundation.org","subject":"[PATCH 2/2] Add support for \"commit name decorations\" to log family of commands","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2007-04-16T23:05:10Z","receivedAt":"2007-04-16T23:05:10Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nThis adds \"--decorate\" as a log option, which prints out the ref names \nof any commits that are shown.\n\nSigned-off-by: Linus Torvalds <torvalds@linux-foundation.org>\n---\n\nI'm not married to the exact format, but if people prefer some other \nsetup it should be easy to change. The code is fairly simple and obvious.\n\n builtin-log.c |   34 ++++++++++++++++++++++++++++++++--\n commit.h      |    8 ++++++++\n log-tree.c    |   21 +++++++++++++++++++++\n 3 files changed, 61 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin-log.c b/builtin-log.c\nindex 4699494..38bf52f 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -13,16 +13,43 @@\n #include \"tag.h\"\n #include \"reflog-walk.h\"\n #include \"patch-ids.h\"\n+#include \"refs.h\"\n \n static int default_show_root = 1;\n \n /* this is in builtin-diff.c */\n void add_head(struct rev_info *revs);\n \n+static void add_name_decoration(const char *prefix, const char *name, struct object *obj)\n+{\n+\tint plen = strlen(prefix);\n+\tint nlen = strlen(name);\n+\tstruct name_decoration *res = xmalloc(sizeof(struct name_decoration) + plen + nlen);\n+\tmemcpy(res->name, prefix, plen);\n+\tmemcpy(res->name + plen, name, nlen + 1);\n+\tres->next = add_decoration(&name_decoration, obj, res);\n+}\n+\n+static int add_ref_decoration(const char *refname, const unsigned char *sha1, int flags, void *cb_data)\n+{\n+\tstruct object *obj = parse_object(sha1);\n+\tif (!obj)\n+\t\treturn 0;\n+\tadd_name_decoration(\"\", refname, obj);\n+\twhile (obj->type == OBJ_TAG) {\n+\t\tobj = ((struct tag *)obj)->tagged;\n+\t\tif (!obj)\n+\t\t\tbreak;\n+\t\tadd_name_decoration(\"tag: \", refname, obj);\n+\t}\n+\treturn 0;\n+}\n+\n static void cmd_log_init(int argc, const char **argv, const char *prefix,\n \t\t      struct rev_info *rev)\n {\n \tint i;\n+\tint decorate = 0;\n \n \trev->abbrev = DEFAULT_ABBREV;\n \trev->commit_format = CMIT_FMT_DEFAULT;\n@@ -39,8 +66,11 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,\n \t\t\t\tgit_log_output_encoding = xstrdup(arg);\n \t\t\telse\n \t\t\t\tgit_log_output_encoding = \"\";\n-\t\t}\n-\t\telse\n+\t\t} else if (!strcmp(arg, \"--decorate\")) {\n+\t\t\tif (!decorate)\n+\t\t\t\tfor_each_ref(add_ref_decoration, NULL);\n+\t\t\tdecorate = 1;\n+\t\t} else\n \t\t\tdie(\"unrecognized argument: %s\", arg);\n \t}\n }\ndiff --git a/commit.h b/commit.h\nindex 83507a0..59de17e 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -3,6 +3,7 @@\n \n #include \"object.h\"\n #include \"tree.h\"\n+#include \"decorate.h\"\n \n struct commit_list {\n \tstruct commit *item;\n@@ -21,6 +22,13 @@ struct commit {\n extern int save_commit_buffer;\n extern const char *commit_type;\n \n+/* While we can decorate any object with a name, it's only used for commits.. */\n+extern struct decoration name_decoration;\n+struct name_decoration {\n+\tstruct name_decoration *next;\n+\tchar name[1];\n+};\n+\n struct commit *lookup_commit(const unsigned char *sha1);\n struct commit *lookup_commit_reference(const unsigned char *sha1);\n struct commit *lookup_commit_reference_gently(const unsigned char *sha1,\ndiff --git a/log-tree.c b/log-tree.c\nindex dad5513..300b733 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -4,6 +4,8 @@\n #include \"log-tree.h\"\n #include \"reflog-walk.h\"\n \n+struct decoration name_decoration = { \"object names\" };\n+\n static void show_parents(struct commit *commit, int abbrev)\n {\n \tstruct commit_list *p;\n@@ -13,6 +15,23 @@ static void show_parents(struct commit *commit, int abbrev)\n \t}\n }\n \n+static void show_decorations(struct commit *commit)\n+{\n+\tconst char *prefix;\n+\tstruct name_decoration *decoration;\n+\n+\tdecoration = lookup_decoration(&name_decoration, &commit->object);\n+\tif (!decoration)\n+\t\treturn;\n+\tprefix = \" (\";\n+\twhile (decoration) {\n+\t\tprintf(\"%s%s\", prefix, decoration->name);\n+\t\tprefix = \", \";\n+\t\tdecoration = decoration->next;\n+\t}\n+\tputchar(')');\n+}\n+\n /*\n  * Search for \"^[-A-Za-z]+: [^@]+@\" pattern. It usually matches\n  * Signed-off-by: and Acked-by: lines.\n@@ -136,6 +155,7 @@ void show_log(struct rev_info *opt, const char *sep)\n \t\tfputs(diff_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);\n \t\tif (opt->parents)\n \t\t\tshow_parents(commit, abbrev_commit);\n+\t\tshow_decorations(commit);\n \t\tputchar(opt->diffopt.line_termination);\n \t\treturn;\n \t}\n@@ -240,6 +260,7 @@ void show_log(struct rev_info *opt, const char *sep)\n \t\t\tprintf(\" (from %s)\",\n \t\t\t       diff_unique_abbrev(parent->object.sha1,\n \t\t\t\t\t\t  abbrev_commit));\n+\t\tshow_decorations(commit);\n \t\tprintf(\"%s\",\n \t\t       diff_get_color(opt->diffopt.color_diff, DIFF_RESET));\n \t\tputchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\\n');\n-- \n1.5.1.1.107.g7a15\n"}]}