LCOV - code coverage report
Current view: top level - lib - hindex.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 7 7 100.0 %
Date: 2016-09-14 01:02:56 Functions: 2 2 100.0 %
Branches: 4 4 100.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2013, 2016 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #ifndef HINDEX_H
      18                 :            : #define HINDEX_H 1
      19                 :            : 
      20                 :            : /* Hashed multimap.
      21                 :            :  *
      22                 :            :  * hindex is a hash table data structure that gracefully handles duplicates.
      23                 :            :  * With a high-quality hash function, insertion, deletion, and search are O(1)
      24                 :            :  * expected time, regardless of the number of duplicates for a given key.  */
      25                 :            : 
      26                 :            : #include <stdbool.h>
      27                 :            : #include <stdlib.h>
      28                 :            : #include "util.h"
      29                 :            : 
      30                 :            : /* A hash index node, to embed inside the data structure being indexed.
      31                 :            :  *
      32                 :            :  * Nodes are linked together like this (the boxes are labeled with hash
      33                 :            :  * values):
      34                 :            :  *
      35                 :            :  *             +--------+ d   +--------+ d   +--------+ d
      36                 :            :  *  bucket---> |    6   |---->|   20   |---->|   15   |---->null
      37                 :            :  *             +-|------+     +-|------+     +-|------+
      38                 :            :  *               |    ^         |              |    ^
      39                 :            :  *              s|    |d        |s            s|    |d
      40                 :            :  *               V    |         V              V    |
      41                 :            :  *             +------|-+      null          +------|-+
      42                 :            :  *             |    6   |                    |   15   |
      43                 :            :  *             +-|------+                    +-|------+
      44                 :            :  *               |    ^                        |
      45                 :            :  *              s|    |d                      s|
      46                 :            :  *               V    |                        V
      47                 :            :  *             +------|-+                     null
      48                 :            :  *             |    6   |
      49                 :            :  *             +-|------+
      50                 :            :  *               |
      51                 :            :  *              s|
      52                 :            :  *               V
      53                 :            :  *              null
      54                 :            :  *
      55                 :            :  * The basic usage is:
      56                 :            :  *
      57                 :            :  *     - To visit the unique hash values in the hindex, follow the 'd'
      58                 :            :  *       ("different") pointers starting from each bucket.  The nodes visited
      59                 :            :  *       this way are called "head" nodes, because they are at the head of the
      60                 :            :  *       vertical chains.
      61                 :            :  *
      62                 :            :  *     - To visit the nodes with hash value H, follow the 'd' pointers in the
      63                 :            :  *       appropriate bucket until you find one with hash H, then follow the 's'
      64                 :            :  *       ("same") pointers until you hit a null pointer.  The non-head nodes
      65                 :            :  *       visited this way are called "body" nodes.
      66                 :            :  *
      67                 :            :  *     - The 'd' pointers in body nodes point back to the previous body node
      68                 :            :  *       or, for the first body node, to the head node.  (This makes it
      69                 :            :  *       possible to remove a body node without traversing all the way downward
      70                 :            :  *       from the head).
      71                 :            :  */
      72                 :            : struct hindex_node {
      73                 :            :     /* Hash value. */
      74                 :            :     size_t hash;
      75                 :            : 
      76                 :            :     /* In a head node, the next head node (with a hash different from this
      77                 :            :      * node), or NULL if this is the last node in this bucket.
      78                 :            :      *
      79                 :            :      * In a body node, the previous head or body node (with the same hash as
      80                 :            :      * this node).  Never null. */
      81                 :            :     struct hindex_node *d;
      82                 :            : 
      83                 :            :     /* In a head or a body node, the next body node with the same hash as this
      84                 :            :      * node.  NULL if this is the last node with this hash. */
      85                 :            :     struct hindex_node *s;
      86                 :            : };
      87                 :            : 
      88                 :            : /* A hash index. */
      89                 :            : struct hindex {
      90                 :            :     struct hindex_node **buckets; /* Must point to 'one' iff 'mask' == 0. */
      91                 :            :     struct hindex_node *one;
      92                 :            :     size_t mask;      /* 0 or more lowest-order bits set, others cleared. */
      93                 :            :     size_t n_unique;  /* Number of unique hashes (the number of head nodes). */
      94                 :            : };
      95                 :            : 
      96                 :            : /* Initializer for an empty hash index. */
      97                 :            : #define HINDEX_INITIALIZER(HINDEX) \
      98                 :            :     { (struct hindex_node **const) &(HINDEX)->one, NULL, 0, 0 }
      99                 :            : 
     100                 :            : /* Initialization. */
     101                 :            : void hindex_init(struct hindex *);
     102                 :            : void hindex_destroy(struct hindex *);
     103                 :            : void hindex_clear(struct hindex *);
     104                 :            : void hindex_swap(struct hindex *a, struct hindex *b);
     105                 :            : void hindex_moved(struct hindex *hindex);
     106                 :            : static inline bool hindex_is_empty(const struct hindex *);
     107                 :            : 
     108                 :            : /* Adjusting capacity. */
     109                 :            : void hindex_expand(struct hindex *);
     110                 :            : void hindex_shrink(struct hindex *);
     111                 :            : void hindex_reserve(struct hindex *, size_t capacity);
     112                 :            : 
     113                 :            : /* Insertion and deletion. */
     114                 :            : void hindex_insert_fast(struct hindex *, struct hindex_node *, size_t hash);
     115                 :            : void hindex_insert(struct hindex *, struct hindex_node *, size_t hash);
     116                 :            : void hindex_remove(struct hindex *, struct hindex_node *);
     117                 :            : 
     118                 :            : /* Search.
     119                 :            :  *
     120                 :            :  * HINDEX_FOR_EACH_WITH_HASH iterates NODE over all of the nodes in HINDEX that
     121                 :            :  * have hash value equal to HASH.  MEMBER must be the name of the 'struct
     122                 :            :  * hindex_node' member within NODE.
     123                 :            :  *
     124                 :            :  * The loop should not change NODE to point to a different node or insert or
     125                 :            :  * delete nodes in HINDEX (unless it "break"s out of the loop to terminate
     126                 :            :  * iteration).
     127                 :            :  *
     128                 :            :  * Evaluates HASH only once.
     129                 :            :  */
     130                 :            : #define HINDEX_FOR_EACH_WITH_HASH(NODE, MEMBER, HASH, HINDEX)               \
     131                 :            :     for (INIT_CONTAINER(NODE, hindex_node_with_hash(HINDEX, HASH), MEMBER); \
     132                 :            :          NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER);                     \
     133                 :            :          ASSIGN_CONTAINER(NODE, (NODE)->MEMBER.s, MEMBER))
     134                 :            : 
     135                 :            : /* Safe when NODE may be freed (not needed when NODE may be removed from the
     136                 :            :  * hash map but its members remain accessible and intact). */
     137                 :            : #define HINDEX_FOR_EACH_WITH_HASH_SAFE(NODE, NEXT, MEMBER, HASH, HINDEX) \
     138                 :            :     for (INIT_CONTAINER(NODE, hindex_node_with_hash(HINDEX, HASH), MEMBER); \
     139                 :            :          (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)                 \
     140                 :            :           ? INIT_CONTAINER(NEXT, (NODE)->MEMBER.s, MEMBER), 1           \
     141                 :            :           : 0);                                                         \
     142                 :            :          (NODE) = (NEXT))
     143                 :            : 
     144                 :            : /* Returns the head node in 'hindex' with the given 'hash', or a null pointer
     145                 :            :  * if no nodes have that hash value. */
     146                 :            : static inline struct hindex_node *
     147                 :    1327861 : hindex_node_with_hash(const struct hindex *hindex, size_t hash)
     148                 :            : {
     149                 :    1327861 :     struct hindex_node *node = hindex->buckets[hash & hindex->mask];
     150                 :            : 
     151 [ +  + ][ +  + ]:    1793670 :     while (node && node->hash != hash) {
     152                 :     465809 :         node = node->d;
     153                 :            :     }
     154                 :    1327861 :     return node;
     155                 :            : }
     156                 :            : 
     157                 :            : /* Iteration. */
     158                 :            : 
     159                 :            : /* Iterates through every node in HINDEX. */
     160                 :            : #define HINDEX_FOR_EACH(NODE, MEMBER, HINDEX)                           \
     161                 :            :     for (INIT_CONTAINER(NODE, hindex_first(HINDEX), MEMBER);            \
     162                 :            :          NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER);                 \
     163                 :            :          ASSIGN_CONTAINER(NODE, hindex_next(HINDEX, &(NODE)->MEMBER), MEMBER))
     164                 :            : 
     165                 :            : /* Safe when NODE may be freed (not needed when NODE may be removed from the
     166                 :            :  * hash index but its members remain accessible and intact). */
     167                 :            : #define HINDEX_FOR_EACH_SAFE(NODE, NEXT, MEMBER, HINDEX)              \
     168                 :            :     for (INIT_CONTAINER(NODE, hindex_first(HINDEX), MEMBER);          \
     169                 :            :          (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)                 \
     170                 :            :           ? INIT_CONTAINER(NEXT, hindex_next(HINDEX, &(NODE)->MEMBER), MEMBER), 1 \
     171                 :            :           : 0);                                                         \
     172                 :            :          (NODE) = (NEXT))
     173                 :            : 
     174                 :            : struct hindex_node *hindex_first(const struct hindex *);
     175                 :            : struct hindex_node *hindex_next(const struct hindex *,
     176                 :            :                                 const struct hindex_node *);
     177                 :            : 
     178                 :            : /* Returns true if 'hindex' currently contains no nodes, false otherwise. */
     179                 :            : static inline bool
     180                 :     144897 : hindex_is_empty(const struct hindex *hindex)
     181                 :            : {
     182                 :     144897 :     return hindex->n_unique == 0;
     183                 :            : }
     184                 :            : 
     185                 :            : #endif /* hindex.h */

Generated by: LCOV version 1.12