#include "oidtree.h"
#include "hash.h"
-struct oidtree_iter_data {
- oidtree_iter fn;
- void *arg;
- size_t *last_nibble_at;
- uint32_t algo;
- uint8_t last_byte;
-};
-
void oidtree_init(struct oidtree *ot)
{
cb_init(&ot->tree);
cb_insert(&ot->tree, on, sizeof(*oid));
}
-
-int oidtree_contains(struct oidtree *ot, const struct object_id *oid)
+bool oidtree_contains(struct oidtree *ot, const struct object_id *oid)
{
struct object_id k;
size_t klen = sizeof(k);
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;
+ return !!cb_lookup(&ot->tree, (const uint8_t *)&k, klen);
}
-static enum cb_next iter(struct cb_node *n, void *arg)
+struct oidtree_each_data {
+ oidtree_each_cb cb;
+ void *cb_data;
+ size_t *last_nibble_at;
+ uint32_t algo;
+ uint8_t last_byte;
+};
+
+static enum cb_next iter(struct cb_node *n, void *cb_data)
{
- struct oidtree_iter_data *x = arg;
+ 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 (x->algo != GIT_HASH_UNKNOWN && x->algo != k.algo)
+ if (data->algo != GIT_HASH_UNKNOWN && data->algo != k.algo)
return CB_CONTINUE;
- if (x->last_nibble_at) {
- if ((k.hash[*x->last_nibble_at] ^ x->last_byte) & 0xf0)
+ if (data->last_nibble_at) {
+ if ((k.hash[*data->last_nibble_at] ^ data->last_byte) & 0xf0)
return CB_CONTINUE;
}
- return x->fn(&k, x->arg);
+ return data->cb(&k, data->cb_data);
}
-void oidtree_each(struct oidtree *ot, const struct object_id *oid,
- size_t oidhexsz, oidtree_iter fn, void *arg)
+void oidtree_each(struct oidtree *ot, const struct object_id *prefix,
+ size_t prefix_hex_len, oidtree_each_cb cb, void *cb_data)
{
- 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;
+ struct oidtree_each_data data = {
+ .cb = cb,
+ .cb_data = cb_data,
+ .algo = prefix->algo,
+ };
+ size_t klen = prefix_hex_len / 2;
+ assert(prefix_hex_len <= GIT_MAX_HEXSZ);
+
+ if (prefix_hex_len & 1) {
+ data.last_byte = prefix->hash[klen];
+ data.last_nibble_at = &klen;
}
- cb_each(&ot->tree, (const uint8_t *)oid, klen, iter, &x);
+
+ cb_each(&ot->tree, prefix->hash, klen, iter, &data);
}
#include "hash.h"
#include "mem-pool.h"
+/*
+ * OID trees are an efficient storage for object IDs that use a critbit tree
+ * internally. Common prefixes are duplicated and object IDs are stored in a
+ * way that allow easy iteration over the objects in lexicographic order. As a
+ * consequence, operations that want to enumerate all object IDs that match a
+ * given prefix can be answered efficiently.
+ *
+ * Note that it is not (yet) possible to store data other than the object IDs
+ * themselves in this tree.
+ */
struct oidtree {
struct cb_tree tree;
struct mem_pool mem_pool;
};
-void oidtree_init(struct oidtree *);
-void oidtree_clear(struct oidtree *);
-void oidtree_insert(struct oidtree *, const struct object_id *);
-int oidtree_contains(struct oidtree *, const struct object_id *);
+/* Initialize the oidtree so that it is ready for use. */
+void oidtree_init(struct oidtree *ot);
-typedef enum cb_next (*oidtree_iter)(const struct object_id *, void *data);
-void oidtree_each(struct oidtree *, const struct object_id *,
- size_t oidhexsz, oidtree_iter, void *data);
+/*
+ * Release all memory associated with the oidtree and reinitialize it for
+ * subsequent use.
+ */
+void oidtree_clear(struct oidtree *ot);
+
+/* Insert the object ID into the tree. */
+void oidtree_insert(struct oidtree *ot, const struct object_id *oid);
+
+/* Check whether the tree contains the given object ID. */
+bool oidtree_contains(struct oidtree *ot, const struct object_id *oid);
+
+/* Callback function used for `oidtree_each()`. */
+typedef enum cb_next (*oidtree_each_cb)(const struct object_id *oid,
+ void *cb_data);
+
+/*
+ * Iterate through all object IDs in the tree whose prefix matches the given
+ * object ID prefix and invoke the callback function on each of them.
+ */
+void oidtree_each(struct oidtree *ot,
+ const struct object_id *prefix, size_t prefix_hex_len,
+ oidtree_each_cb cb, void *cb_data);
#endif /* OIDTREE_H */
return 0;
}
-static void check_contains(struct oidtree *ot, const char *hex, int expected)
+static void check_contains(struct oidtree *ot, const char *hex, bool expected)
{
struct object_id oid;
void test_oidtree__contains(void)
{
FILL_TREE(&ot, "444", "1", "2", "3", "4", "5", "a", "b", "c", "d", "e");
- check_contains(&ot, "44", 0);
- check_contains(&ot, "441", 0);
- check_contains(&ot, "440", 0);
- check_contains(&ot, "444", 1);
- check_contains(&ot, "4440", 1);
- check_contains(&ot, "4444", 0);
+ check_contains(&ot, "44", false);
+ check_contains(&ot, "441", false);
+ check_contains(&ot, "440", false);
+ check_contains(&ot, "444", true);
+ check_contains(&ot, "4440", true);
+ check_contains(&ot, "4444", false);
}
void test_oidtree__each(void)