--- parser3/src/include/pa_inline_hash.h 2026/04/29 23:30:44 1.4 +++ parser3/src/include/pa_inline_hash.h 2026/04/30 16:06:48 1.7 @@ -8,14 +8,14 @@ #ifndef PA_INLINE_HASH_H #define PA_INLINE_HASH_H -#define IDENT_PA_INLINE_HASH_H "$Id: pa_inline_hash.h,v 1.4 2026/04/29 23:30:44 moko Exp $" +#define IDENT_PA_INLINE_HASH_H "$Id: pa_inline_hash.h,v 1.7 2026/04/30 16:06:48 moko Exp $" #include "pa_hash.h" -#define PA_INLINE_HASH_N 13 +#define PA_INLINE_HASH_N 13 // Low overflow rate, high first-hit ratio +#define PA_PROBE_LIMIT 8 // Prevents long probe chains from degrading the inline table // Linear-probing inline hash with PA_INLINE_HASH_N slots before overflow to HashString. -// Inits 8*N bytes, while HASH allocates (and inits) at least template class InlineHashString: public PA_Object { public: @@ -33,13 +33,15 @@ public: const String::Body& nb = name; const uint hash = nb.get_hash_code(); int i = hash % PA_INLINE_HASH_N; - for(int probe = 0; probe < PA_INLINE_HASH_N; probe++) { - if(!fkeys[i]) { - return foverflow ? foverflow->get(name) : 0; - } - if(fkeys[i]->get_hash_code() == hash && *fkeys[i] == nb) - return fvalues[i]; + + // Optimized first, >50% hits + if(!fkeys[i]) return 0; // NULL implies foverflow==NULL + if(fkeys[i]->get_hash_code() == hash && *fkeys[i] == nb) return fvalues[i]; + // Сollision + for(int n = 0; n < PA_PROBE_LIMIT-1; n++) { if(++i >= PA_INLINE_HASH_N) i = 0; + if(!fkeys[i]) return 0; + if(fkeys[i]->get_hash_code() == hash && *fkeys[i] == nb) return fvalues[i]; } return foverflow ? foverflow->get(name) : 0; } @@ -48,17 +50,15 @@ public: const String::Body& nb = name; const uint hash = nb.get_hash_code(); int i = hash % PA_INLINE_HASH_N; - for(int probe = 0; probe < PA_INLINE_HASH_N; probe++) { - if(!fkeys[i]) { - fkeys[i] = &nb; - fvalues[i] = value; - return false; - } - if(fkeys[i]->get_hash_code() == hash && *fkeys[i] == nb) { - fvalues[i] = value; - return true; - } + + // Optimized first + if(!fkeys[i]) { fkeys[i] = &nb; fvalues[i] = value; return false; } + if(fkeys[i]->get_hash_code() == hash && *fkeys[i] == nb) { fvalues[i] = value; return true; } + // Сollision + for(int n = 0; n < PA_PROBE_LIMIT-1; n++) { if(++i >= PA_INLINE_HASH_N) i = 0; + if(!fkeys[i]) { fkeys[i] = &nb; fvalues[i] = value; return false; } + if(fkeys[i]->get_hash_code() == hash && *fkeys[i] == nb) { fvalues[i] = value; return true; } } if(!foverflow) foverflow = new HashString(); @@ -69,14 +69,15 @@ public: const String::Body& nb = name; const uint hash = nb.get_hash_code(); int i = hash % PA_INLINE_HASH_N; - for(int probe = 0; probe < PA_INLINE_HASH_N; probe++) { - if(!fkeys[i]) - return foverflow ? foverflow->put_replaced(name, value) : false; - if(fkeys[i]->get_hash_code() == hash && *fkeys[i] == nb) { - fvalues[i] = value; - return true; - } + + // Optimized first + if(!fkeys[i]) return false; + if(fkeys[i]->get_hash_code() == hash && *fkeys[i] == nb) { fvalues[i] = value; return true; } + // Сollision + for(int n = 0; n < PA_PROBE_LIMIT-1; n++) { if(++i >= PA_INLINE_HASH_N) i = 0; + if(!fkeys[i]) return false; + if(fkeys[i]->get_hash_code() == hash && *fkeys[i] == nb) { fvalues[i] = value; return true; } } return foverflow ? foverflow->put_replaced(name, value) : false; }