Diff for /parser3/src/include/pa_hash.h between versions 1.76 and 1.85

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

Removed from v.1.76  
changed lines
  Added in v.1.85


E-mail: