Sather Home Page

Section 8.5.1.2.1:
ARRAY

class ARRAY{T} < $ARR{T} is -- This class implements one-dimensional arrays of elements of type T. -- The operations provided include sorting, searching, etc. Array indices -- start at 0 and go up to `asize-1'. -- -- Most features here work when self is void. The intent is that -- a void array behaves just like a zero-sized array. Thus self may be void -- on operations which don't try to directly access specific elements since -- any such access would be out of range. -- Version 1.2 Oct 98. Copyright K Hopper, U of Waikato -- Development History -- ------------------- -- Date Who By Detail -- ---- ------ ------ -- 11 Jul 96 bg Original for Sather 1.1 -- 13 Jan 97 kh Changed to CARD from INT -- 4 Nov 98 kh Now as 1.2 dist, added pre/post conditions. include CONTAINER{T} ; private include AREF{T} aget -> aget, aset -> aset, asize -> asize, array_ptr -> array_ptr ; -- Note that self may not be void for these public included routines. create : SAME is -- This routine creates an empty array. return SAME::create(0) end ; create( sz : CARD ) : SAME is -- This routine xreates a new array of size sz, all of whose elements -- are void. return new(sz) end ; create( arr : ARRAY{T} ) : SAME is -- This routine creates a new array which has exactly the same contents -- as arr. me : SAME := create(arr.size) ; loop me.set!(arr.elt!) end ; return me end ; create_from( elems : $ELT{T} ) : SAME is -- This routine creates an array out of the elements of "elems". It is -- expensive - first converts the argument into an FLIST to determine the -- number of elements and then converts the FLIST into an array. flist : FLIST{T} := FLIST{T}::create ; loop flist := flist.push(elems.elt!) end ; me : SAME := SAME::create(flist.size) ; loop me.set!(flist.elt!) end ; return me end ; size : CARD is -- This routine returns the number of elements in the array. Self may -- be void. Built-in to this implementation. builtin ARRAY_SIZE end ; clear is -- This routine sets each array element to void. Built-in to this -- implementation. Self may be void. builtin ARRAY_CLEAR end ; equals( arr : $CONTAINER{T} ) : BOOL is -- This predicate returns true if and only if all elements of self are -- the same as the corresponding elements of arr. typecase arr when SAME then loop if ~elt_eq(elt!,arr.elt!) then return false end end ; return true else return false end end ; has_ind( val : CARD ) : BOOL is -- This predicate returns true if and only if val is a valid index for -- the array. return val < size end ; inds : ARRAY{CARD} pre ~void(self) post (result.size = size) is -- This routine returns an index array which is the same size as self -- and is set to the values of the indices. sz : CARD := size ; res : ARRAY{CARD} := ARRAY{CARD}::create(sz) ; index : CARD := 0 ; loop until!(index >= sz) ; res[index] := ind! ; index := index + 1 end ; return res end ; resize( new_size : CARD ) : SAME pre ~void(self) post (result.size = new_size) is -- This routine allocates a new array and copies whatever will fit of -- self. It then returns the new array. res : SAME := SAME::create(new_size) ; loop res.set!(elt!) end ; return res end ; copy : SAME pre true post (result.size = self.size) -- (result = self) is -- This routine returns a copy of self. if void(self) then return void end ; res : SAME := create(size) ; res.copy(self) ; return res end ; copy( src : SAME ) pre ~void(self) and ~void(src) post true -- (self.size >= src.size) -- and {forall ind member dom.src -- | self(ind) = src(ind)} -- and {forall ind member dom.self -- and ~member dom.src -- | self(ind) = -- initial(self(ind)) -- or (self.size < src.size) -- and {forall ind member dom.self -- | self(ind) = src(ind)} is -- This routine copies as many elements from src to self as will fit. -- Built-in to this implementation. builtin ARRAY_COPY end ; copy( beg : CARD, src : SAME ) pre ~void(self) and ((beg <= (size - 1)) or (src.size = 0)) post true -- + vdm stuff!?! is -- This routine copies as many elements from src to self as will fit -- when starting at index beg of self. Self may not be void but src may -- be void. Built-in to this implementation. builtin ARRAY_COPY_BEG end ; copy( beg, num : CARD, src : SAME ) pre ~void(self) and ~void(src) and (beg <= (size - 1)) and (num <= (size - beg)) and (num <= src.size) post (self.size = initial(self.size)) is -- This routine copies num elements from src to self starting at index -- beg of self. Neither self nor src may be void. Built-in to this -- implementation. builtin ARRAY_COPY_BEG_NUM end ; copy( beg, num, srcbeg : CARD, src : SAME ) pre ~void(self) and ~void(src) and (beg <= (size - 1)) and (num <= (size - beg)) and (num <= (src.size - srcbeg)) post (self.size = initial(self.size)) is -- This routine copies num elements from src to self starting at index -- beg of self and index srcbeg of src. Neither self nor src may be void. -- Built-in to this implementation. builtin ARRAY_COPY_BEG_NUM_SRCBEG end ; subarr( beg, num : CARD ) : SAME pre ~void(self) and (beg <= (size - 1)) and (num = (size - beg)) post (result.size = num) is -- This routine returns a new array which is a sub-sequence of self, -- with num entries copied from self starting at beg. Self may not be void. res : SAME := new(num) ; res.copy(0,num,beg,self) ; return res end ; to_reverse pre ~void(self) post true -- and is reversed, of course! is -- This routine reverses the order of the elements in self. Self may -- not be void. loop index : CARD := (size/2).times! ; up_index : CARD := size - index - 1 ; temp : T := [index ] ; [index] := [up_index] ; [up_index] := temp end end ; reverse : SAME pre true post void(result) or true -- (result.to_reverse = self) is -- This routine returns a copy of self with all elements in reverse -- order. Self may be void. if void(self) then return void else res: SAME := new(size) ; loop res.set!(asize - 1,asize, -1,elt!) end ; return res end end ; to( src : SAME ) pre (src.size = size) post true -- (src = self) is -- This routine sets self to be a copy of src. Both may be void! loop set!(src.elt!) end end ; to_val( val : T ) pre true post void(self) or (count(val) = size) is -- This routine sets each element of self to val. Self may be void. loop set!(val) end end ; append( arr : SAME ) : SAME pre true post true -- + vdm stuff !?! is -- This routine returns a new array consisting of self followed by -- arr. Both may be void. if void(self) then return arr.copy elsif void(arr) then return copy else res : SAME := new(size + arr.size) ; res.copy(self) ; res.copy(size,arr) ; return res end end ; append( arr1, arr2 : SAME ) : SAME pre true post true -- + vdm stuff !?! is -- This routine returns a new array consisting of self followed by -- arr1 and then arr2. This is more efficient than two appends. Any of -- the arrays may be void. if void(self) then return arr1.append(arr2) elsif void(arr1) then return append(arr2) elsif void(arr2) then return append(arr1) else res : SAME := new(size + arr1.size + arr2.size) ; res.copy(self) ; res.copy(size,arr1) ; res.copy(size + arr1.size,arr2) ; return res end end ; append( arr1, arr2, arr3 : SAME ) : SAME pre true post true -- + vdm stuff !?! is -- This routine returns a new array consisting of self followed by -- arr1 then arr2 and finally arr3. This is more efficient than three -- appends. Any of the arrays may be void. if void(self) then return arr1.append(arr2,arr3) elsif void(arr1) then return append(arr2,arr3) elsif void(arr2) then return append(arr1,arr3) elsif void(arr3) then return append(arr1,arr2) else res : SAME := new(size + arr1.size + arr2.size + arr3.size) ; res.copy(self) ; res.copy(size,arr1) ; res.copy(size + arr1.size,arr2) ; res.copy(size + arr1.size + arr2.size,arr3) ; return res end end ; contains( elem : T ) : BOOL is -- This predicate returns true if and only if self contains an element -- for which elt_eq returns true, otherwise false. if void(self) then return false end ; loop if elt_eq(elt!,elem) then return true end end ; return false end ; has( elem : T ) : BOOL is -- This predicate is a renaming of contains. return contains(elem) end ; count( val : T ) : CARD pre true post true -- irrespective of result! is -- This routine returns the number of array elements which are elt_eq -- to val. Self may be void. res : CARD := 0 ; loop if elt_eq(elt!,val) then res := res + 1 end end ; return res end ; index_of( elem : T ) : CARD pre true post (result = CARD::maxval) or (~void(self) and(count(elem) > 0)) is -- This routine returns the lowest index of an element which is elt_eq -- to elem. If there is no such element then CARD::maxval is returned. -- Self may be void. loop res : CARD := ind! ; if elt_eq(elem,[res]) then return res end end ; return CARD::maxval end ; remove( elem : T ) : SAME pre true post ~result.contains(elem) is -- This routine returns a new array in which no elements are elt_eq to -- elem. Self may be void. if void(self) then return void else res : SAME := create(size - count(elem)) ; loop loc_elem : T := elt! ; if ~elt_eq(loc_elem,elem) then res.set!(loc_elem) end end ; return res end end ; remove_if( test : ROUT{T} : BOOL ) : SAME pre void(self) or ~void(test) post true is -- This routine returns a new array without those elements which satisfy -- the given test. Self may be void. if void(self) then return void else res : SAME := create(size - count_if(test)) ; loop elem : T := elt! ; if ~test.call(elem) then res.set!(elem) end end ; return res end end ; private is_sorted( lower : CARD, upper : CARD ) : BOOL is -- This predicate returns true if and only if the elements of self are -- sorted according to the relation elt_lt. Self may be void. loop index : CARD := (lower + 1).upto!(upper) ; if elt_lt([index],[index - 1]) then return false end end ; return true end ; is_sorted : BOOL is -- This predicate returns true if and only if the elements of self are -- sorted according to the relation elt_lt. Self may be void. if self.size = 0 then return true else return is_sorted(0,(asize - 1)) end end ; remove_duplicates : SAME pre is_sorted post (result.size <= size) is -- This routine returns a new arry with only the first copy of -- duplicated elements. Self may be void. If not it must be sorted -- prior to calling this routine. if void(self) or self.size = 1 then return self end ; res : SAME := new(size) ; -- Same size as self for now... num_elems : CARD := 0 ; -- No of elems in res! prev : T := [0] ; loop curr : T := elt!(1) ; if ~elt_eq(prev,curr) then res[num_elems] := prev ; num_elems := num_elems + 1 end ; prev := curr end ; res[num_elems] := [size - 1] ; num_elems := num_elems + 1 ; return res.resize(num_elems) end ; to_replace( old, new_val : T ) pre true post (initial(count(old)) <= count(new_val)) is -- This routine replaces those elements that are elt_eq to old by -- new_val wherever the match is found. Self may be void. loop elem : T := elt! ; if elt_eq(elem,old) then elem := new_val end ; set!(elem) end end ; to_replace_if( test : ROUT{T} : BOOL, new_val : T ) pre void(self) or ~void(test) post true is -- This routine replaces all of the elements of self which satisfy -- the given test by new_val. Self may be void. loop elem : T := elt! ; if test.call(elem) then elem := new_val end ; set!(elem) end end ; find_if( test : ROUT{T} : BOOL ) : T pre void(self) or ~void(test) post true is -- Searching from the lowest index, this routine returns the first -- element which satisfies the given test. If there is no such element -- then void is returned. Self may be void. loop res : T := elt! ; if test.call(res) then return res end end ; return void end ; index_if( test : ROUT{T} : BOOL ) : CARD pre void(self) or ~void(test) post (result = CARD::maxval) or test.call([result]) is -- This routine returns the index of the first element, searching from -- zero, which satisfies the given test. If there is no such element then -- CARD::maxval is returned. Self may be void. loop res : CARD := ind! ; if test.call([res]) then return res end end ; return CARD::maxval end ; mismatch( arr : SAME ) : CARD pre true post (result = CARD::maxval) or (result < asize) is -- This routine returns the index of the first element of self which -- differs from the corresponding element of arr. If there is no such -- element or self is void or self is a prefix of arr then CARD::maxval is -- returned. if void(self) then return CARD::maxval end ; loop res : CARD := ind! ; if ~elt_eq([res],arr.elt!) then return res end end ; return CARD::maxval end ; search( arr : SAME ) : CARD pre true post (result = CARD::maxval) or (result < asize) is -- This routine returns the index of the first sub-array of self, -- starting at zero, which matches arr. If self is void or there is no -- match then CARD::maxval is returned. if void(self) then return CARD::maxval end ; loop res : CARD := 0.upto!(size - arr.size) ; match : BOOL := true ; loop if ~elt_eq(elt!(res),arr.elt!) then match := false ; break! end end ; if match then return res end end ; return CARD::maxval end ; search( beg : CARD, arr : SAME ) : CARD pre ~void(self) and ~void(arr) and (beg <= (asize - 1)) post (result = CARD::maxval) or (result < asize) is -- This routine returns the index of the beginning of the first -- sub-array of self which matches arr, starting at zero. If there is no -- such sub-array then CARD::maxval is returned. loop res : CARD := beg.upto!(size - arr.size) ; match : BOOL := true ; loop if ~elt_eq(elt!(res),arr.elt!) then match := false ; break! end end ; if match then return res end end ; return CARD::maxval end ; map( operation : ROUT{T} : T ) pre ~void(operation) post true is -- This routine sets each element of self to be the result of applying -- the given operation to it. Self may be void. loop set!(operation.call(elt!)) end end ; reduce( operation : ROUT{T,T} : T ) : T pre ~void(operation) post true is -- This routine returns the result of applying the given operation -- to self from the lowest index to the highest. Void is returned if self -- is void. if size = 0 then return void end ; val : T := [0] ; loop val := operation.call(val,elt!(1,size - 1)) end ; return val end ; scan( operation : ROUT{T,T} : T ) pre ~void(operation) post true is -- This routine sets each element of self to be the result of applying -- the given operation to adjacent elements of self from lowest to highest -- index. The element with index zero is not altered. Self may be void. if ~void(self) then loop index : CARD := 1.upto!(size - 1) ; [index] := operation.call([index - 1],[index]) end end end ; -- The following group of operations relate to sorted arrays insertion_sort_range( lower, upper : CARD ) pre (self.size > 1) and (lower < upper) and (upper <= (asize - 1)) post is_sorted(lower,upper) is -- This routine performs an insertion sort of the elements of self -- in the index range lower to upper. Ordering is defined by elt_lt. loop out_index : CARD := (lower + 1).upto!(upper) ; elem : T := [out_index] ; loop in_index : CARD := out_index.downto!(lower) ; if (in_index = lower) then [lower] := elem ; break! elsif (elt_lt([in_index - 1], elem)) then [in_index] := elem ; break! else [in_index] := [in_index - 1] end end end end ; private const quicksort_limit : CARD := 10 ; -- The value of this is used to stop quicksort recursion and switch to an -- insertion sort. quicksort_range( lower, upper : CARD ) pre (self.size > 1) and (lower < upper) and (upper <= (asize - 1)) post is_sorted(lower,upper) is -- This routine implements part of the quicksort algorithm to search -- the range of self between lower and upper according to the relation elt_lt if (upper - lower) > quicksort_limit then res : CARD := RANDOM::card(lower,upper) ; temp : T := [res] ; -- Swap the random element & lower [res] := [lower] ; [lower] := temp ; middle : CARD := lower ; loop index : CARD := (lower + 1).upto!(upper) ; if elt_lt([index],temp) then middle := middle + 1 ; stemp : T := [middle] ; [middle] := [index] ; [index ] := stemp end end ; temp := [lower] ; [lower] := [middle] ; [middle] := temp ; if (middle > 0) and (lower < (middle - 1)) then quicksort_range(lower,middle - 1) end ; if (middle + 1) < upper then quicksort_range(middle + 1,upper) end else insertion_sort_range(lower,upper) end end ; sort pre true post is_sorted is -- This routine sorts the entire array using quick-sort with respect -- to elt_lt. Self may be void. if self.size > 1 then -- less than 2 is sorted! quicksort_range(0,asize - 1) end end ; stable_sort pre true post is_sorted is -- This routine uses an insertion sort to permute the elements of self -- so that it is sorted with respect to elt_lt and equal elements are in -- the original order. Self may be void. if self.size > 0 then insertion_sort_range(0,asize - 1) end end ; binary_search( elem : T ) : CARD pre is_sorted post (result = CARD::maxval) or (result < asize) is -- This search routine assumes that self is sorted. It returns -- the index of the element preceding the first element greater than elem -- according to elt_lt or CARD::maxval if self is void or if all elements -- are greater than elem. if void(self) then return CARD::maxval end ; lower : CARD := 0 ; upper : CARD := asize - 1 ; if ~elt_lt(elem,[upper]) then return upper end ; if elt_lt(elem,[lower]) then return CARD::maxval end ; -- At this point [u] is always greater than elem, and [l] is not -- greater than elem. loop while!(upper > (lower + 1)) ; index : CARD := (upper + lower)/2 ; if elt_lt(elem,[index]) then upper := index else lower :=index end end ; return lower end ; is_sorted_by( order : ROUT{T,T} : BOOL ) : BOOL pre void(self) or ~void(order) post true is -- This predicate returns true if and only if the elements of self are -- sorted in an order specified by the order routine which is expected to -- return true if and only if its first argument is less than its second -- argument. Self may be void. if ~void(self) then loop index : CARD := 1.upto!(asize - 1) ; if order.call([index],[index - 1]) then return false end end end ; return true end ; insertion_sort_by( order : ROUT{T,T} : BOOL ) pre ~void(order) post is_sorted_by(order) is -- This routine sorts the elements of self using insertion sorting -- in an order specified by the order routine which is expected to return -- true if and only if its first argument is less than its second argument. -- Self may be void. if void(self) then return end ; loop out_index : CARD := 1.upto!(asize - 1) ; elem : T := [out_index] ; loop in_index : CARD := (out_index).downto!(0) ; if (in_index = 0) then [in_index] := elem ; break! elsif (order.call([in_index - 1], elem)) then [in_index] := elem ; break! else [in_index] := [in_index - 1] end end end end ; binary_search_by( elem : T, order : ROUT{T,T} : BOOL ) : CARD pre ~void(order) and is_sorted_by(order) post (result = CARD::maxval) or (result < asize) is -- This routine returns the index of the element of self preceding -- the first element greater than elem unless self is void or all elements -- are greater then elem, when CARD::maxval is returned. if void(self) then return CARD::maxval end ; lower : CARD := 0 ; upper : CARD := asize - 1 ; if ~order.call(elem,[upper]) then return upper end ; if order.call(elem,[lower]) then return CARD::maxval end ; -- At this point [upper] is known to be greater than elem, and -- [lower] is not greater than elem. loop while!(upper > (lower + 1)) ; index : CARD := (upper + lower)/2 ; if order.call(elem,[index]) then upper := index else lower := index end end ; return lower end ; merge_with_by( arr : SAME, order : ROUT{T,T} : BOOL ) : SAME pre is_sorted_by(order) and arr.is_sorted_by(order) post result.is_sorted_by(order) is -- This routine returns a new array with the elements of self merged -- together according to order which should return true if and only if its -- first argument is less than its second. if void(self) then return arr.copy end ; if void(arr) then return copy end ; res : SAME := create(size + arr.size) ; self_index, arr_index : CARD ; temp : T ; loop if self_index = size then temp := arr[arr_index] ; arr_index := arr_index + 1 elsif arr_index = arr.size then temp := [self_index] ; self_index := self_index + 1 elsif order.call([self_index],arr[arr_index]) then temp := [self_index] ; self_index := self_index + 1 else temp := arr[arr_index] ; arr_index := arr_index + 1 end ; res.set!(temp) end ; return res end ; select( index : CARD ) pre ~void(self) and (index < size) post true is -- This routine moves the elements of self so that the element with -- the given index is not elt_lt any element with lower indices and -- no element with a larger index is elt_lt it. lower : CARD := 0 ; upper : CARD := size - 1 ; loop until!(lower >= upper) ; out_index : CARD := RANDOM::card(lower,upper) ; temp : T := [out_index] ; [out_index] := [lower] ; [lower] := temp ; middle : CARD := lower ; loop in_index : CARD := (lower + 1).upto!(upper) ; if elt_lt([out_index],temp) then middle := middle + 1 ; temp := [middle] ; [middle] := [in_index] ; [in_index] := temp end end ; temp := [lower] ; [lower] := [middle] ; [middle] := temp ; if middle <= out_index then lower := middle + 1 end ; if middle >= out_index then upper := middle - 1 end end end ; median : T pre true post void(result) or self.contains(result) is -- This routine returns the median of the elements contained in self -- according to the ordering relation elt_lt. This permutes the elements -- of self. Void is returned if self is void. if size = 0 then return void end ; middle : CARD := (size - 1)/2 ; select(middle) ; return [middle] end ; select_by( order : ROUT{T,T} : BOOL, index : CARD ) pre ~void(self) and ~void(order) and (index < size) post true is -- This routine moves the elements of self so that the element with -- the given index is not less than (as determined by the order routine, -- which is expected to return true if and only if its first argument is -- less than its second) any element with lower indices and no element with -- a larger index is less than it. lower : CARD := 0 ; upper : CARD := size - 1 ; loop until!(lower >= upper) ; out_index : CARD := RANDOM::card(lower,upper) ; temp : T := [out_index] ; [out_index] := [lower] ; [lower] := temp ; middle : CARD := lower ; loop in_index : CARD := (lower + 1).upto!(upper) ; if order.call([in_index],temp) then middle := middle + 1 ; temp := [middle] ; [middle] := [in_index] ; [in_index] := temp end end ; temp := [lower] ; [lower] := [middle] ; [middle] := temp ; if middle <= out_index then lower := middle + 1 end ; if middle >=out_index then upper := middle - 1 end end end ; -- The iters over array elements. elt! : T pre ~void(self) post (self.contains(result)) is -- This iter yields each element of self in order. Self may be void. -- Built-in to this implementation. builtin ARRAY_ELTB end ; elt!( once beg : CARD ) : T pre ~void(self) and (beg <= (asize - 1)) post contains(result) -- (result = [ind!]) is -- This iter yields each element of self starting at `beg'. Self may -- not be void. Built-in to this implementation. builtin ARRAY_ELT_BEGB end ; elt!( once beg, once num : CARD ) : T pre ~void(self) and (beg <= (size - 1)) and (num <= (size - beg)) post contains(result) -- (result = [beg + ind!]) is -- This iter yields num successive elements of self starting at -- index beg. Self may not be void. Built-in to this implementation. builtin ARRAY_ELT_BEG_NUMB end ; elt!( once beg, once num : CARD, once step : INT ) : T pre ~void(self) and is_legal_aelts_arg(beg,num,step) post contains(result) -- (result = [beg + ind!]) is -- This iter yields num elements of self starting at beg and stepping -- by step which must not be zero. Self may not be void. Built-in to this -- implementation. builtin ARRAY_ELT_BEG_NUM_STEPB end ; set!( val : T ) pre true post contains(val) -- ([ind!] = val) is -- This iter sets successive elements of self to the values of val. -- Self may be void. Built_in to this implementation. builtin ARRAY_SETB end ; set!( once beg : CARD, val : T ) pre ~void(self) and (beg <= (size - 1)) post contains(val) -- ([beg + ind!] = val) is -- This iter sets successive elements starting at beg to the values of -- val. Self may not be void. Built-in to this implementation. builtin ARRAY_SET_BEGB end ; set!( once beg, once num : CARD, val : T ) pre ~void(self) and (beg <= (size - 1)) and (num <= (size - beg)) post contains(val) -- ([beg + ind!] = val) is -- This iter sets num successive elements of self starting at beg -- to the values of val. Self may not be void. Built-in to this -- implementation. builtin ARRAY_SET_BEG_NUMB end ; set!( once beg, once num : CARD, once step : INT, val : T ) pre ~void(self) and is_legal_aelts_arg(beg,num,step) post contains(val) -- + vdm stuff !?! is -- This iter sets num elements of self starting at beg stepping by -- step to the values of val. Step must not be zero. Self may not be void. -- Built-in to this implementation. builtin ARRAY_SET_BEG_NUM_STEPB end ; ind! : CARD pre true post (result < size) is -- This iter yields the indices of self in order. Self may be void. -- Built-in to this implementation. builtin ARRAY_INDB end ; ind1! : CARD pre true post (result < size) is -- This iter yields the indices of self in order. Self may be void. -- Built-in to this implementation. -- -- NOTE This is provided for consistency with ARRAY2 and ARRAY3 classes. builtin ARRAY_INDB end ; end ; -- class ARRAY{T}
Language Index Library Index Container Index
Comments or enquiries should be made to Keith Hopper.
Page last modified: Thursday, 25 May 2000.
Produced with Amaya