mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-18 10:53:40 +00:00
Estimated hours taken: 0.5 NEWS: mention the changes to map and tree234. library/map.m: added map__foldl/4 and map__map_values/3 which forward to the corresponding predicates in tree234. library/tree234.m: implement tree234__foldl and tree234__map_values.
414 lines
13 KiB
Mathematica
414 lines
13 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1993-1997 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU Library General
|
|
% Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File: map.m.
|
|
% Main author: fjh, conway.
|
|
% Stability: high.
|
|
%
|
|
% This file provides the 'map' ADT.
|
|
% A map (also known as a dictionary or an associative array) is a collection
|
|
% of (Key,Data) pairs which allows you to look up any Data item given the
|
|
% Key.
|
|
%
|
|
% The implementation is using balanced binary trees, as provided by
|
|
% tree234.m. Virtually all the predicates in this file just
|
|
% forward the work to the corresponding predicate in tree234.m.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module map.
|
|
:- interface.
|
|
:- import_module set, list, assoc_list.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type map(_K, _V).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Initialize an empty map.
|
|
:- pred map__init(map(_,_)).
|
|
:- mode map__init(uo) is det.
|
|
|
|
% Check whether a map is empty.
|
|
:- pred map__is_empty(map(_,_)).
|
|
:- mode map__is_empty(in) is semidet.
|
|
|
|
% Check whether map contains key
|
|
:- pred map__contains(map(K,_V), K).
|
|
:- mode map__contains(in, in) is semidet.
|
|
|
|
:- pred map__member(map(K,V), K, V).
|
|
:- mode map__member(in, out, out) is nondet.
|
|
|
|
% Search map for key.
|
|
:- pred map__search(map(K,V), K, V).
|
|
:- mode map__search(in, in, in) is semidet. % implied
|
|
:- mode map__search(in, in, out) is semidet.
|
|
|
|
% Search map for key, but abort if search fails.
|
|
:- pred map__lookup(map(K,V), K, V).
|
|
:- mode map__lookup(in, in, in) is semidet. % implied
|
|
:- mode map__lookup(in, in, out) is det.
|
|
|
|
% Search map for data.
|
|
:- pred map__inverse_search(map(K,V), V, K).
|
|
:- mode map__inverse_search(in, in, out) is nondet.
|
|
|
|
% Insert a new key and corresponding value into a map.
|
|
% Fail if the key already exists.
|
|
:- pred map__insert(map(K,V), K, V, map(K,V)).
|
|
:- mode map__insert(in, in, in, out) is semidet.
|
|
|
|
% Insert a new key and corresponding value into a map.
|
|
% Abort if the key already exists.
|
|
:- pred map__det_insert(map(K,V), K, V, map(K,V)).
|
|
:- mode map__det_insert(in, in, in, out) is det.
|
|
|
|
% Apply map__det_insert to key - value pairs from corresponding lists.
|
|
:- pred map__det_insert_from_corresponding_lists(map(K,V), list(K),
|
|
list(V), map(K,V)).
|
|
:- mode map__det_insert_from_corresponding_lists(in, in, in, out) is det.
|
|
|
|
% Update the value corresponding to a given key
|
|
% Fail if the key doesn't already exist.
|
|
:- pred map__update(map(K,V), K, V, map(K,V)).
|
|
:- mode map__update(in, in, in, out) is semidet.
|
|
|
|
% Update the value corresponding to a given key
|
|
% Abort if the key doesn't already exist.
|
|
:- pred map__det_update(map(K,V), K, V, map(K,V)).
|
|
:- mode map__det_update(in, in, in, out) is det.
|
|
|
|
% Update value if the key is already present, otherwise
|
|
% insert new key and value.
|
|
:- pred map__set(map(K,V), K, V, map(K,V)).
|
|
:- mode map__set(di, di, di, uo) is det.
|
|
:- mode map__set(in, in, in, out) is det.
|
|
|
|
% Given a map, return a list of all the keys in the map
|
|
:- pred map__keys(map(K, _V), list(K)).
|
|
:- mode map__keys(in, out) is det.
|
|
|
|
% Given a map, return a list of all the data values in the map
|
|
:- pred map__values(map(_K, V), list(V)).
|
|
:- mode map__values(in, out) is det.
|
|
|
|
% convert a map to an association list
|
|
:- pred map__to_assoc_list(map(K,V), assoc_list(K,V)).
|
|
:- mode map__to_assoc_list(in, out) is det.
|
|
|
|
% convert an association list to a map
|
|
:- pred map__from_assoc_list(assoc_list(K,V), map(K,V)).
|
|
:- mode map__from_assoc_list(in, out) is det.
|
|
|
|
% convert a sorted association list to a map
|
|
:- pred map__from_sorted_assoc_list(assoc_list(K,V), map(K,V)).
|
|
:- mode map__from_sorted_assoc_list(in, out) is det.
|
|
|
|
% delete a key-value pair from a map
|
|
% if the key is not present, leave the map unchanged
|
|
:- pred map__delete(map(K,V), K, map(K,V)).
|
|
:- mode map__delete(di, in, uo) is det.
|
|
:- mode map__delete(in, in, out) is det.
|
|
|
|
% apply map__delete/3 to a list of keys
|
|
:- pred map__delete_list(map(K,V), list(K), map(K,V)).
|
|
:- mode map__delete_list(di, in, uo) is det.
|
|
:- mode map__delete_list(in, in, out) is det.
|
|
|
|
% delete a key-value pair from a map and return the value.
|
|
% fail if the key is not present
|
|
:- pred map__remove(map(K,V), K, V, map(K,V)).
|
|
:- mode map__remove(in, in, out, out) is semidet.
|
|
|
|
% delete a key-value pair from a map and return the value.
|
|
% abort if the key is not present
|
|
:- pred map__det_remove(map(K,V), K, V, map(K,V)).
|
|
:- mode map__det_remove(in, in, out, out) is det.
|
|
|
|
% Count the number of elements in the map.
|
|
:- pred map__count(map(K, V), int).
|
|
:- mode map__count(in, out) is det.
|
|
|
|
% Convert a pair of lists (which must be of the same length)
|
|
% to a map.
|
|
:- pred map__from_corresponding_lists(list(K), list(V), map(K, V)).
|
|
:- mode map__from_corresponding_lists(in, in, out) is det.
|
|
|
|
% For map__merge(MapA, MapB, Map), MapA and MapB must
|
|
% not both contain the same key.
|
|
:- pred map__merge(map(K, V), map(K, V), map(K, V)).
|
|
:- mode map__merge(in, in, out) is det.
|
|
|
|
% For map__overlay(MapA, MapB, Map), if MapA and MapB both
|
|
% contain the same key, then Map will map that key to
|
|
% the value from MapB. In otherwords, MapB takes precedence
|
|
% over MapA.
|
|
:- pred map__overlay(map(K,V), map(K,V), map(K,V)).
|
|
:- mode map__overlay(in, in, out) is det.
|
|
|
|
% map__select takes a map and a set of keys and returns
|
|
% a map containing the keys in the set and their corresponding
|
|
% values.
|
|
:- pred map__select(map(K,V), set(K), map(K,V)).
|
|
:- mode map__select(in, in, out) is det.
|
|
|
|
% Given a list of keys, produce a list of their corresponding
|
|
% values in a specified map.
|
|
:- pred map__apply_to_list(list(K), map(K, V), list(V)).
|
|
:- mode map__apply_to_list(in, in, out) is det.
|
|
|
|
% Declaratively, a NOP.
|
|
% Operationally, a suggestion that the implemention
|
|
% optimize the representation of the map in the expectation
|
|
% of a number of lookups but few or no modifications.
|
|
:- pred map__optimize(map(K, V), map(K, V)).
|
|
:- mode map__optimize(in, out) is det.
|
|
|
|
% Remove the smallest item from the map, fail if
|
|
% the map is empty.
|
|
:- pred map__remove_smallest(map(K, V), K, V, map(K, V)).
|
|
:- mode map__remove_smallest(in, out, out, out) is semidet.
|
|
|
|
% Perform an inorder tranversal of the map, applying
|
|
% an accumulator predicate for each key-value pair.
|
|
:- pred map__foldl(pred(K, V, T, T), map(K, V), T, T).
|
|
:- mode map__foldl(pred(in, in, in, out) is det, in, in, out) is det.
|
|
:- mode map__foldl(pred(in, in, in, out) is semidet, in, in, out) is semidet.
|
|
:- mode map__foldl(pred(in, in, di, uo) is det, in, di, uo) is det.
|
|
|
|
% Apply a transformation predicate to all the values
|
|
% in a map.
|
|
:- pred map__map_values(pred(K, V, W), map(K, V), map(K, W)).
|
|
:- mode map__map_values(pred(in, in, out) is det, in, out) is det.
|
|
:- mode map__map_values(pred(in, in, out) is semidet, in, out) is semidet.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- import_module tree234.
|
|
|
|
:- type map(K,V) == tree234(K,V).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
:- import_module std_util, require, string.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
map__init(M) :-
|
|
tree234__init(M).
|
|
|
|
map__is_empty(M) :-
|
|
tree234__init(M).
|
|
|
|
map__contains(Map, K) :-
|
|
map__search(Map, K, _).
|
|
|
|
map__member(Map, K, V) :-
|
|
tree234__member(Map, K, V).
|
|
|
|
:- map__search(_Map, K, _V) when K. % required by bimap.m
|
|
|
|
map__search(Map, K, V) :-
|
|
tree234__search(Map, K, V).
|
|
|
|
:- map__lookup(_Map, K, _V) when K. % required by bimap.m
|
|
|
|
map__lookup(Map, K, V) :-
|
|
( tree234__search(Map, K, V1) ->
|
|
V = V1
|
|
;
|
|
KeyType = type_name(type_of(K)),
|
|
ValueType = type_name(type_of(V)),
|
|
string__append_list(
|
|
["map__lookup: key not found\n",
|
|
"\tKey Type: ",
|
|
KeyType,
|
|
"\n\tValue Type: ",
|
|
ValueType
|
|
],
|
|
ErrorString),
|
|
error(ErrorString)
|
|
).
|
|
|
|
map__insert(Map0, K, V, Map) :-
|
|
tree234__insert(Map0, K, V, Map).
|
|
|
|
map__det_insert(Map0, K, V, Map) :-
|
|
( tree234__insert(Map0, K, V, Map1) ->
|
|
Map = Map1
|
|
;
|
|
error("map__det_insert: key already present")
|
|
).
|
|
|
|
map__det_insert_from_corresponding_lists(Map0, Ks, Vs, Map) :-
|
|
( Ks = [Key | Keys], Vs = [Value | Values] ->
|
|
map__det_insert(Map0, Key, Value, Map1),
|
|
map__det_insert_from_corresponding_lists(Map1, Keys,
|
|
Values, Map)
|
|
;
|
|
Ks = [], Vs = []
|
|
->
|
|
Map = Map0
|
|
;
|
|
error("map__det_insert_from_corresponding_lists - lists do not correspond")
|
|
).
|
|
|
|
map__update(Map0, K, V, Map) :-
|
|
tree234__update(Map0, K, V, Map).
|
|
|
|
map__det_update(Map0, K, V, Map) :-
|
|
( tree234__update(Map0, K, V, Map1) ->
|
|
Map = Map1
|
|
;
|
|
error("map__det_update: key not found")
|
|
).
|
|
|
|
map__set(Map0, K, V, Map) :-
|
|
tree234__set(Map0, K, V, Map).
|
|
|
|
map__keys(Map, KeyList) :-
|
|
tree234__keys(Map, KeyList).
|
|
|
|
map__values(Map, KeyList) :-
|
|
tree234__values(Map, KeyList).
|
|
|
|
map__to_assoc_list(M, L) :-
|
|
tree234__tree234_to_assoc_list(M, L).
|
|
|
|
map__from_assoc_list(L, M) :-
|
|
tree234__assoc_list_to_tree234(L, M).
|
|
|
|
map__from_sorted_assoc_list(L, M) :-
|
|
tree234__assoc_list_to_tree234(L, M).
|
|
|
|
map__delete(Map0, Key, Map) :-
|
|
tree234__delete(Map0, Key, Map).
|
|
|
|
map__delete_list(Map, [], Map).
|
|
map__delete_list(Map0, [Key | Keys], Map) :-
|
|
map__delete(Map0, Key, Map1),
|
|
map__delete_list(Map1, Keys, Map).
|
|
|
|
map__remove(Map0, Key, Value, Map) :-
|
|
tree234__remove(Map0, Key, Value, Map).
|
|
|
|
map__det_remove(Map0, Key, Value, Map) :-
|
|
( tree234__remove(Map0, Key, Value1, Map1) ->
|
|
Value = Value1,
|
|
Map = Map1
|
|
;
|
|
error("map__det_remove: key not found")
|
|
).
|
|
|
|
map__count(Map, Count) :-
|
|
tree234__count(Map, Count).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% XXX inefficient
|
|
|
|
map__inverse_search(Map, V, K) :-
|
|
tree234__tree234_to_assoc_list(Map, AssocList),
|
|
assoc_list_member(K, V, AssocList).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% The code here is deliberately written using very simple
|
|
% modes.
|
|
% The reason we don't just use member/2 is that we want to
|
|
% bootstrap this thing ASAP.
|
|
|
|
:- pred assoc_list_member(K, V, list(pair(K,V))).
|
|
:- mode assoc_list_member(in, out, in) is nondet.
|
|
:- mode assoc_list_member(out, in, in) is nondet.
|
|
:- mode assoc_list_member(in, in, in) is semidet.
|
|
assoc_list_member(K, V, [K - V | _]).
|
|
assoc_list_member(K, V, [_ | Xs]) :-
|
|
assoc_list_member(K, V, Xs).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
map__from_corresponding_lists(Keys, Values, Map) :-
|
|
assoc_list__from_corresponding_lists(Keys, Values, AssocList),
|
|
tree234__assoc_list_to_tree234(AssocList, Map).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
map__merge(M0, M1, M) :-
|
|
map__to_assoc_list(M0, ML0),
|
|
map__to_assoc_list(M1, ML1),
|
|
list__merge(ML0, ML1, ML),
|
|
map__from_sorted_assoc_list(ML, M).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
map__optimize(Map, Map).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
map__overlay(Map0, Map1, Map) :-
|
|
map__to_assoc_list(Map1, AssocList),
|
|
map__overlay_2(AssocList, Map0, Map).
|
|
|
|
:- pred map__overlay_2(assoc_list(K,V), map(K,V), map(K,V)).
|
|
:- mode map__overlay_2(in, in, out) is det.
|
|
|
|
map__overlay_2([], Map, Map).
|
|
map__overlay_2([K - V | AssocList], Map0, Map) :-
|
|
map__set(Map0, K, V, Map1),
|
|
map__overlay_2(AssocList, Map1, Map).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
map__select(Original, KeySet, NewMap) :-
|
|
set__to_sorted_list(KeySet, KeyList),
|
|
map__init(NewMap0),
|
|
map__select_2(KeyList, Original, NewMap0, NewMap).
|
|
|
|
:- pred map__select_2(list(K), map(K,V), map(K,V), map(K,V)).
|
|
:- mode map__select_2(in, in, in, out) is det.
|
|
|
|
map__select_2([], _Original, New, New).
|
|
map__select_2([K|Ks], Original, New0, New) :-
|
|
(
|
|
map__search(Original, K, V)
|
|
->
|
|
map__set(New0, K, V, New1)
|
|
;
|
|
New1 = New0
|
|
),
|
|
map__select_2(Ks, Original, New1, New).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
map__apply_to_list([], _, []).
|
|
map__apply_to_list([K | Ks], Map, [V | Vs]) :-
|
|
map__lookup(Map, K, V),
|
|
map__apply_to_list(Ks, Map, Vs).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
map__remove_smallest(Map0, K, V, Map) :-
|
|
tree234__remove_smallest(Map0, K, V, Map).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
map__foldl(Pred, Map, Acc0, Acc) :-
|
|
tree234__foldl(Pred, Map, Acc0, Acc).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
map__map_values(Pred, Map0, Map) :-
|
|
tree234__map_values(Pred, Map0, Map).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|