Files
mercury/library/array.m
Andrew Bromage cb84bd7b64 Fixed some stuff in array.m.
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.
1995-10-29 03:55:13 +00:00

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)
)
).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%