|
|
| version 1.8, 2001/01/29 20:10:32 | version 1.43, 2001/10/29 13:04:46 |
|---|---|
| Line 1 | Line 1 |
| /* | /** @file |
| $Id$ | Parser: hash class. |
| Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com) | |
| Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf) | |
| $Id$ | |
| */ | */ |
| /* | /* |
| Line 10 | Line 15 |
| For more information about Zend please visit http://www.zend.com/ | For more information about Zend please visit http://www.zend.com/ |
| */ | */ |
| #include "pa_pool.h" | #include "pa_hash.h" |
| #include "pa_threads.h" | |
| void *Hash::Pair::operator new(size_t size, Pool& apool) { | void *Hash::Pair::operator new(size_t size, Pool& apool) { |
| return apool.malloc(size); | return apool.malloc(size, 6); |
| } | } |
| /* Zend comment: Generated on an Octa-ALPHA 300MHz CPU & 2.5GB RAM monster */ | /* Zend comment: Generated on an Octa-ALPHA 300MHz CPU & 2.5GB RAM monster */ |
| uint Hash::sizes[]={ | uint Hash::allocates[]={ |
| 5, 11, 19, 53, 107, 223, 463, 983, 1979, 3907, 7963, | 5, 11, 19, 53, 107, 223, 463, 983, 1979, 3907, 7963, |
| 16229, 32531, 65407, 130987, 262237, 524521, 1048793, | 16229, 32531, 65407, 130987, 262237, 524521, 1048793, |
| 2097397, 4194103, 8388857, 16777447, 33554201, 67108961, | 2097397, 4194103, 8388857, 16777447, 33554201, 67108961, |
| 134217487, 268435697, 536870683, 1073741621, 2147483399}; | 134217487, 268435697, 536870683, 1073741621, 2147483399}; |
| int Hash::sizes_count= | int Hash::allocates_count= |
| sizeof(sizes)/sizeof(uint); | sizeof(allocates)/sizeof(uint); |
| void *Hash::operator new(size_t size, Pool& apool) { | |
| return apool.malloc(size); | |
| } | |
| Hash::Hash(Pool& apool, bool athread_safe) : | void Hash::construct_new() { |
| pool(apool), | allocated=allocates[allocates_index=0]; |
| thread_safe(athread_safe) { | threshold=allocated*THRESHOLD_PERCENT/100; |
| count=used=0; | |
| size=sizes[size_index=0]; | refs=static_cast<Pair **>(calloc(sizeof(Pair *)*allocated)); |
| threshold=size*THRESHOLD_PERCENT/100; | } |
| used=0; | |
| refs=static_cast<Pair **>(pool.calloc(sizeof(Pair *)*size)); | void Hash::construct_copy(const Hash& source) { |
| allocates_index=source.allocates_index; | |
| allocated=source.allocated; | |
| threshold=source.threshold; | |
| used=source.used; | |
| count=source.count; | |
| size_t size=sizeof(Pair *)*allocated; | |
| refs=static_cast<Pair **>(malloc(size, 7)); memcpy(refs, source.refs, size); | |
| } | } |
| void Hash::expand() { | void Hash::expand() { |
| int old_size=size; | int old_size=allocated; |
| Pair **old_refs=refs; | Pair **old_refs=refs; |
| // allocated bigger refs array | // allocated bigger refs array |
| size_index=size_index+1<sizes_count?size_index+1:sizes_count-1; | allocates_index=allocates_index+1<allocates_count?allocates_index+1:allocates_count-1; |
| size=sizes[size_index]; | allocated=allocates[allocates_index]; |
| refs=static_cast<Pair **>(pool.calloc(sizeof(Pair *)*size)); | threshold=allocated*THRESHOLD_PERCENT/100; |
| refs=static_cast<Pair **>(calloc(sizeof(Pair *)*allocated)); | |
| // rehash | // rehash |
| Pair **old_ref=old_refs; | Pair **old_ref=old_refs; |
| Line 55 void Hash::expand() { | Line 64 void Hash::expand() { |
| for(Pair *pair=*old_ref++; pair; ) { | for(Pair *pair=*old_ref++; pair; ) { |
| Pair *linked_pair=pair->link; | Pair *linked_pair=pair->link; |
| uint new_index=pair->code%size; | uint new_index=pair->code%allocated; |
| Pair **new_ref=&refs[new_index]; | Pair **new_ref=&refs[new_index]; |
| pair->link=*new_ref; | pair->link=*new_ref; |
| *new_ref=pair; | *new_ref=pair; |
| Line 64 void Hash::expand() { | Line 73 void Hash::expand() { |
| } | } |
| } | } |
| uint Hash::generic_code(uint aresult, char *start, uint size) { | uint Hash::generic_code(uint aresult, const char *start, uint allocated) { |
| uint result=aresult, g; | uint result=aresult, g; |
| char *end=start+size; | const char *end=start+allocated; |
| while (start<end) { | while (start<end) { |
| result=(result<<4)+*start++; | result=(result<<4)+*start++; |
| Line 78 uint Hash::generic_code(uint aresult, ch | Line 87 uint Hash::generic_code(uint aresult, ch |
| return result; | return result; |
| } | } |
| void Hash::put(Key& key, Value *value) { SYNCHRONIZED(thread_safe); | bool Hash::put(const Key& key, Val *value) { |
| if(full()) | if(full()) |
| expand(); | expand(); |
| uint code=key.hash_code(); | uint code=key.hash_code(); |
| uint index=code%size; | uint index=code%allocated; |
| Pair **ref=&refs[index]; | Pair **ref=&refs[index]; |
| for(Pair *pair=*ref; pair; pair=pair->link) | for(Pair *pair=*ref; pair; pair=pair->link) |
| if(pair->code==code && pair->key==key) { | if(pair->code==code && pair->key==key) { |
| // found a pair with the same key | // found a pair with the same key |
| pair->value=value; | pair->value=value; |
| return; | return true; |
| } | } |
| // proper pair not found -- create&link_in new pair | // proper pair not found -- create&link_in new pair |
| *ref=new(pool) Pair(code, key, value, *ref); | if(!*ref) // root cell were used? |
| used++; // not, we'll use it and record the fact | |
| *ref=NEW Pair(code, key, value, *ref); | |
| count++; | |
| return false; | |
| } | } |
| Hash::Value *Hash::get(Key& key) { SYNCHRONIZED(thread_safe); | Hash::Val *Hash::get(const Key& key) const { |
| uint code=key.hash_code(); | uint code=key.hash_code(); |
| uint index=code%size; | uint index=code%allocated; |
| for(Pair *pair=refs[index]; pair; pair=pair->link) | for(Pair *pair=refs[index]; pair; pair=pair->link) |
| if(pair->code==code && pair->key==key) | if(pair->code==code && pair->key==key) |
| return pair->value; | return pair->value; |
| return 0; | return 0; |
| } | } |
| bool Hash::put_replace(const Key& key, Val *value) { | |
| uint code=key.hash_code(); | |
| uint index=code%allocated; | |
| for(Pair *pair=refs[index]; pair; pair=pair->link) | |
| if(pair->code==code && pair->key==key) { | |
| // found a pair with the same key, replacing | |
| pair->value=value; | |
| return true; | |
| } | |
| // proper pair not found | |
| return false; | |
| } | |
| bool Hash::put_dont_replace(const Key& key, Val *value) { | |
| if(full()) | |
| expand(); | |
| uint code=key.hash_code(); | |
| uint index=code%allocated; | |
| Pair **ref=&refs[index]; | |
| for(Pair *pair=*ref; pair; pair=pair->link) | |
| if(pair->code==code && pair->key==key) { | |
| // found a pair with the same key, NOT replacing | |
| return true; | |
| } | |
| // proper pair not found -- create&link_in new pair | |
| if(!*ref) // root cell were used? | |
| used++; // not, we'll use it and record the fact | |
| *ref=NEW Pair(code, key, value, *ref); | |
| count++; | |
| return false; | |
| } | |
| void Hash::merge_dont_replace(const Hash& src) { | |
| for(int i=0; i<src.allocated; i++) | |
| for(Pair *pair=src.refs[i]; pair; pair=pair->link) | |
| put_dont_replace(pair->key, pair->value); | |
| // MAY:optimize this.allocated==src.allocated case | |
| } | |
| void Hash::for_each(For_each_func func, void *info) const { | |
| Pair **ref=refs; | |
| for(int index=0; index<allocated; index++) | |
| for(Pair *pair=*ref++; pair; pair=pair->link) | |
| if(pair->value) | |
| (*func)(pair->key, pair->value, info); | |
| } | |
| void Hash::for_each(For_each_func_refed func, void *info) const { | |
| Pair **ref=refs; | |
| for(int index=0; index<allocated; index++) | |
| for(Pair *pair=*ref++; pair; pair=pair->link) | |
| if(pair->value) | |
| (*func)(pair->key, pair->value, info); | |
| } | |
| void* Hash::first_that(First_that_func func, void *info) const { | |
| Pair **ref=refs; | |
| for(int index=0; index<allocated; index++) | |
| for(Pair *pair=*ref++; pair; pair=pair->link) | |
| if(pair->value) | |
| if(void *result=(*func)(pair->key, pair->value, info)) | |
| return result; | |
| return 0; | |
| } | |
| void Hash::clear() { | |
| memset(refs, 0, sizeof(*refs)*allocated); | |
| count=used=0; | |
| } |