% This file has been included as an YAP library by Vitor Santos Costa, 1999

%   File   : ASSOC.PL
%   Author : R.A.O'Keefe
%   Updated: 9 November 1983
%   Purpose: Binary tree implementation of "association lists".

%   Note   : the keys should be ground, the associated values need not be.

:- module(assoc, [
	assoc_to_list/2,
	gen_assoc/3,
	get_assoc/3,
	get_assoc/5,
	list_to_assoc/2,
	map_assoc/3,
	ord_list_to_assoc/2,
	put_assoc/4,
	empty_assoc/1
    ]).

:- meta_predicate map_assoc(:, ?, ?).

/*
:- mode
	assoc_to_list(+, -),
	assoc_to_list(+, -, +),
	gen_assoc(+, ?, ?),
	get_assoc(+, +, ?),
	get_assoc(+, +, +, +, +, ?),
	list_to_assoc(+, -),
	list_to_assoc(+, +, -, +),
	map_assoc(+, +, -),
	put_assoc(+, +, +, -),
	put_assoc(+, +, +,+,+,+, +, -).
*/


empty_assoc(t).

assoc_to_list(Assoc, List) :-
	assoc_to_list(Assoc, List, []).


	assoc_to_list(t(Key,Val,L,R), List, Rest) :-
		assoc_to_list(L, List, [Key-Val|More]),
		assoc_to_list(R, More, Rest).
	assoc_to_list(t, List, List).



gen_assoc(t(_,_,L,_), Key, Val) :-
	gen_assoc(L, Key, Val).
gen_assoc(t(Key,Val,_,_), Key, Val).
gen_assoc(t(_,_,_,R), Key, Val) :-
	gen_assoc(R, Key, Val).



get_assoc(Key, t(K,V,L,R), Val) :-
	compare(Rel, Key, K),
	get_assoc(Rel, Key, V, L, R, Val).


	get_assoc(=, _, Val, _, _, Val).
	get_assoc(<, Key, _, Tree, _, Val) :-
		get_assoc(Key, Tree, Val).
	get_assoc(>, Key, _, _, Tree, Val) :-
		get_assoc(Key, Tree, Val).


get_assoc(Key, t(K,V,L,R), Val, t(K,NV,NL,NR), NVal) :-
	compare(Rel, Key, K),
	get_assoc(Rel, Key, V, L, R, Val, NV, NL, NR, NVal).


	get_assoc(=, _, Val, L, R, Val, NVal, L, R, NVal).
	get_assoc(<, Key, V, L, R, Val, V, NL, R, NVal) :-
		get_assoc(Key, L, Val, NL, NVal).
	get_assoc(>, Key, V, L, R, Val, V, L, NR, NVal) :-
		get_assoc(Key, R, Val, NR, NVal).



list_to_assoc(List, Assoc) :-
	list_to_assoc(List, t, Assoc).

	list_to_assoc([], Assoc, Assoc).
	list_to_assoc([Key-Val|List], Assoc0, Assoc) :-
	         put_assoc(Key, Assoc0, Val, AssocI),
		 list_to_assoc(List, AssocI, Assoc).

ord_list_to_assoc(Keys, Assoc) :-
	list_to_assoc(Keys, Assoc).
/*
	length(Keys,L),
	list_to_assoc(N, Keys, Assoc, []).


	ord_list_to_assoc(0, List, t, List).
	ord_list_to_assoc(N, List, t(Key,Val,L,R), Rest) :-
		A is (N-1)//2,
		Z is (N-1)-A,
		ord_list_to_assoc(A, List, L, [Key-Val|More]),
		ord_list_to_assoc(Z, More, R, Rest).
*/

map_assoc(Pred, t(Key,Val,L0,R0), t(Key,Ans,L1,R1)) :- !,
	map_assoc(Pred, L0, L1),
	assoc_apply(Pred, [Val,Ans]),
	map_assoc(Pred, R0, R1).
map_assoc(_, t, t).

assoc_apply(Pred,Args) :-
	G =.. [Pred,Args],
	call(G), !.

put_assoc(Key, t(K,V,L,R), Val, New) :-
	compare(Rel, Key, K),
	put_assoc(Rel, Key, K, V, L, R, Val, New).
put_assoc(Key, t, Val, t(Key,Val,t,t)).


	put_assoc(=, Key, _, _, L, R, Val, t(Key,Val,L,R)).
	put_assoc(<, Key, K, V, L, R, Val, t(K,V,Tree,R)) :-
		put_assoc(Key, L, Val, Tree).
	put_assoc(>, Key, K, V, L, R, Val, t(K,V,L,Tree)) :-
		put_assoc(Key, R, Val, Tree).

