LCOV - code coverage report
Current view: top level - lib - lwan-trie.c (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 44 76 57.9 %
Date: 2023-04-18 16:19:03 Functions: 3 5 60.0 %

          Line data    Source code
       1             : /*
       2             :  * lwan - web server
       3             :  * Copyright (c) 2012 L. A. F. Pereira <l@tia.mat.br>
       4             :  *
       5             :  * This program is free software; you can redistribute it and/or
       6             :  * modify it under the terms of the GNU General Public License
       7             :  * as published by the Free Software Foundation; either version 2
       8             :  * of the License, or any later version.
       9             :  *
      10             :  * This program is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :  * GNU General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License
      16             :  * along with this program; if not, write to the Free Software
      17             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
      18             :  * USA.
      19             :  */
      20             : 
      21             : #include <stdlib.h>
      22             : #include <string.h>
      23             : 
      24             : #include "lwan-private.h"
      25             : 
      26             : struct lwan_trie_node {
      27             :     struct lwan_trie_node *next[8];
      28             :     struct lwan_trie_leaf *leaf;
      29             :     int ref_count;
      30             : };
      31             : 
      32             : struct lwan_trie_leaf {
      33             :     char *key;
      34             :     void *data;
      35             :     struct lwan_trie_leaf *next;
      36             : };
      37             : 
      38          92 : bool lwan_trie_init(struct lwan_trie *trie, void (*free_node)(void *data))
      39             : {
      40          92 :     if (!trie)
      41           0 :         return false;
      42          92 :     trie->root = NULL;
      43          92 :     trie->free_node = free_node;
      44          92 :     return true;
      45             : }
      46             : 
      47             : static ALWAYS_INLINE struct lwan_trie_leaf *
      48             : find_leaf_with_key(struct lwan_trie_node *node, const char *key, size_t len)
      49             : {
      50        2563 :     struct lwan_trie_leaf *leaf = node->leaf;
      51             : 
      52        2563 :     if (!leaf)
      53        1959 :         return NULL;
      54             : 
      55         604 :     if (!leaf->next) /* No collisions -- no need to strncmp() */
      56         604 :         return leaf;
      57             : 
      58           0 :     for (; leaf; leaf = leaf->next) {
      59           0 :         if (!strncmp(leaf->key, key, len - 1))
      60           0 :             return leaf;
      61             :     }
      62             : 
      63           0 :     return NULL;
      64             : }
      65             : 
      66             : #define GET_NODE()                                                             \
      67             :     do {                                                                       \
      68             :         if (!(node = *knode)) {                                                \
      69             :             *knode = node = lwan_aligned_alloc(sizeof(*node), 64);             \
      70             :             if (!node)                                                         \
      71             :                 goto oom;                                                      \
      72             :             memset(node, 0, sizeof(*node));                                    \
      73             :         }                                                                      \
      74             :         ++node->ref_count;                                                     \
      75             :     } while (0)
      76             : 
      77        1959 : void lwan_trie_add(struct lwan_trie *trie, const char *key, void *data)
      78             : {
      79        1959 :     if (UNLIKELY(!trie || !key || !data))
      80           0 :         return;
      81             : 
      82             :     struct lwan_trie_node **knode, *node;
      83        1959 :     const char *orig_key = key;
      84             : 
      85             :     /* Traverse the trie, allocating nodes if necessary */
      86       17191 :     for (knode = &trie->root; *key; knode = &node->next[(int)(*key++ & 7)])
      87       15232 :         GET_NODE();
      88             : 
      89             :     /* Get the leaf node (allocate it if necessary) */
      90        1959 :     GET_NODE();
      91             : 
      92             :     struct lwan_trie_leaf *leaf =
      93        1959 :         find_leaf_with_key(node, orig_key, (size_t)(key - orig_key));
      94        1959 :     bool had_key = leaf;
      95        1959 :     if (!leaf) {
      96        1959 :         leaf = lwan_aligned_alloc(sizeof(*leaf), 64);
      97        1959 :         if (!leaf)
      98           0 :             lwan_status_critical_perror("malloc");
      99           0 :     } else if (trie->free_node) {
     100           0 :         trie->free_node(leaf->data);
     101             :     }
     102             : 
     103        1959 :     leaf->data = data;
     104        1959 :     if (!had_key) {
     105        1959 :         leaf->key = strdup(orig_key);
     106        1959 :         leaf->next = node->leaf;
     107        1959 :         node->leaf = leaf;
     108             :     }
     109        1959 :     return;
     110             : 
     111           0 : oom:
     112           0 :     lwan_status_critical_perror("calloc");
     113             : }
     114             : 
     115             : #undef GET_NODE
     116             : 
     117             : static ALWAYS_INLINE struct lwan_trie_node *
     118             : lookup_node(struct lwan_trie_node *root, const char *key, size_t *prefix_len)
     119             : {
     120         604 :     struct lwan_trie_node *node, *previous_node = NULL;
     121         604 :     const char *orig_key = key;
     122             : 
     123        4533 :     for (node = root; node && *key; node = node->next[(int)(*key++ & 7)]) {
     124        3929 :         if (node->leaf)
     125         603 :             previous_node = node;
     126             :     }
     127             : 
     128         604 :     *prefix_len = (size_t)(key - orig_key);
     129             : 
     130         604 :     if (node && node->leaf)
     131         530 :         return node;
     132             : 
     133          74 :     return previous_node;
     134             : }
     135             : 
     136         604 : ALWAYS_INLINE void *lwan_trie_lookup_prefix(struct lwan_trie *trie,
     137             :                                             const char *key)
     138             : {
     139         604 :     assert(trie);
     140         604 :     assert(key);
     141             : 
     142             :     size_t prefix_len;
     143         604 :     struct lwan_trie_node *node = lookup_node(trie->root, key, &prefix_len);
     144             : 
     145         604 :     if (node) {
     146         604 :         struct lwan_trie_leaf *leaf = find_leaf_with_key(node, key, prefix_len);
     147             : 
     148         604 :         if (leaf)
     149         604 :             return leaf->data;
     150             :     }
     151             : 
     152           0 :     return NULL;
     153             : }
     154             : 
     155           0 : static void lwan_trie_node_destroy(struct lwan_trie *trie,
     156             :                                    struct lwan_trie_node *node)
     157             : {
     158           0 :     if (!node)
     159           0 :         return;
     160             : 
     161           0 :     int32_t nodes_destroyed = node->ref_count;
     162             : 
     163           0 :     for (struct lwan_trie_leaf *leaf = node->leaf; leaf;) {
     164           0 :         struct lwan_trie_leaf *tmp = leaf->next;
     165             : 
     166           0 :         if (trie->free_node)
     167           0 :             trie->free_node(leaf->data);
     168             : 
     169           0 :         free(leaf->key);
     170           0 :         free(leaf);
     171           0 :         leaf = tmp;
     172             :     }
     173             : 
     174           0 :     for (int32_t i = 0; nodes_destroyed > 0 && i < 8; i++) {
     175           0 :         if (node->next[i]) {
     176           0 :             lwan_trie_node_destroy(trie, node->next[i]);
     177           0 :             --nodes_destroyed;
     178             :         }
     179             :     }
     180             : 
     181           0 :     free(node);
     182             : }
     183             : 
     184           0 : void lwan_trie_destroy(struct lwan_trie *trie)
     185             : {
     186           0 :     if (!trie || !trie->root)
     187           0 :         return;
     188           0 :     lwan_trie_node_destroy(trie, trie->root);
     189             : }

Generated by: LCOV version 1.15-2-gb9d6727