--- parser3/src/include/pa_hash.h 2017/02/07 22:00:34 1.96 +++ parser3/src/include/pa_hash.h 2021/11/03 21:45:15 1.102 @@ -1,7 +1,7 @@ /** @file Parser: hash class decl. - Copyright (c) 2001-2017 Art. Lebedev Studio (http://www.artlebedev.com) + Copyright (c) 2001-2020 Art. Lebedev Studio (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) */ @@ -17,7 +17,7 @@ #ifndef PA_HASH_H #define PA_HASH_H -#define IDENT_PA_HASH_H "$Id: pa_hash.h,v 1.96 2017/02/07 22:00:34 moko Exp $" +#define IDENT_PA_HASH_H "$Id: pa_hash.h,v 1.102 2021/11/03 21:45:15 moko Exp $" #include "pa_memory.h" #include "pa_types.h" @@ -125,7 +125,7 @@ public: HASH() { allocated=Hash_allocates[allocates_index=0]; fpairs_count=fused_refs=0; - refs=new Pair*[allocated]; + refs=new(PointerGC) Pair*[allocated]; HASH_ORDER_CLEAR(); } @@ -134,7 +134,7 @@ public: allocated=source.allocated; fused_refs=source.fused_refs; fpairs_count=source.fpairs_count; - refs=new Pair*[allocated]; + refs=new(PointerGC) Pair*[allocated]; // clone & rehash #ifdef HASH_ORDER HASH_ORDER_CLEAR(); @@ -163,7 +163,7 @@ public: delete pair; pair=next; } - delete[] refs; + operator delete[](refs); } #endif @@ -255,9 +255,12 @@ public: 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 { - if (fpairs_count) { - Pair* pair = (Pair*)((char *)last - offsetof(Pair, next)); + if(Pair* pair = last_pair()) { #ifdef HASH_CODE_CACHING return String::Body(pair->key, pair->code); #else @@ -269,7 +272,9 @@ public: } 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() { @@ -282,7 +287,6 @@ public: *last=pair; last=&(pair->next); } - #endif //HASH_ORDER /// put a [value] under the [key] if that [key] existed @returns existed or not @@ -419,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) { @@ -491,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) { @@ -517,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; @@ -530,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; @@ -546,12 +550,12 @@ public: } else { key=0; } - 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,(CORD)key)==0) 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 @@ -563,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 @@ -586,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) { @@ -602,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 @@ -675,7 +717,42 @@ public: #endif 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& 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)); + } + + operator bool () { + return fcurrent != NULL; } String::Body key(){ @@ -694,6 +771,7 @@ public: return fcurrent; } }; +#endif };