8bff5ca030
We had several C files ignoring the rule to include one of the appropriate headers first; fix that. While at it, the rule in Documentation/CodingGuidelines about which header to include has also fallen out of sync, so update the wording to mention other allowed headers. Unfortunately, C files in reftable/ don't actually follow the previous or updated rule. If you follow the #include chain in its C files, reftable/system.h _tends_ to be first (i.e. record.c first includes record.h, which first includes basics.h, which first includees system.h), but not always (e.g. publicbasics.c includes another header first that does not include system.h). However, I'm going to punt on making actual changes to the C files in reftable/ since I do not want to risk bringing it out-of-sync with any version being used externally. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
111 lines
2.5 KiB
C
111 lines
2.5 KiB
C
/*
|
|
* A wrapper around cbtree which stores oids
|
|
* May be used to replace oid-array for prefix (abbreviation) matches
|
|
*/
|
|
#include "git-compat-util.h"
|
|
#include "oidtree.h"
|
|
#include "alloc.h"
|
|
#include "hash.h"
|
|
|
|
struct oidtree_iter_data {
|
|
oidtree_iter fn;
|
|
void *arg;
|
|
size_t *last_nibble_at;
|
|
int algo;
|
|
uint8_t last_byte;
|
|
};
|
|
|
|
void oidtree_init(struct oidtree *ot)
|
|
{
|
|
cb_init(&ot->tree);
|
|
mem_pool_init(&ot->mem_pool, 0);
|
|
}
|
|
|
|
void oidtree_clear(struct oidtree *ot)
|
|
{
|
|
if (ot) {
|
|
mem_pool_discard(&ot->mem_pool, 0);
|
|
oidtree_init(ot);
|
|
}
|
|
}
|
|
|
|
void oidtree_insert(struct oidtree *ot, const struct object_id *oid)
|
|
{
|
|
struct cb_node *on;
|
|
struct object_id k;
|
|
|
|
if (!oid->algo)
|
|
BUG("oidtree_insert requires oid->algo");
|
|
|
|
on = mem_pool_alloc(&ot->mem_pool, sizeof(*on) + sizeof(*oid));
|
|
|
|
/*
|
|
* Clear the padding and copy the result in separate steps to
|
|
* respect the 4-byte alignment needed by struct object_id.
|
|
*/
|
|
oidcpy_with_padding(&k, oid);
|
|
memcpy(on->k, &k, sizeof(k));
|
|
|
|
/*
|
|
* n.b. Current callers won't get us duplicates, here. If a
|
|
* future caller causes duplicates, there'll be a a small leak
|
|
* that won't be freed until oidtree_clear. Currently it's not
|
|
* worth maintaining a free list
|
|
*/
|
|
cb_insert(&ot->tree, on, sizeof(*oid));
|
|
}
|
|
|
|
|
|
int oidtree_contains(struct oidtree *ot, const struct object_id *oid)
|
|
{
|
|
struct object_id k;
|
|
size_t klen = sizeof(k);
|
|
|
|
oidcpy_with_padding(&k, oid);
|
|
|
|
if (oid->algo == GIT_HASH_UNKNOWN)
|
|
klen -= sizeof(oid->algo);
|
|
|
|
/* cb_lookup relies on memcmp on the struct, so order matters: */
|
|
klen += BUILD_ASSERT_OR_ZERO(offsetof(struct object_id, hash) <
|
|
offsetof(struct object_id, algo));
|
|
|
|
return cb_lookup(&ot->tree, (const uint8_t *)&k, klen) ? 1 : 0;
|
|
}
|
|
|
|
static enum cb_next iter(struct cb_node *n, void *arg)
|
|
{
|
|
struct oidtree_iter_data *x = arg;
|
|
struct object_id k;
|
|
|
|
/* Copy to provide 4-byte alignment needed by struct object_id. */
|
|
memcpy(&k, n->k, sizeof(k));
|
|
|
|
if (x->algo != GIT_HASH_UNKNOWN && x->algo != k.algo)
|
|
return CB_CONTINUE;
|
|
|
|
if (x->last_nibble_at) {
|
|
if ((k.hash[*x->last_nibble_at] ^ x->last_byte) & 0xf0)
|
|
return CB_CONTINUE;
|
|
}
|
|
|
|
return x->fn(&k, x->arg);
|
|
}
|
|
|
|
void oidtree_each(struct oidtree *ot, const struct object_id *oid,
|
|
size_t oidhexsz, oidtree_iter fn, void *arg)
|
|
{
|
|
size_t klen = oidhexsz / 2;
|
|
struct oidtree_iter_data x = { 0 };
|
|
assert(oidhexsz <= GIT_MAX_HEXSZ);
|
|
|
|
x.fn = fn;
|
|
x.arg = arg;
|
|
x.algo = oid->algo;
|
|
if (oidhexsz & 1) {
|
|
x.last_byte = oid->hash[klen];
|
|
x.last_nibble_at = &klen;
|
|
}
|
|
cb_each(&ot->tree, (const uint8_t *)oid, klen, iter, &x);
|
|
}
|