To avoid the penalty of having to branch in hash comparison functions, we'll want to always compare the full hash member in a struct object_id, which will require that SHA-1 object IDs be zero-padded. To do so, add a function which finalizes a hash context and writes it into an object ID that performs this padding. Move the definition of struct object_id and the constant definitions higher up so we they are available for us to use. Signed-off-by: brian m. carlson <sandals@xxxxxxxxxxxxxxxxxxxx> --- hash.h | 50 +++++++++++++++++++++++++++----------------------- object-file.c | 25 +++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/hash.h b/hash.h index dafdcb3335..c8f03d8aee 100644 --- a/hash.h +++ b/hash.h @@ -95,6 +95,29 @@ static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *s /* Number of algorithms supported (including unknown). */ #define GIT_HASH_NALGOS (GIT_HASH_SHA256 + 1) +/* The length in bytes and in hex digits of an object name (SHA-1 value). */ +#define GIT_SHA1_RAWSZ 20 +#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ) +/* The block size of SHA-1. */ +#define GIT_SHA1_BLKSZ 64 + +/* The length in bytes and in hex digits of an object name (SHA-256 value). */ +#define GIT_SHA256_RAWSZ 32 +#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ) +/* The block size of SHA-256. */ +#define GIT_SHA256_BLKSZ 64 + +/* The length in byte and in hex digits of the largest possible hash value. */ +#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ +#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ +/* The largest possible block size for any supported hash. */ +#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ + +struct object_id { + unsigned char hash[GIT_MAX_RAWSZ]; + int algo; +}; + /* A suitably aligned type for stack allocations of hash contexts. */ union git_hash_ctx { git_SHA_CTX sha1; @@ -106,6 +129,7 @@ typedef void (*git_hash_init_fn)(git_hash_ctx *ctx); typedef void (*git_hash_clone_fn)(git_hash_ctx *dst, const git_hash_ctx *src); typedef void (*git_hash_update_fn)(git_hash_ctx *ctx, const void *in, size_t len); typedef void (*git_hash_final_fn)(unsigned char *hash, git_hash_ctx *ctx); +typedef void (*git_hash_final_oid_fn)(struct object_id *oid, git_hash_ctx *ctx); struct git_hash_algo { /* @@ -138,6 +162,9 @@ struct git_hash_algo { /* The hash finalization function. */ git_hash_final_fn final_fn; + /* The hash finalization function for object IDs. */ + git_hash_final_oid_fn final_oid_fn; + /* The OID of the empty tree. */ const struct object_id *empty_tree; @@ -161,29 +188,6 @@ static inline int hash_algo_by_ptr(const struct git_hash_algo *p) return p - hash_algos; } -/* The length in bytes and in hex digits of an object name (SHA-1 value). */ -#define GIT_SHA1_RAWSZ 20 -#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ) -/* The block size of SHA-1. */ -#define GIT_SHA1_BLKSZ 64 - -/* The length in bytes and in hex digits of an object name (SHA-256 value). */ -#define GIT_SHA256_RAWSZ 32 -#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ) -/* The block size of SHA-256. */ -#define GIT_SHA256_BLKSZ 64 - -/* The length in byte and in hex digits of the largest possible hash value. */ -#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ -#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ -/* The largest possible block size for any supported hash. */ -#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ - -struct object_id { - unsigned char hash[GIT_MAX_RAWSZ]; - int algo; -}; - #define the_hash_algo the_repository->hash_algo extern const struct object_id null_oid; diff --git a/object-file.c b/object-file.c index f5847ee20f..58d31452d8 100644 --- a/object-file.c +++ b/object-file.c @@ -89,6 +89,12 @@ static void git_hash_sha1_final(unsigned char *hash, git_hash_ctx *ctx) git_SHA1_Final(hash, &ctx->sha1); } +static void git_hash_sha1_final_oid(struct object_id *oid, git_hash_ctx *ctx) +{ + git_SHA1_Final(oid->hash, &ctx->sha1); + memset(oid->hash + GIT_SHA1_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA1_RAWSZ); +} + static void git_hash_sha256_init(git_hash_ctx *ctx) { @@ -110,6 +116,16 @@ static void git_hash_sha256_final(unsigned char *hash, git_hash_ctx *ctx) git_SHA256_Final(hash, &ctx->sha256); } +static void git_hash_sha256_final_oid(struct object_id *oid, git_hash_ctx *ctx) +{ + git_SHA256_Final(oid->hash, &ctx->sha256); + /* + * This currently does nothing, so the compiler should optimize it out, + * but keep it in case we extend the hash size again. + */ + memset(oid->hash + GIT_SHA256_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA256_RAWSZ); +} + static void git_hash_unknown_init(git_hash_ctx *ctx) { BUG("trying to init unknown hash"); @@ -130,6 +146,12 @@ static void git_hash_unknown_final(unsigned char *hash, git_hash_ctx *ctx) BUG("trying to finalize unknown hash"); } +static void git_hash_unknown_final_oid(struct object_id *oid, git_hash_ctx *ctx) +{ + BUG("trying to finalize unknown hash"); +} + + const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = { { NULL, @@ -141,6 +163,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = { git_hash_unknown_clone, git_hash_unknown_update, git_hash_unknown_final, + git_hash_unknown_final_oid, NULL, NULL, }, @@ -155,6 +178,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = { git_hash_sha1_clone, git_hash_sha1_update, git_hash_sha1_final, + git_hash_sha1_final_oid, &empty_tree_oid, &empty_blob_oid, }, @@ -169,6 +193,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = { git_hash_sha256_clone, git_hash_sha256_update, git_hash_sha256_final, + git_hash_sha256_final_oid, &empty_tree_oid_sha256, &empty_blob_oid_sha256, }