require '_h2ph_pre.ph';

unless(defined(&_GHASH_H)) {
    eval 'sub _GHASH_H () {1;}' unless defined(&_GHASH_H);
    eval 'sub DEF_HASH_FUZZY_STRUCTS {
        local($NAME,$HASHSIZE,$TYPE) = @_;
	    eval q(\'struct NAME\' &_table { $TYPE *  $hashtable[$HASHSIZE]; $TYPE *  &sorted_list; \'int\'  &nr_entries;};\'struct NAME\' &_ptrs { $TYPE *  &next_hash; $TYPE *  &prev_hash; $TYPE *  &next_sorted; $TYPE *  &prev_sorted;};);
    }' unless defined(&DEF_HASH_FUZZY_STRUCTS);
    eval 'sub DEF_HASH_FUZZY {
        local($LINKAGE,$NAME,$HASHSIZE,$TYPE,$PTRS,$KEYTYPE,$KEY,$KEYCMP,$KEYEQ,$HASHFN) = @_;
	    eval q($LINKAGE  &void  &insert_$NAME &_hash(\'struct NAME\' &_table *  &tbl, $TYPE *  &elem){ \'int\'  &ix = $HASHFN( ($elem->{KEY})); $TYPE **  &base =  ($tbl->{hashtable[&ix]}); $TYPE *  &ptr = * &base; $TYPE *  &prev =  &NULL;  ($tbl->{nr_entries})++;  &while( &ptr  && $KEYCMP( ($ptr->{KEY}),  ($elem->{KEY}))) {  &base =  ($ptr->{PTRS}->{next_hash});  &prev =  &ptr;  &ptr = * &base; }  ($elem->{PTRS}->{next_hash}) =  &ptr;  ($elem->{PTRS}->{prev_hash}) =  &prev;  &if {  ($ptr->{PTRS}->{prev_hash}) =  &elem; } * &base =  &elem;  &ptr =  &prev;  &if(! &ptr) {  &ptr =  ($tbl->{sorted_list});  &prev =  &NULL; }  &else {  &prev =  ($ptr->{PTRS}->{prev_sorted}); }  &while { $TYPE *  &next =  ($ptr->{PTRS}->{next_hash});  &if( &next  && $KEYCMP( ($next->{KEY}),  ($elem->{KEY}))) {  &prev =  &ptr;  &ptr =  &next; }  &else  &if($KEYCMP( ($ptr->{KEY}),  ($elem->{KEY}))) {  &prev =  &ptr;  &ptr =  ($ptr->{PTRS}->{next_sorted}); }  &else  &break; }  ($elem->{PTRS}->{next_sorted}) =  &ptr;  ($elem->{PTRS}->{prev_sorted}) =  &prev;  &if {  ($ptr->{PTRS}->{prev_sorted}) =  &elem; }  &if {  ($prev->{PTRS}->{next_sorted}) =  &elem; }  &else {  ($tbl->{sorted_list}) =  &elem; }}$LINKAGE  &void  &remove_$NAME &_hash(\'struct NAME\' &_table *  &tbl, $TYPE *  &elem){ $TYPE *  &next =  ($elem->{PTRS}->{next_hash}); $TYPE *  &prev =  ($elem->{PTRS}->{prev_hash});  ($tbl->{nr_entries})--;  &if  ($next->{PTRS}->{prev_hash}) =  &prev;  &if  ($prev->{PTRS}->{next_hash}) =  &next;  &else { \'int\'  &ix = $HASHFN( ($elem->{KEY}));  ($tbl->{hashtable[&ix]}) =  &next; }  &next =  ($elem->{PTRS}->{next_sorted});  &prev =  ($elem->{PTRS}->{prev_sorted});  &if  ($next->{PTRS}->{prev_sorted}) =  &prev;  &if  ($prev->{PTRS}->{next_sorted}) =  &next;  &else  ($tbl->{sorted_list}) =  &next;}$LINKAGE $TYPE *  &find_$NAME &_hash(\'struct NAME\' &_table *  &tbl, $KEYTYPE  &pos){ \'int\'  &ix =  &hashfn( &pos); $TYPE *  &ptr =  ($tbl->{hashtable[&ix]});  &while( &ptr  && $KEYCMP( ($ptr->{KEY}),  &pos))  &ptr =  ($ptr->{PTRS}->{next_hash});  &if( &ptr  && !$KEYEQ( ($ptr->{KEY}),  &pos))  &ptr =  &NULL;  &return  &ptr;}$LINKAGE $TYPE *  &find_$NAME &_hash_fuzzy(\'struct NAME\' &_table *  &tbl, $KEYTYPE  &pos){ \'int\'  &ix; \'int\'  &offset; $TYPE *  &ptr; $TYPE *  &next;  &ptr =  ($tbl->{sorted_list});  &if(! &ptr || $KEYCMP( &pos,  ($ptr->{KEY})))  &return  &NULL;  &ix = $HASHFN( &pos);  &offset = $HASHSIZE;  &do {  &offset >>= 1;  &next =  ($tbl->{hashtable[(ix+offset) & ((HASHSIZE)}-1)]);  &if( &next  && ($KEYCMP( ($next->{KEY}),  &pos) || $KEYEQ( ($next->{KEY}),  &pos))  && $KEYCMP( ($ptr->{KEY}),  ($next->{KEY})))  &ptr =  &next; }  &while( &offset);  &for(;;) {  &next =  ($ptr->{PTRS}->{next_hash});  &if( &next) {  &if($KEYCMP( ($next->{KEY}),  &pos)) {  &ptr =  &next;  &continue; } }  &next =  ($ptr->{PTRS}->{next_sorted});  &if( &next  && $KEYCMP( ($next->{KEY}),  &pos)) {  &ptr =  &next;  &continue; }  &return  &ptr; }  &return  &NULL;});
    }' unless defined(&DEF_HASH_FUZZY);
    eval 'sub DEF_HASH_STRUCTS {
        local($NAME,$HASHSIZE,$TYPE) = @_;
	    eval q(\'struct NAME\' &_table { $TYPE *  $hashtable[$HASHSIZE]; \'int\'  &nr_entries;};\'struct NAME\' &_ptrs { $TYPE *  &next_hash; $TYPE *  &prev_hash;};);
    }' unless defined(&DEF_HASH_STRUCTS);
    eval 'sub DEF_HASH {
        local($LINKAGE,$NAME,$HASHSIZE,$TYPE,$PTRS,$KEYTYPE,$KEY,$KEYCMP,$KEYEQ,$HASHFN) = @_;
	    eval q($LINKAGE  &void  &insert_$NAME &_hash(\'struct NAME\' &_table *  &tbl, $TYPE *  &elem){ \'int\'  &ix = $HASHFN( ($elem->{KEY})); $TYPE **  &base =  ($tbl->{hashtable[&ix]}); $TYPE *  &ptr = * &base; $TYPE *  &prev =  &NULL;  ($tbl->{nr_entries})++;  &while( &ptr  && $KEYCMP( ($ptr->{KEY}),  ($elem->{KEY}))) {  &base =  ($ptr->{PTRS}->{next_hash});  &prev =  &ptr;  &ptr = * &base; }  ($elem->{PTRS}->{next_hash}) =  &ptr;  ($elem->{PTRS}->{prev_hash}) =  &prev;  &if {  ($ptr->{PTRS}->{prev_hash}) =  &elem; } * &base =  &elem;}$LINKAGE  &void  &remove_$NAME &_hash(\'struct NAME\' &_table *  &tbl, $TYPE *  &elem){ $TYPE *  &next =  ($elem->{PTRS}->{next_hash}); $TYPE *  &prev =  ($elem->{PTRS}->{prev_hash});  ($tbl->{nr_entries})--;  &if  ($next->{PTRS}->{prev_hash}) =  &prev;  &if  ($prev->{PTRS}->{next_hash}) =  &next;  &else { \'int\'  &ix = $HASHFN( ($elem->{KEY}));  ($tbl->{hashtable[&ix]}) =  &next; }}$LINKAGE $TYPE *  &find_$NAME &_hash(\'struct NAME\' &_table *  &tbl, $KEYTYPE  &pos){ \'int\'  &ix =  &hashfn( &pos); $TYPE *  &ptr =  ($tbl->{hashtable[&ix]});  &while( &ptr  && $KEYCMP( ($ptr->{KEY}),  &pos))  &ptr =  ($ptr->{PTRS}->{next_hash});  &if( &ptr  && !$KEYEQ( ($ptr->{KEY}),  &pos))  &ptr =  &NULL;  &return  &ptr;});
    }' unless defined(&DEF_HASH);
}
1;
