--- parser3/src/include/pa_hash.h 2012/03/16 09:24:09 1.84 +++ parser3/src/include/pa_hash.h 2023/09/26 20:49:07 1.103 @@ -1,9 +1,9 @@ /** @file Parser: hash class decl. - Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com) + Copyright (c) 2001-2023 Art. Lebedev Studio (http://www.artlebedev.com) - Author: Alexandr Petrosian (http://paf.design.ru) + Authors: Konstantin Morshnev , Alexandr Petrosian */ /* @@ -17,7 +17,7 @@ #ifndef PA_HASH_H #define PA_HASH_H -#define IDENT_PA_HASH_H "$Id: pa_hash.h,v 1.84 2012/03/16 09:24:09 moko Exp $" +#define IDENT_PA_HASH_H "$Id: pa_hash.h,v 1.103 2023/09/26 20:49:07 moko Exp $" #include "pa_memory.h" #include "pa_types.h" @@ -90,11 +90,13 @@ inline uint hash_code(int self) { #undef HASH #undef HASH_STRING #undef HASH_NEW_PAIR +#undef HASH_ORDER_CLEAR #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_ORDER_CLEAR() first=0; last=&first #define HASH_FOR_EACH \ for(Pair *pair=this->first; pair; pair=pair->next) @@ -104,6 +106,7 @@ inline uint hash_code(int self) { #define HASH Hash #define HASH_STRING HashString #define HASH_NEW_PAIR(code, key, value) *ref=new Pair(code, key, value, *ref) +#define HASH_ORDER_CLEAR() #define HASH_FOR_EACH \ Pair **ref=this->refs; \ @@ -113,19 +116,17 @@ inline uint hash_code(int self) { #endif template class HASH: public PA_Object { +protected: + class Pair; public: - typedef K key_type; typedef V value_type; HASH() { allocated=Hash_allocates[allocates_index=0]; fpairs_count=fused_refs=0; - refs=new(UseGC) Pair*[allocated]; -#ifdef HASH_ORDER - first=0; - last=&first; -#endif + refs=new(PointerGC) Pair*[allocated]; + HASH_ORDER_CLEAR(); } HASH(const HASH& source) { @@ -133,11 +134,10 @@ public: allocated=source.allocated; fused_refs=source.fused_refs; fpairs_count=source.fpairs_count; - refs=new(UseGC) Pair*[allocated]; + refs=new(PointerGC) Pair*[allocated]; // clone & rehash #ifdef HASH_ORDER - first=0; - last=&first; + HASH_ORDER_CLEAR(); for(Pair *pair=source.first; pair; pair=pair->next) { uint index=pair->code%allocated; @@ -163,7 +163,7 @@ public: delete pair; pair=next; } - delete[] refs; + operator delete[](refs); } #endif @@ -210,7 +210,6 @@ public: else last=pair->prev; #endif - delete pair; *ref=next; --fpairs_count; return true; @@ -244,14 +243,51 @@ public: } #ifdef HASH_ORDER + String::Body first_key() const { +#ifdef HASH_CODE_CACHING + return (first) ? String::Body(first->key, first->code) : String::Body(); +#else + return (first) ? first->key : String::Body(); +#endif + } + 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); + inline Pair* last_pair() const { + return (fpairs_count) ? (Pair*)((char *)last - offsetof(Pair, next)) : NULL; } + + String::Body last_key() const { + if(Pair* pair = last_pair()) { +#ifdef HASH_CODE_CACHING + return String::Body(pair->key, pair->code); +#else + return pair->key; #endif + } else { + return String::Body(); + } + } + + V last_value() const { + if(Pair* pair = last_pair()) + return pair->value; + return NULL; + } + + void order_clear() { + HASH_ORDER_CLEAR(); + } + + void order_next(Pair* pair) { + pair->prev=last; + pair->next=0; + *last=pair; + last=&(pair->next); + } +#endif //HASH_ORDER /// put a [value] under the [key] if that [key] existed @returns existed or not bool put_replaced(K key, V value) { @@ -335,11 +371,8 @@ public: /// remove all elements void clear() { memset(refs, 0, sizeof(*refs)*allocated); - fpairs_count=fused_refs=0; -#ifdef HASH_ORDER - first=0; - last=&first; -#endif + fpairs_count=fused_refs=0; + HASH_ORDER_CLEAR(); } protected: @@ -390,7 +423,7 @@ protected: if (allocates_indexallocated; + 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) { @@ -462,7 +495,7 @@ public: bool remove(K str) { CORD key=str.get_cord(); 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){ Pair *pair=*ref; if(pair->code==code && CORD_cmp(pair->key,key)==0) { @@ -475,7 +508,6 @@ public: else this->last=pair->prev; #endif - delete pair; *ref=next; --this->fpairs_count; return true; @@ -489,7 +521,7 @@ public: bool contains(K str){ CORD key=str.get_cord(); 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){ if(pair->code==code && CORD_cmp(pair->key,key)==0) return true; @@ -502,7 +534,7 @@ public: V get(K str) const { CORD key=str.get_cord(); 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) if(pair->code==code && CORD_cmp(pair->key,key)==0) return pair->value; @@ -510,6 +542,22 @@ public: return V(0); } + /// get associated [value] by the [key], optimized + V get(const char *key) const { + uint code=0; + if(key && *key){ + generic_hash_code(code, key); + } else { + key=0; + } + uint index=code % this->allocated; + for(Pair *pair=this->refs[index]; pair; pair=pair->link) + if(pair->code==code && CORD_cmp(pair->key,(CORD)key)==0) + return pair->value; + + return V((const char *)0); + } + /// put a [value] under the [key] if that [key] existed @returns existed or not bool put_replaced(K str, V value) { if(!value) { @@ -519,7 +567,7 @@ public: CORD key=str.get_cord(); 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) if(pair->code==code && CORD_cmp(pair->key,key)==0) { // found a pair with the same key, replacing @@ -542,7 +590,7 @@ public: CORD key=str.get_cord(); uint code=str.get_hash_code(); - uint index=code%this->allocated; + 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) { @@ -558,6 +606,44 @@ public: 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 void merge_dont_replace(const HASH_STRING& src) { #ifdef HASH_ORDER @@ -589,54 +675,123 @@ public: return V(0); } +#else //HASH_CODE_CACHING + +template class HASH_STRING: public HASH{ +public: + typedef typename HASH::Pair Pair; + +#endif //HASH_CODE_CACHING + /// simple hash iterator class Iterator { const HASH_STRING& fhash; Pair *fcurrent; +#ifndef HASH_ORDER + int i; +#endif public: +#ifdef HASH_ORDER Iterator(const HASH_STRING& ahash): fhash(ahash) { fcurrent=fhash.first; } - operator bool () { - return fcurrent != 0; + void next() { + fcurrent=fcurrent->next; + } +#else + Iterator(const HASH_STRING& ahash): fhash(ahash) { + fcurrent=0; + for(i=0; inext; + if(fcurrent=fcurrent->link) + return; + for(i++; ikey, fcurrent->code); +#else + return fcurrent->key; +#endif } V value(){ return fcurrent->value; } + + Pair *pair(){ + return fcurrent; + } }; -}; -#else //HASH_CODE_CACHING -template class HASH_STRING: public HASH{}; +#ifdef HASH_ORDER + /// simple reverse hash iterator + class ReverseIterator { + const HASH_STRING& fhash; + Pair *fcurrent; + public: + ReverseIterator(const HASH_STRING& ahash): fhash(ahash) { + fcurrent=fhash.last_pair(); + } + + void prev() { + fcurrent=(fcurrent->prev == &fhash.first) ? NULL : (Pair*)((char *)fcurrent->prev - offsetof(Pair, next)); + } -#endif //HASH_CODE_CACHING + operator bool () { + 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; + } + }; +#endif + +}; #ifndef HASH_ORDER /// Auto-object used to temporarily substituting/removing string hash values -template +template class Temp_hash_value { - HashString &fhash; - K fname; + H *fhash; + String::Body fname; V saved_value; public: - Temp_hash_value(HashString& ahash, K aname, V avalue) : - fhash(ahash), - fname(aname), - saved_value(ahash.get(aname)) { - fhash.put(aname, avalue); + Temp_hash_value(H *ahash, String::Body aname, V avalue) : fhash(ahash), fname(aname) { + if(fhash){ + saved_value=fhash->get(aname); + fhash->put(aname, avalue); + } } - ~Temp_hash_value() { - fhash.put(fname, saved_value); + ~Temp_hash_value() { + if(fhash) + fhash->put(fname, saved_value); } }; #endif