diff --git a/src/mapping.c b/src/mapping.c index 7773ea2801a41ce1c0bdc07255422fe0bca83cfb..0bac36f53c513a84f7113401738ecdd1123426aa 100644 --- a/src/mapping.c +++ b/src/mapping.c @@ -306,6 +306,7 @@ PMOD_EXPORT void do_free_mapping(struct mapping *m) * order in each hash chain. This is to prevent mappings from becoming * inefficient just after being rehashed. */ +/* Evil: Steal the svalues from the old md. */ static void mapping_rehash_backwards_evil(struct mapping_data *md, struct keypair *from) { @@ -326,6 +327,49 @@ static void mapping_rehash_backwards_evil(struct mapping_data *md, /* Rehash and reverse the hash chain. */ while (from) { + if (md->flags & MAPPING_WEAK) { + + switch(md->flags & MAPPING_WEAK) { + default: + Pike_fatal("Instable mapping data flags.\n"); + case MAPPING_WEAK_INDICES: + if ((TYPEOF(from->ind) <= MAX_REF_TYPE) && + (*from->ind.u.refs > 1)) { + goto keep_keypair; + } + break; + case MAPPING_WEAK_VALUES: + if ((TYPEOF(from->val) <= MAX_REF_TYPE) && + (*from->val.u.refs > 1)) { + goto keep_keypair; + } + break; + case MAPPING_WEAK: + if ((TYPEOF(from->ind) <= MAX_REF_TYPE) && + (*from->ind.u.refs > 1) && + (TYPEOF(from->val) <= MAX_REF_TYPE) && + (*from->val.u.refs > 1)) { + goto keep_keypair; + } + break; + } + + /* Free. + * Note that we don't need to free or unlink the keypair, + * since that will be done by the caller anyway. */ + free_svalue(&from->ind); + free_svalue(&from->val); + + /* Reverse */ + prev = from->next; + from->next = next; + next = from; + from = prev; + + continue; + } + keep_keypair: + /* unlink */ k=md->free_list; #ifndef PIKE_MAPPING_KEYPAIR_LOOP @@ -359,6 +403,7 @@ static void mapping_rehash_backwards_evil(struct mapping_data *md, } } +/* Good: Copy the svalues from the old md. */ static void mapping_rehash_backwards_good(struct mapping_data *md, struct keypair *from) { @@ -379,6 +424,50 @@ static void mapping_rehash_backwards_good(struct mapping_data *md, /* Rehash and reverse the hash chain. */ while (from) { + if (md->flags & MAPPING_WEAK) { + + switch(md->flags & MAPPING_WEAK) { + default: + Pike_fatal("Instable mapping data flags.\n"); + case MAPPING_WEAK_INDICES: + if ((TYPEOF(from->ind) <= MAX_REF_TYPE) && + (*from->ind.u.refs > 1)) { + goto keep_keypair; + } + break; + case MAPPING_WEAK_VALUES: + if ((TYPEOF(from->val) <= MAX_REF_TYPE) && + (*from->val.u.refs > 1)) { + goto keep_keypair; + } + break; + case MAPPING_WEAK: + if ((TYPEOF(from->ind) <= MAX_REF_TYPE) && + (*from->ind.u.refs > 1) && + (TYPEOF(from->val) <= MAX_REF_TYPE) && + (*from->val.u.refs > 1)) { + goto keep_keypair; + } + break; + } + + /* Skip copying of this keypair. + * + * NB: We can't mess with the original md here, + * since it might be in use by an iterator + * or similar. + */ + + /* Reverse */ + prev = from->next; + from->next = next; + next = from; + from = prev; + + continue; + } + keep_keypair: + /* unlink */ k=md->free_list; #ifndef PIKE_MAPPING_KEYPAIR_LOOP @@ -452,12 +541,19 @@ static struct mapping *rehash(struct mapping *m, int new_size) if(md->refs>1) { /* good */ + /* More than one reference to the md ==> We need to + * keep it afterwards. + */ for(e=0;e<md->hashsize;e++) mapping_rehash_backwards_good(new_md, md->hash[e]); unlink_mapping_data(md); }else{ /* evil */ + /* We have the only reference to the md, + * so we can just copy the svalues without + * bothering about type checking. + */ for(e=0;e<md->hashsize;e++) mapping_rehash_backwards_evil(new_md, md->hash[e]);