]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add data oriented API to match rb / hash APIs
authorAlan T. DeKok <aland@freeradius.org>
Fri, 16 Apr 2021 13:59:17 +0000 (09:59 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Fri, 16 Apr 2021 14:30:16 +0000 (10:30 -0400)
src/lib/util/trie.c
src/lib/util/trie.h

index 7729a91fb029d41806f3442a9a9c088f0b4c8e17..3aa43a01e5fc4efb3584b91e6107d6be024b6edb 100644 (file)
@@ -725,19 +725,28 @@ static fr_trie_comp_t *fr_trie_comp_alloc(TALLOC_CTX *ctx, int bits)
 }
 #endif /* WITH_NODE_COMPRESSION */
 
+typedef struct {
+       uint8_t         buffer[16]; /* for get_key callbacks */
+       fr_trie_key_t   get_key;
+       fr_free_t       free_data;
+} fr_trie_ctx_t;
+
 /** Allocate a trie
  *
  * @param ctx The talloc ctx
+ * @param get_key The "get key from object" function.
  * @return
  *     - NULL on error
  *     - fr_trie_node_t on success
  */
-fr_trie_t *fr_trie_alloc(TALLOC_CTX *ctx)
+fr_trie_t *_fr_trie_alloc(TALLOC_CTX *ctx, fr_trie_key_t get_key, fr_free_t free_data)
 {
        fr_trie_user_t *user;
+       fr_trie_ctx_t *uctx;
 
        /*
-        *      The trie itself is just a user node with user data that is the talloc ctx
+        *      The trie itself is just a user node with user data
+        *      that is the get_key function.
         */
        user = (fr_trie_user_t *) fr_trie_user_alloc(ctx, "");
        if (!user) return NULL;
@@ -745,7 +754,15 @@ fr_trie_t *fr_trie_alloc(TALLOC_CTX *ctx)
        /*
         *      Only the top-level node here can have 'user->data == NULL'
         */
-       user->data = ctx;
+       user->data = uctx = talloc_zero(user, fr_trie_ctx_t);
+       if (!user->data) {
+               talloc_free(user);
+               return NULL;
+       }
+
+       uctx->get_key = get_key;
+       uctx->free_data = free_data;
+
        return (fr_trie_t *) user;
 }
 
@@ -2607,6 +2624,166 @@ int fr_trie_walk(fr_trie_t *ft, void *ctx, fr_trie_walk_t callback)
        return trie_key_walk(ft->trie, &my_cb, 0, false);
 }
 
+
+/**********************************************************************/
+
+/*
+ *     Object API.
+ */
+
+/** Find an element in the trie, returning the data.
+ *
+ * @param[in] ft to search in.
+ * @param[in] data to find.
+ * @return
+ *     - User data matching the data passed in.
+ *     - NULL if nothing matched passed data.
+ */
+void *fr_trie_find(fr_trie_t *ft, void const *data)
+{
+       fr_trie_user_t *user = (fr_trie_user_t *) ft;
+       fr_trie_ctx_t *uctx = talloc_get_type_abort(user->data, fr_trie_ctx_t);
+       uint8_t *key;
+       size_t keylen;
+
+       key = &uctx->buffer[0];
+       keylen = sizeof(uctx->buffer) * 8;
+
+       if (!uctx->get_key) return false;
+
+       if (uctx->get_key(&key, &keylen, data) < 0) return false;
+
+       return fr_trie_lookup_by_key(ft, key, keylen);
+}
+
+/** Insert data into a trie
+ *
+ * @param[in] ft       to insert data into.
+ * @param[in] data     to insert.
+ * @return
+ *     - true if data was inserted.
+ *     - false if data already existed and was not inserted.
+ */
+bool fr_trie_insert(fr_trie_t *ft, void const *data)
+{
+       fr_trie_user_t *user = (fr_trie_user_t *) ft;
+       fr_trie_ctx_t *uctx = talloc_get_type_abort(user->data, fr_trie_ctx_t);
+       uint8_t *key;
+       size_t keylen;
+
+       key = &uctx->buffer[0];
+       keylen = sizeof(uctx->buffer) * 8;
+
+       if (!uctx->get_key) return false;
+
+       if (uctx->get_key(&key, &keylen, data) < 0) return false;
+
+       if (fr_trie_insert_by_key(ft, key, keylen, data) < 0) return false;
+
+       return true;
+}
+
+/** Replace old data with new data, OR insert if there is no old
+ *
+ * @param[in] ft       to insert data into.
+ * @param[in] data     to replace.
+ * @return
+ *      - 1 if data was inserted.
+ *     - 0 if data was replaced.
+ *      - -1 if we failed to replace data
+ */
+int fr_trie_replace(fr_trie_t *ft, void const *data)
+{
+       fr_trie_user_t *user = (fr_trie_user_t *) ft;
+       fr_trie_ctx_t *uctx = talloc_get_type_abort(user->data, fr_trie_ctx_t);
+       uint8_t *key;
+       size_t keylen;
+       void *found;
+
+       key = &uctx->buffer[0];
+       keylen = sizeof(uctx->buffer) * 8;
+
+       if (!uctx->get_key) return -1;
+
+       if (uctx->get_key(&key, &keylen, data) < 0) return -1;
+
+       found = trie_key_match(ft, key, 0, keylen, true); /* do exact match */
+       if (found) {
+               if (fr_trie_remove_by_key(ft, key, keylen) != found) return -1;
+       }
+
+       /*
+        *      Insert the new key.
+        */
+       return fr_trie_insert_by_key(ft, key, keylen, data);
+}
+
+/** Remove an entry, without freeing the data
+ *
+ * @param[in] ft       to remove data from.
+ * @param[in] data     to remove.
+ * @return
+ *      - The user data we removed.
+ *     - NULL if we couldn't find any matching data.
+ */
+void *fr_trie_remove(fr_trie_t *ft, void const *data)
+{
+       fr_trie_user_t *user = (fr_trie_user_t *) ft;
+       fr_trie_ctx_t *uctx = talloc_get_type_abort(user->data, fr_trie_ctx_t);
+       uint8_t *key;
+       size_t keylen;
+
+       key = &uctx->buffer[0];
+       keylen = sizeof(uctx->buffer) * 8;
+
+       if (!uctx->get_key) return NULL;
+
+       if (uctx->get_key(&key, &keylen, data) < 0) return NULL;
+
+       return fr_trie_remove_by_key(ft, key, keylen);
+}
+
+/** Remove node and free data (if a free function was specified)
+ *
+ * @param[in] ft       to remove data from.
+ * @param[in] data     to remove/free.
+ * @return
+ *     - true if we removed data.
+ *      - false if we couldn't find any matching data.
+ */
+bool fr_trie_delete(fr_trie_t *ft, void const *data)
+{
+       fr_trie_user_t *user = (fr_trie_user_t *) ft;
+       fr_trie_ctx_t *uctx = talloc_get_type_abort(user->data, fr_trie_ctx_t);
+       uint8_t *key;
+       size_t keylen;
+       void *found;
+
+       key = &uctx->buffer[0];
+       keylen = sizeof(uctx->buffer) * 8;
+
+       if (!uctx->get_key) return false;
+
+       if (uctx->get_key(&key, &keylen, data) < 0) return false;
+
+       found = fr_trie_remove_by_key(ft, key, keylen);
+       if (!found) return false;
+
+       if (!uctx->free_data) return true;
+
+       uctx->free_data(found);
+       return true;
+}
+
+/** Return how many nodes there are in a trie
+ *
+ * @param[in] ft       to return node count for.
+ */
+uint64_t fr_trie_num_elements(UNUSED fr_trie_t *ft)
+{
+       return 0;
+}
+
 #ifdef TESTING
 static bool print_lineno = false;
 
