backtrack global hash table.
This commit is contained in:
		
							
								
								
									
										165
									
								
								library/bhash.yap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								library/bhash.yap
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,165 @@
 | 
			
		||||
/* 
 | 
			
		||||
 | 
			
		||||
This code implements hash-arrays.
 | 
			
		||||
It requires the hash key to be a ground term.
 | 
			
		||||
 | 
			
		||||
It relies on dynamic array code.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
:- source.
 | 
			
		||||
:- yap_flag(unknown,error).
 | 
			
		||||
:- style_check(all).
 | 
			
		||||
 | 
			
		||||
:- module(b_hash, [    b_hash_new/1,
 | 
			
		||||
		      b_hash_new/2,
 | 
			
		||||
		      b_hash_new/3,
 | 
			
		||||
		      b_hash_lookup/3,
 | 
			
		||||
		      b_hash_update/3,
 | 
			
		||||
		      b_hash_update/4,
 | 
			
		||||
		      b_hash_insert/3
 | 
			
		||||
		    ]).
 | 
			
		||||
 | 
			
		||||
:- use_module(library(terms), [ term_hash/4 ]).
 | 
			
		||||
 | 
			
		||||
array_default_size(4).
 | 
			
		||||
 | 
			
		||||
b_hash_new(hash(Keys, Vals, Size, N, _)) :-
 | 
			
		||||
	array_default_size(Size),
 | 
			
		||||
	array(Keys, Size),
 | 
			
		||||
	array(Vals, Size),
 | 
			
		||||
	create_mutable(0, N).
 | 
			
		||||
 | 
			
		||||
b_hash_new(hash(Keys,Vals, Size, N, _), Size) :-
 | 
			
		||||
	array(Keys, Size),
 | 
			
		||||
	array(Vals, Size),
 | 
			
		||||
	create_mutable(0, N).
 | 
			
		||||
 | 
			
		||||
b_hash_new(hash(Keys,Vals, Size, N, HashF), Size, HashF) :-
 | 
			
		||||
	array(Keys, Size),
 | 
			
		||||
	array(Vals, Size),
 | 
			
		||||
	create_mutable(0, N).
 | 
			
		||||
 | 
			
		||||
b_hash_lookup(Key, Val, hash(Keys, Vals, Size, F)):-
 | 
			
		||||
	hash_f(Key, Size, Index, F),
 | 
			
		||||
	term_hash(Key,-1,Size,Index),
 | 
			
		||||
	fetch_key(Keys, Index, Size, Key, ActualIndex),
 | 
			
		||||
	array_element(Vals, ActualIndex, Mutable),
 | 
			
		||||
	get_mutable(Val, Mutable).
 | 
			
		||||
 | 
			
		||||
fetch_key(Keys, Index, Size, Key, ActualIndex) :-
 | 
			
		||||
	array_element(Keys, Index, El),
 | 
			
		||||
	nonvar(El),
 | 
			
		||||
	(
 | 
			
		||||
	    El == Key
 | 
			
		||||
	->
 | 
			
		||||
	    Index = ActualIndex
 | 
			
		||||
	;
 | 
			
		||||
	    I1 is (Index+1) mod Size,
 | 
			
		||||
	    fetch_key(Keys, I1, Size, Key, ActualIndex)
 | 
			
		||||
	).
 | 
			
		||||
 | 
			
		||||
b_hash_update(Hash, Key, NewVal):-
 | 
			
		||||
	Hash = hash(Keys, Vals, Size, _, F),
 | 
			
		||||
	hash_f(Key,Size,Index,F),
 | 
			
		||||
	fetch_key(Keys, Index, Size, Key, ActualIndex),
 | 
			
		||||
	array_element(Vals, ActualIndex, Mutable),
 | 
			
		||||
	update_mutable(NewVal, Mutable).
 | 
			
		||||
 | 
			
		||||
b_hash_update(Hash, Key, OldVal, NewVal):-
 | 
			
		||||
	Hash = hash(Keys, Vals, Size, _, F),
 | 
			
		||||
	hash_f(Key,Size,Index,F),
 | 
			
		||||
	fetch_key(Keys, Index, Size, Key, ActualIndex),
 | 
			
		||||
	array_element(Vals, ActualIndex, Mutable),
 | 
			
		||||
	get_mutable(OldVal, Mutable),
 | 
			
		||||
	update_mutable(NewVal, Mutable).
 | 
			
		||||
 | 
			
		||||
b_hash_insert(Hash, Key, NewVal):-
 | 
			
		||||
	Hash = hash(Keys, Vals, Size, N, F),
 | 
			
		||||
	hash_f(Key,Size,Index,F),
 | 
			
		||||
	find_or_insert(Keys, Index, Size, N, Vals, Key, NewVal, Hash).
 | 
			
		||||
 | 
			
		||||
find_or_insert(Keys, Index, Size, N, Vals, Key, NewVal, Hash) :-
 | 
			
		||||
	array_element(Keys, Index, El),
 | 
			
		||||
	(
 | 
			
		||||
	    var(El)
 | 
			
		||||
	->
 | 
			
		||||
	    add_element(Keys, Index, Size, N, Vals, Key, NewVal, Hash)
 | 
			
		||||
	;
 | 
			
		||||
	    El == Key
 | 
			
		||||
	->
 | 
			
		||||
	     % do rb_update
 | 
			
		||||
	    array_element(Vals, Index, Mutable),
 | 
			
		||||
	    update_mutable(NewVal, Mutable)
 | 
			
		||||
	;
 | 
			
		||||
	    I1 is (Index+1) mod Size,
 | 
			
		||||
	    find_or_insert(Keys, I1, Size, N, Vals, Key, NewVal, Hash)
 | 
			
		||||
	).
 | 
			
		||||
 | 
			
		||||
add_element(Keys, Index, Size, N, Vals, Key, NewVal, Hash) :-
 | 
			
		||||
	get_mutable(NEls, N),
 | 
			
		||||
	NN is NEls+1,
 | 
			
		||||
	update_mutable(NN, N),
 | 
			
		||||
	(
 | 
			
		||||
	    NN > 3*Size/4
 | 
			
		||||
	->
 | 
			
		||||
	    expand_array(Key, NewVal, Hash)
 | 
			
		||||
	;
 | 
			
		||||
	    array_element(Keys, Index, Key),
 | 
			
		||||
	    update_mutable(NN, N),
 | 
			
		||||
	    array_element(Vals, Index, Mutable),
 | 
			
		||||
	    create_mutable(NewVal, Mutable)
 | 
			
		||||
	).
 | 
			
		||||
 | 
			
		||||
expand_array(Key, NewVal, Hash) :-
 | 
			
		||||
	Hash = hash(Keys, Vals, Size, _, F),
 | 
			
		||||
	new_size(Size, NewSize),
 | 
			
		||||
	array(NewKeys, NewSize),
 | 
			
		||||
	array(NewVals, NewSize),
 | 
			
		||||
	copy_hash_table(Size, Keys, Vals, F, NewSize, NewKeys, NewVals),
 | 
			
		||||
	setarg(1, Hash, NewKeys),
 | 
			
		||||
	setarg(2, Hash, NewVals),
 | 
			
		||||
	setarg(3, Hash, NewSize),
 | 
			
		||||
	create_mutable(NewVal, Mut),
 | 
			
		||||
	insert_el(Key, Mut, NewSize, F, NewKeys, NewVals).
 | 
			
		||||
 | 
			
		||||
new_size(Size, NewSize) :-
 | 
			
		||||
	Size > 1048576, !,
 | 
			
		||||
	NewSize is Size+1048576.
 | 
			
		||||
new_size(Size, NewSize) :-
 | 
			
		||||
	NewSize is Size*2.
 | 
			
		||||
 | 
			
		||||
copy_hash_table(0, _, _, _, _, _, _) :- !.
 | 
			
		||||
copy_hash_table(I1, Keys, Vals, F, Size, NewKeys, NewVals) :-
 | 
			
		||||
	I is I1-1,
 | 
			
		||||
	array_element(Keys, I, Key),
 | 
			
		||||
	nonvar(Key), !,
 | 
			
		||||
	array_element(Vals, I, Val),
 | 
			
		||||
	insert_el(Key, Val, Size, F, NewKeys, NewVals),
 | 
			
		||||
	copy_hash_table(I, Keys, Vals, F, Size, NewKeys, NewVals).
 | 
			
		||||
copy_hash_table(I1, Keys, Vals, F, Size, NewKeys, NewVals) :-
 | 
			
		||||
	I is I1-1,
 | 
			
		||||
	copy_hash_table(I, Keys, Vals, F, Size, NewKeys, NewVals).
 | 
			
		||||
 | 
			
		||||
insert_el(Key, Val, Size, F, NewKeys, NewVals) :-
 | 
			
		||||
	hash_f(Key,Size,Index, F),
 | 
			
		||||
	find_free(Index, Size, NewKeys, TrueIndex),
 | 
			
		||||
	array_element(NewKeys, TrueIndex, Key),
 | 
			
		||||
	array_element(NewVals, TrueIndex, Val).
 | 
			
		||||
 | 
			
		||||
find_free(Index, Size, Keys, NewIndex) :-
 | 
			
		||||
	array_element(Keys, Index, El),
 | 
			
		||||
	(
 | 
			
		||||
	    var(El)
 | 
			
		||||
	->
 | 
			
		||||
	    NewIndex = Index
 | 
			
		||||
	;
 | 
			
		||||
	    I1 is (Index+1) mod Size,
 | 
			
		||||
	    find_free(I1, Keys, NewIndex)
 | 
			
		||||
	).
 | 
			
		||||
 | 
			
		||||
hash_f(Key, Size, Index, F) :-
 | 
			
		||||
	var(F), !,
 | 
			
		||||
	term_hash(Key,-1,Size,Index).
 | 
			
		||||
hash_f(Key, Size, Index, F) :-
 | 
			
		||||
	call(F, Key, Size, Index).
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user