|
|
| version 1.58.2.18.2.5, 2003/03/21 16:16:43 | version 1.71, 2009/04/17 13:13:09 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: hash class decl. | 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 <paf@design.ru> (http://paf.design.ru) | Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) |
| */ | */ |
| Line 17 | Line 17 |
| #ifndef PA_HASH_H | #ifndef PA_HASH_H |
| #define PA_HASH_H | #define PA_HASH_H |
| static const char* IDENT_HASH_H="$Date$"; | static const char * const IDENT_HASH_H="$Date$"; |
| #include "pa_memory.h" | #include "pa_memory.h" |
| #include "pa_types.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}; | |
| /// 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 void generic_hash_code(uint& result, const char* buf, size_t size) { | |
| const char* end=buf+size; | |
| while(buf<end) { | |
| result=(result<<4)+*buf++; | |
| if(uint g=(result&0xF0000000)) { | |
| result=result^(g>>24); | |
| result=result^g; | |
| } | |
| } | |
| } | |
| /// simple hash code of int. used by EXIF mapping | |
| inline uint hash_code(int self) { | |
| uint result=0; | |
| generic_hash_code(result, (const char*)&self, sizeof(self)); | |
| return result; | |
| } | |
| /** | /** |
| Simple hash. | Simple hash. |
| Line 37 public: | Line 87 public: |
| typedef V value_type; | typedef V value_type; |
| Hash() { | Hash() { |
| allocated=allocates[allocates_index=0]; | allocated=Hash_allocates[allocates_index=0]; |
| threshold=allocated*THRESHOLD_PERCENT/100; | threshold=allocated*THRESHOLD_PERCENT/100; |
| fpairs_count=fused_refs=0; | fpairs_count=fused_refs=0; |
| refs=new(0) Pair*[allocated]; | refs=new(UseGC) Pair*[allocated]; |
| } | } |
| Hash(const Hash& source) { | Hash(const Hash& source) { |
| Line 49 public: | Line 99 public: |
| threshold=source.threshold; | threshold=source.threshold; |
| fused_refs=source.fused_refs; | fused_refs=source.fused_refs; |
| fpairs_count=source.fpairs_count; | fpairs_count=source.fpairs_count; |
| refs=new(0) Pair*[allocated]; | refs=new(UseGC) Pair*[allocated]; |
| // clone & rehash | // clone & rehash |
| Pair **old_ref=source.refs; | Pair **old_ref=source.refs; |
| Line 64 public: | Line 114 public: |
| } | } |
| } | } |
| ~Hash() { | |
| delete[] refs; | |
| } | |
| /// put a [value] under the [key] @returns existed or not | /// put a [value] under the [key] @returns existed or not |
| bool put(K key, V value) { | bool put(K key, V value) { |
| if(!value) { | if(!value) { |
| Line 91 public: | Line 145 public: |
| return false; | return false; |
| } | } |
| /// put a [value] under the [key] @returns existed or not | |
| template<typename R, typename F, typename I> 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<R>(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<typename R, typename F1, typename F2, typename I> | |
| 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<R>(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<typename R, typename F1, typename I> | |
| 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<R>(1); | |
| } | |
| return 0; | |
| } | |
| /// remove the [key] @returns existed or not | /// remove the [key] @returns existed or not |
| bool remove(K key) { | bool remove(K key) { |
| uint code=hash_code(key); | uint code=hash_code(key); |
| Line 108 public: | Line 271 public: |
| return false; | return false; |
| } | } |
| /// return true if key exists | |
| bool contains(K key){ | |
| 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) | |
| return true; | |
| } | |
| return false; | |
| } | |
| /// get associated [value] by the [key] | /// get associated [value] by the [key] |
| V get(K key) const { | V get(K key) const { |
| uint code=hash_code(key); | uint code=hash_code(key); |
| Line 119 public: | Line 294 public: |
| return V(0); | return V(0); |
| } | } |
| /// get associated [value] by the [key] + [code] (faster) | |
| V get_by_hash_code(uint code, K key) const { | |
| uint index=code%allocated; | |
| for(Pair *pair=refs[index]; pair; pair=pair->link) | |
| if(pair->code==code && pair->key==key) | |
| return pair->value; | |
| return V(0); | |
| } | |
| /// put a [value] under the [key] if that [key] existed @returns existed or not | /// 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) { | if(!value) { |
| remove(key); | remove(key); |
| return false; | return false; |
| Line 138 public: | Line 323 public: |
| return false; | return false; |
| } | } |
| /// put a [value] under the [key] if that [key] existed @returns existed or not | |
| template<typename R, typename F> 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<R>(1); | |
| } | |
| // proper pair not found | |
| return 0; | |
| } | |
| /// put a [value] under the [key] if that [key] NOT existed @returns existed or not | /// put a [value] under the [key] if that [key] NOT existed @returns existed or not |
| bool put_dont_replace(K key, V value) { | bool put_dont_replace(K key, V value) { |
| if(!value) { | if(!value) { |
| Line 184 public: | Line 395 public: |
| callback(pair->key, pair->value, info); | callback(pair->key, pair->value, info); |
| } | } |
| /// iterate over all pairs | |
| template<typename I> void for_each_ref(void callback(K, V&, I), I info) const { | |
| Pair **ref=refs; | |
| for(int index=0; index<allocated; index++) | |
| for(Pair *pair=*ref++; pair; pair=pair->link) | |
| callback(pair->key, pair->value, info); | |
| } | |
| /// iterate over all pairs until condition becomes true, return that element | /// iterate over all pairs until condition becomes true, return that element |
| template<typename I> V first_that(bool callback(K, V, I), I info) const { | template<typename I> V first_that(bool callback(K, V, I), I info) const { |
| Pair **ref=refs; | Pair **ref=refs; |
| Line 208 private: | Line 427 private: |
| THRESHOLD_PERCENT=75 | THRESHOLD_PERCENT=75 |
| }; | }; |
| /// the index of [allocated] in [allocates] | /// the index of [allocated] in [Hash_allocates] |
| int allocates_index; | int allocates_index; |
| /// possible [allocates]. prime numbers | |
| static uint allocates[]; | |
| static int allocates_count; | |
| /// number of allocated pairs | /// number of allocated pairs |
| int allocated; | int allocated; |
| Line 251 private: | Line 465 private: |
| int old_allocated=allocated; | int old_allocated=allocated; |
| Pair **old_refs=refs; | Pair **old_refs=refs; |
| allocates_index=allocates_index+1<allocates_count?allocates_index+1:allocates_count-1; | allocates_index=allocates_index+1<HASH_ALLOCATES_COUNT?allocates_index+1:HASH_ALLOCATES_COUNT-1; |
| // allocated bigger refs array | // allocated bigger refs array |
| allocated=allocates[allocates_index]; | allocated=Hash_allocates[allocates_index]; |
| threshold=allocated*THRESHOLD_PERCENT/100; | threshold=allocated*THRESHOLD_PERCENT/100; |
| refs=new(UseGC) Pair*[allocated]; | refs=new(UseGC) Pair*[allocated]; |
| Line 279 private: //disabled | Line 493 private: //disabled |
| Hash& operator = (const Hash&) { return *this; } | Hash& operator = (const Hash&) { return *this; } |
| }; | }; |
| /* Zend comment: Generated on an Octa-ALPHA 300MHz CPU & 2.5GB RAM monster */ | |
| template<typename K, typename V> | |
| uint Hash<K, V>::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<typename K, typename V> | |
| int Hash<K, V>::allocates_count=sizeof(allocates)/sizeof(uint); | |
| /// 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 void generic_hash_code(uint& result, const char* buf, size_t size) { | |
| const char* end=buf+size; | |
| while(buf<end) { | |
| result=(result<<4)+*buf++; | |
| if(uint g=(result&0xF0000000)) { | |
| result=result^(g>>24); | |
| result=result^g; | |
| } | |
| } | |
| } | |
| /// simple hash code of int. used by EXIF mapping | |
| inline uint hash_code(int self) { | |
| uint result=0; | |
| generic_hash_code(result, (const char*)&self, sizeof(self)); | |
| return result; | |
| } | |
| /// Auto-object used to temporarily substituting/removing hash values | /// Auto-object used to temporarily substituting/removing hash values |
| template <typename K, typename V> | template <typename K, typename V> |
| class Temp_hash_value { | class Temp_hash_value { |