Skip to content

Commit 7860626

Browse files
arrbeeVicent Marti
authored andcommitted
Add callback to git_objects_table
This adds create and free callback to the git_objects_table so that more of the creation and destruction of objects can be table driven instead of using switch statements. This also makes the semantics of certain object creation functions consistent so that we can make better use of function pointers. This also fixes a theoretical error case where an object allocation fails and we end up storing NULL into the cache.
1 parent 917f60c commit 7860626

File tree

15 files changed

+128
-184
lines changed

15 files changed

+128
-184
lines changed

src/blob.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,17 @@ int git_blob__getbuf(git_buf *buffer, git_blob *blob)
3535
git_odb_object_size(blob->odb_object));
3636
}
3737

38-
void git_blob__free(git_blob *blob)
38+
void git_blob__free(void *blob)
3939
{
40-
git_odb_object_free(blob->odb_object);
40+
git_odb_object_free(((git_blob *)blob)->odb_object);
4141
git__free(blob);
4242
}
4343

44-
int git_blob__parse(git_blob *blob, git_odb_object *odb_obj)
44+
int git_blob__from_odb_object(void *blob, git_odb_object *odb_obj)
4545
{
4646
assert(blob);
4747
git_cached_obj_incref((git_cached_obj *)odb_obj);
48-
blob->odb_object = odb_obj;
48+
((git_blob *)blob)->odb_object = odb_obj;
4949
return 0;
5050
}
5151

src/blob.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ struct git_blob {
1717
git_odb_object *odb_object;
1818
};
1919

20-
void git_blob__free(git_blob *blob);
21-
int git_blob__parse(git_blob *blob, git_odb_object *obj);
20+
void git_blob__free(void *blob);
21+
int git_blob__from_odb_object(void *blob, git_odb_object *obj);
2222
int git_blob__getbuf(git_buf *buffer, git_blob *blob);
2323

2424
#endif

src/cache.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,6 @@ int git_cache_init(git_cache *cache)
7070
return 0;
7171
}
7272

73-
void git_cache_free(git_cache *cache)
74-
{
75-
git_oidmap_free(cache->map);
76-
git_mutex_free(&cache->lock);
77-
}
78-
7973
void git_cache_clear(git_cache *cache)
8074
{
8175
git_cached_obj *evict = NULL;
@@ -93,6 +87,14 @@ void git_cache_clear(git_cache *cache)
9387
git_mutex_unlock(&cache->lock);
9488
}
9589

90+
void git_cache_free(git_cache *cache)
91+
{
92+
git_cache_clear(cache);
93+
94+
git_oidmap_free(cache->map);
95+
git_mutex_free(&cache->lock);
96+
}
97+
9698
/* Call with lock, yo */
9799
static void cache_evict_entries(git_cache *cache, size_t evict_count)
98100
{

src/cache.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,17 @@ enum {
2121
};
2222

2323
typedef struct {
24-
git_oid oid;
25-
int16_t type;
26-
uint16_t flags;
27-
size_t size;
24+
git_oid oid;
25+
int16_t type; /* git_otype value */
26+
uint16_t flags; /* GIT_CACHE_STORE value */
27+
size_t size;
2828
git_atomic refcount;
2929
} git_cached_obj;
3030

3131
typedef struct {
3232
git_oidmap *map;
33-
git_mutex lock;
34-
size_t used_memory;
33+
git_mutex lock;
34+
size_t used_memory;
3535
} git_cache;
3636

3737
extern bool git_cache__enabled;

src/commit.c

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ static void clear_parents(git_commit *commit)
3131
git_vector_clear(&commit->parent_ids);
3232
}
3333

34-
void git_commit__free(git_commit *commit)
34+
void git_commit__free(void *_commit)
3535
{
36+
git_commit *commit = _commit;
37+
3638
clear_parents(commit);
3739
git_vector_free(&commit->parent_ids);
3840

@@ -166,10 +168,9 @@ int git_commit_create(
166168
return retval;
167169
}
168170

169-
int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len)
171+
int git_commit__parse(void *_commit, const char *buffer, const char *buffer_end)
170172
{
171-
const char *buffer = data;
172-
const char *buffer_end = (const char *)data + len;
173+
git_commit *commit = _commit;
173174
git_oid parent_id;
174175

175176
if (git_vector_init(&commit->parent_ids, 4, NULL) < 0)
@@ -241,13 +242,6 @@ int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len)
241242
return -1;
242243
}
243244

