Changeset 3d5c1b18b9912541a77e63bdb908db34f068b328

Show
Ignore:
Timestamp:
04/23/08 10:02:37 (9 months ago)
Author:
David Balmain <dbalmain@…>
Parents:
399100f1271aa3320cae55afa2d8364875291971
Children:
b39568e8202274e6aed953a924659cef1f971d55, aee5f1150b23fd9469c1afe18187627c2320550d
git-committer:
David Balmain <dbalmain@gmail.com> / 2008-04-23T10:02:37Z+1000
Message:

Modifed integer Hash to also accept pointers

Integer hash has been improved so that it stores a dummy key instead of any old
junk which it was storing before. The h_lookup_int has been changed to
h_lookup_ptr but it is still used by h_set_int etc. I'll soon be adding
h_new_ptr which will be an optimized hash, especially for storing Symbols.

Location:
c
Files:
6 modified

Legend:

Unmodified
Added
Removed
  • c/Rakefile

    r553474 r3d5c1b  
    386386end 
    387387 
    388 task :valgrind => 'testall' do 
    389         sh "valgrind --suppressions=valgrind.supp " + 
    390                 "--leak-check=yes             " + 
    391                 "--show-reachable=yes         " + 
    392                 "--workaround-gcc296-bugs=yes -v ./testall -q" 
    393 end 
    394  
    395 task :gen_valgrind => 'build:testall' do 
    396         sh "valgrind --suppressions=valgrind.supp " + 
    397                 "--leak-check=yes             " + 
    398                 "--show-reachable=yes         " + 
    399                 "--gen-suppressions=yes       " + 
    400                 "--workaround-gcc296-bugs=yes -v ./testall -q" 
     388task :valgrind do 
     389  check_coptions 
     390  Rake::Task[:testall].invoke 
     391  sh "valgrind --suppressions=valgrind.supp " + 
     392              "--leak-check=yes             " + 
     393              "--show-reachable=yes         " + 
     394              "--workaround-gcc296-bugs=yes -v ./testall -q" 
     395end 
     396 
     397task :gen_valgrind do 
     398  check_coptions 
     399  Rake::Task[:testall].invoke 
     400  sh "valgrind --suppressions=valgrind.supp " + 
     401              "--leak-check=yes             " + 
     402              "--show-reachable=yes         " + 
     403              "--gen-suppressions=yes       " + 
     404              "--workaround-gcc296-bugs=yes -v ./testall -q" 
    401405end 
    402406 
  • c/include/hash.h

    r553474 r3d5c1b  
    6161     * used outside of the Hash methods */ 
    6262    FrtHashEntry *(*lookup_i)(struct FrtHash *self, 
    63                                     register const void *key); 
     63                              register const void *key); 
    6464    unsigned long (*hash_i)(const void *key); 
    6565    int           (*eq_i)(const void *key1, const void *key2); 
     
    275275 * @param self the Hash to add the value to 
    276276 * @param key the key to use to reference the value 
    277  * @return HashEntry a pointer to the hash entry object now reserved for this 
     277 * @param he HashEntry a pointer to the hash entry object now reserved for this 
    278278 * value. Be sure to set both the *key* and the *value* 
    279  */ 
    280 extern FrtHashEntry *frt_h_set_ext(FrtHash *ht, const void *key); 
     279 * @return true if the key was empty, false otherwise 
     280 */ 
     281extern FRT_INLINE bool h_set_ext(FrtHash *self, 
     282                                 const void *key, 
     283                                 FrtHashEntry **he); 
    281284 
    282285/** 
  • c/include/internal.h

    r4ba05f r3d5c1b  
    528528#define h_rem_int                               frt_h_rem_int 
    529529#define h_set                                   frt_h_set 
    530 #define h_set_ext                               frt_h_set_ext 
    531530#define h_set_int                               frt_h_set_int 
    532531#define h_set_safe                              frt_h_set_safe 
  • c/src/hash.c

    r48290f r3d5c1b  
    1313 
    1414static char *dummy_key = ""; 
     15static char *dummy_int_key = "i"; 
     16 
    1517 
    1618#define PERTURB_SHIFT 5 
     
    4749} 
    4850 
    49 static int int_eq(const void *q1, const void *q2) 
    50 { 
    51     (void)q1; 
    52     (void)q2; 
    53     return true; 
    54 } 
    55  
    56 static unsigned long int_hash(const void *i) 
    57 { 
    58     return *((unsigned long *)i); 
    59 } 
    60  
    61 typedef HashEntry *(*lookup_ft)(struct Hash *ht, register const void *key); 
     51typedef HashEntry *(*lookup_ft)(struct Hash *self, register const void *key); 
    6252 
    6353/** 
     
    6555 * deletes to worry about. 
    6656 * 
    67  * @param ht the Hash to do the fast lookup in 
     57 * @param self the Hash to do the fast lookup in 
    6858 * @param the hashkey we are looking for 
    6959 */ 
    70 static INLINE HashEntry *h_resize_lookup(Hash *ht, 
     60static INLINE HashEntry *h_resize_lookup(Hash *self, 
    7161                                         register const unsigned long hash) 
    7262{ 
    7363    register unsigned long perturb; 
    74     register int mask = ht->mask; 
    75     register HashEntry *he0 = ht->table; 
     64    register int mask = self->mask; 
     65    register HashEntry *he0 = self->table; 
    7666    register int i = hash & mask; 
    7767    register HashEntry *he = &he0[i]; 
     
    9282} 
    9383 
    94 static HashEntry *h_lookup_int(Hash *ht, const void *key) 
    95 { 
    96     register const unsigned long hash = *((int *)key); 
     84static HashEntry *h_lookup_ptr(Hash *self, const void *key) 
     85{ 
     86    register const unsigned long hash = (long)key; 
    9787    register unsigned long perturb; 
    98     register int mask = ht->mask; 
    99     register HashEntry *he0 = ht->table; 
     88    register int mask = self->mask; 
     89    register HashEntry *he0 = self->table; 
    10090    register int i = hash & mask; 
    10191    register HashEntry *he = &he0[i]; 
     
    129119} 
    130120 
    131 HashEntry *h_lookup(Hash *ht, register const void *key) 
    132 { 
    133     register const unsigned long hash = ht->hash_i(key); 
     121HashEntry *h_lookup(Hash *self, register const void *key) 
     122{ 
     123    register const unsigned long hash = self->hash_i(key); 
    134124    register unsigned long perturb; 
    135     register int mask = ht->mask; 
    136     register HashEntry *he0 = ht->table; 
     125    register int mask = self->mask; 
     126    register HashEntry *he0 = self->table; 
    137127    register int i = hash & mask; 
    138128    register HashEntry *he = &he0[i]; 
    139129    register HashEntry *freeslot = NULL; 
    140     eq_ft eq = ht->eq_i; 
     130    eq_ft eq = self->eq_i; 
    141131 
    142132    if (he->key == NULL || he->key == key) { 
     
    176166Hash *h_new_str(free_ft free_key, free_ft free_value) 
    177167{ 
    178     Hash *ht; 
     168    Hash *self; 
    179169    if (num_free_hts > 0) { 
    180         ht = free_hts[--num_free_hts]; 
     170        self = free_hts[--num_free_hts]; 
    181171    } 
    182172    else { 
    183         ht = ALLOC(Hash); 
    184     } 
    185     ht->fill = 0; 
    186     ht->size = 0; 
    187     ht->mask = HASH_MINSIZE - 1; 
    188     ht->table = ht->smalltable; 
    189     memset(ht->smalltable, 0, sizeof(ht->smalltable)); 
    190     ht->lookup_i = (lookup_ft)&h_lookup; 
    191     ht->eq_i = str_eq; 
    192     ht->hash_i = (hash_ft)str_hash; 
    193  
    194     ht->free_key_i = free_key != NULL ? free_key : &dummy_free; 
    195     ht->free_value_i = free_value != NULL ? free_value : &dummy_free; 
    196     ht->ref_cnt = 1; 
    197     return ht; 
     173        self = ALLOC(Hash); 
     174    } 
     175    self->fill = 0; 
     176    self->size = 0; 
     177    self->mask = HASH_MINSIZE - 1; 
     178    self->table = self->smalltable; 
     179    memset(self->smalltable, 0, sizeof(self->smalltable)); 
     180    self->lookup_i = (lookup_ft)&h_lookup; 
     181    self->eq_i = str_eq; 
     182    self->hash_i = (hash_ft)str_hash; 
     183 
     184    self->free_key_i = free_key != NULL ? free_key : &dummy_free; 
     185    self->free_value_i = free_value != NULL ? free_value : &dummy_free; 
     186    self->ref_cnt = 1; 
     187    return self; 
    198188} 
    199189 
    200190Hash *h_new_int(free_ft free_value) 
    201191{ 
    202     Hash *ht = h_new_str(NULL, free_value); 
    203     ht->lookup_i = &h_lookup_int; 
    204     ht->eq_i = int_eq; 
    205     ht->hash_i = int_hash; 
    206     return ht; 
     192    Hash *self     = h_new_str(NULL, free_value); 
     193 
     194    self->lookup_i = &h_lookup_ptr; 
     195    self->eq_i     = NULL; 
     196    self->hash_i   = NULL; 
     197 
     198    return self; 
     199} 
     200 
     201Hash *h_new_ptr(free_ft free_key, free_ft free_value) 
     202{ 
     203    Hash *self     = h_new_str(free_key, free_value); 
     204 
     205    self->lookup_i = &h_lookup_ptr; 
     206    self->eq_i     = NULL; 
     207    self->hash_i   = NULL; 
     208 
     209    return self; 
    207210} 
    208211 
    209212Hash *h_new(hash_ft hash, eq_ft eq, free_ft free_key, free_ft free_value) 
    210213{ 
    211     Hash *ht = h_new_str(free_key, free_value); 
    212  
    213     ht->lookup_i = &h_lookup; 
    214     ht->eq_i = eq; 
    215     ht->hash_i = hash; 
    216     return ht; 
    217 } 
    218  
    219 void h_clear(Hash *ht) 
     214    Hash *self     = h_new_str(free_key, free_value); 
     215 
     216    self->lookup_i = &h_lookup; 
     217    self->eq_i     = eq; 
     218    self->hash_i   = hash; 
     219 
     220    return self; 
     221} 
     222 
     223void h_clear(Hash *self) 
    220224{ 
    221225    int i; 
    222226    HashEntry *he; 
    223     free_ft free_key = ht->free_key_i; 
    224     free_ft free_value = ht->free_value_i; 
     227    free_ft free_key   = self->free_key_i; 
     228    free_ft free_value = self->free_value_i; 
    225229 
    226230    /* Clear all the hash values and keys as necessary */ 
    227231    if (free_key != dummy_free || free_value != dummy_free) { 
    228         for (i = 0; i <= ht->mask; i++) { 
    229             he = &ht->table[i]; 
     232        for (i = 0; i <= self->mask; i++) { 
     233            he = &self->table[i]; 
    230234            if (he->key != NULL && he->key != dummy_key) { 
    231235                free_value(he->value); 
     
    235239        } 
    236240    } 
    237     ZEROSET_N(ht->table, HashEntry, ht->mask + 1); 
    238     ht->size = 0; 
    239     ht->fill = 0; 
    240 } 
    241  
    242 void h_destroy(Hash *ht) 
    243 { 
    244     if (--(ht->ref_cnt) <= 0) { 
    245         h_clear(ht); 
     241    ZEROSET_N(self->table, HashEntry, self->mask + 1); 
     242    self->size = 0; 
     243    self->fill = 0; 
     244} 
     245 
     246void h_destroy(Hash *self) 
     247{ 
     248    if (--(self->ref_cnt) <= 0) { 
     249        h_clear(self); 
    246250 
    247251        /* if a new table was created, be sure to free it */ 
    248         if (ht->table != ht->smalltable) { 
    249             free(ht->table); 
     252        if (self->table != self->smalltable) { 
     253            free(self->table); 
    250254        } 
    251255 
    252256#ifdef DEBUG 
    253         free(ht); 
     257        free(self); 
    254258#else 
    255259        if (num_free_hts < MAX_FREE_HASH_TABLES) { 
    256             free_hts[num_free_hts++] = ht; 
     260            free_hts[num_free_hts++] = self; 
    257261        } 
    258262        else { 
    259             free(ht); 
     263            free(self); 
    260264        } 
    261265#endif 
     
    263267} 
    264268 
    265 void *h_get(Hash *ht, const void *key) 
     269void *h_get(Hash *self, const void *key) 
    266270{ 
    267271    /* Note: lookup_i will never return NULL. */ 
    268     return ht->lookup_i(ht, key)->value; 
    269 } 
    270  
    271 int h_del(Hash *ht, const void *key) 
    272 { 
    273     HashEntry *he = ht->lookup_i(ht, key); 
     272    return self->lookup_i(self, key)->value; 
     273} 
     274 
     275int h_del(Hash *self, const void *key) 
     276{ 
     277    HashEntry *he = self->lookup_i(self, key); 
    274278 
    275279    if (he->key != NULL && he->key != dummy_key) { 
    276         ht->free_key_i(he->key); 
    277         ht->free_value_i(he->value); 
     280        self->free_key_i(he->key); 
     281        self->free_value_i(he->value); 
    278282        he->key = dummy_key; 
    279283        he->value = NULL; 
    280         ht->size--; 
     284        self->size--; 
    281285        return true; 
    282286    } 
     
    286290} 
    287291 
    288 void *h_rem(Hash *ht, const void *key, bool destroy_key) 
     292void *h_rem(Hash *self, const void *key, bool destroy_key) 
    289293{ 
    290294    void *val; 
    291     HashEntry *he = ht->lookup_i(ht, key); 
     295    HashEntry *he = self->lookup_i(self, key); 
    292296 
    293297    if (he->key != NULL && he->key != dummy_key) { 
    294298        if (destroy_key) { 
    295             ht->free_key_i(he->key); 
     299            self->free_key_i(he->key); 
    296300        } 
    297301 
     
    299303        val = he->value; 
    300304        he->value = NULL; 
    301         ht->size--; 
     305        self->size--; 
    302306        return val; 
    303307    } 
     
    307311} 
    308312 
    309 static int h_resize(Hash *ht, int min_newsize) 
     313static int h_resize(Hash *self, int min_newsize) 
    310314{ 
    311315    HashEntry smallcopy[HASH_MINSIZE]; 
     
    318322    } 
    319323 
    320     oldtable = ht->table; 
     324    oldtable = self->table; 
    321325    if (newsize == HASH_MINSIZE) { 
    322         if (ht->table == ht->smalltable) { 
    323             /* need to copy the d*(int *)ata out so we can rebuild the table into 
     326        if (self->table == self->smalltable) { 
     327            /* need to copy the data out so we can rebuild the table into 
    324328             * the same space */ 
    325             memcpy(smallcopy, ht->smalltable, sizeof(smallcopy)); 
     329            memcpy(smallcopy, self->smalltable, sizeof(smallcopy)); 
    326330            oldtable = smallcopy; 
    327331        } 
    328332        else { 
    329             ht->table = ht->smalltable; 
     333            self->table = self->smalltable; 
    330334        } 
    331335    } 
    332336    else { 
    333         ht->table = ALLOC_N(HashEntry, newsize); 
    334     } 
    335     memset(ht->table, 0, sizeof(HashEntry) * newsize); 
    336     ht->fill = ht->size; 
    337     ht->mask = newsize - 1; 
    338  
    339     for (num_active = ht->size, he_old = oldtable; num_active > 0; he_old++) { 
     337        self->table = ALLOC_N(HashEntry, newsize); 
     338    } 
     339    memset(self->table, 0, sizeof(HashEntry) * newsize); 
     340    self->fill = self->size; 
     341    self->mask = newsize - 1; 
     342 
     343    for (num_active = self->size, he_old = oldtable; num_active > 0; he_old++) { 
    340344        if (he_old->key && he_old->key != dummy_key) {    /* active entry */ 
    341             /*he_new = ht->lookup_i(ht, he_old->key); */ 
    342             he_new = h_resize_lookup(ht, he_old->hash); 
     345            /*he_new = self->lookup_i(self, he_old->key); */ 
     346            he_new = h_resize_lookup(self, he_old->hash); 
    343347            he_new->key = he_old->key; 
    344348            he_new->value = he_old->value; 
     
    346350        }                       /* else empty entry so nothing to do */ 
    347351    } 
    348     if (oldtable != smallcopy && oldtable != ht->smalltable) { 
     352    if (oldtable != smallcopy && oldtable != self->smalltable) { 
    349353        free(oldtable); 
    350354    } 
     
    352356} 
    353357 
    354 HashKeyStatus h_set(Hash *ht, const void *key, void *value) 
     358INLINE bool h_set_ext(Hash *self, const void *key, HashEntry **he) 
     359{ 
     360    *he = self->lookup_i(self, key); 
     361    if ((*he)->key == NULL) { 
     362        if (self->fill * 3 > self->mask * 2) { 
     363            h_resize(self, self->size * ((self->size > SLOW_DOWN) ? 4 : 2)); 
     364            *he = self->lookup_i(self, key); 
     365        } 
     366        self->fill++; 
     367        self->size++; 
     368        return true; 
     369    } 
     370    else if ((*he)->key == dummy_key) { 
     371        self->size++; 
     372        return true; 
     373    } 
     374 
     375    return false; 
     376} 
     377 
     378HashKeyStatus h_set(Hash *self, const void *key, void *value) 
    355379{ 
    356380    HashKeyStatus ret_val = HASH_KEY_DOES_NOT_EXIST; 
    357     HashEntry *he = ht->lookup_i(ht, key); 
    358     if (he->key == NULL) { 
    359         if (ht->fill * 3 > ht->mask * 2) { 
    360             h_resize(ht, ht->size * ((ht->size > SLOW_DOWN) ? 4 : 2)); 
    361             he = ht->lookup_i(ht, key); 
    362         } 
    363         ht->fill++; 
    364         ht->size++; 
    365     } 
    366     else if (he->key == dummy_key) { 
    367         ht->size++; 
    368     } 
    369     else if (he->key != key) { 
    370         ht->free_key_i(he->key); 
    371         if (he->value != value) { 
    372             ht->free_value_i(he->value); 
    373         } 
    374         ret_val = HASH_KEY_EQUAL; 
    375     } 
    376     else { 
    377         /* safety check. Only free old value if it isn't the new value */ 
    378         if (he->value != value) { 
    379             ht->free_value_i(he->value); 
    380         } 
    381         ret_val = HASH_KEY_SAME; 
     381    HashEntry *he; 
     382    if (!h_set_ext(self, key, &he)) { 
     383        if (he->key != key) { 
     384            self->free_key_i(he->key); 
     385            if (he->value != value) { 
     386                self->free_value_i(he->value); 
     387            } 
     388            ret_val = HASH_KEY_EQUAL; 
     389        } 
     390        else { 
     391            /* Only free old value if it isn't the new value */ 
     392            if (he->value != value) { 
     393                self->free_value_i(he->value); 
     394            } 
     395            ret_val = HASH_KEY_SAME; 
     396        } 
    382397    } 
    383398    he->key = (void *)key; 
    384399    he->value = value; 
    385400 
    386     /* 
    387     if ((ht->fill > fill) && (ht->fill * 3 > ht->mask * 2)) { 
    388         h_resize(ht, ht->size * ((ht->size > SLOW_DOWN) ? 4 : 2)); 
    389     } 
    390     */ 
    391401    return ret_val; 
    392402} 
    393403 
    394 HashEntry *h_set_ext(Hash *ht, const void *key) 
    395 { 
    396     HashEntry *he = ht->lookup_i(ht, key); 
    397     if (he->key == NULL) { 
    398         if (ht->fill * 3 > ht->mask * 2) { 
    399             h_resize(ht, ht->size * ((ht->size > SLOW_DOWN) ? 4 : 2)); 
    400             he = ht->lookup_i(ht, key); 
    401         } 
    402         ht->fill++; 
    403         ht->size++; 
    404     } 
    405     else if (he->key == dummy_key) { 
    406         ht->size++; 
    407     } 
    408  
    409     return he; 
    410 } 
    411  
    412 int h_set_safe(Hash *ht, const void *key, void *value) 
    413 { 
    414     HashEntry *he = ht->lookup_i(ht, key); 
    415     int fill = ht->fill; 
    416     if (he->key == NULL) { 
    417         ht->fill++; 
    418         ht->size++; 
    419     } 
    420     else if (he->key == dummy_key) { 
    421         ht->size++; 
     404int h_set_safe(Hash *self, const void *key, void *value) 
     405{ 
     406    HashEntry *he; 
     407    if (h_set_ext(self, key, &he)) { 
     408        he->key = (void *)key; 
     409        he->value = value; 
     410        return true; 
    422411    } 
    423412    else { 
    424413        return false; 
    425414    } 
    426     he->key = (void *)key; 
    427     he->value = value; 
    428  
    429     if ((ht->fill > fill) && (ht->fill * 3 > ht->mask * 2)) { 
    430         h_resize(ht, ht->size * ((ht->size > SLOW_DOWN) ? 4 : 2)); 
    431     } 
    432     return true; 
    433 } 
    434  
    435 HashKeyStatus h_has_key(Hash *ht, const void *key) 
    436 { 
    437     HashEntry *he = ht->lookup_i(ht, key); 
     415} 
     416 
     417HashKeyStatus h_has_key(Hash *self, const void *key) 
     418{ 
     419    HashEntry *he = self->lookup_i(self, key); 
    438420    if (he->key == NULL || he->key == dummy_key) { 
    439421        return HASH_KEY_DOES_NOT_EXIST; 
     
    445427} 
    446428 
    447 void *h_get_int(Hash *self, const unsigned long key) 
    448 { 
    449     return h_get(self, &key); 
    450 } 
    451  
    452 int h_del_int(Hash *self, const unsigned long key) 
    453 { 
    454     return h_del(self, &key); 
    455 } 
    456  
    457 void *h_rem_int(Hash *self, const unsigned long key) 
    458 { 
    459     return h_rem(self, &key, false); 
    460 } 
    461  
    462 HashKeyStatus h_set_int(Hash *self, 
    463                              const unsigned long key, 
    464                              void *value) 
    465 { 
    466     return h_set(self, &key, value); 
    467 } 
    468  
    469 int h_set_safe_int(Hash *self, const unsigned long key, void *value) 
    470 { 
    471     return h_set_safe(self, &key, value); 
    472 } 
    473  
    474 int h_has_key_int(Hash *self, const unsigned long key) 
    475 { 
    476     return h_has_key(self, &key); 
    477 } 
    478  
    479 void h_each(Hash *ht, 
     429INLINE void *h_get_int(Hash *self, const unsigned long key) 
     430{ 
     431    return h_get(self, (const void *)key); 
     432} 
     433 
     434INLINE int h_del_int(Hash *self, const unsigned long key) 
     435{ 
     436    return h_del(self, (const void *)key); 
     437} 
     438 
     439INLINE void *h_rem_int(Hash *self, const unsigned long key) 
     440{ 
     441    return h_rem(self, (const void *)key, false); 
     442} 
     443 
     444INLINE HashKeyStatus h_set_int(Hash *self, 
     445                               const unsigned long key, 
     446                               void *value) 
     447{ 
     448    HashKeyStatus ret_val = HASH_KEY_DOES_NOT_EXIST; 
     449    HashEntry *he; 
     450    if (!h_set_ext(self, (const void *)key, &he)) { 
     451        /* Only free old value if it isn't the new value */ 
     452        if (he->value != value) { 
     453            self->free_value_i(he->value); 
     454        } 
     455        ret_val = HASH_KEY_EQUAL; 
     456    } 
     457    he->key = dummy_int_key; 
     458    he->value = value; 
     459 
     460    return ret_val; 
     461} 
     462 
     463INLINE int h_set_safe_int(Hash *self, const unsigned long key, void *value) 
     464{ 
     465    HashEntry *he; 
     466    if (h_set_ext(self, (const void *)key, &he)) { 
     467        he->key = dummy_int_key; 
     468        he->value = value; 
     469        return true; 
     470    } 
     471    return false; 
     472} 
     473 
     474INLINE int h_has_key_int(Hash *self, const unsigned long key) 
     475{ 
     476    return h_has_key(self, (const void *)key); 
     477} 
     478 
     479void h_each(Hash *self, 
    480480            void (*each_kv) (void *key, void *value, void *arg), void *arg) 
    481481{ 
    482482    HashEntry *he; 
    483     int i = ht->size; 
    484     for (he = ht->table; i > 0; he++) { 
     483    int i = self->size; 
     484    for (he = self->table; i > 0; he++) { 
    485485        if (he->key && he->key != dummy_key) {        /* active entry */ 
    486486            each_kv(he->key, he->value, arg); 
     
    490490} 
    491491 
    492 Hash *h_clone(Hash *ht, 
    493                    h_clone_ft clone_key, h_clone_ft clone_value) 
     492Hash *h_clone(Hash *self, h_clone_ft clone_key, h_clone_ft clone_value) 
    494493{ 
    495494    void *key, *value; 
    496495    HashEntry *he; 
    497     int i = ht->size; 
     496    int i = self->size; 
    498497    Hash *ht_clone; 
    499498 
    500   &n