LCOV - code coverage report
Current view: directory - src/trusted/service_runtime/generic_container - container.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 180 77 42.8 %
Date: 2012-02-16 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright 2008 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can
       4                 :  * be found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : /*
       8                 :  * NaCl Generic containers.
       9                 :  */
      10                 : #include "native_client/src/include/portability.h"
      11                 : #include <stdio.h>
      12                 : #include <stdlib.h>
      13                 : 
      14                 : #include "native_client/src/trusted/service_runtime/generic_container/container.h"
      15                 : 
      16                 : static struct NaClContainerVtbl const  kNaClContainerListVtbl = {
      17                 :   NaClContainerListInsert,
      18                 :   NaClContainerListFind,
      19                 :   NaClContainerListDtor,
      20                 :   sizeof(struct NaClContainerListIter),
      21                 :   NaClContainerListIterCtor,
      22                 : };
      23                 : 
      24                 : 
      25                 : /*
      26                 :  * functor_obj is the comparison functor, and is the first argument to
      27                 :  * cmp_fn as the "self" (or more commonly "this") argument.  arguably
      28                 :  * we should create an explicit object with a vtable containing the
      29                 :  * single comparison function pointer, but this is so simple that that
      30                 :  * seems overkill.
      31                 :  */
      32                 : int NaClContainerListCtor(struct NaClContainerList  *self,
      33               0 :                           struct NaClCmpFunctor     *cmp_functor) {
      34               0 :   self->cmp_functor = cmp_functor;
      35               0 :   self->head = 0;
      36                 : 
      37               0 :   self->base.vtbl = &kNaClContainerListVtbl;
      38               0 :   return 1;
      39                 : }
      40                 : 
      41                 : 
      42               0 : int NaClContainerListIterAtEnd(struct NaClContainerIter *vself) {
      43               0 :   struct NaClContainerListIter  *self = (struct NaClContainerListIter *) vself;
      44                 : 
      45               0 :   return *self->cur == 0;
      46                 : }
      47                 : 
      48                 : 
      49               0 : void *NaClContainerListIterStar(struct NaClContainerIter *vself) {
      50               0 :   struct NaClContainerListIter  *self = (struct NaClContainerListIter *) vself;
      51                 : 
      52               0 :   return (*self->cur)->datum;
      53                 : }
      54                 : 
      55                 : 
      56               0 : void NaClContainerListIterIncr(struct NaClContainerIter  *vself) {
      57               0 :   struct NaClContainerListIter  *self = (struct NaClContainerListIter *) vself;
      58                 : 
      59               0 :   self->cur = &(*self->cur)->next;
      60               0 : }
      61                 : 
      62                 : 
      63               0 : void NaClContainerListIterErase(struct NaClContainerIter  *vself) {
      64               0 :   struct NaClContainerListIter  *self = (struct NaClContainerListIter *) vself;
      65               0 :   struct NaClItemList           *doomed = *self->cur;
      66               0 :   struct NaClItemList           *next = (*self->cur)->next;
      67                 : 
      68               0 :   *self->cur = next;
      69               0 :   free(doomed->datum);
      70               0 :   free(doomed);
      71               0 : }
      72                 : 
      73                 : 
      74               0 : void *NaClContainerListIterExtract(struct NaClContainerIter  *vself) {
      75               0 :   struct NaClContainerListIter  *self = (struct NaClContainerListIter *) vself;
      76               0 :   struct NaClItemList           *doomed = *self->cur;
      77               0 :   struct NaClItemList           *next = (*self->cur)->next;
      78                 :   void                          *datum;
      79                 : 
      80               0 :   *self->cur = next;
      81               0 :   datum = doomed->datum;
      82               0 :   free(doomed);
      83               0 :   return datum;
      84                 : }
      85                 : 
      86                 : static struct NaClContainerIterVtbl const   kNaClContainerListIterVtbl = {
      87                 :   NaClContainerListIterAtEnd,
      88                 :   NaClContainerListIterStar,
      89                 :   NaClContainerListIterIncr,
      90                 :   NaClContainerListIterErase,
      91                 :   NaClContainerListIterExtract,
      92                 : };
      93                 : 
      94                 : 
      95                 : int NaClContainerListInsert(struct NaClContainer  *vself,
      96               0 :                             void                  *obj) {
      97               0 :   struct NaClContainerList    *self = (struct NaClContainerList *) vself;
      98               0 :   struct NaClItemList         *new_entry = malloc(sizeof *new_entry);
      99                 :   struct NaClItemList         **ipp;
     100                 :   struct NaClItemList         *ip;
     101                 : 
     102               0 :   if (!new_entry)
     103               0 :     return 0;
     104                 : 
     105               0 :   new_entry->datum = obj;
     106                 : 
     107               0 :   for (ipp = &self->head; 0 != (ip = *ipp); ipp = &ip->next) {
     108               0 :     if ((*self->cmp_functor->vtbl->OrderCmp)(self->cmp_functor,
     109                 :                                              obj, ip->datum) >= 0) {
     110               0 :       break;
     111                 :     }
     112                 :   }
     113                 : 
     114               0 :   new_entry->next = ip;
     115               0 :   *ipp = new_entry;
     116               0 :   return 1;
     117                 : }
     118                 : 
     119                 : 
     120                 : struct NaClContainerIter  *NaClContainerListFind(
     121                 :     struct NaClContainer      *vself,
     122                 :     void                      *key,
     123               0 :     struct NaClContainerIter  *vout) {
     124               0 :   struct NaClContainerList        *self = (struct NaClContainerList *) vself;
     125                 :   struct NaClItemList             **ipp;
     126                 :   struct NaClItemList             *ip;
     127               0 :   struct NaClContainerListIter    *out = (struct NaClContainerListIter *) vout;
     128                 : 
     129               0 :   for (ipp = &self->head; (ip = *ipp) != 0; ipp = &ip->next) {
     130               0 :     if ((*self->cmp_functor->vtbl->OrderCmp)(self->cmp_functor,
     131                 :                                              key, ip->datum) == 0) {
     132               0 :       break;
     133                 :     }
     134                 :   }
     135               0 :   out->cur = ipp;
     136                 : 
     137               0 :   vout->vtbl = &kNaClContainerListIterVtbl;
     138               0 :   return vout;
     139                 : }
     140                 : 
     141                 : 
     142               0 : void NaClContainerListDtor(struct NaClContainer  *vself) {
     143               0 :   struct NaClContainerList    *self = (struct NaClContainerList *) vself;
     144                 :   struct NaClItemList         *cur, *next;
     145                 : 
     146               0 :   for (cur = self->head; cur; cur = next) {
     147               0 :     next = cur->next;
     148               0 :     free(cur->datum);
     149               0 :     free(cur);
     150                 :   }
     151               0 : }
     152                 : 
     153                 : 
     154                 : int NaClContainerListIterCtor(struct NaClContainer      *vself,
     155               0 :                               struct NaClContainerIter  *viter) {
     156               0 :   struct NaClContainerList      *self = (struct NaClContainerList *) vself;
     157               0 :   struct NaClContainerListIter  *iter = (struct NaClContainerListIter *) viter;
     158                 : 
     159               0 :   iter->cur = &self->head;
     160                 : 
     161               0 :   viter->vtbl = &kNaClContainerListIterVtbl;
     162               0 :   return 1;
     163                 : }
     164                 : 
     165                 : 
     166                 : static struct NaClContainerVtbl const  kNaClContainerHashTblVtbl = {
     167                 :   NaClContainerHashTblInsert,
     168                 :   NaClContainerHashTblFind,
     169                 :   NaClContainerHashTblDtor,
     170                 :   sizeof(struct NaClContainerHashTblIter),
     171                 :   NaClContainerHashTblIterCtor,
     172                 : };
     173                 : 
     174                 : #define HASH_TABLE_LOAD_FACTOR      2
     175                 : #define HASH_TABLE_STRIDE           17
     176                 : /*
     177                 :  * The stride p is prime, so it is co-prime with any num_bucket value
     178                 :  * (except for its own multiples) and thus linear probing by
     179                 :  * increments of the stride will visit every bucket.  (I.e., the
     180                 :  * stride value is a generator for the additive group Z_k^+, where
     181                 :  * k=num_bucket.)  Assume that (k,p)=1.
     182                 :  *
     183                 :  * (p,+) is a generator is another way of saying that
     184                 :  * 0,p,2p,3p,...,(k-1)p (mod k) is a permutation of 0,1,...,k-1.
     185                 :  *
     186                 :  * assume otherwise, so (p,+) generates a subgroup of Z_k^+.  let n be
     187                 :  * the least integer greater than 0 where np=0 mod k, i.e., 0 < n < k.
     188                 :  * since (p) doesn't generate Z_k^+, we have n < k.  then np=mk for
     189                 :  * some integer m>0.  since p is prime and p \not| k but p divides mk,
     190                 :  * p must divide m.  write m=pq.  then np = pqk, so n = qk.  =><=
     191                 :  *
     192                 :  * The co-primality of the stride and number of bucket is a
     193                 :  * precondition for the insertion algorithm terminating.  (Another
     194                 :  * precondition is that there is an unused slot.)
     195                 :  *
     196                 :  * We expand the hash table by doubling the number of buckets.  Thus,
     197                 :  * if num_bucket starts off co-prime with the stride, it will remain
     198                 :  * so.
     199                 :  */
     200                 : #define HASH_TABLE_MIN_BUCKETS      32
     201                 : /*
     202                 :  * must be greater than HASH_TABLE_STRIDE and not a multiple so that
     203                 :  * they're co-prime.
     204                 :  */
     205                 : 
     206                 : static struct NaClContainerHashTblEntry *NaClContainerHashTblMakeBucket(
     207             240 :     size_t size) {
     208                 :   struct NaClContainerHashTblEntry    *bucket;
     209                 : 
     210             240 :   if (SIZE_T_MAX / sizeof *bucket < size) {
     211               0 :     return NULL;
     212                 :   }
     213             240 :   bucket = calloc(size, sizeof *bucket);
     214             240 :   return bucket;
     215                 : }
     216                 : 
     217                 : 
     218                 : /*
     219                 :  * The functor_obj is the comparison and hash functor.  It is always
     220                 :  * passed as the first arguments to cmp_fn and hash_fn to allow these
     221                 :  * member functions to use its members to determine how to
     222                 :  * compare/hash.  Arguably we should define a class with a vtable
     223                 :  * containing two virtual functions, but we don't expect there to be
     224                 :  * many object instances.
     225                 :  */
     226                 : int NaClContainerHashTblCtor(struct NaClContainerHashTbl  *self,
     227                 :                              struct NaClHashFunctor       *hash_functor,
     228              48 :                              size_t                       num_buckets) {
     229                 :   int success;
     230                 : 
     231              48 :   self->base.vtbl = (struct NaClContainerVtbl *) NULL;
     232                 : 
     233                 :   /* silently increase number of buckets if too small */
     234              48 :   if (num_buckets < HASH_TABLE_MIN_BUCKETS) {
     235               0 :     num_buckets = HASH_TABLE_MIN_BUCKETS;
     236                 :   }
     237                 :   /* if a multiple of stride, silently increase it */
     238              48 :   if (0 == (num_buckets % HASH_TABLE_STRIDE)) {
     239               0 :     ++num_buckets;
     240                 :   }
     241                 : 
     242              48 :   self->hash_functor = hash_functor;
     243              48 :   self->num_buckets = num_buckets;
     244              48 :   self->num_entries = 0;
     245              48 :   self->bucket = NaClContainerHashTblMakeBucket(num_buckets);
     246                 : 
     247              48 :   success = self->bucket != 0;
     248                 : 
     249              48 :   if (success) {
     250              48 :     self->base.vtbl = &kNaClContainerHashTblVtbl;
     251                 :   }
     252              48 :   return success;
     253                 : }
     254                 : 
     255                 : 
     256          190848 : int NaClContainerHashTblCheckLoad(struct NaClContainerHashTbl *self) {
     257                 :   struct NaClContainerHashTblEntry  *entry;
     258                 :   struct NaClContainerHashTblEntry  *new_table;
     259                 :   struct NaClContainerHashTblEntry  *old_table;
     260                 :   size_t                            new_size;
     261                 :   size_t                            old_size;
     262                 :   size_t                            i;
     263                 : 
     264                 :   /*
     265                 :    * Check load factor.  If greater than THRESHOLD, double number of
     266                 :    * buckets and rehash.
     267                 :    */
     268          190848 :   if (HASH_TABLE_LOAD_FACTOR * self->num_entries < self->num_buckets)
     269          190656 :     return 1;
     270                 : 
     271             192 :   old_size = self->num_buckets;
     272             192 :   new_size = 2 * old_size;
     273                 :   /*
     274                 :    * arithmetic overflow?!?  we normally would not have enough memory
     275                 :    */
     276             192 :   if (new_size < old_size)
     277               0 :     return 0;
     278                 : 
     279             192 :   new_table = NaClContainerHashTblMakeBucket(new_size);
     280             192 :   if (!new_table)
     281               0 :     return 0;
     282                 : 
     283             192 :   old_table = self->bucket;
     284             192 :   self->bucket = new_table;
     285                 : 
     286             192 :   self->num_buckets = new_size;
     287             192 :   self->num_entries = 0;
     288                 : 
     289                 :   /*
     290                 :    * The rehash/transfer to the new, expanded table should not fail,
     291                 :    * since the Insert method (below) does not fail.
     292                 :    */
     293          185232 :   for (i = 0; i < old_size; i++) {
     294          185040 :     entry = &old_table[i];
     295          185040 :     if (NACL_CHTE_USED != entry->flags) {
     296           92496 :       continue;
     297                 :     }
     298           92544 :     (*self->base.vtbl->Insert)((struct NaClContainer *) self,
     299                 :                                entry->datum);
     300                 :   }
     301                 : 
     302             192 :   free(old_table);
     303             192 :   return 1;
     304                 : }
     305                 : 
     306                 : 
     307                 : static uintptr_t HashNext(uintptr_t idx,
     308          168915 :                           size_t    modulus) {
     309          168915 :   idx += HASH_TABLE_STRIDE;
     310          339076 :   while (idx >= modulus) {
     311            1246 :     idx -= modulus;
     312                 :   }
     313          168915 :   return idx;
     314                 : }
     315                 : 
     316                 : 
     317                 : int NaClContainerHashTblInsert(struct NaClContainer *vself,
     318          190848 :                                void                 *obj) {
     319          190848 :   struct NaClContainerHashTbl *self = (struct NaClContainerHashTbl *) vself;
     320                 :   uintptr_t                   idx;
     321                 : 
     322                 :   for (idx = (*self->hash_functor->vtbl->Hash)(self->hash_functor,
     323          190848 :                                                obj) % self->num_buckets;
     324          428394 :        NACL_CHTE_USED == self->bucket[idx].flags;
     325           46698 :        idx = HashNext(idx, self->num_buckets)) {
     326                 :   }
     327                 :   /* unused or deleted */
     328          190848 :   self->bucket[idx].datum = obj;
     329          190848 :   self->bucket[idx].flags = NACL_CHTE_USED;
     330          190848 :   ++self->num_entries;
     331                 : 
     332          190848 :   return NaClContainerHashTblCheckLoad(self);
     333                 : }
     334                 : 
     335                 : 
     336                 : /* fwd */
     337                 : static struct NaClContainerIterVtbl const kNaClContainerHashTblIterVtbl;
     338                 : 
     339                 : 
     340                 : struct NaClContainerIter *NaClContainerHashTblFind(
     341                 :     struct NaClContainer      *vself,
     342                 :     void                      *key,
     343          344016 :     struct NaClContainerIter  *vout) {
     344                 :   struct NaClContainerHashTbl     *self
     345          344016 :       = (struct NaClContainerHashTbl *) vself;
     346                 :   uintptr_t                       idx;
     347                 :   struct NaClContainerHashTblIter *out
     348          344016 :       = (struct NaClContainerHashTblIter *) vout;
     349                 : 
     350                 :   for (idx = (*self->hash_functor->vtbl->Hash)(self->hash_functor,
     351          344016 :                                                key) % self->num_buckets;
     352          810249 :        0 != self->bucket[idx].flags;
     353          122217 :        idx = HashNext(idx, self->num_buckets)) {
     354          318777 :     if (0 != (self->bucket[idx].flags & NACL_CHTE_USED)
     355                 :         && ((*self->hash_functor->vtbl->base.OrderCmp)
     356                 :             ((struct NaClCmpFunctor *) self->hash_functor,
     357                 :              self->bucket[idx].datum, key)) == 0) {
     358          196560 :       break;
     359                 :     }
     360                 :   }
     361          344016 :   if (0 == self->bucket[idx].flags) {
     362                 :     /* not found */
     363          147456 :     idx = self->num_buckets;
     364                 :   }
     365                 : 
     366          344016 :   out->htbl = self;
     367          344016 :   out->idx = idx;
     368                 : 
     369          344016 :   vout->vtbl = &kNaClContainerHashTblIterVtbl;
     370          344016 :   return vout;
     371                 : }
     372                 : 
     373                 : 
     374              48 : void NaClContainerHashTblDtor(struct NaClContainer *vself) {
     375              48 :   struct NaClContainerHashTbl *self = (struct NaClContainerHashTbl *) vself;
     376                 :   unsigned int                idx;
     377                 : 
     378          197424 :   for (idx = 0; idx < self->num_buckets; ++idx) {
     379          197376 :     if (self->bucket[idx].flags & NACL_CHTE_USED) {
     380           98304 :       free(self->bucket[idx].datum);
     381                 :     }
     382                 :   }
     383              48 :   free(self->bucket);
     384              48 :   self->bucket = 0;
     385              48 : }
     386                 : 
     387                 : 
     388          344016 : int NaClContainerHashTblIterAtEnd(struct NaClContainerIter  *vself) {
     389                 :   struct NaClContainerHashTblIter *self
     390          344016 :       = (struct NaClContainerHashTblIter *) vself;
     391                 : 
     392          344016 :   return self->idx >= self->htbl->num_buckets;
     393                 : }
     394                 : 
     395                 : 
     396          196560 : void *NaClContainerHashTblIterStar(struct NaClContainerIter  *vself) {
     397                 :   struct NaClContainerHashTblIter *self
     398          196560 :       = (struct NaClContainerHashTblIter *) vself;
     399                 : 
     400          196560 :   return self->htbl->bucket[self->idx].datum;
     401                 : }
     402                 : 
     403                 : 
     404               0 : void NaClContainerHashTblIterIncr(struct NaClContainerIter   *vself) {
     405                 :   struct NaClContainerHashTblIter *self
     406               0 :       = (struct NaClContainerHashTblIter *) vself;
     407                 : 
     408               0 :   while (++self->idx < self->htbl->num_buckets) {
     409               0 :     if (self->htbl->bucket[self->idx].flags == NACL_CHTE_USED)
     410               0 :       return;
     411                 :   }
     412                 :   /* self->idx == self->htbl->num_buckets imply AtEnd */
     413               0 :   return;
     414                 : }
     415                 : 
     416                 : 
     417               0 : void NaClContainerHashTblIterErase(struct NaClContainerIter   *vself) {
     418                 :   struct NaClContainerHashTblIter *self
     419               0 :       = (struct NaClContainerHashTblIter *) vself;
     420                 : 
     421               0 :   if (self->htbl->bucket[self->idx].flags == NACL_CHTE_USED) {
     422               0 :     --self->htbl->num_entries;
     423                 :   }
     424               0 :   self->htbl->bucket[self->idx].flags = NACL_CHTE_DELETED;
     425               0 :   free(self->htbl->bucket[self->idx].datum);
     426               0 :   self->htbl->bucket[self->idx].datum = 0;
     427               0 :   (*vself->vtbl->Incr)(vself);
     428               0 : }
     429                 : 
     430                 : 
     431               0 : void *NaClContainerHashTblIterExtract(struct NaClContainerIter   *vself) {
     432                 :   struct NaClContainerHashTblIter *self
     433               0 :       = (struct NaClContainerHashTblIter *) vself;
     434                 :   void                        *datum;
     435                 : 
     436               0 :   if (self->htbl->bucket[self->idx].flags == NACL_CHTE_USED) {
     437               0 :     --self->htbl->num_entries;
     438                 :   }
     439               0 :   self->htbl->bucket[self->idx].flags = NACL_CHTE_DELETED;
     440               0 :   datum = self->htbl->bucket[self->idx].datum;
     441               0 :   self->htbl->bucket[self->idx].datum = 0;
     442               0 :   (*vself->vtbl->Incr)(vself);
     443                 : 
     444               0 :   return datum;
     445                 : }
     446                 : 
     447                 : 
     448                 : static struct NaClContainerIterVtbl const kNaClContainerHashTblIterVtbl = {
     449                 :   NaClContainerHashTblIterAtEnd,
     450                 :   NaClContainerHashTblIterStar,
     451                 :   NaClContainerHashTblIterIncr,
     452                 :   NaClContainerHashTblIterErase,
     453                 :   NaClContainerHashTblIterExtract,
     454                 : };
     455                 : 
     456                 : 
     457                 : int NaClContainerHashTblIterCtor(struct NaClContainer     *vself,
     458               0 :                                  struct NaClContainerIter *viter) {
     459                 :   struct NaClContainerHashTbl     *self
     460               0 :       = (struct NaClContainerHashTbl *) vself;
     461                 :   struct NaClContainerHashTblIter *iter
     462               0 :       = (struct NaClContainerHashTblIter *) viter;
     463                 : 
     464               0 :   viter->vtbl = &kNaClContainerHashTblIterVtbl;
     465               0 :   iter->htbl = self;
     466               0 :   iter->idx = 0;
     467               0 :   if (0 == (self->bucket[0].flags & NACL_CHTE_USED)) {
     468               0 :     NaClContainerHashTblIterIncr(viter);
     469                 :   }
     470               0 :   return 1;
     471                 : }

Generated by: LCOV version 1.7