index f4ee10890c606915ca52bb03d878923d7d233465..213a2cea69d5528d10b856662ffc03df94e565a1 100644 (file)
@@ -42,7 +42,24 @@ typedef struct fr_trie_s fr_trie_t;
  */
 typedef int (*fr_trie_walk_t)(uint8_t const *key, size_t keylen, void *data, void *uctx);
 
-fr_trie_t      *fr_trie_alloc(TALLOC_CTX *ctx);
+/* Get a key from data.
+ *
+ * @param[in,out] out - set to a small buffer on input.  If the callback has more data
+ *               than is available here, the callback can update "out" to point elsewhere
+ * @param[in,out] outlen The number of bits available in the initial buffer.  On output,
+ *               the number of bits available in the key
+ * @param[in] data the data which contains the key
+ * @return
+ *     - <0 on error
+ *     - 0 on success
+ */
+typedef int (*fr_trie_key_t)(uint8_t **out, size_t *outlen, void const *data);
+
+#define fr_trie_alloc(_ctx) _fr_trie_alloc(_ctx, NULL, NULL)
+
+#define fr_trie_generic_alloc(_ctx, _get_key, _free_data) _fr_trie_alloc(_ctx, _get_key, _free_data)
+
+fr_trie_t      *_fr_trie_alloc(TALLOC_CTX *ctx, fr_trie_key_t get_key, fr_free_t free_node);
 int            fr_trie_insert_by_key(fr_trie_t *ft, void const *key, size_t keylen, void const *data) CC_HINT(nonnull);
 
 void           *fr_trie_lookup_by_key(fr_trie_t const *ft, void const *key, size_t keylen) CC_HINT(nonnull);
@@ -51,6 +68,21 @@ void         *fr_trie_remove_by_key(fr_trie_t *ft, void const *key, size_t keylen) CC_H
 
 int            fr_trie_walk(fr_trie_t *ft, void *ctx, fr_trie_walk_t callback) CC_HINT(nonnull(1,3));
 
+/*
+ *     Data oriented API.
+ */
+void           *fr_trie_find(fr_trie_t *ft, void const *data) CC_HINT(nonnull);
+
+bool           fr_trie_insert(fr_trie_t *ft, void const *data) CC_HINT(nonnull);
+
+int            fr_trie_replace(fr_trie_t *ft, void const *data) CC_HINT(nonnull);
+
+void           *fr_trie_remove(fr_trie_t *ft, void const *data) CC_HINT(nonnull);
+
+bool           fr_trie_delete(fr_trie_t *ft, void const *data) CC_HINT(nonnull);
+
+uint64_t       fr_trie_num_elements(fr_trie_t *ft) CC_HINT(nonnull); /* always returns 0 */
+
 #ifdef __cplusplus
 }
 #endif