--- parser3/src/include/pa_hash.h 2009/07/29 05:01:46 1.78 +++ parser3/src/include/pa_hash.h 2015/03/12 08:18:18 1.86 @@ -1,7 +1,7 @@ /** @file Parser: hash class decl. - Copyright (c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com) + Copyright (c) 2001-2012 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 -static const char * const IDENT_HASH_H="$Date: 2009/07/29 05:01:46 $"; +#define IDENT_PA_HASH_H "$Id: pa_hash.h,v 1.86 2015/03/12 08:18:18 misha Exp $" #include "pa_memory.h" #include "pa_types.h" @@ -89,17 +89,26 @@ inline uint hash_code(int self) { #undef HASH #undef HASH_STRING -#undef NEW_PAIR +#undef HASH_NEW_PAIR +#undef HASH_FOR_EACH #define HASH OrderedHash #define HASH_STRING OrderedHashString -#define NEW_PAIR(code, key, value) *ref=new Pair(code, key, value, *ref, this->last); this->last=&((*ref)->next) +#define HASH_NEW_PAIR(code, key, value) *ref=new Pair(code, key, value, *ref, this->last); this->last=&((*ref)->next) + +#define HASH_FOR_EACH \ + for(Pair *pair=this->first; pair; pair=pair->next) #else #define HASH Hash #define HASH_STRING HashString -#define NEW_PAIR(code, key, value) *ref=new Pair(code, key, value, *ref) +#define HASH_NEW_PAIR(code, key, value) *ref=new Pair(code, key, value, *ref) + +#define HASH_FOR_EACH \ + Pair **ref=this->refs; \ + for(int index=0; indexallocated; index++) \ + for(Pair *pair=*ref++; pair; pair=pair->link) #endif @@ -111,7 +120,6 @@ public: HASH() { allocated=Hash_allocates[allocates_index=0]; - threshold=allocated*THRESHOLD_PERCENT/100; fpairs_count=fused_refs=0; refs=new(UseGC) Pair*[allocated]; #ifdef HASH_ORDER @@ -123,25 +131,27 @@ public: 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(UseGC) Pair*[allocated]; + // clone & rehash #ifdef HASH_ORDER first=0; last=&first; -#endif - // clone & rehash - Pair **old_ref=source.refs; - for(int index=0; indexlink; - - Pair **ref=&refs[index]; - NEW_PAIR(pair->code, pair->key, pair->value); - - pair=next; + for(Pair *pair=source.first; pair; pair=pair->next) + { + uint index=pair->code%allocated; + Pair **ref=&refs[index]; + HASH_NEW_PAIR(pair->code, pair->key, pair->value); + } +#else + for(int i=0; ilink) + { + Pair **ref=&refs[i]; + HASH_NEW_PAIR(pair->code, pair->key, pair->value); } +#endif } #ifdef USE_DESTRUCTORS @@ -179,120 +189,11 @@ public: // 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 - NEW_PAIR(code, key, value); + HASH_NEW_PAIR(code, key, value); fpairs_count++; return false; } - /// put a [value] under the [key] @returns existed or not - template R replace_maybe_append(K key, V value, F prevent, I info) { - if(!value) { - // they can come here from somewhere (true with maybe_replace_maybe_append, keeping parallel) - remove(key); - // this has nothing to do with properties, doing no special property handling here - return 0; - } - - 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 reinterpret_cast(1); - } - - // proper pair not found - // prevent-function intercepted append? - if(R result=prevent(value, info)) - return result; - - //create&link_in new pair - if(!*ref) // root cell were fused_refs? - fused_refs++; // not, we'll use it and record the fact - NEW_PAIR(code, key, value); - fpairs_count++; - return 0; - } - - /// put a [value] under the [key] @returns existed or not - template - R maybe_replace_maybe_append(K key, V value, F1 prevent_replace, F2 prevent_append, I info) - { - if(!value) { - // they can come here from Temp_value_element::dctor to restore some empty value - remove(key); - // this has nothing to do with properties, doing no special property handling here - return 0; - } - - 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 - - // prevent-function intercepted replace? - if(R result=prevent_replace(pair->value, info)) - return result; - - pair->value=value; - return reinterpret_cast(1); - } - - // proper pair not found - // prevent-function intercepted append? - if(R result=prevent_append(value, info)) - return result; - - //create&link_in new pair - if(!*ref) // root cell were fused_refs? - fused_refs++; // not, we'll use it and record the fact - NEW_PAIR(code, key, value); - fpairs_count++; - return 0; - } - - /// put a [value] under the [key] @returns existed or not - template - R maybe_replace_never_append(K key, V value, F1 prevent_replace, I info) - { - if(!value) { - // they can come here from somewhere (true with maybe_replace_maybe_append, keeping parallel) - remove(key); - // this has nothing to do with properties, doing no special property handling here - return 0; - } - - 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 - - // prevent-function intercepted replace? - if(R result=prevent_replace(pair->value, info)) - return result; - - pair->value=value; - return reinterpret_cast(1); - } - - return 0; - } - /// remove the [key] @returns existed or not bool remove(K key) { uint code=hash_code(key); @@ -342,49 +243,46 @@ public: return V(0); } - /// put a [value] under the [key] if that [key] existed @returns existed or not - bool put_replaced(K key, V value) { - if(!value) { - remove(key); - return false; +#ifdef HASH_ORDER + String::Body first_key() const { + return (first) ? String::Body(first->key, first->code) : String::Body(); + } + + V first_value() const { + return (first) ? first->value : V(0); + } + + String::Body last_key() const { + if (fpairs_count) { + Pair* pair = (Pair*)((char *)last - offsetof(Pair, next)); + return String::Body(pair->key, pair->code); + } else { + return String::Body(); } - 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; + V last_value() const { + return (fpairs_count) ? ((Pair *)((char *)last - offsetof(Pair, next)))->value : V(0); } +#endif /// put a [value] under the [key] if that [key] existed @returns existed or not - template R maybe_put_replaced(K key, V value, F prevent) { + bool put_replaced(K key, V value) { if(!value) { - // they can come here from Temp_value_element::dctor to restore some empty value remove(key); - // this has nothing to do with properties, doing no special property handling here - return 0; + return false; } - 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 - // prevent-function intercepted put? - if(R result=prevent(pair->value)) - return result; - pair->value=value; - return reinterpret_cast(1); + return true; } // proper pair not found - return 0; + return false; } /// put a [value] under the [key] if that [key] NOT existed @returns existed or not @@ -408,17 +306,19 @@ public: // 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 - NEW_PAIR(code, key, value); + HASH_NEW_PAIR(code, key, value); fpairs_count++; return false; } - /** put all 'src' values if NO with same key existed - @todo optimize this.allocated==src.allocated case - */ + /// put all 'src' values if NO with same key existed void merge_dont_replace(const HASH& src) { +#ifdef HASH_ORDER + for(Pair *pair=src.first; pair; pair=pair->next) +#else for(int i=0; ilink) +#endif put_dont_replace(pair->key, pair->value); } @@ -427,43 +327,21 @@ public: /// iterate over all pairs template void for_each(void callback(K, V, I), I info) const { -#ifdef HASH_ORDER - for(Pair *pair=first; pair; pair=pair->next) + HASH_FOR_EACH callback(pair->key, pair->value, info); -#else - Pair **ref=refs; - for(int index=0; indexlink) - callback(pair->key, pair->value, info); -#endif } /// iterate over all pairs template void for_each_ref(void callback(K, V&, I), I info) const { -#ifdef HASH_ORDER - for(Pair *pair=first; pair; pair=pair->next) + HASH_FOR_EACH callback(pair->key, pair->value, info); -#else - Pair **ref=refs; - for(int index=0; indexlink) - callback(pair->key, pair->value, info); -#endif } /// iterate over all pairs until condition becomes true, return that element template V first_that(bool callback(K, V, I), I info) const { -#ifdef HASH_ORDER - for(Pair *pair=first; pair; pair=pair->next) + HASH_FOR_EACH if(callback(pair->key, pair->value, info)) return pair->value; -#else - Pair **ref=refs; - for(int index=0; indexlink) - if(callback(pair->key, pair->value, info)) - return pair->value; -#endif return V(0); } @@ -479,20 +357,12 @@ public: protected: - /// expand when these %% of allocated exausted - enum { - THRESHOLD_PERCENT=75 - }; - /// the index of [allocated] in [Hash_allocates] int allocates_index; /// number of allocated pairs int allocated; - /// helper: expanding when fused_refs == threshold - int threshold; - /// used pairs int fused_refs; @@ -522,18 +392,17 @@ protected: Pair **last; #endif - /// filled to threshold: needs expanding - bool is_full() { return fused_refs==threshold; } + /// filled to threshold (THRESHOLD_PERCENT=75), needs expanding + bool is_full() { return fused_refs + allocated/4 >= allocated; } /// allocate larger buffer & rehash void expand() { int old_allocated=allocated; Pair **old_refs=refs; - allocates_index=allocates_index+1fused_refs++; // not, we'll use it and record the fact - NEW_PAIR(code, key, value); + HASH_NEW_PAIR(code, key, value); this->fpairs_count++; return false; } - /// put a [value] under the [key] @returns existed or not - template R replace_maybe_append(K str, V value, F prevent, I info) { - if(!value) { - // they can come here from somewhere (true with maybe_replace_maybe_append, keeping parallel) - remove(str); - // this has nothing to do with properties, doing no special property handling here - return 0; - } - - if(this->is_full()) - this->expand(); - - CORD key=str.get_cord(); - - uint code=str.get_hash_code(); - 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) { - // found a pair with the same key - pair->value=value; - return reinterpret_cast(1); - } - - // proper pair not found - // prevent-function intercepted append? - if(R result=prevent(value, info)) - return result; - - //create&link_in new pair - if(!*ref) // root cell were fused_refs? - this->fused_refs++; // not, we'll use it and record the fact - NEW_PAIR(code, key, value); - this->fpairs_count++; - return 0; - } - - /// put a [value] under the [key] @returns existed or not - template - R maybe_replace_maybe_append(K str, V value, F1 prevent_replace, F2 prevent_append, I info) { - if(!value) { - // they can come here from Temp_value_element::dctor to restore some empty value - remove(str); - // this has nothing to do with properties, doing no special property handling here - return 0; - } - - if(this->is_full()) - this->expand(); - - CORD key=str.get_cord(); - - uint code=str.get_hash_code(); - 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) { - // found a pair with the same key - - // prevent-function intercepted replace? - if(R result=prevent_replace(pair->value, info)) - return result; - - pair->value=value; - return reinterpret_cast(1); - } - - // proper pair not found - // prevent-function intercepted append? - if(R result=prevent_append(value, info)) - return result; - - //create&link_in new pair - if(!*ref) // root cell were fused_refs? - this->fused_refs++; // not, we'll use it and record the fact - NEW_PAIR(code, key, value); - this->fpairs_count++; - return 0; - } - - /// put a [value] under the [key] @returns existed or not - template - R maybe_replace_never_append(K str, V value, F1 prevent_replace, I info) { - if(!value) { - // they can come here from somewhere (true with maybe_replace_maybe_append, keeping parallel) - remove(str); - // this has nothing to do with properties, doing no special property handling here - return 0; - } - - if(this->is_full()) - this->expand(); - - CORD key=str.get_cord(); - - uint code=str.get_hash_code(); - 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) { - // found a pair with the same key - - // prevent-function intercepted replace? - if(R result=prevent_replace(pair->value, info)) - return result; - - pair->value=value; - return reinterpret_cast(1); - } - - return 0; - - } - /// remove the [key] @returns existed or not bool remove(K str) { CORD key=str.get_cord(); @@ -789,33 +544,6 @@ public: return false; } - /// put a [value] under the [key] if that [key] existed @returns existed or not - template R maybe_put_replaced(K str, V value, F prevent) { - if(!value) { - // they can come here from Temp_value_element::dctor to restore some empty value - remove(str); - // this has nothing to do with properties, doing no special property handling here - return 0; - } - - CORD key=str.get_cord(); - uint code=str.get_hash_code(); - 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 - // prevent-function intercepted put? - if(R result=prevent(pair->value)) - return result; - - pair->value=value; - return reinterpret_cast(1); - } - - // proper pair not found - return 0; - } - /// put a [value] under the [key] if that [key] NOT existed @returns existed or not bool put_dont_replace(K str, V value) { if(!value) { @@ -838,52 +566,67 @@ public: // proper pair not found -- create&link_in new pair if(!*ref) // root cell were fused_refs? this->fused_refs++; // not, we'll use it and record the fact - NEW_PAIR(code, key, value); + HASH_NEW_PAIR(code, key, value); this->fpairs_count++; return false; } - /// iterate over all pairs - template void for_each(void callback(K, V, I), I info) const { + /// put all 'src' values if NO with same key existed + void merge_dont_replace(const HASH_STRING& src) { #ifdef HASH_ORDER - for(Pair *pair=this->first; pair; pair=pair->next) - callback(pair->key, pair->value, info); + for(Pair *pair=src.first; pair; pair=pair->next) #else - Pair **ref=this->refs; - for(int index=0; indexallocated; index++) - for(Pair *pair=*ref++; pair; pair=pair->link) - callback(String::Body(pair->key, pair->code), pair->value, info); + for(int i=0; ilink) #endif + put_dont_replace(String::Body(pair->key, pair->code), pair->value); + } + + /// iterate over all pairs + template void for_each(void callback(K, V, I), I info) const { + HASH_FOR_EACH + callback(String::Body(pair->key, pair->code), pair->value, info); } /// iterate over all pairs template void for_each_ref(void callback(K, V&, I), I info) const { -#ifdef HASH_ORDER - for(Pair *pair=this->first; pair; pair=pair->next) - callback(pair->key, pair->value, info); -#else - Pair **ref=this->refs; - for(int index=0; indexallocated; index++) - for(Pair *pair=*ref++; pair; pair=pair->link) - callback(String::Body(pair->key, pair->code), pair->value, info); -#endif + HASH_FOR_EACH + callback(String::Body(pair->key, pair->code), pair->value, info); } /// iterate over all pairs until condition becomes true, return that element template V first_that(bool callback(K, V, I), I info) const { -#ifdef HASH_ORDER - for(Pair *pair=this->first; pair; pair=pair->next) + HASH_FOR_EACH if(callback(String::Body(pair->key, pair->code), pair->value, info)) return pair->value; -#else - Pair **ref=this->refs; - for(int index=0; indexallocated; index++) - for(Pair *pair=*ref++; pair; pair=pair->link) - if(callback(String::Body(pair->key, pair->code), pair->value, info)) - return pair->value; -#endif return V(0); } + + /// simple hash iterator + class Iterator { + const HASH_STRING& fhash; + Pair *fcurrent; + public: + Iterator(const HASH_STRING& ahash): fhash(ahash) { + fcurrent=fhash.first; + } + + operator bool () { + return fcurrent != 0; + } + + void next() { + fcurrent=fcurrent->next; + } + + String::Body key(){ + return String::Body(fcurrent->key, fcurrent->code); + } + + V value(){ + return fcurrent->value; + } + }; }; #else //HASH_CODE_CACHING @@ -893,20 +636,21 @@ template class HASH_STRING: #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