Diff for /parser3/src/include/pa_hash.h between versions 1.67 and 1.80

version 1.67, 2007/05/18 12:44:00 version 1.80, 2009/12/04 04:19:58
Line 1 Line 1
 /** @file  /** @file
         Parser: hash class decl.          Parser: hash class decl.
   
         Copyright (c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com)          Copyright (c) 2001-2009 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 21  static const char * const IDENT_HASH_H=" Line 21  static const char * const IDENT_HASH_H="
   
 #include "pa_memory.h"  #include "pa_memory.h"
 #include "pa_types.h"  #include "pa_types.h"
   #include "pa_string.h"
   
 const int HASH_ALLOCATES_COUNT=29;  const int HASH_ALLOCATES_COUNT=29;
   
Line 34  static uint Hash_allocates[HASH_ALLOCATE Line 35  static uint Hash_allocates[HASH_ALLOCATE
         2097397, 4194103, 8388857, 16777447, 33554201, 67108961,           2097397, 4194103, 8388857, 16777447, 33554201, 67108961, 
         134217487, 268435697, 536870683, 1073741621, 2147483399};          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;
   }
   
   #endif // PA_HASH_H
   
   #ifndef PA_HASH_CLASS
   #define PA_HASH_CLASS
 /**   /** 
         Simple hash.          Simple hash.
   
Line 42  static uint Hash_allocates[HASH_ALLOCATE Line 85  static uint Hash_allocates[HASH_ALLOCATE
                 get returning 0 means there were no such.                  get returning 0 means there were no such.
                 "put value 0" means "remove"                  "put value 0" means "remove"
 */  */
 template<typename K, typename V> class Hash: public PA_Object {  #ifdef HASH_ORDER
   
   #undef HASH
   #undef HASH_STRING
   #undef HASH_NEW_PAIR
   #undef HASH_FOR_EACH
   
   #define HASH OrderedHash
   #define HASH_STRING OrderedHashString
   #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
   
   #define HASH Hash
   #define HASH_STRING HashString
   #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
   
   template<typename K, typename V> class HASH: public PA_Object {
 public:  public:
   
         typedef K key_type;          typedef K key_type;
         typedef V value_type;          typedef V value_type;
   
         Hash() {           HASH() { 
                 allocated=Hash_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(UseGC) Pair*[allocated];                  refs=new(UseGC) Pair*[allocated];
   #ifdef HASH_ORDER
                   first=0;
                   last=&first;
   #endif
         }          }
   
         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;                  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];
   #ifdef HASH_ORDER
                   first=0;
                   last=&first;
   #endif
                 // clone & rehash                  // clone & rehash
                 Pair **old_ref=source.refs;                  Pair **old_ref=source.refs;
                 for(int index=0; index<allocated; index++)                  for(int index=0; index<allocated; index++)
                         for(Pair *pair=*old_ref++; pair; ) {                          for(Pair *pair=*old_ref++; pair; ) {
                                 Pair *next=pair->link;                                  Pair *next=pair->link;
   
                                 Pair **new_ref=&refs[index];                                  Pair **ref=&refs[index];
                                 *new_ref=new Pair(pair->code, pair->key, pair->value, *new_ref);                                  HASH_NEW_PAIR(pair->code, pair->key, pair->value);
   
                                 pair=next;                                  pair=next;
                         }                          }
         }          }
   
   #ifdef USE_DESTRUCTORS
           ~HASH() {
                   Pair **ref=refs;
                   for(int index=0; index<allocated; index++)
                           for(Pair *pair=*ref++; pair;){
                                   Pair *next=pair->link;
                                   delete pair;
                                   pair=next;
                           }
                   delete[] refs;
           }
   #endif
   
         /// 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 98  public: Line 188  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
                 *ref=new Pair(code, key, value, *ref);                  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  
                 *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);
                 uint index=code%allocated;                  uint index=code%allocated;
                 for(Pair **ref=&refs[index]; *ref; ref=&(*ref)->link)                  for(Pair **ref=&refs[index]; *ref; ref=&(*ref)->link){
                         if((*ref)->code==code && (*ref)->key==key) {                          Pair *pair=*ref;
                           if(pair->code==code && pair->key==key) {
                                 // found a pair with the same key                                  // found a pair with the same key
                                 Pair *next=(*ref)->link;                                  Pair *next=pair->link;
                                 delete *ref;  #ifdef HASH_ORDER
                                   *(pair->prev)=pair->next;
                                   if(pair->next)
                                           pair->next->prev=pair->prev;
                                   else
                                           last=pair->prev;
   #endif
                                   delete pair;
                                 *ref=next;                                  *ref=next;
                                 --fpairs_count;                                  --fpairs_count;
                                 return true;                                  return true;
                         }                          }
                   }
   
                 return false;                  return false;
         }          }
   
         /// returns exist key or not          /// return true if key exists
         bool contain(K key){          bool contains(K key){
                 uint code=hash_code(key);                  uint code=hash_code(key);
                 uint index=code%allocated;                  uint index=code%allocated;
                 for(Pair **ref=&refs[index]; *ref; ref=&(*ref)->link){                  for(Pair *pair=refs[index]; pair; pair=pair->link){
                         if((*ref)->code==code && (*ref)->key==key) {                          if(pair->code==code && pair->key==key)
                                 return true;                                  return true;
                         }  
                 }                  }
   
                 return false;                  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 253  public: Line 241  public:
                                   
                 return V(0);                  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_replaced(K key, V value) {          bool put_replaced(K key, V value) {
                 if(!value) {                  if(!value) {
Line 273  public: Line 261  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 320  public: Line 282  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
                 *ref=new Pair(code, key, value, *ref);                  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) {
         */  #ifdef HASH_ORDER
         void merge_dont_replace(const Hash& src) {                  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 339  public: Line 303  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 {
                 Pair **ref=refs;                  HASH_FOR_EACH
                 for(int index=0; index<allocated; index++)                          callback(pair->key, pair->value, info);
                         for(Pair *pair=*ref++; pair; pair=pair->link)  
                                 callback(pair->key, 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 {
                 Pair **ref=refs;                  HASH_FOR_EACH
                 for(int index=0; index<allocated; index++)                          callback(pair->key, pair->value, info);
                         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;                  HASH_FOR_EACH
                 for(int index=0; index<allocated; index++)                          if(callback(pair->key, pair->value, info))
                         for(Pair *pair=*ref++; pair; pair=pair->link)                                  return pair->value;
                                 if(callback(pair->key, pair->value, info))  
                                         return pair->value;  
                   
                 return V(0);                  return V(0);
         }          }
   
Line 368  public: Line 325  public:
         void clear() {          void clear() {
                 memset(refs, 0, sizeof(*refs)*allocated);                  memset(refs, 0, sizeof(*refs)*allocated);
                 fpairs_count=fused_refs=0;                        fpairs_count=fused_refs=0;      
   #ifdef HASH_ORDER
                   first=0;
                   last=&first;
   #endif
         }          }
   
 private:  protected:
   
         /// expand when these %% of allocated exausted          /// expand when these %% of allocated exausted
         enum {          enum {
Line 399  private: Line 360  private:
                 K key;                  K key;
                 V value;                  V value;
                 Pair *link;                  Pair *link;
                   #ifdef HASH_ORDER
                 Pair(uint acode, K akey, V avalue, Pair *alink) :                  Pair **prev;
                         code(acode),                  Pair *next;
                         key(akey),  
                         value(avalue),                  Pair(uint acode, K akey, V avalue, Pair *alink, Pair **aprev) : code(acode), key(akey), value(avalue), link(alink), 
                         link(alink) {}                          prev(aprev), next(0) { *aprev=this; }
   #else
                   Pair(uint acode, K akey, V avalue, Pair *alink) : code(acode), key(akey), value(avalue), link(alink) {}
   #endif
         } **refs;          } **refs;
   
   #ifdef HASH_ORDER
           Pair *first;
           Pair **last;
   #endif
   
         /// filled to threshold: needs expanding          /// filled to threshold: needs expanding
         bool is_full() { return fused_refs==threshold; }          bool is_full() { return fused_refs==threshold; }
   
Line 440  private: Line 409  private:
   
 private: //disabled  private: //disabled
   
         Hash& operator = (const Hash&) { return *this; }          HASH& operator = (const HASH&) { return *this; }
 };  };
   
 /// useful generic hash function  /** 
 inline void generic_hash_code(uint& result, char c) {          Simple String::body hash.
         result=(result<<4)+c;          Allows hash code caching
         if(uint g=(result&0xF0000000)) {  */
                 result=result^(g>>24);  
                 result=result^g;  #ifdef HASH_CODE_CACHING
   
   template<typename V> class HASH_STRING: public HASH<const CORD,V> {
   public:
   
           typedef typename HASH<const CORD,V>::Pair Pair; 
           typedef const String::Body &K;
   
           typedef K key_type;
           
           /// put a [value] under the [key] @returns existed or not
           bool put(K str, V value) {
                   if(!value) {
                           remove(str);
                           return false;
                   }
                   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 true;
                           }
   
                   // proper pair not found -- create&link_in new pair
                   if(!*ref) // root cell were fused_refs?
                           this->fused_refs++; // not, we'll use it and record the fact
                   HASH_NEW_PAIR(code, key, value);
                   this->fpairs_count++;
                   return false;
         }          }
 }  
 /// useful generic hash function          /// remove the [key] @returns existed or not
 inline void generic_hash_code(uint& result, const char* s) {          bool remove(K str) {
         while(char c=*s++) {                  CORD key=str.get_cord();
                 result=(result<<4)+c;                  uint code=str.get_hash_code();
                 if(uint g=(result&0xF0000000)) {                  uint index=code%this->allocated;
                         result=result^(g>>24);                  for(Pair **ref=&this->refs[index]; *ref; ref=&(*ref)->link){
                         result=result^g;                          Pair *pair=*ref;
                           if(pair->code==code && CORD_cmp(pair->key,key)==0) {
                                   // found a pair with the same key
                                   Pair *next=pair->link;
   #ifdef HASH_ORDER
                                   *(pair->prev)=pair->next;
                                   if(pair->next)
                                           pair->next->prev=pair->prev;
                                   else
                                           this->last=pair->prev;
   #endif
                                   delete pair;
                                   *ref=next;
                                   --this->fpairs_count;
                                   return true;
                           }
                 }                  }
   
                   return false;
         }          }
 }  
   
 /// useful generic hash function          /// return true if key exists
 inline void generic_hash_code(uint& result, const char* buf, size_t size) {          bool contains(K str){
         const char* end=buf+size;                  CORD key=str.get_cord();
         while(buf<end) {                  uint code=str.get_hash_code();
                 result=(result<<4)+*buf++;                  uint index=code%this->allocated;
                 if(uint g=(result&0xF0000000)) {                  for(Pair *pair=this->refs[index]; pair; pair=pair->link){
                         result=result^(g>>24);                          if(pair->code==code && CORD_cmp(pair->key,key)==0)
                         result=result^g;                                  return true;
                 }                  }
   
                   return false;
         }          }
 }  
   
 /// simple hash code of int. used by EXIF mapping          /// get associated [value] by the [key]
 inline uint hash_code(int self) {          V get(K str) const {
         uint result=0;                  CORD key=str.get_cord();
         generic_hash_code(result, (const char*)&self, sizeof(self));                  uint code=str.get_hash_code();
         return result;                  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)
                                   return pair->value;
   
                   return V(0);
           }
   
           /// put a [value] under the [key] if that [key] existed @returns existed or not
           bool put_replaced(K str, V value) {
                   if(!value) {
                           remove(str);
                           return false;
                   }
   
                   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
                                   pair->value=value;
                                   return true;
                           }
   
                   // proper pair not found 
                   return false;
           }
   
           /// put a [value] under the [key] if that [key] NOT existed @returns existed or not
           bool put_dont_replace(K str, V value) {
                   if(!value) {
                           remove(str);
                           return false;
                   }
                   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, NOT replacing
                                   return true;
                           }
   
                   // proper pair not found -- create&link_in new pair
                   if(!*ref) // root cell were fused_refs?
                           this->fused_refs++; // not, we'll use it and record the fact
                   HASH_NEW_PAIR(code, key, value);
                   this->fpairs_count++;
                   return false;
           }
   
           /// put all 'src' values if NO with same key existed
           void merge_dont_replace(const HASH_STRING& src) {
   #ifdef HASH_ORDER
                   for(Pair *pair=src.first; pair; pair=pair->next)
   #else
                   for(int i=0; i<src.allocated; i++)
                           for(Pair *pair=src.refs[i]; pair; pair=pair->link)
   #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);
           }
   
 ///     Auto-object used to temporarily substituting/removing hash values          /// iterate over all pairs
           template<typename I> void for_each_ref(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 until condition becomes true, return that element
           template<typename I> V first_that(bool callback(K, V, I), I info) const {
                   HASH_FOR_EACH
                           if(callback(String::Body(pair->key, pair->code), pair->value, info))
                                   return pair->value;
                   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 //HASH_CODE_CACHING
   
   template<typename V> class HASH_STRING: public HASH<const String::Body,V>{};
   
   #endif //HASH_CODE_CACHING
   
   #ifndef HASH_ORDER
   ///    Auto-object used to temporarily substituting/removing string hash values
 template <typename K, typename V>  template <typename K, typename V>
 class Temp_hash_value {  class Temp_hash_value {
         Hash<K, V>& fhash;          HashString<V> &fhash;
         K fname;          K fname;
         V saved_value;          V saved_value;
 public:  public:
         Temp_hash_value(Hash<K, V>& ahash, K aname, V avalue) :           Temp_hash_value(HashString<V>& ahash, K aname, V avalue) :
                 fhash(ahash),                  fhash(ahash),
                 fname(aname),                  fname(aname),
                 saved_value(ahash.get(aname)) {                  saved_value(ahash.get(aname)) {
Line 498  public: Line 637  public:
                 fhash.put(fname, saved_value);                  fhash.put(fname, saved_value);
         }          }
 };  };
   
 #endif  #endif
   
   #endif //PA_HASH_CLASS

Removed from v.1.67  
changed lines
  Added in v.1.80


E-mail: