requires: {#Sequence}. provides: {#Array. #ByteArray. #ArrayMD. #MDArraySlice}. Array traits atSlotNamed: #parent0 put: Sequence traits. "Ensures that the primitive Array type has the behaviors and features of a Sequence." a@(Array traits) copy [ a clone ]. a@(Array traits) arrayType [a]. _@(Array traits) elementType [Root]. ByteArray traits atSlotNamed: #parent0 put: Sequence traits. "Ensures that the primitive ByteArray type has the behaviors and features of a Sequence." a@(ByteArray traits) copy [ a clone ]. a@(ByteArray traits) arrayType [a]. _@(ByteArray traits) elementType [SmallInteger]. a@(ByteArray traits) at: i [ a byteAt: i ]. a@(ByteArray traits) at: i put: byte [ a byteAt: i put: byte ]. collections addPrototype: #ArrayMD derivedFrom: {Collection}. "Multi-dimensional arrays don't readily admit to sequencing or mutation." ArrayMD addSlot: #dimensions valued: {1}. "Default is a scalar: one dimension, of extent 1." ArrayMD addSlot: #contents valued: (Array newSize: 1). "Store the contents in an array of exactly the right size." mda@(ArrayMD traits) newEmpty "Deprecated. Meant for compatibility with Collection methods that require it, particularly select:-type methods. The alternative is to return a new array of the same dimensions and sparsely populate it, but that's over- complicated." [ Bag newEmpty ]. mda@(ArrayMD traits) newSize: _ "Deprecated. Meant for compatibility with Collection methods that require it. It takes it's dimensions from the target array, so is not meant to be called on the ArrayMD prototype itself." [| newMDA | newMDA: mda clone. newMDA dimensions: mda dimensions. newMDA contents: (mda contents newSizeOf: mda). newMDA ]. mda@(ArrayMD traits) newWithDimensions: sc@(Sequence traits) "Set up the array to hold enough elements as specified by an array or vector of dimension sizes. Dimension size 0 is coerced to 1." [| newMDA size | size: 1. sc do: [| :each | size: size * each ]. newMDA: mda clone. newMDA contents: (mda contents newSize: size). newMDA dimensions: (sc collect: [| :each | each max: 1]). newMDA ]. mda@(ArrayMD traits) newWithDimensions: seq defaultElement: x [| newMDA | newMDA: (mda newWithDimensions: seq). newMDA contents keysDo: [| :index | newMDA contents at: index put: x]. newMDA ]. mda@(ArrayMD traits) size [ mda contents size ]. mda@(ArrayMD traits) numDimensions "Dimensions of size 0 or 1 don't introduce actual variations." [ mda dimensions count: [| :each | each > 1] ]. mda@(ArrayMD traits) at: n@(Integer traits) "Return a slice of the mda using an index of the first dimension." [ ]. mda@(ArrayMD traits) indexOf: sc@(Sequence traits) "Returns the place in the contents where the given sequence of coordinates maps to. This should not be called repetitively, as it would duplicate a lot of calculation." [| final offset | sc size = mda dimensions size ifFalse: [mda notYetImplemented]. final: 0. offset: 1. sc with: mda dimensions do: [| :index :dimSize | final: final + (index * offset). offset: offset * dimSize]. final ]. mda@(ArrayMD traits) at: sc@(Sequence traits) [ mda contents at: (mda indexOf: sc) ]. mda@(ArrayMD traits) at: sc@(Sequence traits) put: obj [ mda contents at: (mda indexOf: sc) put: obj ]. mda@(ArrayMD traits) do: block [ mda contents do: block ]. mda@(ArrayMD traits) sliceAt: m in: n "Return an array slice, defined by the array of all addresses having value m in position n. This works lazily." [ MDArraySlice for: mda at: m in: n ]. mda@(ArrayMD traits) sliceAt: m in: n do: block "Act on all elements having index m in dimension n, in order. This has a dimension of one less than mda's." [| firstIndex stepIndex | firstIndex: (mda indexOf: ((Array newSize: mda numDimensions) at: n put: m)). stepIndex: (mda dimensions inject: 1 into: [| :step :each | ]). firstIndex upTo: mda size - 1 by: stepIndex do: block. ]. ArrayMD traits addPrototype: #Slice derivedFrom: {Collection}. "A Slice of a multi-dimensional Array." "TODO: eventually handle multi-dimensional Slices." ArrayMD Slice addSlot: #array. "The source array." ArrayMD Slice addSlot: #dimension. "Which dimension is the slice through?" ArrayMD Slice addSlot: #start. "The starting index value." ArrayMD Slice addSlot: #end. "The ending value, or Nil for thin slices." as@(ArrayMD Slice traits) for: mda@(ArrayMD traits) at: m in: n [| newSlice | n > mda numDimensions ifTrue: [^ Nil]. m >= (mda dimensions at: n) ifTrue: [^ Nil]. newSlice: as clone. newSlice array: mda. newSlice dimension: n. newSlice start: m. newSlice end: Nil. newSlice ]. as@(ArrayMD Slice traits) for: mda@(ArrayMD traits) from: m to: l in: n [| newSlice | n > mda numDimensions ifTrue: [^ Nil]. m >= (mda dimensions at: n) ifTrue: [^ Nil]. newSlice: as clone. newSlice array: mda. newSlice dimension: n. newSlice start: (m min: l). newSlice end: (l max: m). newSlice ]. " collections addPrototype: #NumericArrayMD derivedFrom: {ArrayMD}. NumericArrayMD contents: (NumericArray newSize: 1). a1@(NumericArrayMD traits) + a2@(NumericArrayMD traits) [| newMDA | a1 dimensions = a2 dimensions ifFalse: [Nil]. newMDA: a1 clone. newMDA contents: a1 contents + a2 contents. newMDA ]. mda@(NumericArrayMD traits) negated [| newMDA | newMDA: mda clone. newMDA contents: mda contents negated. ]. a1@(NumericArrayMD traits) - a2@(NumericArrayMD traits) [ a1 + a2 negated ]. "