Module: internal Author: Jonathan Bachrach Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND // BOOTED: define ... class ... end; //////////// // INTERFACE //////////// // Open generics on define open generic rank (array :: ) => (rank :: ); define open generic row-major-index (array :: , #rest subscripts) => (index :: ); define open generic aref (array :: , #rest indices) => object; define open generic aref-setter (new-value, array :: , #rest indices) => object; define open generic dimensions (array :: ) => (dims :: ); define open generic dimension (array :: , axis :: ) => (dim :: ); define open generic limited-array (of :: , dimensions :: false-or()) => (type :: ); ///////////////// // IMPLEMENTATION ///////////////// // // RANK // define inline method rank (array :: ) => (rank :: ) size(array.dimensions) end method rank; // // ROW-MAJOR-INDEX // define function aref-rank-error (array :: , subscripts) => (will-never-return :: ) // We don't embed the collection in the condition as it will prevent the // collection having dynamic extent. A debugger should be able to display // the collection. error(make(, format-string: "Number of subscripts not equal to " "rank of array %=", format-arguments: list(array))) end function aref-rank-error; define method general-row-major-index (array :: , #rest subscripts :: ) => (index :: ) %dynamic-extent(subscripts); let sum :: = 0; for (dimension :: in array.dimensions, index :: in subscripts) unless (element-range-check(index, dimension)) element-range-error(array, subscripts); end unless; sum := (sum * dimension) + index; end for; sum end method general-row-major-index; define inline method two-row-major-index (array :: , #rest subscripts :: ) => (index :: ) %dynamic-extent(subscripts); let dimensions = dimensions(array); without-bounds-checks let dim-0 :: = dimensions[0]; let idx-0 :: = subscripts[0]; let dim-1 :: = dimensions[1]; let idx-1 :: = subscripts[1]; unless (element-range-check(idx-0, dim-0) & element-range-check(idx-1, dim-1)) element-range-error(array, subscripts); end unless; idx-0 * dim-1 + idx-1 end without-bounds-checks; end method two-row-major-index; define inline method row-major-index (array :: , #rest subscripts :: ) => (index :: ) %dynamic-extent(subscripts); let n-subscripts = size(subscripts); unless (array.rank = n-subscripts) aref-rank-error(array, subscripts); end unless; if (n-subscripts = 2) apply(two-row-major-index, array, subscripts); else apply(general-row-major-index, array, subscripts); end if; end method row-major-index; // // AREF // define inline method aref (array :: , #rest indices :: ) => (object) without-bounds-checks array[apply(row-major-index, array, indices)] end without-bounds-checks; end method aref; // // AREF-SETTER // define inline method aref-setter (new-value, array :: , #rest indices :: ) => (object) without-bounds-checks array[apply(row-major-index, array, indices)] := new-value end without-bounds-checks; end method aref-setter; // // DIMENSION // define inline method dimension (array :: , axis :: ) => (dimension :: ) array.dimensions[axis] end method dimension; // // Specialized inherited generic methods // // // MAKE // define sealed method make (class == , #rest args, #key dimensions = unsupplied(), size: sz = unsupplied()) => (result :: ) case supplied?(sz) => if (supplied?(dimensions) & (size(dimensions) ~= 1 | dimensions[0] ~= sz)) error("Dimensions %= incompatible to size %= in call to make()", dimensions, sz); end if; apply(make, , args); unsupplied?(dimensions) => // TODO: use proper error class error(make(, format-string: "No dimensions in call to make()")); dimensions.size = 1 => apply(make, , size: dimensions.first, args); otherwise => apply(make, , args); end case end method make; // // SHALLOW-COPY // define method shallow-copy (array :: ) => (array :: ) let size = size(array); if (size = 0) make(array.type-for-copy, dimensions: dimensions); else let dimensions :: = array.dimensions; let new-array :: = make(array.type-for-copy, dimensions: dimensions, fill: array[0]); for (key :: from 0 below size) new-array[key] := array[key]; end for; new-array end if; end method shallow-copy; // // TYPE-FOR-COPY // define method type-for-copy (array :: ) => (class :: ) end method type-for-copy; // // AS // define method as (class == , array :: ) => (array :: ) array end method as; define method as (class == , collection :: ) => (array :: ) as(, collection) end method as; // // FILL! // define method fill! (target :: , value, #key start :: = 0, end: last = unsupplied()) => (target :: ) let last :: = check-start-compute-end(target, start, last); for (index :: from start below last) target[index] := value end; target end; // // SIZE // define method size (x :: ) => (res :: ) reduce(\*, 1, dimensions(x)) end method; // // MULTIDIMENSIONAL-ARRAY // define abstract class () end class; define abstract class () end class; // eof