--- parser3/src/include/pa_hash.h 2003/02/06 15:33:15 1.58.2.15 +++ parser3/src/include/pa_hash.h 2007/05/18 12:44:00 1.67 @@ -1,7 +1,7 @@ /** @file Parser: hash class decl. - Copyright (c) 2001-2003 ArtLebedev Group (http://www.artlebedev.com) + Copyright (c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) */ @@ -17,11 +17,23 @@ #ifndef PA_HASH_H #define PA_HASH_H -static const char* IDENT_HASH_H="$Date: 2003/02/06 15:33:15 $"; +static const char * const IDENT_HASH_H="$Date: 2007/05/18 12:44:00 $"; -#include "pa_pool.h" +#include "pa_memory.h" #include "pa_types.h" +const int HASH_ALLOCATES_COUNT=29; + +/** Zend comment: Generated on an Octa-ALPHA 300MHz CPU & 2.5GB RAM monster + + paf: HPUX ld could not handle static member: unsatisfied symbols +*/ +static uint Hash_allocates[HASH_ALLOCATES_COUNT]={ + 5, 11, 19, 53, 107, 223, 463, 983, 1979, 3907, 7963, + 16229, 32531, 65407, 130987, 262237, 524521, 1048793, + 2097397, 4194103, 8388857, 16777447, 33554201, 67108961, + 134217487, 268435697, 536870683, 1073741621, 2147483399}; + /** Simple hash. @@ -37,10 +49,10 @@ public: typedef V value_type; Hash() { - allocated=allocates[allocates_index=0]; + allocated=Hash_allocates[allocates_index=0]; threshold=allocated*THRESHOLD_PERCENT/100; fpairs_count=fused_refs=0; - refs=static_cast(pa_calloc(sizeof(Pair *)*allocated)); + refs=new(UseGC) Pair*[allocated]; } Hash(const Hash& source) { @@ -49,16 +61,27 @@ public: threshold=source.threshold; fused_refs=source.fused_refs; fpairs_count=source.fpairs_count; - refs=new Pair*[allocated]; - memcpy(refs, source.refs, sizeof(Pair *)*allocated); - } - ~Hash() { - destroy_pairs(); - delete refs; + refs=new(UseGC) Pair*[allocated]; + + // clone & rehash + Pair **old_ref=source.refs; + for(int index=0; indexlink; + + Pair **new_ref=&refs[index]; + *new_ref=new Pair(pair->code, pair->key, pair->value, *new_ref); + + pair=next; + } } /// put a [value] under the [key] @returns existed or not bool put(K key, V value) { + if(!value) { + remove(key); + return false; + } if(is_full()) expand(); @@ -80,6 +103,115 @@ public: return false; } + /// put a [value] under the [key] @returns existed or not + template R replace_maybe_append(K key, V value, F prevent, I info) { + if(!value) { + // they can come here from somewhere (true with maybe_replace_maybe_append, keeping parallel) + remove(key); + // this has nothing to do with properties, doing no special property handling here + return 0; + } + + if(is_full()) + expand(); + + uint code=hash_code(key); + 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 + pair->value=value; + return reinterpret_cast(1); + } + + // proper pair not found + // prevent-function intercepted append? + if(R result=prevent(value, info)) + return result; + + //create&link_in new pair + if(!*ref) // root cell were fused_refs? + fused_refs++; // not, we'll use it and record the fact + *ref=new Pair(code, key, value, *ref); + fpairs_count++; + return 0; + } + + /// put a [value] under the [key] @returns existed or not + template + R maybe_replace_maybe_append(K key, V value, F1 prevent_replace, F2 prevent_append, I info) + { + if(!value) { + // they can come here from Temp_value_element::dctor to restore some empty value + remove(key); + // this has nothing to do with properties, doing no special property handling here + return 0; + } + + if(is_full()) + expand(); + + uint code=hash_code(key); + 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 + + // prevent-function intercepted replace? + if(R result=prevent_replace(pair->value, info)) + return result; + + pair->value=value; + return reinterpret_cast(1); + } + + // proper pair not found + // prevent-function intercepted append? + if(R result=prevent_append(value, info)) + return result; + + //create&link_in new pair + if(!*ref) // root cell were fused_refs? + fused_refs++; // not, we'll use it and record the fact + *ref=new Pair(code, key, value, *ref); + fpairs_count++; + return 0; + } + + /// put a [value] under the [key] @returns existed or not + template + R maybe_replace_never_append(K key, V value, F1 prevent_replace, I info) + { + if(!value) { + // they can come here from somewhere (true with maybe_replace_maybe_append, keeping parallel) + remove(key); + // this has nothing to do with properties, doing no special property handling here + return 0; + } + + if(is_full()) + expand(); + + uint code=hash_code(key); + 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 + + // prevent-function intercepted replace? + if(R result=prevent_replace(pair->value, info)) + return result; + + pair->value=value; + return reinterpret_cast(1); + } + + return 0; + } + /// remove the [key] @returns existed or not bool remove(K key) { uint code=hash_code(key); @@ -97,6 +229,20 @@ public: return false; } + /// returns exist key or not + bool contain(K key){ + uint code=hash_code(key); + uint index=code%allocated; + for(Pair **ref=&refs[index]; *ref; ref=&(*ref)->link){ + if((*ref)->code==code && (*ref)->key==key) { + return true; + } + } + + return false; + } + + /// get associated [value] by the [key] V get(K key) const { uint code=hash_code(key); @@ -107,9 +253,13 @@ public: return V(0); } - + /// put a [value] under the [key] if that [key] existed @returns existed or not - bool put_replace(K key, V value) { + bool put_replaced(K key, V value) { + if(!value) { + remove(key); + return false; + } uint code=hash_code(key); uint index=code%allocated; for(Pair *pair=refs[index]; pair; pair=pair->link) @@ -123,8 +273,38 @@ public: return false; } + /// put a [value] under the [key] if that [key] existed @returns existed or not + template R maybe_put_replaced(K key, V value, F prevent) { + if(!value) { + // they can come here from Temp_value_element::dctor to restore some empty value + remove(key); + // this has nothing to do with properties, doing no special property handling here + return 0; + } + + uint code=hash_code(key); + 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 + // prevent-function intercepted put? + if(R result=prevent(pair->value)) + return result; + + pair->value=value; + return reinterpret_cast(1); + } + + // proper pair not found + return 0; + } + /// put a [value] under the [key] if that [key] NOT existed @returns existed or not bool put_dont_replace(K key, V value) { + if(!value) { + remove(key); + return false; + } if(is_full()) expand(); @@ -145,12 +325,13 @@ public: return false; } - /// put all 'src' values if NO with same key existed + /** put all 'src' values if NO with same key existed + @todo optimize this.allocated==src.allocated case + */ void merge_dont_replace(const Hash& src) { for(int i=0; ilink) put_dont_replace(pair->key, pair->value); - // MAY:optimize this.allocated==src.allocated case } /// number of elements in hash @@ -164,6 +345,14 @@ public: callback(pair->key, pair->value, info); } + /// iterate over all pairs + template void for_each_ref(void callback(K, V&, I), I info) const { + Pair **ref=refs; + for(int index=0; indexlink) + callback(pair->key, pair->value, info); + } + /// iterate over all pairs until condition becomes true, return that element template V first_that(bool callback(K, V, I), I info) const { Pair **ref=refs; @@ -177,7 +366,7 @@ public: /// remove all elements void clear() { - destroy_pairs(); memset(refs, 0, sizeof(*refs)*allocated); + memset(refs, 0, sizeof(*refs)*allocated); fpairs_count=fused_refs=0; } @@ -188,14 +377,9 @@ private: THRESHOLD_PERCENT=75 }; - /// the index of [allocated] in [allocates] + /// the index of [allocated] in [Hash_allocates] int allocates_index; - /// possible [allocates]. prime numbers - static uint allocates[]; - - static int allocates_count; - /// number of allocated pairs int allocated; @@ -231,11 +415,11 @@ private: int old_allocated=allocated; Pair **old_refs=refs; + allocates_index=allocates_index+1(pa_calloc(sizeof(Pair *)*allocated)); + refs=new(UseGC) Pair*[allocated]; // rehash Pair **old_ref=old_refs; @@ -251,19 +435,7 @@ private: pair=next; } - delete old_refs; - } - - void destroy_pairs() { - Pair **ref=refs; - for(int index=0; indexlink; - delete pair; - pair=next; - } - } + delete[] old_refs; } private: //disabled @@ -271,36 +443,42 @@ private: //disabled Hash& operator = (const Hash&) { return *this; } }; -/* Zend comment: Generated on an Octa-ALPHA 300MHz CPU & 2.5GB RAM monster */ -template -uint Hash::allocates[]={ - 5, 11, 19, 53, 107, 223, 463, 983, 1979, 3907, 7963, - 16229, 32531, 65407, 130987, 262237, 524521, 1048793, - 2097397, 4194103, 8388857, 16777447, 33554201, 67108961, - 134217487, 268435697, 536870683, 1073741621, 2147483399}; - -template -int Hash::allocates_count=sizeof(allocates)/sizeof(uint); +/// useful generic hash function +inline void generic_hash_code(uint& result, char c) { + result=(result<<4)+c; + if(uint g=(result&0xF0000000)) { + result=result^(g>>24); + result=result^g; + } +} +/// useful generic hash function +inline void generic_hash_code(uint& result, const char* s) { + while(char c=*s++) { + result=(result<<4)+c; + if(uint g=(result&0xF0000000)) { + result=result^(g>>24); + result=result^g; + } + } +} /// useful generic hash function -inline uint generic_hash_code(uint aresult, const char* start, size_t allocated) { - uint result=aresult, g; - const char* end=start+allocated; - - while (start>24); result=result^g; } } - return result; } /// simple hash code of int. used by EXIF mapping inline uint hash_code(int self) { uint result=0; - return generic_hash_code(result, (const char*)self, sizeof(self)); + generic_hash_code(result, (const char*)&self, sizeof(self)); + return result; } /// Auto-object used to temporarily substituting/removing hash values