|
|
| version 1.76, 2009/07/08 09:03:18 | version 1.85, 2013/08/21 12:11:14 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: hash class decl. | Parser: hash class decl. |
| Copyright (c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com) | Copyright (c) 2001-2012 Art. Lebedev Studio (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 * const IDENT_HASH_H="$Date$"; | #define IDENT_PA_HASH_H "$Id$" |
| #include "pa_memory.h" | #include "pa_memory.h" |
| #include "pa_types.h" | #include "pa_types.h" |
| Line 89 inline uint hash_code(int self) { | Line 89 inline uint hash_code(int self) { |
| #undef HASH | #undef HASH |
| #undef HASH_STRING | #undef HASH_STRING |
| #undef NEW_PAIR | #undef HASH_NEW_PAIR |
| #undef HASH_FOR_EACH | |
| #define HASH OrderedHash | #define HASH OrderedHash |
| #define HASH_STRING OrderedHashString | #define HASH_STRING OrderedHashString |
| #define NEW_PAIR(code, key, value) *ref=new Pair(code, key, value, *ref, this->last); this->last=&((*ref)->next) | #define HASH_NEW_PAIR(code, key, value) *ref=new Pair(code, key, value, *ref, this->last); this->last=&((*ref)->next) |
| #define HASH_FOR_EACH \ | |
| for(Pair *pair=this->first; pair; pair=pair->next) | |
| #else | #else |
| #define HASH Hash | #define HASH Hash |
| #define HASH_STRING HashString | #define HASH_STRING HashString |
| #define NEW_PAIR(code, key, value) *ref=new Pair(code, key, value, *ref) | #define HASH_NEW_PAIR(code, key, value) *ref=new Pair(code, key, value, *ref) |
| #define HASH_FOR_EACH \ | |
| Pair **ref=this->refs; \ | |
| for(int index=0; index<this->allocated; index++) \ | |
| for(Pair *pair=*ref++; pair; pair=pair->link) | |
| #endif | #endif |
| Line 111 public: | Line 120 public: |
| HASH() { | HASH() { |
| allocated=Hash_allocates[allocates_index=0]; | allocated=Hash_allocates[allocates_index=0]; |
| threshold=allocated*THRESHOLD_PERCENT/100; | |
| fpairs_count=fused_refs=0; | fpairs_count=fused_refs=0; |
| refs=new(UseGC) Pair*[allocated]; | refs=new(UseGC) Pair*[allocated]; |
| #ifdef HASH_ORDER | #ifdef HASH_ORDER |
| Line 123 public: | Line 131 public: |
| HASH(const HASH& source) { | HASH(const HASH& source) { |
| allocates_index=source.allocates_index; | allocates_index=source.allocates_index; |
| allocated=source.allocated; | allocated=source.allocated; |
| 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(UseGC) Pair*[allocated]; | refs=new(UseGC) Pair*[allocated]; |
| // clone & rehash | |
| #ifdef HASH_ORDER | #ifdef HASH_ORDER |
| first=0; | first=0; |
| last=&first; | last=&first; |
| #endif | for(Pair *pair=source.first; pair; pair=pair->next) |
| // clone & rehash | { |
| Pair **old_ref=source.refs; | uint index=pair->code%allocated; |
| for(int index=0; index<allocated; index++) | Pair **ref=&refs[index]; |
| for(Pair *pair=*old_ref++; pair; ) { | HASH_NEW_PAIR(pair->code, pair->key, pair->value); |
| Pair *next=pair->link; | } |
| #else | |
| Pair **ref=&refs[index]; | for(int i=0; i<source.allocated; i++) |
| NEW_PAIR(pair->code, pair->key, pair->value); | for(Pair *pair=source.refs[i]; pair; pair=pair->link) |
| { | |
| pair=next; | Pair **ref=&refs[i]; |
| HASH_NEW_PAIR(pair->code, pair->key, pair->value); | |
| } | } |
| #endif | |
| } | } |
| #ifdef USE_DESTRUCTORS | #ifdef USE_DESTRUCTORS |
| Line 179 public: | Line 189 public: |
| // proper pair not found -- create&link_in new pair | // proper pair not found -- create&link_in new pair |
| if(!*ref) // root cell were fused_refs? | if(!*ref) // root cell were fused_refs? |
| fused_refs++; // not, we'll use it and record the fact | fused_refs++; // not, we'll use it and record the fact |
| NEW_PAIR(code, key, value); | HASH_NEW_PAIR(code, key, value); |
| fpairs_count++; | fpairs_count++; |
| 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 | |
| NEW_PAIR(code, key, value); | |
| 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 | |
| NEW_PAIR(code, key, value); | |
| 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 342 public: | Line 243 public: |
| return V(0); | return V(0); |
| } | } |
| #ifdef HASH_ORDER | |
| V first_value() const { | |
| return (first) ? first->value : V(0); | |
| } | |
| V last_value() const { | |
| return (fpairs_count) ? ((Pair *)((char *)last - offsetof(Pair, next)))->value : V(0); | |
| } | |
| #endif | |
| /// 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_replaced(K key, V value) { | bool put_replaced(K key, V value) { |
| if(!value) { | if(!value) { |
| Line 361 public: | Line 272 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 408 public: | Line 293 public: |
| // proper pair not found -- create&link_in new pair | // proper pair not found -- create&link_in new pair |
| if(!*ref) // root cell were fused_refs? | if(!*ref) // root cell were fused_refs? |
| fused_refs++; // not, we'll use it and record the fact | fused_refs++; // not, we'll use it and record the fact |
| NEW_PAIR(code, key, value); | HASH_NEW_PAIR(code, key, value); |
| fpairs_count++; | fpairs_count++; |
| return false; | 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) { | void merge_dont_replace(const HASH& src) { |
| #ifdef HASH_ORDER | |
| for(Pair *pair=src.first; pair; pair=pair->next) | |
| #else | |
| for(int i=0; i<src.allocated; i++) | for(int i=0; i<src.allocated; i++) |
| for(Pair *pair=src.refs[i]; pair; pair=pair->link) | for(Pair *pair=src.refs[i]; pair; pair=pair->link) |
| #endif | |
| put_dont_replace(pair->key, pair->value); | put_dont_replace(pair->key, pair->value); |
| } | } |
| Line 427 public: | Line 314 public: |
| /// iterate over all pairs | /// iterate over all pairs |
| template<typename I> void for_each(void callback(K, V, I), I info) const { | template<typename I> void for_each(void callback(K, V, I), I info) const { |
| #ifdef HASH_ORDER | HASH_FOR_EACH |
| for(Pair *pair=first; pair; pair=pair->next) | |
| callback(pair->key, pair->value, info); | callback(pair->key, pair->value, info); |
| #else | |
| Pair **ref=refs; | |
| for(int index=0; index<allocated; index++) | |
| for(Pair *pair=*ref++; pair; pair=pair->link) | |
| callback(pair->key, pair->value, info); | |
| #endif | |
| } | } |
| /// iterate over all pairs | /// iterate over all pairs |
| template<typename I> void for_each_ref(void callback(K, V&, I), I info) const { | template<typename I> void for_each_ref(void callback(K, V&, I), I info) const { |
| #ifdef HASH_ORDER | HASH_FOR_EACH |
| for(Pair *pair=first; pair; pair=pair->next) | |
| callback(pair->key, pair->value, info); | callback(pair->key, pair->value, info); |
| #else | |
| Pair **ref=refs; | |
| for(int index=0; index<allocated; index++) | |
| for(Pair *pair=*ref++; pair; pair=pair->link) | |
| callback(pair->key, pair->value, info); | |
| #endif | |
| } | } |
| /// 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 { |
| #ifdef HASH_ORDER | HASH_FOR_EACH |
| for(Pair *pair=first; pair; pair=pair->next) | |
| if(callback(pair->key, pair->value, info)) | if(callback(pair->key, pair->value, info)) |
| return pair->value; | return pair->value; |
| #else | |
| Pair **ref=refs; | |
| for(int index=0; index<allocated; index++) | |
| for(Pair *pair=*ref++; pair; pair=pair->link) | |
| if(callback(pair->key, pair->value, info)) | |
| return pair->value; | |
| #endif | |
| return V(0); | return V(0); |
| } | } |
| Line 479 public: | Line 344 public: |
| protected: | protected: |
| /// expand when these %% of allocated exausted | |
| enum { | |
| THRESHOLD_PERCENT=75 | |
| }; | |
| /// the index of [allocated] in [Hash_allocates] | /// the index of [allocated] in [Hash_allocates] |
| int allocates_index; | int allocates_index; |
| /// number of allocated pairs | /// number of allocated pairs |
| int allocated; | int allocated; |
| /// helper: expanding when fused_refs == threshold | |
| int threshold; | |
| /// used pairs | /// used pairs |
| int fused_refs; | int fused_refs; |
| Line 522 protected: | Line 379 protected: |
| Pair **last; | Pair **last; |
| #endif | #endif |
| /// filled to threshold: needs expanding | /// filled to threshold (THRESHOLD_PERCENT=75), needs expanding |
| bool is_full() { return fused_refs==threshold; } | bool is_full() { return fused_refs + allocated/4 >= allocated; } |
| /// allocate larger buffer & rehash | /// allocate larger buffer & rehash |
| void expand() { | void expand() { |
| int old_allocated=allocated; | int old_allocated=allocated; |
| Pair **old_refs=refs; | Pair **old_refs=refs; |
| allocates_index=allocates_index+1<HASH_ALLOCATES_COUNT?allocates_index+1:HASH_ALLOCATES_COUNT-1; | if (allocates_index<HASH_ALLOCATES_COUNT-1) allocates_index++; |
| // allocated bigger refs array | // allocated bigger refs array |
| allocated=Hash_allocates[allocates_index]; | allocated=Hash_allocates[allocates_index]; |
| threshold=allocated*THRESHOLD_PERCENT/100; | |
| refs=new(UseGC) Pair*[allocated]; | refs=new(UseGC) Pair*[allocated]; |
| // rehash | // rehash |
| Line 597 public: | Line 453 public: |
| // proper pair not found -- create&link_in new pair | // proper pair not found -- create&link_in new pair |
| if(!*ref) // root cell were fused_refs? | if(!*ref) // root cell were fused_refs? |
| this->fused_refs++; // not, we'll use it and record the fact | this->fused_refs++; // not, we'll use it and record the fact |
| NEW_PAIR(code, key, value); | HASH_NEW_PAIR(code, key, value); |
| this->fpairs_count++; | this->fpairs_count++; |
| 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 str, V value, F prevent, I info) { | |
| if(!value) { | |
| // they can come here from somewhere (true with maybe_replace_maybe_append, keeping parallel) | |
| remove(str); | |
| // this has nothing to do with properties, doing no special property handling here | |
| return 0; | |
| } | |
| if(this->is_full()) | |
| this->expand(); | |
| CORD key=str.get_cord(); | |
| uint code=str.get_hash_code(); | |
| uint index=code%this->allocated; | |
| Pair **ref=&this->refs[index]; | |
| for(Pair *pair=*ref; pair; pair=pair->link) | |
| if(pair->code==code && CORD_cmp(pair->key,key)==0) { | |
| // 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? | |
| this->fused_refs++; // not, we'll use it and record the fact | |
| NEW_PAIR(code, key, value); | |
| this->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 str, 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(str); | |
| // this has nothing to do with properties, doing no special property handling here | |
| return 0; | |
| } | |
| if(this->is_full()) | |
| this->expand(); | |
| CORD key=str.get_cord(); | |
| uint code=str.get_hash_code(); | |
| uint index=code%this->allocated; | |
| Pair **ref=&this->refs[index]; | |
| for(Pair *pair=*ref; pair; pair=pair->link) | |
| if(pair->code==code && CORD_cmp(pair->key,key)==0) { | |
| // 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? | |
| this->fused_refs++; // not, we'll use it and record the fact | |
| NEW_PAIR(code, key, value); | |
| this->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 str, V value, F1 prevent_replace, I info) { | |
| if(!value) { | |
| // they can come here from somewhere (true with maybe_replace_maybe_append, keeping parallel) | |
| remove(str); | |
| // this has nothing to do with properties, doing no special property handling here | |
| return 0; | |
| } | |
| if(this->is_full()) | |
| this->expand(); | |
| CORD key=str.get_cord(); | |
| uint code=str.get_hash_code(); | |
| uint index=code%this->allocated; | |
| Pair **ref=&this->refs[index]; | |
| for(Pair *pair=*ref; pair; pair=pair->link) | |
| if(pair->code==code && CORD_cmp(pair->key,key)==0) { | |
| // 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 str) { | bool remove(K str) { |
| CORD key=str.get_cord(); | CORD key=str.get_cord(); |
| Line 789 public: | Line 531 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 str, V value, F prevent) { | |
| if(!value) { | |
| // they can come here from Temp_value_element::dctor to restore some empty value | |
| remove(str); | |
| // this has nothing to do with properties, doing no special property handling here | |
| return 0; | |
| } | |
| CORD key=str.get_cord(); | |
| uint code=str.get_hash_code(); | |
| uint index=code%this->allocated; | |
| for(Pair *pair=this->refs[index]; pair; pair=pair->link) | |
| if(pair->code==code && CORD_cmp(pair->key,key)==0) { | |
| // 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 str, V value) { | bool put_dont_replace(K str, V value) { |
| if(!value) { | if(!value) { |
| Line 838 public: | Line 553 public: |
| // proper pair not found -- create&link_in new pair | // proper pair not found -- create&link_in new pair |
| if(!*ref) // root cell were fused_refs? | if(!*ref) // root cell were fused_refs? |
| this->fused_refs++; // not, we'll use it and record the fact | this->fused_refs++; // not, we'll use it and record the fact |
| NEW_PAIR(code, key, value); | HASH_NEW_PAIR(code, key, value); |
| this->fpairs_count++; | this->fpairs_count++; |
| return false; | return false; |
| } | } |
| /// iterate over all pairs | /// put all 'src' values if NO with same key existed |
| template<typename I> void for_each(void callback(K, V, I), I info) const { | void merge_dont_replace(const HASH_STRING& src) { |
| #ifdef HASH_ORDER | #ifdef HASH_ORDER |
| for(Pair *pair=first; pair; pair=pair->next) | for(Pair *pair=src.first; pair; pair=pair->next) |
| callback(pair->key, pair->value, info); | |
| #else | #else |
| Pair **ref=this->refs; | for(int i=0; i<src.allocated; i++) |
| for(int index=0; index<this->allocated; index++) | for(Pair *pair=src.refs[i]; pair; pair=pair->link) |
| for(Pair *pair=*ref++; pair; pair=pair->link) | |
| callback(String::Body(pair->key, pair->code), pair->value, info); | |
| #endif | #endif |
| put_dont_replace(String::Body(pair->key, pair->code), pair->value); | |
| } | |
| /// iterate over all pairs | |
| template<typename I> void for_each(void callback(K, V, I), I info) const { | |
| HASH_FOR_EACH | |
| callback(String::Body(pair->key, pair->code), pair->value, info); | |
| } | } |
| /// iterate over all pairs | /// iterate over all pairs |
| template<typename I> void for_each_ref(void callback(K, V&, I), I info) const { | template<typename I> void for_each_ref(void callback(K, V&, I), I info) const { |
| #ifdef HASH_ORDER | HASH_FOR_EACH |
| for(Pair *pair=first; pair; pair=pair->next) | callback(String::Body(pair->key, pair->code), pair->value, info); |
| callback(pair->key, pair->value, info); | |
| #else | |
| Pair **ref=this->refs; | |
| for(int index=0; index<this->allocated; index++) | |
| for(Pair *pair=*ref++; pair; pair=pair->link) | |
| callback(String::Body(pair->key, pair->code), pair->value, info); | |
| #endif | |
| } | } |
| /// 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 { |
| #ifdef HASH_ORDER | HASH_FOR_EACH |
| for(Pair *pair=this->first; pair; pair=pair->next) | |
| if(callback(String::Body(pair->key, pair->code), pair->value, info)) | if(callback(String::Body(pair->key, pair->code), pair->value, info)) |
| return pair->value; | return pair->value; |
| #else | |
| Pair **ref=this->refs; | |
| for(int index=0; index<this->allocated; index++) | |
| for(Pair *pair=*ref++; pair; pair=pair->link) | |
| if(callback(String::Body(pair->key, pair->code), pair->value, info)) | |
| return pair->value; | |
| #endif | |
| return V(0); | return V(0); |
| } | } |
| /// simple hash iterator | |
| class Iterator { | |
| const HASH_STRING<V>& fhash; | |
| Pair *fcurrent; | |
| public: | |
| Iterator(const HASH_STRING<V>& ahash): fhash(ahash) { | |
| fcurrent=fhash.first; | |
| } | |
| operator bool () { | |
| return fcurrent != 0; | |
| } | |
| void next() { | |
| fcurrent=fcurrent->next; | |
| } | |
| String::Body key(){ | |
| return String::Body(fcurrent->key, fcurrent->code); | |
| } | |
| V value(){ | |
| return fcurrent->value; | |
| } | |
| }; | |
| }; | }; |
| #else | #else //HASH_CODE_CACHING |
| template<typename V> class HASH_STRING: public HASH<const String::Body,V>{}; | template<typename V> class HASH_STRING: public HASH<const String::Body,V>{}; |
| #endif | #endif //HASH_CODE_CACHING |
| #ifndef HASH_ORDER | #ifndef HASH_ORDER |
| /// Auto-object used to temporarily substituting/removing string hash values | /// Auto-object used to temporarily substituting/removing string hash values |
| template <typename K, typename V> | template <typename H, typename V> |
| class Temp_hash_value { | class Temp_hash_value { |
| HashString<V> &fhash; | H *fhash; |
| K fname; | String::Body fname; |
| V saved_value; | V saved_value; |
| public: | public: |
| Temp_hash_value(HashString<V>& ahash, K aname, V avalue) : | Temp_hash_value(H *ahash, String::Body aname, V avalue) : fhash(ahash), fname(aname) { |
| fhash(ahash), | if(fhash){ |
| fname(aname), | saved_value=fhash->get(aname); |
| saved_value(ahash.get(aname)) { | fhash->put(aname, avalue); |
| fhash.put(aname, avalue); | } |
| } | } |
| ~Temp_hash_value() { | ~Temp_hash_value() { |
| fhash.put(fname, saved_value); | if(fhash) |
| fhash->put(fname, saved_value); | |
| } | } |
| }; | }; |
| #endif | #endif |