LCOV - code coverage report
Current view: top level - src/compiler/hash_tables - scope_table.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 39 39 100.0 %
Date: 2016-11-30 13:12:14 Functions: 6 13 46.2 %
Branches: 31 38 81.6 %

           Branch data     Line data    Source code
       1                 :            :  /* Note: only one hash table can be implemented a single file. */
       2                 :            : 
       3                 :            : 
       4                 :            : /*
       5                 :            :  * The generic hash table is designed to make the key length optional
       6                 :            :  * and we do not need it because our key is a terminated token list.
       7                 :            :  *
       8                 :            :  * The token list avoids having to allocated a new string and the
       9                 :            :  * associated issues of memory management. In most cases the search key
      10                 :            :  * is also a similar token list.
      11                 :            :  *
      12                 :            :  * However, on occasion we need to look up an unparsed string of dot
      13                 :            :  * separated scopes (nested_flatbuffer attributes). This is not
      14                 :            :  * trivially possible without reverting to allocating the strings.
      15                 :            :  * We could parse the attribute into tokens but it is also non-trivial
      16                 :            :  * because the token buffer breaks pointers when reallocating and
      17                 :            :  * the parse output is considered read-only at this point.
      18                 :            :  *
      19                 :            :  * We can however, use a trick to overcome this because the hash table
      20                 :            :  * does not enforce that the search key has same representation as the
      21                 :            :  * stored key. We can use the key length to switch between key types.
      22                 :            :  *
      23                 :            :  * When the key is paresed to a token list:
      24                 :            :  *
      25                 :            :  *   enemy: MyGame . Example.Monster
      26                 :            :  *
      27                 :            :  * the spaces in dots may be ignored by the parser.
      28                 :            :  * Spaces must be handled explicitly or disallowed when the key is
      29                 :            :  * parsed as an attribute string (only the quoted content):
      30                 :            :  *
      31                 :            :  *   (nested_flatbuffer:"MyGame.Example.Monster")
      32                 :            :  *
      33                 :            :  * vs
      34                 :            :  *
      35                 :            :  *   (nested_flatbuffer:"MyGame . Example.Monster")
      36                 :            :  *
      37                 :            :  * Googles flatc allows spaces in the token stream where dots are
      38                 :            :  * operators, but not in attribute strings which are supposed to
      39                 :            :  * be unique so we follow that convention.
      40                 :            :  *
      41                 :            :  * On both key representations, preprocessing must strip the trailing
      42                 :            :  * symbol stored within the scope before lookup - minding that this
      43                 :            :  * lookup only finds the scope itself. For token lists this can be
      44                 :            :  * done by either zero terminating the list early, or by issuing
      45                 :            :  * a negative length (after cast to int) of elements to consider. For
      46                 :            :  * string keys the key length should be made to the length to be
      47                 :            :  * considered.
      48                 :            :  *
      49                 :            :  * If the scope string is zero length, a null key should be issued
      50                 :            :  * with zero length. This is indistinguishly from a null length token
      51                 :            :  * list - both indicating a global scope - null thus being a valid key.
      52                 :            :  * 
      53                 :            :  * Note: it is important to not use a non-null zero length string
      54                 :            :  * as key.
      55                 :            :  */
      56                 :            : 
      57                 :            : #include "../symbols.h"
      58                 :            : 
      59                 :            : static inline size_t scope_hash(const void *s, size_t len);
      60                 :            : #define HT_HASH_FUNCTION scope_hash
      61                 :            : 
      62                 :            : #include "hash/hash_table_def.h"
      63         [ +  - ]:        724 : DEFINE_HASH_TABLE(fb_scope_table)
      64                 :            : #include "hash/hash_table_impl.h"
      65                 :            : 
      66                 :            : /* Null is a valid key used for root scopes. */
      67                 :        169 : static inline int ht_match(const void *key, size_t len, fb_scope_t *scope)
      68                 :            : {
      69                 :        169 :     const fb_ref_t *name = scope->name;
      70                 :        169 :     int count = (int)len;
      71                 :            :     size_t n1, n2, i;
      72                 :            : 
      73                 :            :     /* Note: `name` may be null here - this is the global scope name. */
      74         [ +  + ]:        169 :     if (count <= 0) {
      75                 :            :         const fb_ref_t *keyname = key;
      76                 :            :         /*
      77                 :            :          * If count is negative, this is the token count of the key
      78                 :            :          * which may have suffix to be ignored, otherwise the key is the
      79                 :            :          * full list.
      80                 :            :          */
      81                 :            :         /* `key` is a ref list (a list of tokens). */
      82         [ +  + ]:        234 :         while (name && keyname) {
      83                 :        145 :             n1 = name->ident->len;
      84                 :        145 :             n2 = keyname->ident->len;
      85 [ +  - ][ +  - ]:        145 :             if (n1 != n2 || strncmp(name->ident->text, keyname->ident->text, n1)) {
      86                 :            :                 return 0;
      87                 :            :             }
      88                 :        145 :             name = name->link;
      89                 :        145 :             keyname = keyname->link;
      90         [ +  + ]:        145 :             if (++count == 0) {
      91                 :        247 :                 return name == 0;
      92                 :            :             }
      93                 :            :         }
      94         [ +  + ]:         89 :         if (name || keyname) {
      95                 :            :             return 0;
      96                 :            :         }
      97                 :            :         return 1;
      98                 :            :     } else {
      99                 :            :         /* `key` is a dotted string. */
     100                 :            :         const char *s1, *s2 = key;
     101         [ +  - ]:          2 :         while (name) {
     102                 :          2 :             s1 = name->ident->text;
     103                 :          2 :             n1 = name->ident->len;
     104         [ +  - ]:          2 :             if (n1 > len) {
     105                 :            :                 return 0;
     106                 :            :             }
     107         [ +  + ]:         13 :             for (i = 0; i < n1; ++i) {
     108         [ +  - ]:         11 :                 if (s1[i] != s2[i]) {
     109                 :            :                     return 0;
     110                 :            :                 }
     111                 :            :             }
     112         [ +  + ]:          2 :             if (n1 == len) {
     113                 :          1 :                 return name->link == 0;
     114                 :            :             }
     115         [ +  - ]:          1 :             if (s2[i] != '.') {
     116                 :            :                 return 0;
     117                 :            :             }
     118                 :          1 :             len -= n1 + 1;
     119                 :          1 :             s2 += n1 + 1;
     120                 :          1 :             name = name->link;
     121                 :            :         }
     122                 :            :         return 0;
     123                 :            :     }
     124                 :            : }
     125                 :            : 
     126                 :            : static inline const void *ht_key(fb_scope_t *scope)
     127                 :            : {
     128                 :            :     return scope->name;
     129                 :            : }
     130                 :            : 
     131                 :            : static inline size_t ht_key_len(fb_scope_t *scope)
     132                 :            : {
     133                 :            :     (void)scope;
     134                 :            :     /*
     135                 :            :      * Must be zero because the result is passed to ht_match
     136                 :            :      * when comparing two stored items for hash conflicts.
     137                 :            :      * Only external lookup keys can be non-zero.
     138                 :            :      */
     139                 :            :     return 0;
     140                 :            : }
     141                 :            : 
     142                 :        249 : static inline size_t scope_hash(const void *key, size_t len)
     143                 :            : {
     144                 :            :     size_t h = 0, i;
     145                 :        249 :     int count = (int)len;
     146                 :            : 
     147         [ +  + ]:        249 :     if (count <= 0) {
     148                 :            :         const fb_ref_t *name = key;
     149                 :            : 
     150         [ +  + ]:        427 :         while (name) {
     151                 :        258 :             h ^= ht_strn_hash_function(name->ident->text, name->ident->len);
     152                 :            :             h = ht_int_hash_function((void *)h, 0);
     153                 :        258 :             name = name->link;
     154         [ +  + ]:        506 :             if (++count == 0) {
     155                 :            :                 break;
     156                 :            :             }
     157                 :            :         }
     158                 :            :         return h;
     159                 :            :     } else {
     160                 :            :         const char *s = key;
     161                 :            :         for (;;) {
     162         [ +  + ]:         13 :             for (i = 0; i < len; ++i) {
     163         [ +  + ]:         13 :                 if (s[i] == '.') {
     164                 :            :                     break;
     165                 :            :                 }
     166                 :            :             }
     167                 :          2 :             h ^= ht_strn_hash_function(s, i);
     168                 :            :             h = ht_int_hash_function((void *)h, 0);
     169         [ +  + ]:          2 :             if (i == len) {
     170                 :            :                 break;
     171                 :            :             }
     172                 :          1 :             len -= i + 1;
     173                 :          1 :             s += i + 1;
     174                 :            :         }
     175                 :            :         return h;
     176                 :            :     }
     177                 :            : }

Generated by: LCOV version 1.12