hash: add a function to finalize object IDs
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@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
brian m. carlson committed
Apr 26, 2021 at 01:02 UTC
ab795f0d77aec52496557eb69a5fc9e4f60ea1fd
2 files changed
+52
-23
hash.h
+27
-23
@@ -95,6 +95,29 @@ static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *s
95
/* Number of algorithms supported (including unknown). */
96
#define GIT_HASH_NALGOS (GIT_HASH_SHA256 + 1)
97
98
+/* The length in bytes and in hex digits of an object name (SHA-1 value). */
99
+#define GIT_SHA1_RAWSZ 20
100
+#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ)
101
+/* The block size of SHA-1. */
102
+#define GIT_SHA1_BLKSZ 64
103
+
104
+/* The length in bytes and in hex digits of an object name (SHA-256 value). */
105
+#define GIT_SHA256_RAWSZ 32
106
+#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ)
107
+/* The block size of SHA-256. */
108
+#define GIT_SHA256_BLKSZ 64
109
+
110
+/* The length in byte and in hex digits of the largest possible hash value. */
111
+#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ
112
+#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ
113
+/* The largest possible block size for any supported hash. */
114
+#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ
115
+
116
+struct object_id {
117
+ unsigned char hash[GIT_MAX_RAWSZ];
118
+ int algo;
119
+};
120
+
121
/* A suitably aligned type for stack allocations of hash contexts. */
122
union git_hash_ctx {
123
git_SHA_CTX sha1;
@@ -106,6 +129,7 @@ typedef void (*git_hash_init_fn)(git_hash_ctx *ctx);
129
typedef void (*git_hash_clone_fn)(git_hash_ctx *dst, const git_hash_ctx *src);
130
typedef void (*git_hash_update_fn)(git_hash_ctx *ctx, const void *in, size_t len);
131
typedef void (*git_hash_final_fn)(unsigned char *hash, git_hash_ctx *ctx);
132
+typedef void (*git_hash_final_oid_fn)(struct object_id *oid, git_hash_ctx *ctx);
133
134
struct git_hash_algo {
135
/*
@@ -138,6 +162,9 @@ struct git_hash_algo {
162
/* The hash finalization function. */
163
git_hash_final_fn final_fn;
164
165
+ /* The hash finalization function for object IDs. */
166
+ git_hash_final_oid_fn final_oid_fn;
167
+
168
/* The OID of the empty tree. */
169
const struct object_id *empty_tree;
170
@@ -161,29 +188,6 @@ static inline int hash_algo_by_ptr(const struct git_hash_algo *p)
188
return p - hash_algos;
189
}
190
164
-/* The length in bytes and in hex digits of an object name (SHA-1 value). */
165
-#define GIT_SHA1_RAWSZ 20
166
-#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ)
167
-/* The block size of SHA-1. */
168
-#define GIT_SHA1_BLKSZ 64
169
-
170
-/* The length in bytes and in hex digits of an object name (SHA-256 value). */
171
-#define GIT_SHA256_RAWSZ 32
172
-#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ)
173
-/* The block size of SHA-256. */
174
-#define GIT_SHA256_BLKSZ 64
175
-
176
-/* The length in byte and in hex digits of the largest possible hash value. */
177
-#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ
178
-#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ
179
-/* The largest possible block size for any supported hash. */
180
-#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ
181
-
182
-struct object_id {
183
- unsigned char hash[GIT_MAX_RAWSZ];
184
- int algo;
185
-};
186
-
191
#define the_hash_algo the_repository->hash_algo
192
193
extern const struct object_id null_oid;
object-file.c
+25
@@ -89,6 +89,12 @@ static void git_hash_sha1_final(unsigned char *hash, git_hash_ctx *ctx)
89
git_SHA1_Final(hash, &ctx->sha1);
90
}
91
92
+static void git_hash_sha1_final_oid(struct object_id *oid, git_hash_ctx *ctx)
93
+{
94
+ git_SHA1_Final(oid->hash, &ctx->sha1);
95
+ memset(oid->hash + GIT_SHA1_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA1_RAWSZ);
96
+}
97
+
98
99
static void git_hash_sha256_init(git_hash_ctx *ctx)
100
{
@@ -110,6 +116,16 @@ static void git_hash_sha256_final(unsigned char *hash, git_hash_ctx *ctx)
116
git_SHA256_Final(hash, &ctx->sha256);
117
}
118
119
+static void git_hash_sha256_final_oid(struct object_id *oid, git_hash_ctx *ctx)
120
+{
121
+ git_SHA256_Final(oid->hash, &ctx->sha256);
122
+ /*
123
+ * This currently does nothing, so the compiler should optimize it out,
124
+ * but keep it in case we extend the hash size again.
125
+ */
126
+ memset(oid->hash + GIT_SHA256_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA256_RAWSZ);
127
+}
128
+
129
static void git_hash_unknown_init(git_hash_ctx *ctx)
130
{
131
BUG("trying to init unknown hash");
@@ -130,6 +146,12 @@ static void git_hash_unknown_final(unsigned char *hash, git_hash_ctx *ctx)
146
BUG("trying to finalize unknown hash");
147
}
148
149
+static void git_hash_unknown_final_oid(struct object_id *oid, git_hash_ctx *ctx)
150
+{
151
+ BUG("trying to finalize unknown hash");
152
+}
153
+
154
+
155
const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
156
{
157
NULL,
@@ -141,6 +163,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
163
git_hash_unknown_clone,
164
git_hash_unknown_update,
165
git_hash_unknown_final,
166
+ git_hash_unknown_final_oid,
167
NULL,
168
NULL,
169
},
@@ -155,6 +178,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
178
git_hash_sha1_clone,
179
git_hash_sha1_update,
180
git_hash_sha1_final,
181
+ git_hash_sha1_final_oid,
182
&empty_tree_oid,
183
&empty_blob_oid,
184
},
@@ -169,6 +193,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
193
git_hash_sha256_clone,
194
git_hash_sha256_update,
195
git_hash_sha256_final,
196
+ git_hash_sha256_final_oid,
197
&empty_tree_oid_sha256,
198
&empty_blob_oid_sha256,
199
}