/** @file
Parser: inline-storage hash decls.
Copyright (c) 2001-2026 Art. Lebedev Studio (https://www.artlebedev.com)
Authors: Konstantin Morshnev <moko@design.ru>
*/
#ifndef PA_INLINE_HASH_H
#define PA_INLINE_HASH_H
#define IDENT_PA_INLINE_HASH_H "$Id: pa_inline_hash.h,v 1.8 2026/05/28 14:29:56 moko Exp $"
#include "pa_hash.h"
#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<V>.
template<typename V> class InlineHashString: public PA_Object {
public:
InlineHashString() : foverflow(0) {
memset(fkeys, 0, sizeof(fkeys));
}
~InlineHashString() {
#ifdef USE_DESTRUCTORS
if(foverflow) delete foverflow;
#endif
}
V get(const String& name) const {
const String::Body& nb = name;
const uint hash = nb.get_hash_code();
int i = hash % PA_INLINE_HASH_N;
// 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;
}
bool put(const String& name, V value) {
const String::Body& nb = name;
const uint hash = nb.get_hash_code();
int i = hash % PA_INLINE_HASH_N;
// 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<V>();
return foverflow->put(name, value);
}
bool put_replaced(const String& name, V value) {
const String::Body& nb = name;
const uint hash = nb.get_hash_code();
int i = hash % PA_INLINE_HASH_N;
// 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;
}
template<typename I> void for_each(void callback(const String::Body&, V, I), I info) const {
for(int i = 0; i < PA_INLINE_HASH_N; i++) {
if(fkeys[i])
callback(*fkeys[i], fvalues[i], info);
}
if(foverflow)
foverflow->for_each(callback, info);
}
private:
HashString<V>* foverflow;
const String::Body* fkeys[PA_INLINE_HASH_N]; // NULL=empty, initialized in constructor
V fvalues[PA_INLINE_HASH_N];
};
#endif // PA_INLINE_HASH_H
E-mail: