X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=object.c;h=5b468893421794c50741ce9085c12bc41fb1985f;hb=723024d696a47556baac77700e47fef288691f37;hp=37784cee9a90a7e5b44dd660d6b7ea9191b59486;hpb=16bf4e1f1ed040ae9f745408d6585b7806a1bfb0;p=git.git diff --git a/object.c b/object.c index 37784cee9..5b4688934 100644 --- a/object.c +++ b/object.c @@ -5,100 +5,121 @@ #include "commit.h" #include "tag.h" -struct object **objs; -static int nr_objs; -int obj_allocs; +static struct object **obj_hash; +static int nr_objs, obj_hash_size; -const char *type_names[] = { - "none", "blob", "tree", "commit", "bad" +unsigned int get_max_object_index(void) +{ + return obj_hash_size; +} + +struct object *get_indexed_object(unsigned int idx) +{ + return obj_hash[idx]; +} + +static const char *object_type_strings[] = { + NULL, /* OBJ_NONE = 0 */ + "commit", /* OBJ_COMMIT = 1 */ + "tree", /* OBJ_TREE = 2 */ + "blob", /* OBJ_BLOB = 3 */ + "tag", /* OBJ_TAG = 4 */ }; +const char *typename(unsigned int type) +{ + if (type >= ARRAY_SIZE(object_type_strings)) + return NULL; + return object_type_strings[type]; +} + +int type_from_string(const char *str) +{ + int i; + + for (i = 1; i < ARRAY_SIZE(object_type_strings); i++) + if (!strcmp(str, object_type_strings[i])) + return i; + die("invalid object type \"%s\"", str); +} + +static unsigned int hash_obj(struct object *obj, unsigned int n) +{ + unsigned int hash = *(unsigned int *)obj->sha1; + return hash % n; +} + +static void insert_obj_hash(struct object *obj, struct object **hash, unsigned int size) +{ + int j = hash_obj(obj, size); + + while (hash[j]) { + j++; + if (j >= size) + j = 0; + } + hash[j] = obj; +} + static int hashtable_index(const unsigned char *sha1) { unsigned int i; memcpy(&i, sha1, sizeof(unsigned int)); - return (int)(i % obj_allocs); + return (int)(i % obj_hash_size); } -static int find_object(const unsigned char *sha1) +struct object *lookup_object(const unsigned char *sha1) { int i; + struct object *obj; - if (!objs) - return -1; + if (!obj_hash) + return NULL; i = hashtable_index(sha1); - while (objs[i]) { - if (memcmp(sha1, objs[i]->sha1, 20) == 0) - return i; + while ((obj = obj_hash[i]) != NULL) { + if (!hashcmp(sha1, obj->sha1)) + break; i++; - if (i == obj_allocs) + if (i == obj_hash_size) i = 0; } - return -1 - i; + return obj; } -struct object *lookup_object(const unsigned char *sha1) +static void grow_object_hash(void) { - int pos = find_object(sha1); - if (pos >= 0) - return objs[pos]; - return NULL; + int i; + int new_hash_size = obj_hash_size < 32 ? 32 : 2 * obj_hash_size; + struct object **new_hash; + + new_hash = xcalloc(new_hash_size, sizeof(struct object *)); + for (i = 0; i < obj_hash_size; i++) { + struct object *obj = obj_hash[i]; + if (!obj) + continue; + insert_obj_hash(obj, new_hash, new_hash_size); + } + free(obj_hash); + obj_hash = new_hash; + obj_hash_size = new_hash_size; } void created_object(const unsigned char *sha1, struct object *obj) { - int pos; - obj->parsed = 0; - memcpy(obj->sha1, sha1, 20); - obj->type = TYPE_NONE; obj->used = 0; + obj->type = OBJ_NONE; + obj->flags = 0; + hashcpy(obj->sha1, sha1); - if (obj_allocs - 1 <= nr_objs * 2) { - int i, count = obj_allocs; - obj_allocs = (obj_allocs < 32 ? 32 : 2 * obj_allocs); - objs = xrealloc(objs, obj_allocs * sizeof(struct object *)); - memset(objs + count, 0, (obj_allocs - count) - * sizeof(struct object *)); - for (i = 0; i < obj_allocs; i++) - if (objs[i]) { - int j = find_object(objs[i]->sha1); - if (j != i) { - j = -1 - j; - objs[j] = objs[i]; - objs[i] = NULL; - } - } - } - - pos = find_object(sha1); - if (pos >= 0) - die("Inserting %s twice\n", sha1_to_hex(sha1)); - pos = -pos-1; + if (obj_hash_size - 1 <= nr_objs * 2) + grow_object_hash(); - objs[pos] = obj; + insert_obj_hash(obj, obj_hash, obj_hash_size); nr_objs++; } -struct object *lookup_object_type(const unsigned char *sha1, const char *type) -{ - if (!type) { - return lookup_unknown_object(sha1); - } else if (!strcmp(type, blob_type)) { - return &lookup_blob(sha1)->object; - } else if (!strcmp(type, tree_type)) { - return &lookup_tree(sha1)->object; - } else if (!strcmp(type, commit_type)) { - return &lookup_commit(sha1)->object; - } else if (!strcmp(type, tag_type)) { - return &lookup_tag(sha1)->object; - } else { - error("Unknown type %s", type); - return NULL; - } -} - union any_object { struct object object; struct commit commit; @@ -113,48 +134,62 @@ struct object *lookup_unknown_object(const unsigned char *sha1) if (!obj) { union any_object *ret = xcalloc(1, sizeof(*ret)); created_object(sha1, &ret->object); - ret->object.type = TYPE_NONE; + ret->object.type = OBJ_NONE; return &ret->object; } return obj; } +struct object *parse_object_buffer(const unsigned char *sha1, enum object_type type, unsigned long size, void *buffer, int *eaten_p) +{ + struct object *obj; + int eaten = 0; + + if (type == OBJ_BLOB) { + struct blob *blob = lookup_blob(sha1); + parse_blob_buffer(blob, buffer, size); + obj = &blob->object; + } else if (type == OBJ_TREE) { + struct tree *tree = lookup_tree(sha1); + obj = &tree->object; + if (!tree->object.parsed) { + parse_tree_buffer(tree, buffer, size); + eaten = 1; + } + } else if (type == OBJ_COMMIT) { + struct commit *commit = lookup_commit(sha1); + parse_commit_buffer(commit, buffer, size); + if (!commit->buffer) { + commit->buffer = buffer; + eaten = 1; + } + obj = &commit->object; + } else if (type == OBJ_TAG) { + struct tag *tag = lookup_tag(sha1); + parse_tag_buffer(tag, buffer, size); + obj = &tag->object; + } else { + obj = NULL; + } + *eaten_p = eaten; + return obj; +} + struct object *parse_object(const unsigned char *sha1) { unsigned long size; - char type[20]; - void *buffer = read_sha1_file(sha1, type, &size); + enum object_type type; + int eaten; + void *buffer = read_sha1_file(sha1, &type, &size); + if (buffer) { struct object *obj; - if (check_sha1_signature(sha1, buffer, size, type) < 0) + if (check_sha1_signature(sha1, buffer, size, typename(type)) < 0) printf("sha1 mismatch %s\n", sha1_to_hex(sha1)); - if (!strcmp(type, blob_type)) { - struct blob *blob = lookup_blob(sha1); - parse_blob_buffer(blob, buffer, size); - obj = &blob->object; - } else if (!strcmp(type, tree_type)) { - struct tree *tree = lookup_tree(sha1); - obj = &tree->object; - if (!tree->object.parsed) { - parse_tree_buffer(tree, buffer, size); - buffer = NULL; - } - } else if (!strcmp(type, commit_type)) { - struct commit *commit = lookup_commit(sha1); - parse_commit_buffer(commit, buffer, size); - if (!commit->buffer) { - commit->buffer = buffer; - buffer = NULL; - } - obj = &commit->object; - } else if (!strcmp(type, tag_type)) { - struct tag *tag = lookup_tag(sha1); - parse_tag_buffer(tag, buffer, size); - obj = &tag->object; - } else { - obj = NULL; - } - free(buffer); + + obj = parse_object_buffer(sha1, type, size, buffer, &eaten); + if (!eaten) + free(buffer); return obj; } return NULL;