#include "git-compat-util.h"
#include "cbtree.h"
+static inline uint8_t *cb_node_key(struct cb_tree *t, struct cb_node *node)
+{
+ return (uint8_t *) node + t->key_offset;
+}
+
static struct cb_node *cb_node_of(const void *p)
{
return (struct cb_node *)((uintptr_t)p - 1);
uint8_t c;
int newdirection;
struct cb_node **wherep, *p;
+ uint8_t *node_key, *p_key;
assert(!((uintptr_t)node & 1)); /* allocations must be aligned */
return NULL; /* success */
}
+ node_key = cb_node_key(t, node);
+
/* see if a node already exists */
- p = cb_internal_best_match(t->root, node->k, klen);
+ p = cb_internal_best_match(t->root, node_key, klen);
+ p_key = cb_node_key(t, p);
/* find first differing byte */
for (newbyte = 0; newbyte < klen; newbyte++) {
- if (p->k[newbyte] != node->k[newbyte])
+ if (p_key[newbyte] != node_key[newbyte])
goto different_byte_found;
}
return p; /* element exists, let user deal with it */
different_byte_found:
- newotherbits = p->k[newbyte] ^ node->k[newbyte];
+ newotherbits = p_key[newbyte] ^ node_key[newbyte];
newotherbits |= newotherbits >> 1;
newotherbits |= newotherbits >> 2;
newotherbits |= newotherbits >> 4;
newotherbits = (newotherbits & ~(newotherbits >> 1)) ^ 255;
- c = p->k[newbyte];
+ c = p_key[newbyte];
newdirection = (1 + (newotherbits | c)) >> 8;
node->byte = newbyte;
break;
if (q->byte == newbyte && q->otherbits > newotherbits)
break;
- c = q->byte < klen ? node->k[q->byte] : 0;
+ c = q->byte < klen ? node_key[q->byte] : 0;
direction = (1 + (q->otherbits | c)) >> 8;
wherep = q->child + direction;
}
{
struct cb_node *p = cb_internal_best_match(t->root, k, klen);
- return p && !memcmp(p->k, k, klen) ? p : NULL;
+ return p && !memcmp(cb_node_key(t, p), k, klen) ? p : NULL;
}
static int cb_descend(struct cb_node *p, cb_iter fn, void *arg)
struct cb_node *p = t->root;
struct cb_node *top = p;
size_t i = 0;
+ uint8_t *p_key;
if (!p)
return 0; /* empty tree */
top = p;
}
+ p_key = cb_node_key(t, p);
for (i = 0; i < klen; i++) {
- if (p->k[i] != kpfx[i])
+ if (p_key[i] != kpfx[i])
return 0; /* "best" match failed */
}
*
* This is adapted to store arbitrary data (not just NUL-terminated C strings
* and allocates no memory internally. The user needs to allocate
- * "struct cb_node" and fill cb_node.k[] with arbitrary match data
- * for memcmp.
- * If "klen" is variable, then it should be embedded into "c_node.k[]"
+ * "struct cb_node" and provide `key_offset` to indicate where the key can be
+ * found relative to the `struct cb_node` for memcmp.
+ * If "klen" is variable, then it should be embedded into the key.
* Recursion is bound by the maximum value of "klen" used.
*/
#ifndef CBTREE_H
*/
uint32_t byte;
uint8_t otherbits;
- uint8_t k[FLEX_ARRAY]; /* arbitrary data, unaligned */
};
struct cb_tree {
struct cb_node *root;
+ ptrdiff_t key_offset;
};
-#define CBTREE_INIT { 0 }
-
-static inline void cb_init(struct cb_tree *t)
+static inline void cb_init(struct cb_tree *t,
+ ptrdiff_t key_offset)
{
- struct cb_tree blank = CBTREE_INIT;
+ struct cb_tree blank = {
+ .key_offset = key_offset,
+ };
memcpy(t, &blank, sizeof(*t));
}
#include "oidtree.h"
#include "hash.h"
+struct oidtree_node {
+ struct cb_node base;
+ struct object_id key;
+};
+
void oidtree_init(struct oidtree *ot)
{
- cb_init(&ot->tree);
+ cb_init(&ot->tree, offsetof(struct oidtree_node, key));
mem_pool_init(&ot->mem_pool, 0);
}
void oidtree_insert(struct oidtree *ot, const struct object_id *oid)
{
- struct cb_node *on;
- struct object_id k;
+ struct oidtree_node *on;
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(&k, oid);
- memcpy(on->k, &k, sizeof(k));
+ on = mem_pool_alloc(&ot->mem_pool, sizeof(*on));
+ oidcpy(&on->key, oid);
/*
* n.b. Current callers won't get us duplicates, here. If a
* that won't be freed until oidtree_clear. Currently it's not
* worth maintaining a free list
*/
- cb_insert(&ot->tree, on, sizeof(*oid));
+ cb_insert(&ot->tree, &on->base, sizeof(*oid));
}
bool oidtree_contains(struct oidtree *ot, const struct object_id *oid)
static int iter(struct cb_node *n, void *cb_data)
{
+ struct oidtree_node *node = container_of(n, struct oidtree_node, base);
struct oidtree_each_data *data = cb_data;
- struct object_id k;
-
- /* Copy to provide 4-byte alignment needed by struct object_id. */
- memcpy(&k, n->k, sizeof(k));
- if (data->algo != GIT_HASH_UNKNOWN && data->algo != k.algo)
+ if (data->algo != GIT_HASH_UNKNOWN && data->algo != node->key.algo)
return 0;
if (data->last_nibble_at) {
- if ((k.hash[*data->last_nibble_at] ^ data->last_byte) & 0xf0)
+ if ((node->key.hash[*data->last_nibble_at] ^ data->last_byte) & 0xf0)
return 0;
}
- return data->cb(&k, data->cb_data);
+ return data->cb(&node->key, data->cb_data);
}
int oidtree_each(struct oidtree *ot, const struct object_id *prefix,