Files
mercury/library/one_or_more_map.m
Zoltan Somogyi 8ff61f8a4b Delete quotes from `VarNames' in stdlib comments.
In the Mercury standard library, every exported predicate or function
has (or at least *should* have) a comment that documents it, including
the meanings of its arguments. About 35-40% of these modules put `'s
(left and right quotes) around the names of the variable representing
those arguments. Some tried to do it consistently (though there were spots
with unquoted or half quoted names), while some did it only a few places.
This is inconsistent: we should either do it everywhere, or nowhere.
This diff makes it nowhere, because

- this is what the majority of the standard library modules do;
- this is what virtually all of the modules in the compiler, profiler,
  deep_profiler etc directories do;
- typing all those quotes when adding new predicates in modules that
  follow this convention is a pain in the ass; and because
- on many modern terminals, `' looks non-symmetrical and weird.

Likewise, the comment explaining a predicate often started with

    % `predname(arguments)' returns ...

This diff deletes these quotes as well, since they add nothing useful.

This diff does leave in place quotes around code fragments, both terms
and goals, where this helps delineate the boundaries of that fragment.
2022-03-07 11:49:00 +11:00

677 lines
24 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ts=4 sw=4 et ft=mercury
%---------------------------------------------------------------------------%
% Copyright (C) 2020 The Mercury team.
% This file is distributed under the terms specified in COPYING.LIB.
%---------------------------------------------------------------------------%
%
% File: one_or_more_map.m.
%
% This file provides a version of the 'multi_map' ADT.
% 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 key the range type is one_or_more(V), which *does* express
% this invariant.
%
%---------------------------------------------------------------------------%
:- module one_or_more_map.
:- interface.
:- import_module assoc_list.
:- import_module list.
:- import_module one_or_more.
:- import_module map.
:- 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,
% succeed once for each of the 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.
% 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.
% (`add' is a synonym for `set'.)
%
:- 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.
:- 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.
% Add the given value-key pair to the one_or_more_map.
%
:- 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 to 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.
% 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.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module cord.
:- import_module int.
:- import_module pair.
:- import_module require.
%---------------------------------------------------------------------------%
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).
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).
set(!.OneOrMoreMap, Key, Value) = !:OneOrMoreMap :-
one_or_more_map.set(Key, Value, !OneOrMoreMap).
set(Key, Value, !OneOrMoreMap) :-
( if map.search(!.OneOrMoreMap, Key, Values0) then
Values = one_or_more.cons(Value, Values0),
map.set(Key, Values, !OneOrMoreMap)
else
map.det_insert(Key, one_or_more(Value, []), !OneOrMoreMap)
).
add(!.OneOrMoreMap, Key, Value) = !:OneOrMoreMap :-
one_or_more_map.set(Key, Value, !OneOrMoreMap).
add(Key, Value, !OneOrMoreMap) :-
one_or_more_map.set(Key, Value, !OneOrMoreMap).
reverse_set(!.OneOrMoreMap, Value, Key) = !:OneOrMoreMap :-
one_or_more_map.reverse_set(Value, Key, !OneOrMoreMap).
reverse_set(Value, Key, !OneOrMoreMap) :-
one_or_more_map.set(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(OneOrMoreMap0) = Count :-
one_or_more_map.count(OneOrMoreMap0, Count).
count(OneOrMoreMap, Count) :-
map.count(OneOrMoreMap, Count).
all_count(OneOrMoreMap0) = Count :-
one_or_more_map.all_count(OneOrMoreMap0, Count).
all_count(OneOrMoreMap, Count) :-
map.foldl_values(one_or_more_map.accumulate_length, OneOrMoreMap,
0, Count).
:- pred accumulate_length(one_or_more(V)::in, int::in, int::out) is det.
accumulate_length(Vs, !Count) :-
one_or_more.length(Vs, NumVs),
!:Count = !.Count + NumVs.
%---------------------------------------------------------------------------%
:- end_module one_or_more_map.
%---------------------------------------------------------------------------%