mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 01:13:30 +00:00
721 lines
25 KiB
Mathematica
721 lines
25 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ts=4 sw=4 et ft=mercury
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2020, 2022, 2024-2026 The Mercury team.
|
|
% This file is distributed under the terms specified in COPYING.LIB.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: one_or_more_map.m.
|
|
% Stability: high.
|
|
%
|
|
% This file provides another version of the multi_map(K, V) abstract data type.
|
|
% A map (also known as a dictionary or an associative array) is a collection
|
|
% of (Key, Value) pairs which allows you to look up any Value given the Key.
|
|
% A multi_map is similar, but it allows more than one Value for each Key.
|
|
% A multi_map represents this by using list(V) as the range type, which works,
|
|
% but does not express the invariant maintained by the relevant operations,
|
|
% which is that these lists are never empty. A one_or_more_map is a multi_map
|
|
% in which the range type is not list(V) but one_or_more(V), which *does*
|
|
% express this invariant. Multiple occurrences of the same Value can be
|
|
% associated with a given Key.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module one_or_more_map.
|
|
:- interface.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module one_or_more.
|
|
:- import_module set.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type one_or_more_map(K, V) == map(K, one_or_more(V)).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Return an empty one_or_more_map.
|
|
%
|
|
:- func init = one_or_more_map(K, V).
|
|
:- pred init(one_or_more_map(K, V)::uo) is det.
|
|
|
|
% Check whether the one_or_more_map is empty.
|
|
%
|
|
:- pred is_empty(one_or_more_map(K, V)::in) is semidet.
|
|
|
|
%---------------------%
|
|
|
|
% Check whether the one_or_more_map has an entry for the given key.
|
|
%
|
|
:- pred contains(one_or_more_map(K, V)::in, K::in) is semidet.
|
|
|
|
% Succeed once for each key-value pair in the one_or_more_map.
|
|
%
|
|
:- pred member(one_or_more_map(K, V)::in, K::out, V::out) is nondet.
|
|
|
|
% If the one_or_more_map has an entry for the given key, return the
|
|
% list of corresponding values.
|
|
%
|
|
:- pred search(one_or_more_map(K, V)::in, K::in, one_or_more(V)::out)
|
|
is semidet.
|
|
|
|
% If the one_or_more_map has an entry for the given key,
|
|
% succeed once for each of the corresponding values.
|
|
%
|
|
:- pred nondet_search(one_or_more_map(K, V)::in, K::in, V::out) is nondet.
|
|
|
|
% If the one_or_more_map has an entry for the given key,
|
|
% return the list of corresponding values.
|
|
% Otherwise, throw an exception.
|
|
%
|
|
:- func lookup(one_or_more_map(K, V), K) = one_or_more(V).
|
|
:- pred lookup(one_or_more_map(K, V)::in, K::in, one_or_more(V)::out) is det.
|
|
|
|
% Return all the values in the map for the given key.
|
|
% If the map does not contain the key, then return the empty list.
|
|
%
|
|
:- func get_values_for_key(one_or_more_map(K, V), K) = list(V).
|
|
|
|
% If the one_or_more_map has an entry for the given key,
|
|
% succeed once for each of the corresponding values.
|
|
% Otherwise, throw an exception.
|
|
%
|
|
:- pred nondet_lookup(one_or_more_map(K, V)::in, K::in, V::out) is nondet.
|
|
|
|
% If the one_or_more_map has an entry for keys with the given value,
|
|
% succeed once for each of those keys.
|
|
%
|
|
% NOTE: The implementation of this predicate is necessarily inefficient,
|
|
% and so this predicate is intended for non-performance-critical uses only.
|
|
%
|
|
:- pred inverse_search(one_or_more_map(K, V)::in, V::in, K::out) is nondet.
|
|
|
|
%---------------------%
|
|
|
|
% Add the given key-value pair to the one_or_more_map.
|
|
% Fail if the key already exists.
|
|
%
|
|
:- pred insert(K::in, V::in,
|
|
one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is semidet.
|
|
|
|
% Add the given key-value pair to the one_or_more_map.
|
|
% Throw an exception if the key already exists.
|
|
%
|
|
:- func det_insert(one_or_more_map(K, V), K, V) = one_or_more_map(K, V).
|
|
:- pred det_insert(K::in, V::in,
|
|
one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is det.
|
|
|
|
% Add the given key-value pair to the one_or_more_map.
|
|
% Fail if the key does not already exist.
|
|
%
|
|
:- pred update(K::in, V::in,
|
|
one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is semidet.
|
|
|
|
% Add the given key-value pair to the one_or_more_map.
|
|
% Throw an exception if the key does not already exist.
|
|
%
|
|
:- func det_update(one_or_more_map(K, V), K, V) = one_or_more_map(K, V).
|
|
:- pred det_update(K::in, V::in,
|
|
one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is det.
|
|
|
|
% Replace the list of values corresponding to the given key.
|
|
% Fails if the key does not already exist.
|
|
%
|
|
:- pred replace(K::in, one_or_more(V)::in,
|
|
one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is semidet.
|
|
|
|
% Replace the list of values corresponding to the given key.
|
|
% Throws an exception if the key does not already exist.
|
|
%
|
|
:- func det_replace(one_or_more_map(K, V), K,
|
|
one_or_more(V)) = one_or_more_map(K, V).
|
|
:- pred det_replace(K::in, one_or_more(V)::in,
|
|
one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is det.
|
|
|
|
% Add the given key-value pair to the one_or_more_map.
|
|
% (`set' is a synonym for `add'.)
|
|
%
|
|
:- func add(one_or_more_map(K, V), K, V) = one_or_more_map(K, V).
|
|
:- pred add(K::in, V::in,
|
|
one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is det.
|
|
:- func set(one_or_more_map(K, V), K, V) = one_or_more_map(K, V).
|
|
:- pred set(K::in, V::in,
|
|
one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is det.
|
|
|
|
% Add the given value-key pair to the one_or_more_map.
|
|
% (`reverse_set' is a synonym for `reverse_add'.)
|
|
%
|
|
:- func reverse_add(one_or_more_map(K, V), V, K) = one_or_more_map(K, V).
|
|
:- pred reverse_add(V::in, K::in,
|
|
one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is det.
|
|
:- func reverse_set(one_or_more_map(K, V), V, K) = one_or_more_map(K, V).
|
|
:- pred reverse_set(V::in, K::in,
|
|
one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Delete a key and its corresponding values from a one_or_more_map.
|
|
% If the key is not present, leave the one_or_more_map unchanged.
|
|
%
|
|
:- func delete(one_or_more_map(K, V), K) = one_or_more_map(K, V).
|
|
:- pred delete(K::in,
|
|
one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is det.
|
|
|
|
% Delete the given key-value pair from a one_or_more_map.
|
|
% If the key is not present, leave the one_or_more_map unchanged.
|
|
%
|
|
:- func delete(one_or_more_map(K, V), K, V) = one_or_more_map(K, V).
|
|
:- pred delete(K::in, V::in,
|
|
one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is det.
|
|
|
|
% Delete a key from a one_or_more_map and return the list of values
|
|
% previously corresponding to it.
|
|
% Fail if the key is not present.
|
|
%
|
|
:- pred remove(K::in, one_or_more(V)::out,
|
|
one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is semidet.
|
|
|
|
% Delete a key from a one_or_more_map and return the list of values
|
|
% previously corresponding to it.
|
|
% Throw an exception if the key is not present.
|
|
%
|
|
:- pred det_remove(K::in, one_or_more(V)::out,
|
|
one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is det.
|
|
|
|
% Remove the smallest key and its corresponding values from the
|
|
% one_or_more_map.
|
|
% Fails if the one_or_more_map is empty.
|
|
%
|
|
:- pred remove_smallest(K::out, one_or_more(V)::out,
|
|
one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is semidet.
|
|
|
|
%---------------------%
|
|
|
|
% Select takes a one_or_more_map and a set of keys and returns
|
|
% a one_or_more_map containing only the keys in the set,
|
|
% together with their corresponding values.
|
|
%
|
|
:- func select(one_or_more_map(K, V), set(K)) = one_or_more_map(K, V).
|
|
:- pred select(one_or_more_map(K, V)::in, set(K)::in,
|
|
one_or_more_map(K, V)::out) is det.
|
|
|
|
%---------------------%
|
|
|
|
% merge(MultiMapA, MultiMapB, MultiMap):
|
|
%
|
|
% Merge MultiMapA and MultiMapB so that
|
|
%
|
|
% - if a key occurs in both MultiMapA and MultiMapB, then the values
|
|
% corresponding to that key in MultiMap will be the concatenation
|
|
% of the values for that key from MultiMapA and MultiMapB; while
|
|
% - if a key occurs in only one of MultiMapA and MultiMapB, then
|
|
% the values corresponding to it in that map will be carried over
|
|
% to MultiMap.
|
|
%
|
|
:- func merge(one_or_more_map(K, V), one_or_more_map(K, V))
|
|
= one_or_more_map(K, V).
|
|
:- pred merge(one_or_more_map(K, V)::in, one_or_more_map(K, V)::in,
|
|
one_or_more_map(K, V)::out) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Declaratively, a no-operation.
|
|
% Operationally, a suggestion that the implementation optimize
|
|
% the representation of the one_or_more_map, in the expectation that the
|
|
% following operations will consist of searches and lookups
|
|
% but (almost) no updates.
|
|
%
|
|
:- func optimize(one_or_more_map(K, V)) = one_or_more_map(K, V).
|
|
:- pred optimize(one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Convert a one_or_more_map to an association list.
|
|
%
|
|
:- func to_flat_assoc_list(one_or_more_map(K, V)) = assoc_list(K, V).
|
|
:- pred to_flat_assoc_list(one_or_more_map(K, V)::in,
|
|
assoc_list(K, V)::out) is det.
|
|
|
|
% Convert an association list to a one_or_more_map.
|
|
%
|
|
:- func from_flat_assoc_list(assoc_list(K, V)) = one_or_more_map(K, V).
|
|
:- pred from_flat_assoc_list(assoc_list(K, V)::in,
|
|
one_or_more_map(K, V)::out) is det.
|
|
|
|
% Convert a one_or_more_map to an association list, with all the values
|
|
% for each key in one element of the association list.
|
|
%
|
|
:- func to_assoc_list(one_or_more_map(K, V)) = assoc_list(K, one_or_more(V)).
|
|
:- pred to_assoc_list(one_or_more_map(K, V)::in,
|
|
assoc_list(K, one_or_more(V))::out) is det.
|
|
|
|
% Convert an association list with all the values for each key
|
|
% in one element of the list to a one_or_more_map.
|
|
%
|
|
:- func from_assoc_list(assoc_list(K, one_or_more(V))) = one_or_more_map(K, V).
|
|
:- pred from_assoc_list(assoc_list(K, one_or_more(V))::in,
|
|
one_or_more_map(K, V)::out) is det.
|
|
|
|
% Convert a sorted association list to a one_or_more_map.
|
|
%
|
|
:- func from_sorted_assoc_list(assoc_list(K, one_or_more(V)))
|
|
= one_or_more_map(K, V).
|
|
:- pred from_sorted_assoc_list(assoc_list(K, one_or_more(V))::in,
|
|
one_or_more_map(K, V)::out) is det.
|
|
|
|
% Convert the corresponding elements of a list of keys and a
|
|
% list of values (which must be of the same length) to a one_or_more_map.
|
|
% A key may occur more than once in the list of keys.
|
|
% Throw an exception if the two lists are not the same length.
|
|
%
|
|
:- func from_corresponding_lists(list(K), list(V))
|
|
= one_or_more_map(K, V).
|
|
:- pred from_corresponding_lists(list(K)::in, list(V)::in,
|
|
one_or_more_map(K, V)::out) is det.
|
|
|
|
% Convert the corresponding elements of a list of keys and a
|
|
% *list of lists* of values to a one_or_more_map.
|
|
% A key may *not* occur more than once in the list of keys.
|
|
% Throw an exception if the two lists are not the same length,
|
|
% or if a key does occur more than once in the list of keys.
|
|
%
|
|
:- func from_corresponding_list_lists(list(K), list(one_or_more(V)))
|
|
= one_or_more_map(K, V).
|
|
:- pred from_corresponding_list_lists(list(K)::in, list(one_or_more(V))::in,
|
|
one_or_more_map(K, V)::out) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Given a list of keys, produce a list of their values in a
|
|
% specified one_or_more_map.
|
|
%
|
|
:- func apply_to_list(list(K), one_or_more_map(K, V)) = list(V).
|
|
:- pred apply_to_list(list(K)::in, one_or_more_map(K, V)::in, list(V)::out)
|
|
is det.
|
|
|
|
%---------------------%
|
|
|
|
% Given a one_or_more_map, return a list of all the keys in it.
|
|
%
|
|
:- func keys(one_or_more_map(K, V)) = list(K).
|
|
:- pred keys(one_or_more_map(K, V)::in, list(K)::out) is det.
|
|
|
|
% Given a one_or_more_map, return a list of all the keys in it
|
|
% in sorted order.
|
|
%
|
|
:- func sorted_keys(one_or_more_map(K, V)) = list(K).
|
|
:- pred sorted_keys(one_or_more_map(K, V)::in, list(K)::out) is det.
|
|
|
|
% Given a one_or_more_map, return a list of all the keys in it
|
|
% as a set.
|
|
%
|
|
:- func keys_as_set(one_or_more_map(K, V)) = set(K).
|
|
:- pred keys_as_set(one_or_more_map(K, V)::in, set(K)::out) is det.
|
|
|
|
% Given a one_or_more_map, return a list of all the values in it.
|
|
%
|
|
:- func values(one_or_more_map(K, V)) = list(V).
|
|
:- pred values(one_or_more_map(K, V)::in, list(V)::out) is det.
|
|
|
|
%---------------------%
|
|
|
|
% Count the number of keys in the one_or_more_map.
|
|
%
|
|
:- func count(one_or_more_map(K, V)) = int.
|
|
:- pred count(one_or_more_map(K, V)::in, int::out) is det.
|
|
:- func ucount(one_or_more_map(K, V)) = uint.
|
|
:- pred ucount(one_or_more_map(K, V)::in, uint::out) is det.
|
|
|
|
% Count the number of key-value pairs in the one_or_more_map.
|
|
%
|
|
:- func all_count(one_or_more_map(K, V)) = int.
|
|
:- pred all_count(one_or_more_map(K, V)::in, int::out) is det.
|
|
:- func all_ucount(one_or_more_map(K, V)) = uint.
|
|
:- pred all_ucount(one_or_more_map(K, V)::in, uint::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module cord.
|
|
:- import_module pair.
|
|
:- import_module require.
|
|
:- import_module uint.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
init = OneOrMoreMap :-
|
|
one_or_more_map.init(OneOrMoreMap).
|
|
|
|
init(OneOrMoreMap) :-
|
|
map.init(OneOrMoreMap).
|
|
|
|
is_empty(OneOrMoreMap) :-
|
|
map.is_empty(OneOrMoreMap).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
contains(OneOrMoreMap, Key) :-
|
|
map.search(OneOrMoreMap, Key, _).
|
|
|
|
member(OneOrMoreMap, Key, Value) :-
|
|
map.member(OneOrMoreMap, Key, Values),
|
|
one_or_more.member(Value, Values).
|
|
|
|
search(OneOrMoreMap, Key, Values) :-
|
|
map.search(OneOrMoreMap, Key, Values).
|
|
|
|
nondet_search(OneOrMoreMap, Key, Value) :-
|
|
map.search(OneOrMoreMap, Key, Values),
|
|
one_or_more.member(Value, Values).
|
|
|
|
lookup(OneOrMoreMap, Key) = Value :-
|
|
one_or_more_map.lookup(OneOrMoreMap, Key, Value).
|
|
|
|
lookup(OneOrMoreMap, Key, Values) :-
|
|
map.lookup(OneOrMoreMap, Key, Values).
|
|
|
|
get_values_for_key(OneOrMoreMap, Key) = Values :-
|
|
( if one_or_more_map.search(OneOrMoreMap, Key, OoMValues) then
|
|
OoMValues = one_or_more(HeadValue, TailValues),
|
|
Values = [HeadValue | TailValues]
|
|
else
|
|
Values = []
|
|
).
|
|
|
|
nondet_lookup(OneOrMoreMap, Key, Value) :-
|
|
map.search(OneOrMoreMap, Key, Values),
|
|
one_or_more.member(Value, Values).
|
|
|
|
inverse_search(OneOrMoreMap, Value, Key) :-
|
|
map.member(OneOrMoreMap, Key, Values),
|
|
one_or_more.member(Value, Values).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
insert(Key, Value, !OneOrMoreMap) :-
|
|
map.insert(Key, one_or_more(Value, []), !OneOrMoreMap).
|
|
|
|
det_insert(!.OneOrMoreMap, Key, Value) = !:OneOrMoreMap :-
|
|
one_or_more_map.det_insert(Key, Value, !OneOrMoreMap).
|
|
|
|
det_insert(Key, Value, !OneOrMoreMap) :-
|
|
map.det_insert(Key, one_or_more(Value, []), !OneOrMoreMap).
|
|
|
|
update(Key, Value, !OneOrMoreMap) :-
|
|
map.search(!.OneOrMoreMap, Key, Values0),
|
|
Values = one_or_more.cons(Value, Values0),
|
|
map.update(Key, Values, !OneOrMoreMap).
|
|
|
|
det_update(!.OneOrMoreMap, Key, Value) = !:OneOrMoreMap :-
|
|
one_or_more_map.det_update(Key, Value, !OneOrMoreMap).
|
|
|
|
det_update(Key, Value, !OneOrMoreMap) :-
|
|
( if one_or_more_map.update(Key, Value, !OneOrMoreMap) then
|
|
true
|
|
else
|
|
report_lookup_error("one_or_more_map.det_update: key not found", Key)
|
|
).
|
|
|
|
replace(Key, Value, !OneOrMoreMap) :-
|
|
map.update(Key, Value, !OneOrMoreMap).
|
|
|
|
det_replace(!.OneOrMoreMap, Key, Values) = !:OneOrMoreMap :-
|
|
one_or_more_map.det_replace(Key, Values, !OneOrMoreMap).
|
|
|
|
det_replace(Key, Values, !OneOrMoreMap) :-
|
|
map.det_update(Key, Values, !OneOrMoreMap).
|
|
|
|
add(!.OneOrMoreMap, Key, Value) = !:OneOrMoreMap :-
|
|
one_or_more_map.add(Key, Value, !OneOrMoreMap).
|
|
|
|
add(Key, Value, !OneOrMoreMap) :-
|
|
( if map.search(!.OneOrMoreMap, Key, Values0) then
|
|
Values = one_or_more.cons(Value, Values0),
|
|
map.det_update(Key, Values, !OneOrMoreMap)
|
|
else
|
|
map.det_insert(Key, one_or_more(Value, []), !OneOrMoreMap)
|
|
).
|
|
|
|
set(!.OneOrMoreMap, Key, Value) = !:OneOrMoreMap :-
|
|
one_or_more_map.add(Key, Value, !OneOrMoreMap).
|
|
|
|
set(Key, Value, !OneOrMoreMap) :-
|
|
one_or_more_map.add(Key, Value, !OneOrMoreMap).
|
|
|
|
reverse_add(!.OneOrMoreMap, Value, Key) = !:OneOrMoreMap :-
|
|
one_or_more_map.add(Key, Value, !OneOrMoreMap).
|
|
|
|
reverse_add(Value, Key, !OneOrMoreMap) :-
|
|
one_or_more_map.add(Key, Value, !OneOrMoreMap).
|
|
|
|
reverse_set(!.OneOrMoreMap, Value, Key) = !:OneOrMoreMap :-
|
|
one_or_more_map.add(Key, Value, !OneOrMoreMap).
|
|
|
|
reverse_set(Value, Key, !OneOrMoreMap) :-
|
|
one_or_more_map.add(Key, Value, !OneOrMoreMap).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
delete(!.OneOrMoreMap, Key) = !:OneOrMoreMap :-
|
|
one_or_more_map.delete(Key, !OneOrMoreMap).
|
|
|
|
delete(Key, !OneOrMoreMap) :-
|
|
map.delete(Key, !OneOrMoreMap).
|
|
|
|
delete(!.OneOrMoreMap, Key, Value) = !:OneOrMoreMap :-
|
|
one_or_more_map.delete(Key, Value, !OneOrMoreMap).
|
|
|
|
delete(Key, Value, !OneOrMoreMap) :-
|
|
( if
|
|
map.search(!.OneOrMoreMap, Key, Values0),
|
|
one_or_more.delete_all(Values0, Value, Values)
|
|
then
|
|
(
|
|
Values = [],
|
|
map.delete(Key, !OneOrMoreMap)
|
|
;
|
|
Values = [VH | VT],
|
|
map.det_update(Key, one_or_more(VH, VT), !OneOrMoreMap)
|
|
)
|
|
else
|
|
true
|
|
).
|
|
|
|
remove(OneOrMoreMap0, Key, Values, OneOrMoreMap) :-
|
|
map.remove(OneOrMoreMap0, Key, Values, OneOrMoreMap).
|
|
|
|
det_remove(OneOrMoreMap0, Key, Values, OneOrMoreMap) :-
|
|
map.det_remove(OneOrMoreMap0, Key, Values, OneOrMoreMap).
|
|
|
|
remove_smallest(OneOrMoreMap0, Key, Values, OneOrMoreMap) :-
|
|
map.remove_smallest(OneOrMoreMap0, Key, Values, OneOrMoreMap).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
select(OneOrMoreMap0, KeySet) = OneOrMoreMap :-
|
|
one_or_more_map.select(OneOrMoreMap0, KeySet, OneOrMoreMap).
|
|
|
|
select(OneOrMoreMap0, KeySet, OneOrMoreMap) :-
|
|
map.select(OneOrMoreMap0, KeySet, OneOrMoreMap).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
merge(OneOrMoreMapA, OneOrMoreMapB) = OneOrMoreMap :-
|
|
one_or_more_map.merge(OneOrMoreMapA, OneOrMoreMapB, OneOrMoreMap).
|
|
|
|
merge(M0, M1, M) :-
|
|
one_or_more_map.to_assoc_list(M0, ML0),
|
|
one_or_more_map.to_assoc_list(M1, ML1),
|
|
one_or_more_map.assoc_list_merge(ML0, ML1, ML),
|
|
one_or_more_map.from_sorted_assoc_list(ML, M).
|
|
|
|
:- pred one_or_more_map.assoc_list_merge(assoc_list(K, one_or_more(V))::in,
|
|
assoc_list(K, one_or_more(V))::in, assoc_list(K, one_or_more(V))::out)
|
|
is det.
|
|
|
|
assoc_list_merge(ListA, ListB, List) :-
|
|
(
|
|
ListA = [],
|
|
List = ListB
|
|
;
|
|
ListA = [HeadA | TailA],
|
|
(
|
|
ListB = [],
|
|
List = ListA
|
|
;
|
|
ListB = [HeadB | TailB],
|
|
HeadA = KeyA - ValuesA,
|
|
HeadB = KeyB - ValuesB,
|
|
compare(Res, KeyA, KeyB),
|
|
(
|
|
Res = (<),
|
|
Key = KeyA,
|
|
Values = ValuesA,
|
|
one_or_more_map.assoc_list_merge(TailA, ListB, Tail)
|
|
;
|
|
Res = (=),
|
|
Key = KeyA,
|
|
one_or_more.append(ValuesA, ValuesB, Values),
|
|
one_or_more_map.assoc_list_merge(TailA, TailB, Tail)
|
|
;
|
|
Res = (>),
|
|
Key = KeyB,
|
|
Values = ValuesB,
|
|
one_or_more_map.assoc_list_merge(ListA, TailB, Tail)
|
|
),
|
|
List = [Key - Values | Tail]
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
optimize(OneOrMoreMap0) = OneOrMoreMap :-
|
|
one_or_more_map.optimize(OneOrMoreMap0, OneOrMoreMap).
|
|
|
|
optimize(OneOrMoreMap0, OneOrMoreMap) :-
|
|
map.optimize(OneOrMoreMap0, OneOrMoreMap).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
to_flat_assoc_list(OneOrMoreMap) = AssocList :-
|
|
one_or_more_map.to_flat_assoc_list(OneOrMoreMap, AssocList).
|
|
|
|
to_flat_assoc_list(OneOrMoreMap, AssocList) :-
|
|
map.foldl(to_flat_assoc_list_acc, OneOrMoreMap, cord.init, Cord),
|
|
AssocList = cord.list(Cord).
|
|
|
|
:- pred to_flat_assoc_list_acc(K::in, one_or_more(V)::in,
|
|
cord(pair(K, V))::in, cord(pair(K, V))::out) is det.
|
|
|
|
to_flat_assoc_list_acc(Key, Values, !Cord) :-
|
|
KeyValues = list.map((func(Value) = Key - Value),
|
|
one_or_more_to_list(Values)),
|
|
!:Cord = !.Cord ++ cord.from_list(KeyValues).
|
|
|
|
%---------------------%
|
|
|
|
from_flat_assoc_list(AssocList) = OneOrMoreMap :-
|
|
one_or_more_map.from_flat_assoc_list(AssocList, OneOrMoreMap).
|
|
|
|
from_flat_assoc_list(AssocList, OneOrMoreMap) :-
|
|
list.foldl(one_or_more_map.add_from_pair, AssocList,
|
|
map.init, OneOrMoreMap).
|
|
|
|
:- pred one_or_more_map.add_from_pair(pair(K, V)::in,
|
|
one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is det.
|
|
|
|
add_from_pair(K - V, !OneOrMoreMap) :-
|
|
one_or_more_map.add(K, V, !OneOrMoreMap).
|
|
|
|
%---------------------%
|
|
|
|
to_assoc_list(OneOrMoreMap) = AssocList :-
|
|
one_or_more_map.to_assoc_list(OneOrMoreMap, AssocList).
|
|
|
|
to_assoc_list(OneOrMoreMap, AssocList) :-
|
|
map.to_assoc_list(OneOrMoreMap, AssocList).
|
|
|
|
from_assoc_list(AssocList) = OneOrMoreMap :-
|
|
one_or_more_map.from_assoc_list(AssocList, OneOrMoreMap).
|
|
|
|
from_assoc_list(AssocList, OneOrMoreMap) :-
|
|
map.from_assoc_list(AssocList, OneOrMoreMap).
|
|
|
|
from_sorted_assoc_list(AssocList) = OneOrMoreMap :-
|
|
one_or_more_map.from_sorted_assoc_list(AssocList, OneOrMoreMap).
|
|
|
|
from_sorted_assoc_list(AssocList, OneOrMoreMap) :-
|
|
map.from_sorted_assoc_list(AssocList, OneOrMoreMap).
|
|
|
|
%---------------------%
|
|
|
|
from_corresponding_lists(Keys, Values) = OneOrMoreMap :-
|
|
one_or_more_map.from_corresponding_lists(Keys, Values, OneOrMoreMap).
|
|
|
|
from_corresponding_lists(Keys, Values, OneOrMoreMap) :-
|
|
one_or_more_map.init(OneOrMoreMap0),
|
|
one_or_more_map.from_corresponding_lists_2(Keys, Values,
|
|
OneOrMoreMap0, OneOrMoreMap).
|
|
|
|
:- pred one_or_more_map.from_corresponding_lists_2(list(K)::in, list(V)::in,
|
|
one_or_more_map(K, V)::in, one_or_more_map(K, V)::out) is det.
|
|
|
|
from_corresponding_lists_2([], [], !OneOrMoreMap).
|
|
from_corresponding_lists_2([], [_ | _], !OneOrMoreMap) :-
|
|
unexpected("from_corresponding_lists", "list length mismatch").
|
|
from_corresponding_lists_2([_ | _], [], !OneOrMoreMap) :-
|
|
unexpected("from_corresponding_lists", "list length mismatch").
|
|
from_corresponding_lists_2([Key | Keys], [Value | Values], !OneOrMoreMap) :-
|
|
one_or_more_map.add(Key, Value, !OneOrMoreMap),
|
|
one_or_more_map.from_corresponding_lists_2(Keys, Values, !OneOrMoreMap).
|
|
|
|
%---------------------%
|
|
|
|
from_corresponding_list_lists(Keys, Values) = OneOrMoreMap :-
|
|
one_or_more_map.from_corresponding_list_lists(Keys, Values, OneOrMoreMap).
|
|
|
|
from_corresponding_list_lists(Keys, Values, OneOrMoreMap) :-
|
|
map.from_corresponding_lists(Keys, Values, OneOrMoreMap).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
apply_to_list(Keys, OneOrMoreMap) = Values :-
|
|
one_or_more_map.apply_to_list(Keys, OneOrMoreMap, Values).
|
|
|
|
apply_to_list([], _, []).
|
|
apply_to_list(Keys @ [_ | _], OneOrMoreMap, Values) :-
|
|
map.apply_to_list(Keys, OneOrMoreMap, ValueLists),
|
|
one_or_more.condense(ValueLists, Values).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
keys(OneOrMoreMap) = Keys :-
|
|
one_or_more_map.keys(OneOrMoreMap, Keys).
|
|
|
|
keys(OneOrMoreMap, Keys) :-
|
|
map.keys(OneOrMoreMap, Keys).
|
|
|
|
sorted_keys(Map) = Keys :-
|
|
map.sorted_keys(Map, Keys).
|
|
|
|
sorted_keys(Map, Keys) :-
|
|
map.sorted_keys(Map, Keys).
|
|
|
|
keys_as_set(Map) = KeySet :-
|
|
one_or_more_map.keys_as_set(Map, KeySet).
|
|
|
|
keys_as_set(Map, KeySet) :-
|
|
one_or_more_map.sorted_keys(Map, Keys),
|
|
set.sorted_list_to_set(Keys, KeySet).
|
|
|
|
values(OneOrMoreMap) = Values :-
|
|
one_or_more_map.values(OneOrMoreMap, Values).
|
|
|
|
values(OneOrMoreMap, Values) :-
|
|
map.values(OneOrMoreMap, ValueLists),
|
|
one_or_more.condense(ValueLists, Values).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
count(OneOrMoreMap) = Count :-
|
|
map.count(OneOrMoreMap, Count).
|
|
|
|
count(OneOrMoreMap, Count) :-
|
|
map.count(OneOrMoreMap, Count).
|
|
|
|
ucount(OneOrMoreMap) = Count :-
|
|
map.ucount(OneOrMoreMap, Count).
|
|
|
|
ucount(OneOrMoreMap, Count) :-
|
|
map.ucount(OneOrMoreMap, Count).
|
|
|
|
all_count(OneOrMoreMap) = ICount :-
|
|
one_or_more_map.all_ucount(OneOrMoreMap, Count),
|
|
ICount = uint.cast_to_int(Count).
|
|
|
|
all_count(OneOrMoreMap, ICount) :-
|
|
one_or_more_map.all_ucount(OneOrMoreMap, Count),
|
|
ICount = uint.cast_to_int(Count).
|
|
|
|
all_ucount(OneOrMoreMap) = Count :-
|
|
map.foldl_values(one_or_more_map.accumulate_length, OneOrMoreMap,
|
|
0u, Count).
|
|
|
|
all_ucount(OneOrMoreMap, Count) :-
|
|
map.foldl_values(one_or_more_map.accumulate_length, OneOrMoreMap,
|
|
0u, Count).
|
|
|
|
:- pred accumulate_length(one_or_more(V)::in, uint::in, uint::out) is det.
|
|
|
|
accumulate_length(Vs, !Count) :-
|
|
one_or_more.ulength(Vs, NumVs),
|
|
!:Count = !.Count + NumVs.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module one_or_more_map.
|
|
%---------------------------------------------------------------------------%
|