(********************************************************************) (* *) (* basearray.s7i Support for arrays with a fixed minimum index. *) (* Copyright (C) 2024 Thomas Mertes *) (* *) (* This file is part of the Seed7 Runtime Library. *) (* *) (* The Seed7 Runtime Library is free software; you can *) (* redistribute it and/or modify it under the terms of the GNU *) (* Lesser General Public License as published by the Free Software *) (* Foundation; either version 2.1 of the License, or (at your *) (* option) any later version. *) (* *) (* The Seed7 Runtime Library is distributed in the hope that it *) (* will be useful, but WITHOUT ANY WARRANTY; without even the *) (* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR *) (* PURPOSE. See the GNU Lesser General Public License for more *) (* details. *) (* *) (* You should have received a copy of the GNU Lesser General *) (* Public License along with this program; if not, write to the *) (* Free Software Foundation, Inc., 51 Franklin Street, *) (* Fifth Floor, Boston, MA 02110-1301, USA. *) (* *) (********************************************************************) (** * Abstract data type, describing arrays with a fixed minimum [[integer]] index. * A base array type defines the minimum allowed index. * All arrays declared with this type have the same minimum index. * All abstract base array types are incompatible to each other. * A type declaration is needed to use the same fixed size array type * at several places. E.g.: * const type: nameList is array [1 .. ] string; * afterwards ''nameList'' can be used in declarations. E.g.: * var nameList: aNameList is nameList.value; * @param minIdx Minimum index of the array type. * @param baseType Type of the array elements. *) const func type: array [ (in integer: minIdx) .. ] (in type: baseType) is func result var type: arrayType is void; local var type: tupleType is void; var type: maxIndexType is void; begin global arrayType := newtype; IN_PARAM_IS_REFERENCE(arrayType); tupleType := tuple(baseType); maxIndexType := newtype; IN_PARAM_IS_VALUE(maxIndexType); const creator: (ref arrayType: dest) ::= (in arrayType: source) is action "ARR_CREATE"; const destroyer: destroy (ref arrayType: aValue) is action "ARR_DESTR"; const proc: (inout arrayType: dest) := (in arrayType: source) is action "ARR_CPY"; (** * Append the array ''extension'' to the array ''arr''. * @exception MEMORY_ERROR Not enough memory for the concatenated * array. *) const proc: (inout arrayType: arr) &:= (in arrayType: extension) is action "ARR_APPEND"; (** * Append the given ''element'' to the array ''arr''. * @exception MEMORY_ERROR Not enough memory for the concatenated * array. *) const proc: (inout arrayType: arr) &:= (in baseType: element) is action "ARR_PUSH"; (** * Concatenate two arrays. * @return the result of the concatenation. *) const func arrayType: (in arrayType: arr1) & (in arrayType: arr2) is action "ARR_CAT"; (** * Access one element from the array ''arr''. * @return the element with the specified ''index'' from ''arr''. * @exception INDEX_ERROR If ''index'' is less than [[#minIdx(in_arrayType)|minIdx]](arr) or * greater than [[#maxIdx(in_arrayType)|maxIdx]](arr) *) const func baseType: (in arrayType: arr) [ (in integer: index) ] is action "ARR_IDX"; const varfunc baseType: (inout arrayType: arr) [ (in integer: index) ] is action "ARR_IDX"; (** * Assign array 'source' to the 'position' of the 'destination'. * A @:= [B] C; * is equivalent to * A := A[..pred(B)] & C & A[B+length(C)..]; * @exception INDEX_ERROR If 'position' is less than [[#minIdx(in_arrayType)|minIdx]](destination) or * elements beyond 'destination' would be overwritten. *) const proc: (inout arrayType: destination) @:= [ (in integer: position) ] (in arrayType: source) is action "ARR_POSCPY"; (** * Get a sub array beginning at the position ''start''. * @return the sub array beginning at the start position. * @exception INDEX_ERROR The start position is less than [[#minIdx(in_arrayType)|minIdx]](arr). * @exception MEMORY_ERROR Not enough memory to represent the result. *) const func arrayType: (in arrayType: arr) [ (in integer: start) .. ] is action "ARR_TAIL"; (** * Get a sub array ending at the position ''stop''. * @return the sub array ending at the stop position. * @exception INDEX_ERROR The stop position is less than pred([[#minIdx(in_arrayType)|minIdx]](arr)). * @exception MEMORY_ERROR Not enough memory to represent the result. *) const func arrayType: (in arrayType: arr) [ .. (in integer: stop) ] is action "ARR_HEAD"; (** * Get a sub array from the position ''start'' to the position ''stop''. * @return the sub array from position ''start'' to ''stop''. * @exception INDEX_ERROR The start position is less than [[#minIdx(in_arrayType)|minIdx]](arr1), or * the stop position is less than pred(start). * @exception MEMORY_ERROR Not enough memory to represent the result. *) const func arrayType: (in arrayType: arr) [ (in integer: start) .. (in integer: stop) ] is action "ARR_RANGE"; (** * Get a sub array from the position ''start'' with maximum length ''len''. * @return the sub array from position ''start'' with maximum length ''len''. * @exception INDEX_ERROR The start position is less than [[#minIdx(in_arrayType)|minIdx]](arr), or * the length is negative. * @exception MEMORY_ERROR Not enough memory to represent the result. *) const func arrayType: (in arrayType: arr) [ (in integer: start) len (in integer: length) ] is action "ARR_SUBARR"; (** * Get a sub array from a ''start'' position with a guaranteed ''length''. * @return the sub array from the ''start'' position with ''length'' elements. * @exception INDEX_ERROR The ''length'' is negative, or the ''start'' position * is outside of the array, or the sub array from the * ''start'' position has less than ''length'' elements. * @exception MEMORY_ERROR Not enough memory to represent the result. *) const func arrayType: (in arrayType: arr) [ (in integer: start) fixLen (in integer: length) ] is action "ARR_SUBARR_FIXLEN"; (** * Insert ''element'' at ''index'' into ''arr''. * Elements are moved backward to create space for the element to be * inserted. This function is tuned for performance and the movement * works without copying elements. * @exception INDEX_ERROR If ''index'' is less than [[#minIdx(in_arrayType)|minIdx]](arr) or * greater than succ([[#maxIdx(in_arrayType)|maxIdx]](arr)) *) const proc: insert (inout arrayType: arr, in integer: index, in baseType: element) is action "ARR_INSERT"; (** * Insert ''elements'' at ''index'' into ''arr''. * Elements are moved backward to create space for the elements to be * inserted. This function is tuned for performance and the movement * works without copying elements. * @exception INDEX_ERROR If ''index'' is less than [[#minIdx(in_arrayType)|minIdx]](arr) or * greater than succ([[#maxIdx(in_arrayType)|maxIdx]](arr)) *) const proc: insert (inout arrayType: arr, in integer: index, in arrayType: elements) is action "ARR_INSERT_ARRAY"; (** * Remove the element with ''index'' from ''arr''. * The elements after the removed element are moved forward. * This function is tuned for performance and the movement works * without copying elements. * @return the removed element. * @exception INDEX_ERROR If ''index'' is less than [[#minIdx(in_arrayType)|minIdx]](arr) or * greater than [[#maxIdx(in_arrayType)|maxIdx]](arr) *) const func baseType: remove (inout arrayType: arr, in integer: index) is action "ARR_REMOVE"; (** * Remove the sub-array with ''index'' and ''length'' from ''arr''. * The elements after the removed sub-array are moved forward. * This function is tuned for performance and the movement works * without copying elements. * @return the removed sub-array. * @exception INDEX_ERROR If ''index'' is less than [[#minIdx(in_arrayType)|minIdx]](arr) or * greater than [[#maxIdx(in_arrayType)|maxIdx]](arr) *) const func arrayType: remove (inout arrayType: arr, in integer: index, in integer: length) is action "ARR_REMOVE_ARRAY"; (** * Determine the length of the array ''arr''. * @return the length of the array. *) const func integer: length (in arrayType: arr) is action "ARR_LNG"; (** * Minimum index of all arrays declared with ''arrayType''. * All arrays declared with ''arrayType'' have this minimum index. * @return the length of the array. *) const integer: minIdx (attr arrayType) is minIdx; (** * Minimum index of array ''arr''. * The minimum index of a fixed size array does not depend on the value. * @return the minimum index of the array. *) const integer: minIdx (in arrayType: arr) is minIdx; (** * Maximum index of array ''arr''. * @return the maximum index of the array. *) const func integer: maxIdx (in arrayType: arr) is action "ARR_MAXIDX"; const func arrayType: SET_MIN_IDX (paren1, in integer: start, paren2, in tupleType: aTuple, attr arrayType) is action "ARR_ARRLIT2"; const func arrayType: SET_MIN_IDX (paren1, in integer: start, paren2, in baseType: anElement, attr arrayType) is action "ARR_BASELIT2"; const func arrayType: SET_MIN_IDX (paren1, in integer: start, paren2, in arrayType: arr) is action "ARR_ARRLIT2"; const func arrayType: TIMES (in integer: factor, times, in baseType: element, attr arrayType) is action "ARR_TIMES"; const arrayType: (attr arrayType) . value is SET_MIN_IDX(paren1, minIdx, paren2, TIMES(0, times, baseType.value, arrayType)); const func arrayType: (attr arrayType) [] (in tupleType: aTuple) is return SET_MIN_IDX(paren1, minIdx, paren2, aTuple, arrayType); const func arrayType: (attr arrayType) [] (in baseType: anElement) is return SET_MIN_IDX(paren1, minIdx, paren2, anElement, arrayType); const creator: (ref maxIndexType: dest) ::= (ref maxIndexType: source) is action "INT_CREATE"; const destroyer: destroy (ref maxIndexType: aValue) is action "GEN_DESTR"; const proc: (inout maxIndexType: dest) := (in maxIndexType: source) is action "INT_CPY"; const func integer: ord (in maxIndexType: maxIndex) is action "INT_ICONV1"; const func maxIndexType: (attr maxIndexType) conv (in integer: number) is action "INT_ICONV3"; const func maxIndexType: (attr arrayType) [ .. (in integer: maxIdx) ] is return maxIndexType conv maxIdx; const func maxIndexType: (attr arrayType) [ len (in integer: length) ] is return maxIndexType conv pred(minIdx + length); (** * Generate a base index array by specifying ''maxIndex'' and ''element''. * const type: baseCharArray0 is array [0 ..] char; * const type: baseCharArray1 is array [1 ..] char; * baseCharArray0 [.. 2] times 'x' returns baseCharArray0 [] ('x', 'x', 'x') * baseCharArray0 [len 2] times 'x' returns baseCharArray0 [] ('x', 'x') * baseCharArray1 [.. 3] times 'x' returns baseCharArray1 [] ('x', 'x', 'x') * baseCharArray1 [len 2] times 'x' returns baseCharArray1 [] ('x', 'x') * @return an array with succ(maxIndex - minIdx) ''elements''. * @exception RANGE_ERROR If ''maxIndex'' is less than pred(minIdx). * @exception MEMORY_ERROR Not enough memory to represent the result. *) const func arrayType: (in maxIndexType: maxIndex) times (in baseType: element) is return SET_MIN_IDX(paren1, minIdx, paren2, TIMES(succ(ord(maxIndex) - minIdx), times, element, arrayType)); (** * For-loop where ''forVar'' loops over the elements of the array ''arr''. *) const proc: for (inout baseType: forVar) range (in arrayType: arr) do (in proc: statements) end for is func local var integer: number is 0; begin for number range minIdx to maxIdx(arr) do forVar := arr[number]; statements; end for; end func; (** * For-loop where ''keyVar'' loops over the indices of the array ''arr''. *) const proc: for key (inout integer: keyVar) range (in arrayType: arr) do (in proc: statements) end for is func begin for keyVar range minIdx to maxIdx(arr) do statements; end for; end func; (** * For-loop where ''forVar'' and ''keyVar'' loop over the array ''arr''. * The variable ''forVar'' loops over the elements of ''arr'' * and ''keyVar'' loops over the indices of ''arr''. *) const proc: for (inout baseType: forVar) key (inout integer: keyVar) range (in arrayType: arr) do (in proc: statements) end for is func begin for keyVar range minIdx to maxIdx(arr) do forVar := arr[keyVar]; statements; end for; end func; (** * For-loop where ''forVar'' loops over the elements of the array ''arr''. * Additionally a ''condition'' is checked before the statements in * the loop body are executed. *) const proc: for (inout baseType: forVar) range (in arrayType: arr) until (ref func boolean: condition) do (in proc: statements) end for is func local var integer: index is 0; var integer: maxIdx is 0; begin index := minIdx; maxIdx := maxIdx(arr); if index <= maxIdx then forVar := arr[index]; while index <= maxIdx and not condition do statements; incr(index); if index <= maxIdx then forVar := arr[index]; end if; end while; end if; end func; const proc: for (inout baseType: forVar) range (in arrayType: arr) until (ref boolean: condition) do (in proc: statements) end for is func local var integer: index is 0; var integer: maxIdx is 0; begin index := minIdx; maxIdx := maxIdx(arr); if index <= maxIdx then forVar := arr[index]; while index <= maxIdx and not condition do statements; incr(index); if index <= maxIdx then forVar := arr[index]; end if; end while; end if; end func; (** * For-loop where ''keyVar'' loops over the indices of the array ''arr''. * Additionally a ''condition'' is checked before the statements in * the loop body are executed. *) const proc: for key (inout integer: keyVar) range (in arrayType: arr) until (ref func boolean: condition) do (in proc: statements) end for is func begin for keyVar range minIdx to maxIdx(arr) until condition do statements; end for; end func; const proc: for key (inout integer: keyVar) range (in arrayType: arr) until (ref boolean: condition) do (in proc: statements) end for is func begin for keyVar range minIdx to maxIdx(arr) until condition do statements; end for; end func; (** * For-loop where ''forVar'' and ''keyVar'' loop over the array ''arr''. * The variable ''forVar'' loops over the elements of ''arr'' * and ''keyVar'' loops over the indices of ''arr''. * Additionally a ''condition'' is checked before the statements in * the loop body are executed. *) const proc: for (inout baseType: forVar) key (inout integer: keyVar) range (in arrayType: arr) until (ref func boolean: condition) do (in proc: statements) end for is func local var integer: maxIdx is 0; begin keyVar := minIdx; maxIdx := maxIdx(arr); if keyVar <= maxIdx then forVar := arr[keyVar]; while keyVar <= maxIdx and not condition do statements; incr(keyVar); if keyVar <= maxIdx then forVar := arr[keyVar]; end if; end while; end if; end func; const proc: for (inout baseType: forVar) key (inout integer: keyVar) range (in arrayType: arr) until (ref boolean: condition) do (in proc: statements) end for is func local var integer: maxIdx is 0; begin keyVar := minIdx; maxIdx := maxIdx(arr); if keyVar <= maxIdx then forVar := arr[keyVar]; while keyVar <= maxIdx and not condition do statements; incr(keyVar); if keyVar <= maxIdx then forVar := arr[keyVar]; end if; end while; end if; end func; (** * Select a random element from ''arr''. * The pseudo-random indices of the elements are uniform distributed. * @return a random element from ''arr''. * @exception RANGE_ERROR If ''arr'' is empty. *) const func baseType: rand (in arrayType: arr) is return arr[rand(minIdx, maxIdx(arr))]; if getobj((in baseType: element1) = (in baseType: element2)) <> NIL and getobj((in baseType: element1) <> (in baseType: element2)) <> NIL then const func boolean: (in arrayType: arr1) = (in arrayType: arr2) is func result var boolean: isEqual is FALSE; local var integer: number is 1; begin if maxIdx(arr1) = maxIdx(arr2) then isEqual := TRUE; while number <= maxIdx(arr1) and isEqual do isEqual := arr1[number] = arr2[number]; incr(number); end while; end if; end func; const func boolean: (in arrayType: arr1) <> (in arrayType: arr2) is func result var boolean: isNotEqual is TRUE; local var integer: number is 1; begin if maxIdx(arr1) = maxIdx(arr2) then isNotEqual := FALSE; while number <= maxIdx(arr1) and not isNotEqual do isNotEqual := arr1[number] <> arr2[number]; incr(number); end while; end if; end func; end if; end global; end func;