Diff for /parser3/src/include/pa_hash.h between versions 1.10 and 1.58.2.11

version 1.10, 2001/01/29 15:56:03 version 1.58.2.11, 2003/02/03 13:01:06
Line 1 Line 1
 /*  /** @file
   $Id$          Parser: hash class decl.
 */  
   
 /*          Copyright (c) 2001-2003 ArtLebedev Group (http://www.artlebedev.com)
   
           Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
   */
   
   /*
           The prime numbers used from zend_hash.c,
           the part of Zend scripting engine library,
           Copyrighted (C) 1999-2000    Zend Technologies Ltd.
           http://www.zend.com/license/0_92.txt
           For more information about Zend please visit http://www.zend.com/
 */  */
   
 #ifndef PA_HASH_H  #ifndef PA_HASH_H
 #define PA_HASH_H  #define PA_HASH_H
   
 #include <stddef.h>  static const char* IDENT_HASH_H="$Date$";
   
   #include "pa_pool.h"
 #include "pa_types.h"  #include "pa_types.h"
 #include "pa_string.h"  
   
 class Pool;  /** 
           Simple hash.
 class Hash {  
 public:  
   
         typedef String Key;  
         typedef void Value;  
   
           Automatically rehashed when almost is_full.
           Contains no 0 values. 
                   get returning 0 means there were no such.
                   "put value 0" means "remove"
   */
   template<typename K, typename V> class Hash: public PA_Object {
 public:  public:
   
         void *operator new(size_t size, Pool *apool);          typedef K key_type;
         Hash(Pool *apool, bool athread_safe);          typedef V value_type;
   
         // useful generic hash function  
         static uint generic_code(uint aresult, char *start, uint size);  
   
         // put a [value] under the [key]          Hash() { 
         /*SYNCHRONIZED*/ void put(Key& key, Value *value);                  allocated=allocates[allocates_index=0];
                   threshold=allocated*THRESHOLD_PERCENT/100;
         // get associated [value] by the [key]                  fpairs_count=fused_refs=0;
         /*SYNCHRONIZED*/ Value* get(Key& key);                  refs=static_cast<Pair **>(pa_calloc(sizeof(Pair *)*allocated));
           }
   
           Hash(const Hash& source) {
                   allocates_index=source.allocates_index;
                   allocated=source.allocated;
                   threshold=source.threshold;
                   fused_refs=source.fused_refs;
                   fpairs_count=source.fpairs_count;
                   refs=new Pair*[allocated];
                   memcpy(refs, source.refs, sizeof(Pair *)*allocated);
           }
           ~Hash() {
                   destroy_pairs();
                   delete refs;
           }
   
           /// put a [value] under the [key] @returns existed or not
           bool put(K key, V value) {
                   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 true;
                           }
                   
                   // proper pair not found -- 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 false;
           }
   
           /// remove the [key] @returns existed or not
           bool remove(K key) {
                   uint code=hash_code(key);
                   uint index=code%allocated;
                   for(Pair **ref=&refs[index]; *ref; ref=&(*ref)->link)
                           if((*ref)->code==code && (*ref)->key==key) {
                                   // found a pair with the same key
                                   Pair *next=(*ref)->link;
                                   delete *ref;
                                   *ref=next;
                                   --fpairs_count;
                                   return true;
                           }
   
                   return false;
           }
   
           /// get associated [value] by the [key]
           V get(K key) const {
                   uint code=hash_code(key);
                   uint index=code%allocated;
                   for(Pair *pair=refs[index]; pair; pair=pair->link)
                           if(pair->code==code && pair->key==key)
                                   return pair->value;
                   
                   return 0;
           }
   
 protected:          /// put a [value] under the [key] if that [key] existed @returns existed or not
           bool put_replace(K key, V value) {
                   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
                                   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 key, V value) {
                   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, NOT replacing
                                   return true;
                           }
   
                   // proper pair not found -- 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 false;
           }
   
           /// put all 'src' values if NO with same key existed
           void merge_dont_replace(const Hash& src) {
                   for(int i=0; i<src.allocated; i++)
                           for(Pair *pair=src.refs[i]; pair; pair=pair->link)
                                   put_dont_replace(pair->key, pair->value);
                   // MAY:optimize this.allocated==src.allocated case
           }
   
           /// number of elements in hash
           int count() const { return fpairs_count; }
   
           /// iterate over all pairs
           template<typename I> void for_each(void callback(K, V, I), I info) const {
                   Pair **ref=refs;
                   for(int index=0; index<allocated; index++)
                           for(Pair *pair=*ref++; pair; pair=pair->link)
                                   callback(pair->key, pair->value, info);
           }
   
           /// iterate over all pairs until condition becomes true, return that element
           template<typename I> V first_that(bool callback(K, V, I), I info) const {
                   Pair **ref=refs;
                   for(int index=0; index<allocated; index++)
                           for(Pair *pair=*ref++; pair; pair=pair->link)
                                   if(callback(pair->key, pair->value, info))
                                           return &pair->value;
                   
                   return 0;//V(0)
           }
   
         // the pool I'm allocated on          /// remove all elements
         Pool *pool;          void clear() {
                   destroy_pairs(); memset(refs, 0, sizeof(*refs)*allocated);
                   fpairs_count=fused_refs=0;      
           }
   
 private:  private:
   
         // expand when these %% of size exausted          /// expand when these %% of allocated exausted
         enum {          enum {
                 THRESHOLD_PERCENT=75                  THRESHOLD_PERCENT=75
         };          };
   
         // am I thread-safe?          /// the index of [allocated] in [allocates]
         bool thread_safe;          int allocates_index;
   
         // the index of [size] in [sizes]  
         int size_index;  
   
         // possible [sizes]. prime numbers          /// possible [allocates]. prime numbers
         static uint sizes[];          static uint allocates[];
         static int sizes_count;          
           static int allocates_count;
   
         // number of allocated pairs          /// number of allocated pairs
         int size;          int allocated;
   
         // helper: expanding when used == threshold          /// helper: expanding when fused_refs == threshold
         int threshold;          int threshold;
   
         // used pairs          /// used pairs
         int used;          int fused_refs;
   
         // main storage          /// stored pairs total (including those by links)
         class Pair {          int fpairs_count;
                 friend Hash;  
   
           /// pair storage
           class Pair: public PA_Allocated {
           public:
                 uint code;                  uint code;
                 Key key;                  K key;
                 Value *value;                  V value;
                 Pair *link;                  Pair *link;
                                   
                 void *operator new(size_t size, Pool *apool);                  Pair(uint acode, K akey, V avalue, Pair *alink) :
   
                 Pair(uint acode, Key& akey, Value *avalue, Pair *alink) :  
                         code(acode),                          code(acode),
                         key(akey),                          key(akey),
                         value(avalue),                          value(avalue),
                         link(alink) {}                          link(alink) {}
         } **refs;          } **refs;
   
         // filled to threshold: needs expanding          /// filled to threshold: needs expanding
         bool full() { return used==threshold; }          bool is_full() { return fused_refs==threshold; }
   
         // allocate larger buffer & rehash          /// allocate larger buffer & rehash
         void expand();          void expand() {
                   int old_allocated=allocated;
                   Pair **old_refs=refs;
   
                   // allocated bigger refs array
                   allocates_index=allocates_index+1<allocates_count?allocates_index+1:allocates_count-1;
                   allocated=allocates[allocates_index];
                   threshold=allocated*THRESHOLD_PERCENT/100;
                   refs=static_cast<Pair **>(pa_calloc(sizeof(Pair *)*allocated));
   
                   // rehash
                   Pair **old_ref=old_refs;
                   for(int old_index=0; old_index<old_allocated; old_index++)
                           for(Pair *pair=*old_ref++; pair; ) {
                                   Pair *next=pair->link;
   
                                   uint new_index=pair->code%allocated;
                                   Pair **new_ref=&refs[new_index];
                                   pair->link=*new_ref;
                                   *new_ref=pair;
   
                                   pair=next;
                           }
   
                   delete old_refs;
           }
   
           void destroy_pairs() {
                   Pair **ref=refs;
                   for(int index=0; index<allocated; index++) {
                           Pair *pair=*ref++; 
                           while(pair) {
                                   Pair *next=pair->link;
                                   delete pair;
                                   pair=next;
                           }
                   }
           }
   
 private: //disabled  private: //disabled
   
         Hash(Hash&) {}          Hash& operator = (const Hash&) { return *this; }
         Hash& operator = (Hash&) { return *this; }  };
   
   /* Zend comment: Generated on an Octa-ALPHA 300MHz CPU & 2.5GB RAM monster */
   template<typename K, typename V>
   uint Hash<K, V>::allocates[]={
           5, 11, 19, 53, 107, 223, 463, 983, 1979, 3907, 7963, 
           16229, 32531, 65407, 130987, 262237, 524521, 1048793, 
           2097397, 4194103, 8388857, 16777447, 33554201, 67108961, 
           134217487, 268435697, 536870683, 1073741621, 2147483399};
   
   template<typename K, typename V>
   int Hash<K, V>::allocates_count=sizeof(allocates)/sizeof(uint);
   
   /// useful generic hash function
   inline uint generic_hash_code(uint aresult, const char* start, uint allocated) {
           uint result=aresult, g;
           const char* end=start+allocated;
   
           while (start<end) {
                   result=(result<<4)+*start++;
                   if ((g=(result&0xF0000000))) {
                           result=result^(g>>24);
                           result=result^g;
                   }
           }
           return result;
   }
   
   ///     Auto-object used to temporarily substituting/removing hash values
   template <typename K, typename V>
   class Temp_hash_value {
           Hash<K, V>& fhash;
           K fname;
           V saved_value;
   public:
           Temp_hash_value(Hash<K, V>& ahash, K aname, V avalue) : 
                   fhash(ahash),
                   fname(aname),
                   saved_value(ahash.get(aname)) {
                   fhash.put(aname, avalue);
           }
           ~Temp_hash_value() { 
                   fhash.put(fname, saved_value);
           }
 };  };
   
 #endif  #endif

Removed from v.1.10  
changed lines
  Added in v.1.58.2.11


E-mail: