mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-21 12:23:44 +00:00
Estimated hours taken: Not much at all. :-) Fixed some stuff in array.m. library/array.m: Moved array__fetch_items into the interface. Some general cleanups of the documentation.
241 lines
8.4 KiB
Mathematica
241 lines
8.4 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1995 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: array.m
|
|
% Main author: bromage.
|
|
% Based on the original version using 2-3 trees by conway.
|
|
% Stability: low
|
|
|
|
% This file contains a set of predicates for generating an manipulating
|
|
% an array data structure. The current implementation does not actually
|
|
% use an array - instead we use a map with integer keys, which is implemented
|
|
% using a tree data structure.
|
|
%
|
|
% The current interface will eventually be replaced by a version using
|
|
% unique modes, and the implementation will be replaced by one which
|
|
% uses real arrays.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module array.
|
|
:- interface.
|
|
:- import_module int, list.
|
|
|
|
:- type array(T).
|
|
|
|
% array__init creates an array with bounds from Low to High, with each
|
|
% element initialized to Init.
|
|
:- pred array__init(int, int, T, array(T)).
|
|
:- mode array__init(in, in, in, out) is det. % want an array_skeleton?
|
|
|
|
% array__bounds returns the upper and lower bounds of an array.
|
|
:- pred array__bounds(array(_T), int, int).
|
|
:- mode array__bounds(in, out, out) is det.
|
|
|
|
% array__lookup returns the Nth element of an array.
|
|
% It is an error if the index is out of bounds.
|
|
:- pred array__lookup(array(T), int, T).
|
|
:- mode array__lookup(in, in, out) is det.
|
|
|
|
% array__semidet_lookup is like array__lookup except that
|
|
% it fails if the index is out of bounds.
|
|
:- pred array__semidet_lookup(array(T), int, T).
|
|
:- mode array__semidet_lookup(in, in, out) is semidet.
|
|
|
|
% array__set sets the nth element of an array, and returns the
|
|
% resulting array (good opportunity for destructive update ;-).
|
|
% It is an error if the index is out of bounds.
|
|
:- pred array__set(array(T), int, T, array(T)).
|
|
:- mode array__set(in, in, in, out) is det.
|
|
|
|
% array__resize takes an array and new lower and upper bounds.
|
|
% the array is expanded or shrunk at each end to make it fit
|
|
% the new bounds.
|
|
:- pred array__resize(array(T), int, int, array(T)).
|
|
:- mode array__resize(in, in, in, out) is det.
|
|
|
|
% array__from_list takes a list (of nonzero length),
|
|
% and returns an array containing those elements in
|
|
% the same order that they occured in the list.
|
|
:- pred array__from_list(list(T), array(T)).
|
|
:- mode array__from_list(in, out) is det.
|
|
|
|
% array__to_list takes an array and returns a list containing
|
|
% the elements of the array in the same order that they
|
|
% occurred in the array.
|
|
:- pred array__to_list(array(T), list(T)).
|
|
:- mode array__to_list(in, out) is det.
|
|
|
|
% array__fetch_items takes an array and a lower and upper
|
|
% index, and places those items in the array between these
|
|
% indices into a list. It is an error if either index is
|
|
% out of bounds.
|
|
:- pred array__fetch_items(array(T), int, int, list(T)).
|
|
:- mode array__fetch_items(in, in, in, out) is det.
|
|
|
|
% array__bsearch takes an array, an element to be found
|
|
% and a comparison predicate and returns the position of
|
|
% the element in the array. Assumes the array is in sorted
|
|
% order. Fails if the element is not present. If the
|
|
% element to be found appears multiple times, the index of
|
|
% the first occurrence is returned.
|
|
% call/N currently does not allow output arguments to come
|
|
% before input arguments, so you can't just pass compare/3
|
|
% in here. :-(
|
|
:- pred array__bsearch(array(T), T, pred(T, T, comparison_result), int).
|
|
:- mode array__bsearch(in, in, pred(in, in, out) is det, out) is semidet.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module require, map.
|
|
|
|
:- type array(T) ---> array(int, int, map(int,T)).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
array__init(Low, High, Item, array(Low, High, MapOut)) :-
|
|
map__init(MapIn),
|
|
array__init_2(Low, High, Item, MapIn, MapOut).
|
|
|
|
:- pred array__init_2(int, int, T, map(int,T), map(int,T)).
|
|
:- mode array__init_2(in, in, in, in, out) is det.
|
|
|
|
array__init_2(Low, High, Item, ArrayIn, ArrayOut) :-
|
|
( Low > High ->
|
|
ArrayIn = ArrayOut
|
|
;
|
|
map__det_insert(ArrayIn, Low, Item, Array1),
|
|
Low1 is Low + 1,
|
|
array__init_2(Low1, High, Item, Array1, ArrayOut)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
array__bounds(array(Low, High, _), Low, High).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
array__lookup(array(Low, High, Map), Index, Item) :-
|
|
( ( Low =< Index, Index =< High ) ->
|
|
map__lookup(Map, Index, Item)
|
|
;
|
|
error("array__lookup: Array subscript out of bounds")
|
|
).
|
|
|
|
array__semidet_lookup(array(Low, High, Map), Index, Item) :-
|
|
Low =< Index, Index =< High,
|
|
map__lookup(Map, Index, Item).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
array__set(array(Low, High, MapIn), Index, Item, array(Low, High, MapOut)) :-
|
|
( ( Low =< Index, Index =< High ) ->
|
|
map__set(MapIn, Index, Item, MapOut)
|
|
;
|
|
error("array__set: Array subscript out of bounds")
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
array__resize(Array0, L, H, Array) :-
|
|
array__bounds(Array0, L0, H0),
|
|
array__lookup(Array0, L0, Item),
|
|
int__max(L, L0, L1),
|
|
int__min(H, H0, H1),
|
|
array__fetch_items(Array0, L1, H1, Items),
|
|
array__init(L, H, Item, Array1),
|
|
array__insert_items(Array1, L1, Items, Array).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
array__from_list([], array(1, 0, Map)) :-
|
|
map__init(Map).
|
|
array__from_list(List, Array) :-
|
|
List = [ Head | Tail ],
|
|
list__length(List, Len),
|
|
array__init(1, Len, Head, Array0),
|
|
array__insert_items(Array0, 2, Tail, Array).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred array__insert_items(array(T), int, list(T), array(T)).
|
|
:- mode array__insert_items(in, in, in, out) is det.
|
|
|
|
array__insert_items(Array, _N, [], Array).
|
|
array__insert_items(Array0, N, [Head|Tail], Array) :-
|
|
array__set(Array0, N, Head, Array1),
|
|
N1 is N + 1,
|
|
array__insert_items(Array1, N1, Tail, Array).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
array__to_list(Array, List) :-
|
|
array__bounds(Array, Low, High),
|
|
array__fetch_items(Array, Low, High, List).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
array__fetch_items(Array, Low, High, List) :-
|
|
(
|
|
Low > High
|
|
->
|
|
List = []
|
|
;
|
|
Low1 is Low + 1,
|
|
array__fetch_items(Array, Low1, High, List0),
|
|
array__lookup(Array, Low, Item),
|
|
List = [Item|List0]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
array__bsearch(A, El, Compare, I) :-
|
|
array__bounds(A, Lo, Hi),
|
|
Lo =< Hi,
|
|
array__bsearch_2(A, Lo, Hi, El, Compare, I).
|
|
|
|
:- pred array__bsearch_2(array(T), int, int, T,
|
|
pred(T, T, comparison_result), int).
|
|
:- mode array__bsearch_2(in, in, in, in, pred(in, in, out) is det,
|
|
out) is semidet.
|
|
array__bsearch_2(A, Lo, Hi, El, Compare, I) :-
|
|
Width is Hi - Lo,
|
|
|
|
% If Width < 0, there is no range left.
|
|
Width >= 0,
|
|
|
|
% If Width == 0, we may just have found our element.
|
|
% Do a Compare to check.
|
|
( Width = 0 ->
|
|
array__lookup(A, Lo, X),
|
|
call(Compare, El, X, (=)),
|
|
I = Lo
|
|
;
|
|
% Otherwise find the middle element of the range
|
|
% and check against that. NOTE: I used ">> 1"
|
|
% rather than "// 2" because division always
|
|
% rounds towards zero whereas shift right always
|
|
% rounds down. (Indices can be negative.)
|
|
Mid is (Lo + Hi) >> 1,
|
|
array__lookup(A, Mid, XMid),
|
|
call(Compare, XMid, El, Comp),
|
|
( Comp = (<),
|
|
Mid1 is Mid + 1,
|
|
array__bsearch_2(A, Mid1, Hi, El, Compare, I)
|
|
; Comp = (=),
|
|
array__bsearch_2(A, Lo, Mid, El, Compare, I)
|
|
; Comp = (>),
|
|
Mid1 is Mid - 1,
|
|
array__bsearch_2(A, Lo, Mid1, El, Compare, I)
|
|
)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|