244-
int git_commit__parse(git_commit *commit, git_odb_object *obj)
245-
{
246-
assert(commit);
247-
return git_commit__parse_buffer(
248-
commit, git_odb_object_data(obj), git_odb_object_size(obj));
249-
}
250-
251245
#define GIT_COMMIT_GETTER(_rvalue, _name, _return) \
252246
_rvalue git_commit_##_name(const git_commit *commit) \
253247
{\

src/commit.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ struct git_commit {
2727
char *message;
2828
};
2929

30-
void git_commit__free(git_commit *c);
31-
int git_commit__parse(git_commit *commit, git_odb_object *obj);
30+
void git_commit__free(void *commit);
31+
int git_commit__parse(void *commit, const char *buf, const char *bufend);
3232

33-
int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len);
3433
#endif

src/object.c

Lines changed: 52 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -18,117 +18,105 @@
1818

1919
static const int OBJECT_BASE_SIZE = 4096;
2020

21-
static struct {
21+
typedef struct {
2222
const char *str; /* type name string */
23-
int loose; /* valid loose object type flag */
2423
size_t size; /* size in bytes of the object structure */
25-
} git_objects_table[] = {
24+
25+
int (*from_odb)(void *self, git_odb_object *obj);
26+
int (*parse)(void *self, const char *buf, const char *buf_end);
27+
void (*free)(void *self);
28+
} git_object_def;
29+
30+
static git_object_def git_objects_table[] = {
2631
/* 0 = GIT_OBJ__EXT1 */
27-
{ "", 0, 0},
32+
{ "", 0, NULL, NULL, NULL },
2833

2934
/* 1 = GIT_OBJ_COMMIT */
30-
{ "commit", 1, sizeof(struct git_commit)},
35+
{ "commit", sizeof(git_commit), NULL, git_commit__parse, git_commit__free },
3136

3237
/* 2 = GIT_OBJ_TREE */
33-
{ "tree", 1, sizeof(struct git_tree) },
38+
{ "tree", sizeof(git_tree), NULL, git_tree__parse, git_tree__free },
3439

3540
/* 3 = GIT_OBJ_BLOB */
36-
{ "blob", 1, sizeof(struct git_blob) },
41+
{ "blob", sizeof(git_blob), git_blob__from_odb_object, NULL, git_blob__free },
3742

3843
/* 4 = GIT_OBJ_TAG */
39-
{ "tag", 1, sizeof(struct git_tag) },
44+
{ "tag", sizeof(git_tag), NULL, git_tag__parse, git_tag__free },
4045

4146
/* 5 = GIT_OBJ__EXT2 */
42-
{ "", 0, 0 },
43-
47+
{ "", 0, NULL, NULL, NULL },
4448
/* 6 = GIT_OBJ_OFS_DELTA */
45-
{ "OFS_DELTA", 0, 0 },
46-
49+
{ "OFS_DELTA", 0, NULL, NULL, NULL },
4750
/* 7 = GIT_OBJ_REF_DELTA */
48-
{ "REF_DELTA", 0, 0 }
51+
{ "REF_DELTA", 0, NULL, NULL, NULL },
4952
};
5053

51-
static int create_object(git_object **object_out, git_otype type)
52-
{
53-
git_object *object = NULL;
54-
55-
assert(object_out);
56-
57-
*object_out = NULL;
58-
59-
switch (type) {
60-
case GIT_OBJ_COMMIT:
61-
case GIT_OBJ_TAG:
62-
case GIT_OBJ_BLOB:
63-
case GIT_OBJ_TREE:
64-
object = git__malloc(git_object__size(type));
65-
GITERR_CHECK_ALLOC(object);
66-
memset(object, 0x0, git_object__size(type));
67-
break;
68-
69-
default:
70-
giterr_set(GITERR_INVALID, "The given type is invalid");
71-
return -1;
72-
}
73-
74-
*object_out = object;
75-
return 0;
76-
}
77-
7854
int git_object__from_odb_object(
7955
git_object **object_out,
8056
git_repository *repo,
8157
git_odb_object *odb_obj,
8258
git_otype type)
8359
{
8460
int error;
61+
size_t object_size;
62+
git_object_def *def;
8563
git_object *object = NULL;
8664

65+
assert(object_out);
66+
*object_out = NULL;
67+
68+
/* Validate type match */
8769
if (type != GIT_OBJ_ANY && type != odb_obj->cached.type) {
8870
giterr_set(GITERR_INVALID,
8971
"The requested type does not match the type in the ODB");
9072
return GIT_ENOTFOUND;
9173
}
9274

93-
if ((error = create_object(&object, odb_obj->cached.type)) < 0)
94-
return error;
75+
if ((object_size = git_object__size(odb_obj->cached.type)) == 0) {
76+
giterr_set(GITERR_INVALID, "The requested type is invalid");
77+
return GIT_ENOTFOUND;
78+
}
79+
80+
/* Allocate and initialize base object */
81+
object = git__calloc(1, object_size);
82+
GITERR_CHECK_ALLOC(object);
9583

96-
/* Initialize parent object */
9784
git_oid_cpy(&object->cached.oid, &odb_obj->cached.oid);
98-
object->cached.size = odb_obj->cached.size;
9985
object->cached.type = odb_obj->cached.type;
86+
object->cached.size = odb_obj->cached.size;
10087
object->repo = repo;
10188

102-
switch (object->cached.type) {
103-
case GIT_OBJ_COMMIT:
104-
error = git_commit__parse((git_commit *)object, odb_obj);
105-
break;
106-
107-
case GIT_OBJ_TREE:
108-
error = git_tree__parse((git_tree *)object, odb_obj);
109-
break;
110-
111-
case GIT_OBJ_TAG:
112-
error = git_tag__parse((git_tag *)object, odb_obj);
113-
break;
89+
/* Parse raw object data */
90+
def = &git_objects_table[odb_obj->cached.type];
91+
assert(def->free && (def->from_odb || def->parse));
11492

115-
case GIT_OBJ_BLOB:
116-
error = git_blob__parse((git_blob *)object, odb_obj);
117-
break;
118-
119-
default:
120-
break;
93+
if (def->from_odb) {
94+
error = def->from_odb(object, odb_obj);
95+
} else {
96+
const char *data = (const char *)git_odb_object_data(odb_obj);
97+
error = def->parse(object, data, data + git_odb_object_size(odb_obj));
12198
}
12299

123100
if (error < 0) {
124-
git_object__free(object);
101+
def->free(object);
125102
return error;
126103
}
127104

128105
*object_out = git_cache_store_parsed(&repo->objects, object);
129106
return 0;
130107
}
131108

109+
void git_object__free(void *obj)
110+
{
111+
git_otype type = ((git_object *)obj)->cached.type;
112+
113+
if (type < 0 || ((size_t)type) >= ARRAY_SIZE(git_objects_table) ||
114+
!git_objects_table[type].free)
115+
git__free(obj);
116+
else
117+
git_objects_table[type].free(obj);
118+
}
119+
132120
int git_object_lookup_prefix(
133121
git_object **object_out,
134122
git_repository *repo,
@@ -222,35 +210,6 @@ int git_object_lookup(git_object **object_out, git_repository *repo, const git_o
222210
return git_object_lookup_prefix(object_out, repo, id, GIT_OID_HEXSZ, type);
223211
}
224212

225-
void git_object__free(void *_obj)
226-
{
227-
git_object *object = (git_object *)_obj;
228-
229-
assert(object);
230-
231-
switch (object->cached.type) {
232-
case GIT_OBJ_COMMIT:
233-
git_commit__free((git_commit *)object);
234-
break;
235-
236-
case GIT_OBJ_TREE:
237-
git_tree__free((git_tree *)object);
238-
break;
239-
240-
case GIT_OBJ_TAG:
241-
git_tag__free((git_tag *)object);
242-
break;
243-
244-
case GIT_OBJ_BLOB:
245-
git_blob__free((git_blob *)object);
246-
break;
247-
248-
default:
249-
git__free(object);
250-
break;
251-
}
252-
}
253-
254213
void git_object_free(git_object *object)
255214
{
256215
if (object == NULL)
@@ -304,7 +263,7 @@ int git_object_typeisloose(git_otype type)
304263
if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table))
305264
return 0;
306265

307-
return git_objects_table[type].loose;
266+
return (git_objects_table[type].size > 0) ? 1 : 0;
308267
}
309268

310269
size_t git_object__size(git_otype type)

0 commit comments

Comments
 (0)