|
|
| version 1.99, 2017/11/15 22:48:57 | version 1.107, 2025/05/26 00:52:15 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: hash class decl. | Parser: hash class decl. |
| Copyright (c) 2001-2017 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 115 inline uint hash_code(int self) { | Line 104 inline uint hash_code(int self) { |
| #endif | #endif |
| #define HASH_PUT_CSTR(h, cstr, v) \ | |
| { static const String::Body body_##__LINE__(cstr); (h).put(body_##__LINE__, (v)); } | |
| template<typename K, typename V> class HASH: public PA_Object { | template<typename K, typename V> class HASH: public PA_Object { |
| protected: | protected: |
| class Pair; | class Pair; |
| Line 474 public: | Line 466 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 491 public: | Line 483 public: |
| return false; | return false; |
| } | } |
| bool put(const char *str, V value) { | |
| return put(String::Body(str), value); | |
| } | |
| /// 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(); |
| 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 521 public: | Line 517 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 534 public: | Line 530 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 550 public: | Line 546 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 567 public: | Line 563 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 590 public: | Line 586 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 606 public: | Line 602 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 |