struct CBTree {
struct Node *root;
- const char *(*get_key)(void *obj);
+ cbtree_getkey_func get_key;
};
#define SAME_KEY 0xFFFFFFFF
}
/* get specific bit from string */
-static inline unsigned get_bit(unsigned bitpos, const char *key, unsigned klen)
+static inline unsigned get_bit(unsigned bitpos, const unsigned char *key, unsigned klen)
{
unsigned pos = bitpos / 8;
unsigned bit = 7 - (bitpos % 8);
}
/* use callback to get key for a stored object */
-static inline const char *get_key(struct CBTree *tree, void *obj)
+static inline unsigned get_key(struct CBTree *tree, void *obj, const void **key_p)
{
- return tree->get_key(obj);
+ return tree->get_key(obj, key_p);
}
-/* Find first differing bit on 2 zero-terminated strings. */
-static unsigned find_crit_bit(const char *a, const char *b)
+/* check if object key matches argument */
+static inline bool key_matches(struct CBTree *tree, void *obj, const void *key, unsigned klen)
{
- unsigned i, c, pos;
+ const void *o_key;
+ unsigned o_klen;
+ o_klen = get_key(tree, obj, &o_key);
+ return (o_klen == klen) && (memcmp(key, o_key, klen) == 0);
+}
- /* find differing byte */
- for (i = 0; ; i++) {
- /* this handles also size difference */
- if (a[i] != b[i])
- break;
+/* Find first differing bit on 2 strings. */
+static unsigned find_crit_bit(const unsigned char *a, unsigned alen, const unsigned char *b, unsigned blen)
+{
+ unsigned i, c, pos, av, bv;
+ unsigned minlen = (alen > blen) ? blen : alen;
+ unsigned maxlen = (alen > blen) ? alen : blen;
+
+ /* find differing byte in common data */
+ for (i = 0; i < minlen; i++) {
+ av = a[i];
+ bv = b[i];
+ if (av != bv)
+ goto found;
+ }
- /* equal strings? */
- if (a[i] == 0)
- return SAME_KEY;
+ /* find differing byte when one side is zero-filled */
+ for (; i < maxlen; i++) {
+ av = (i < alen) ? a[i] : 0;
+ bv = (i < blen) ? b[i] : 0;
+ if (av != bv)
+ goto found;
}
+ return SAME_KEY;
+found:
/* calculate bits that differ */
- c = a[i] ^ b[i];
+ c = av ^ bv;
/* find the first one */
pos = 8 - fls(c);
*/
/* walk nodes until external pointer is found */
-static void *raw_lookup(struct CBTree *tree, const char *key, unsigned klen)
+static void *raw_lookup(struct CBTree *tree, const void *key, unsigned klen)
{
struct Node *node = tree->root;
unsigned bit;
}
/* actual lookup. returns obj ptr or NULL of not found */
-void *cbtree_lookup(struct CBTree *tree, const char *key)
+void *cbtree_lookup(struct CBTree *tree, const void *key, unsigned klen)
{
- unsigned klen;
void *obj;
if (!tree->root)
return NULL;
/* find match based on bits we know about */
- klen = strlen(key);
obj = raw_lookup(tree, key, klen);
/* need to check if the object actually matches */
- if (strcmp(key, get_key(tree, obj)) == 0)
+ if (key_matches(tree, obj, key, klen))
return obj;
return NULL;
}
/* insert into specific bit-position */
-static bool insert_at(struct CBTree *tree, unsigned newbit, const char *key, unsigned klen, void *obj)
+static bool insert_at(struct CBTree *tree, unsigned newbit, const void *key, unsigned klen, void *obj)
{
/* location of current node/obj pointer under examination */
struct Node **pos = &tree->root;
/* actual insert: returns true -> insert ok or key found, false -> malloc failure */
bool cbtree_insert(struct CBTree *tree, void *obj)
{
- const char *key;
- unsigned newbit, klen;
+ const void *key, *old_key;
+ unsigned newbit, klen, old_klen;
void *old_obj;
if (!tree->root)
return insert_first(tree, obj);
- /* match bits we know about */
- key = get_key(tree, obj);
- klen = strlen(key);
+ /* current key */
+ klen = get_key(tree, obj, &key);
+
+ /* nearest key in tree */
old_obj = raw_lookup(tree, key, klen);
+ old_klen = get_key(tree, obj, &old_key);
/* first differing bit is the target position */
- newbit = find_crit_bit(key, get_key(tree, old_obj));
+ newbit = find_crit_bit(key, klen, old_key, old_klen);
if (newbit == SAME_KEY)
return true;
return insert_at(tree, newbit, key, klen, obj);
*/
/* true -> object was found and removed, false -> not found */
-bool cbtree_delete(struct CBTree *tree, const char *key)
+bool cbtree_delete(struct CBTree *tree, const void *key, unsigned klen)
{
void *obj, *tmp;
unsigned bit = 0;
- unsigned klen = strlen(key);
/* location of current node/obj pointer under examination */
struct Node **pos = &tree->root;
/* if 'pos' has user obj, prev_pos has internal node pointing to it */
/* does the key actually matches */
obj = get_external(*pos);
- if (strcmp(key, get_key(tree, obj)) != 0)
+ if (!key_matches(tree, obj, key, klen))
return false;
/* drop the internal node pointing to our key */