|
|
| version 1.94, 2015/10/26 01:21:55 | version 1.105, 2025/01/06 19:47:18 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: hash class decl. | Parser: hash class decl. |
| Copyright (c) 2001-2015 Art. Lebedev Studio (http://www.artlebedev.com) | Copyright (c) 2001-2024 Art. Lebedev Studio (http://www.artlebedev.com) |
| Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) | Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <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 |
| Line 25 | Line 17 |
| const int HASH_ALLOCATES_COUNT=29; | const int HASH_ALLOCATES_COUNT=29; |
| /** Zend comment: Generated on an Octa-ALPHA 300MHz CPU & 2.5GB RAM monster | // nearest primes to 5 * 2^n |
| paf: HPUX ld could not handle static member: unsatisfied symbols | |
| */ | |
| static uint Hash_allocates[HASH_ALLOCATES_COUNT]={ | static uint Hash_allocates[HASH_ALLOCATES_COUNT]={ |
| 5, 11, 19, 53, 107, 223, 463, 983, 1979, 3907, 7963, | 5, 11, 19, 41, 79, 163, 317, 641, 1279, 2557, 5119, |
| 16229, 32531, 65407, 130987, 262237, 524521, 1048793, | 10243, 20479, 40961, 81919, 163841, 327673, 655357, |
| 2097397, 4194103, 8388857, 16777447, 33554201, 67108961, | 1310719, 2621447, 5242883, 10485767, 20971529, 41943049, |
| 134217487, 268435697, 536870683, 1073741621, 2147483399}; | 83886091, 167772161, 335544323, 671088637, 1342177283}; |
| /// useful generic hash function | /// useful generic hash function |
| inline void generic_hash_code(uint& result, char c) { | inline void generic_hash_code(uint& result, char c) { |
| Line 125 public: | Line 114 public: |
| HASH() { | HASH() { |
| allocated=Hash_allocates[allocates_index=0]; | allocated=Hash_allocates[allocates_index=0]; |
| fpairs_count=fused_refs=0; | fpairs_count=fused_refs=0; |
| refs=new Pair*[allocated]; | refs=new(PointerGC) Pair*[allocated]; |
| HASH_ORDER_CLEAR(); | HASH_ORDER_CLEAR(); |
| } | } |
| Line 134 public: | Line 123 public: |
| allocated=source.allocated; | allocated=source.allocated; |
| fused_refs=source.fused_refs; | fused_refs=source.fused_refs; |
| fpairs_count=source.fpairs_count; | fpairs_count=source.fpairs_count; |
| refs=new Pair*[allocated]; | refs=new(PointerGC) Pair*[allocated]; |
| // clone & rehash | // clone & rehash |
| #ifdef HASH_ORDER | #ifdef HASH_ORDER |
| HASH_ORDER_CLEAR(); | HASH_ORDER_CLEAR(); |
| Line 163 public: | Line 152 public: |
| delete pair; | delete pair; |
| pair=next; | pair=next; |
| } | } |
| delete[] refs; | operator delete[](refs); |
| } | } |
| #endif | #endif |
| Line 210 public: | Line 199 public: |
| else | else |
| last=pair->prev; | last=pair->prev; |
| #endif | #endif |
| delete pair; | |
| *ref=next; | *ref=next; |
| --fpairs_count; | --fpairs_count; |
| return true; | return true; |
| Line 256 public: | Line 244 public: |
| return (first) ? first->value : V(0); | return (first) ? first->value : V(0); |
| } | } |
| inline Pair* last_pair() const { | |
| return (fpairs_count) ? (Pair*)((char *)last - offsetof(Pair, next)) : NULL; | |
| } | |
| String::Body last_key() const { | String::Body last_key() const { |
| if (fpairs_count) { | if(Pair* pair = last_pair()) { |
| Pair* pair = (Pair*)((char *)last - offsetof(Pair, next)); | |
| #ifdef HASH_CODE_CACHING | #ifdef HASH_CODE_CACHING |
| return String::Body(pair->key, pair->code); | return String::Body(pair->key, pair->code); |
| #else | #else |
| Line 270 public: | Line 261 public: |
| } | } |
| V last_value() const { | V last_value() const { |
| return (fpairs_count) ? ((Pair *)((char *)last - offsetof(Pair, next)))->value : V(0); | if(Pair* pair = last_pair()) |
| return pair->value; | |
| return NULL; | |
| } | } |
| void order_clear() { | void order_clear() { |
| Line 283 public: | Line 276 public: |
| *last=pair; | *last=pair; |
| last=&(pair->next); | last=&(pair->next); |
| } | } |
| #endif //HASH_ORDER | #endif //HASH_ORDER |
| /// 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 |
| Line 420 protected: | Line 412 protected: |
| if (allocates_index<HASH_ALLOCATES_COUNT-1) allocates_index++; | 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]; |
| refs=new Pair*[allocated]; | refs=new(PointerGC) Pair*[allocated]; |
| // rehash | // rehash |
| Pair **old_ref=old_refs; | Pair **old_ref=old_refs; |
| Line 436 protected: | Line 428 protected: |
| pair=next; | pair=next; |
| } | } |
| delete[] old_refs; | operator delete[](old_refs); |
| } | } |
| private: //disabled | private: //disabled |
| Line 471 public: | Line 463 public: |
| CORD key=str.get_cord(); | CORD key=str.get_cord(); |
| uint code=str.get_hash_code(); | uint code=str.get_hash_code(); |
| uint index=code%this->allocated; | uint index=code % this->allocated; |
| Pair **ref=&this->refs[index]; | Pair **ref=&this->refs[index]; |
| for(Pair *pair=*ref; pair; pair=pair->link) | for(Pair *pair=*ref; pair; pair=pair->link) |
| if(pair->code==code && CORD_cmp(pair->key,key)==0) { | if(pair->code==code && CORD_cmp(pair->key,key)==0) { |
| Line 492 public: | Line 484 public: |
| bool remove(K str) { | bool remove(K str) { |
| CORD key=str.get_cord(); | CORD key=str.get_cord(); |
| uint code=str.get_hash_code(); | uint code=str.get_hash_code(); |
| uint index=code%this->allocated; | uint index=code % this->allocated; |
| for(Pair **ref=&this->refs[index]; *ref; ref=&(*ref)->link){ | for(Pair **ref=&this->refs[index]; *ref; ref=&(*ref)->link){ |
| Pair *pair=*ref; | Pair *pair=*ref; |
| if(pair->code==code && CORD_cmp(pair->key,key)==0) { | if(pair->code==code && CORD_cmp(pair->key,key)==0) { |
| Line 505 public: | Line 497 public: |
| else | else |
| this->last=pair->prev; | this->last=pair->prev; |
| #endif | #endif |
| delete pair; | |
| *ref=next; | *ref=next; |
| --this->fpairs_count; | --this->fpairs_count; |
| return true; | return true; |
| Line 519 public: | Line 510 public: |
| bool contains(K str){ | bool contains(K str){ |
| CORD key=str.get_cord(); | CORD key=str.get_cord(); |
| uint code=str.get_hash_code(); | uint code=str.get_hash_code(); |
| uint index=code%this->allocated; | uint index=code % this->allocated; |
| for(Pair *pair=this->refs[index]; pair; pair=pair->link){ | for(Pair *pair=this->refs[index]; pair; pair=pair->link){ |
| if(pair->code==code && CORD_cmp(pair->key,key)==0) | if(pair->code==code && CORD_cmp(pair->key,key)==0) |
| return true; | return true; |
| Line 532 public: | Line 523 public: |
| V get(K str) const { | V get(K str) const { |
| CORD key=str.get_cord(); | CORD key=str.get_cord(); |
| uint code=str.get_hash_code(); | uint code=str.get_hash_code(); |
| uint index=code%this->allocated; | uint index=code % this->allocated; |
| for(Pair *pair=this->refs[index]; pair; pair=pair->link) | for(Pair *pair=this->refs[index]; pair; pair=pair->link) |
| if(pair->code==code && CORD_cmp(pair->key,key)==0) | if(pair->code==code && CORD_cmp(pair->key,key)==0) |
| return pair->value; | return pair->value; |
| Line 548 public: | Line 539 public: |
| } else { | } else { |
| key=0; | key=0; |
| } | } |
| uint index=code%this->allocated; | uint index=code % this->allocated; |
| for(Pair *pair=this->refs[index]; pair; pair=pair->link) | for(Pair *pair=this->refs[index]; pair; pair=pair->link) |
| if(pair->code==code && CORD_cmp(pair->key,(CORD)key)==0) | if(pair->code==code && CORD_cmp(pair->key,(CORD)key)==0) |
| return pair->value; | return pair->value; |
| return V(0); | return V((const char *)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 |
| Line 565 public: | Line 556 public: |
| CORD key=str.get_cord(); | CORD key=str.get_cord(); |
| uint code=str.get_hash_code(); | uint code=str.get_hash_code(); |
| uint index=code%this->allocated; | uint index=code % this->allocated; |
| for(Pair *pair=this->refs[index]; pair; pair=pair->link) | for(Pair *pair=this->refs[index]; pair; pair=pair->link) |
| if(pair->code==code && CORD_cmp(pair->key,key)==0) { | if(pair->code==code && CORD_cmp(pair->key,key)==0) { |
| // found a pair with the same key, replacing | // found a pair with the same key, replacing |
| Line 588 public: | Line 579 public: |
| CORD key=str.get_cord(); | CORD key=str.get_cord(); |
| uint code=str.get_hash_code(); | uint code=str.get_hash_code(); |
| uint index=code%this->allocated; | uint index=code % this->allocated; |
| Pair **ref=&this->refs[index]; | Pair **ref=&this->refs[index]; |
| for(Pair *pair=*ref; pair; pair=pair->link) | for(Pair *pair=*ref; pair; pair=pair->link) |
| if(pair->code==code && CORD_cmp(pair->key,key)==0) { | if(pair->code==code && CORD_cmp(pair->key,key)==0) { |
| Line 604 public: | Line 595 public: |
| return false; | return false; |
| } | } |
| /// rename $.from[] to $.to[] | |
| void rename(K from, K to) { | |
| CORD key_from=from.get_cord(); | |
| uint code_from=from.get_hash_code(); | |
| uint index_from=code_from % this->allocated; | |
| CORD key_to=to.get_cord(); | |
| uint code_to=to.get_hash_code(); | |
| uint index_to=code_to % this->allocated; | |
| if(code_from == code_to && CORD_cmp(key_from, key_to)==0) | |
| return; | |
| for(Pair **ref=&this->refs[index_from]; *ref; ref=&(*ref)->link){ | |
| Pair *pair=*ref; | |
| if(pair->code==code_from && CORD_cmp(pair->key,key_from)==0) { | |
| // found a pair with the required key | |
| // remove it from the from key first | |
| Pair *next=pair->link; | |
| *ref=next; | |
| // to simplify code | |
| remove(to); | |
| // change pair key | |
| pair->code=code_to; | |
| (CORD &)(pair->key)=key_to; | |
| // link to the to key, hash order left intact | |
| if(!(pair->link=this->refs[index_to])) // root was unused? | |
| this->fused_refs++; // we've used it and record the fact | |
| this->refs[index_to]=pair; | |
| return; | |
| } | |
| } | |
| } | |
| /// put all 'src' values if NO with same key existed | /// put all 'src' values if NO with same key existed |
| void merge_dont_replace(const HASH_STRING& src) { | void merge_dont_replace(const HASH_STRING& src) { |
| #ifdef HASH_ORDER | #ifdef HASH_ORDER |
| Line 677 public: | Line 706 public: |
| #endif | #endif |
| operator bool () { | operator bool () { |
| return fcurrent != 0; | return fcurrent != NULL; |
| } | |
| String::Body key(){ | |
| #ifdef HASH_CODE_CACHING | |
| return String::Body(fcurrent->key, fcurrent->code); | |
| #else | |
| return fcurrent->key; | |
| #endif | |
| } | |
| V value(){ | |
| return fcurrent->value; | |
| } | |
| Pair *pair(){ | |
| return fcurrent; | |
| } | |
| }; | |
| #ifdef HASH_ORDER | |
| /// simple reverse hash iterator | |
| class ReverseIterator { | |
| const HASH_STRING<V>& fhash; | |
| Pair *fcurrent; | |
| public: | |
| ReverseIterator(const HASH_STRING<V>& ahash): fhash(ahash) { | |
| fcurrent=fhash.last_pair(); | |
| } | |
| void prev() { | |
| fcurrent=(fcurrent->prev == &fhash.first) ? NULL : (Pair*)((char *)fcurrent->prev - offsetof(Pair, next)); | |
| } | |
| operator bool () { | |
| return fcurrent != NULL; | |
| } | } |
| String::Body key(){ | String::Body key(){ |
| Line 696 public: | Line 760 public: |
| return fcurrent; | return fcurrent; |
| } | } |
| }; | }; |
| #endif | |
| }; | }; |