X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=object.c;h=78a44a6ef4e4823487861c9173f3db4a3fb76e3a;hb=95655d79ad13697e0d68e986d3b0b402efad007a;hp=9adc87479bde2a0b2a0a0335aed12a9f485facff;hpb=5f625247ee64276a5ea51359c685be7ddefcfc59;p=git.git diff --git a/object.c b/object.c index 9adc87479..78a44a6ef 100644 --- a/object.c +++ b/object.c @@ -5,164 +5,119 @@ #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; -int track_object_refs = 0; - -static int hashtable_index(const unsigned char *sha1) +unsigned int get_max_object_index(void) { - unsigned int i; - memcpy(&i, sha1, sizeof(unsigned int)); - return (int)(i % obj_allocs); + return obj_hash_size; } -static int find_object(const unsigned char *sha1) +struct object *get_indexed_object(unsigned int idx) { - int i; - - if (!objs) - return -1; - - i = hashtable_index(sha1); - while (objs[i]) { - if (memcmp(sha1, objs[i]->sha1, 20) == 0) - return i; - i++; - if (i == obj_allocs) - i = 0; - } - return -1 - i; + return obj_hash[idx]; } -struct object *lookup_object(const unsigned char *sha1) +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) { - int pos = find_object(sha1); - if (pos >= 0) - return objs[pos]; - return NULL; + if (type >= ARRAY_SIZE(object_type_strings)) + return NULL; + return object_type_strings[type]; } -void created_object(const unsigned char *sha1, struct object *obj) +int type_from_string(const char *str) { - int pos; - - obj->parsed = 0; - memcpy(obj->sha1, sha1, 20); - obj->type = NULL; - obj->refs = NULL; - obj->used = 0; - - 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; - } - } - } + int i; - pos = find_object(sha1); - if (pos >= 0) - die("Inserting %s twice\n", sha1_to_hex(sha1)); - pos = -pos-1; + 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); +} - objs[pos] = obj; - nr_objs++; +static unsigned int hash_obj(struct object *obj, unsigned int n) +{ + unsigned int hash = *(unsigned int *)obj->sha1; + return hash % n; } -struct object_refs *alloc_object_refs(unsigned count) +static void insert_obj_hash(struct object *obj, struct object **hash, unsigned int size) { - struct object_refs *refs; - size_t size = sizeof(*refs) + count*sizeof(struct object *); + int j = hash_obj(obj, size); - refs = xcalloc(1, size); - refs->count = count; - return refs; + while (hash[j]) { + j++; + if (j >= size) + j = 0; + } + hash[j] = obj; } -static int compare_object_pointers(const void *a, const void *b) +static int hashtable_index(const unsigned char *sha1) { - const struct object * const *pa = a; - const struct object * const *pb = b; - if (*pa == *pb) - return 0; - else if (*pa < *pb) - return -1; - else - return 1; + unsigned int i; + memcpy(&i, sha1, sizeof(unsigned int)); + return (int)(i % obj_hash_size); } -void set_object_refs(struct object *obj, struct object_refs *refs) +struct object *lookup_object(const unsigned char *sha1) { - unsigned int i, j; + int i; + struct object *obj; - /* Do not install empty list of references */ - if (refs->count < 1) { - free(refs); - return; - } + if (!obj_hash) + return NULL; - /* Sort the list and filter out duplicates */ - qsort(refs->ref, refs->count, sizeof(refs->ref[0]), - compare_object_pointers); - for (i = j = 1; i < refs->count; i++) { - if (refs->ref[i] != refs->ref[i - 1]) - refs->ref[j++] = refs->ref[i]; - } - if (j < refs->count) { - /* Duplicates were found - reallocate list */ - size_t size = sizeof(*refs) + j*sizeof(struct object *); - refs->count = j; - refs = xrealloc(refs, size); + i = hashtable_index(sha1); + while ((obj = obj_hash[i]) != NULL) { + if (!hashcmp(sha1, obj->sha1)) + break; + i++; + if (i == obj_hash_size) + i = 0; } - - for (i = 0; i < refs->count; i++) - refs->ref[i]->used = 1; - obj->refs = refs; + return obj; } -void mark_reachable(struct object *obj, unsigned int mask) +static void grow_object_hash(void) { - if (!track_object_refs) - die("cannot do reachability with object refs turned off"); - /* If we've been here already, don't bother */ - if (obj->flags & mask) - return; - obj->flags |= mask; - if (obj->refs) { - const struct object_refs *refs = obj->refs; - unsigned i; - for (i = 0; i < refs->count; i++) - mark_reachable(refs->ref[i], mask); + 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; } -struct object *lookup_object_type(const unsigned char *sha1, const char *type) +void created_object(const unsigned char *sha1, struct object *obj) { - 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; - } + obj->parsed = 0; + obj->used = 0; + obj->type = OBJ_NONE; + obj->flags = 0; + hashcpy(obj->sha1, sha1); + + if (obj_hash_size - 1 <= nr_objs * 2) + grow_object_hash(); + + insert_obj_hash(obj, obj_hash, obj_hash_size); + nr_objs++; } union any_object { @@ -179,48 +134,64 @@ 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 = NULL; + 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) - 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; + if (check_sha1_signature(sha1, buffer, size, typename(type)) < 0) { + error("sha1 mismatch %s\n", sha1_to_hex(sha1)); + return NULL; } - free(buffer); + + obj = parse_object_buffer(sha1, type, size, buffer, &eaten); + if (!eaten) + free(buffer); return obj; } return NULL; @@ -266,3 +237,20 @@ int object_list_contains(struct object_list *list, struct object *obj) } return 0; } + +void add_object_array(struct object *obj, const char *name, struct object_array *array) +{ + unsigned nr = array->nr; + unsigned alloc = array->alloc; + struct object_array_entry *objects = array->objects; + + if (nr >= alloc) { + alloc = (alloc + 32) * 2; + objects = xrealloc(objects, alloc * sizeof(*objects)); + array->alloc = alloc; + array->objects = objects; + } + objects[nr].item = obj; + objects[nr].name = name; + array->nr = ++nr; +}