Array traits addDelegate: #parent2 valued: 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) printOn: s [ s nextPut: ${. a do: [| :each | each printOn: s] separatedBy: [s ; '. ']. s nextPut: $}. a ]. ByteArray traits addDelegate: #parent2 valued: 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) printOn: s [ s nextPut: ${. a do: [| :each | each printOn: s] separatedBy: [s ; '. ']. s nextPut: $}. a ]. b@(ByteArray traits) as: a@(Array traits) "Converts the integer codes into character objects." [| result | result: (a newSizeOf: b). b doWithIndex: [| :each :index | result at: index put: (each as: Character)]. result ]. a@(Array traits) as: b@(ByteArray traits) "Converts the integer codes into character objects; this also replaces Nil's with zero-code characters." [| result | result: (b newSizeOf: a). a doWithIndex: [| :each :index | each ifNil: [result at: index put: 0] ifNotNil: [result at: index put: (each as: Integer)]]. result ]. s@(String traits) as: b@(ByteArray traits) "Converts the character objects into their integer codes." [| result | result: (b newSizeOf: s). s doWithIndex: [| :each :index | result at: index put: (each as: Integer)]. result ]. b@(ByteArray traits) as: s@(String traits) "Converts the integer codes into character objects." [| result | result: (s newSizeOf: b). b doWithIndex: [| :each :index | result at: index put: (each as: Character)]. result ]. collections addSlot: #NumericArray valued: Array derive. NumericArray addDelegate: #Numeric valued: NumericMixin. collections addSlot: #ArrayMD valued: Collection derive. "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) 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. ]. collections addSlot: #MDArraySlice valued: Collection derive. MDArraySlice addSlot: #array. "The source array." MDArraySlice addSlot: #dimension. "Which dimension is the slice through?" MDArraySlice addSlot: #start. "The starting index value." MDArraySlice addSlot: #end. "The ending value, or Nil for thin slices." as@(MDArraySlice 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@(MDArraySlice 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 addSlot: #NumericArrayMD valued: ArrayMD derive. 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 ].