requires: {#Collection. #Mapping. #ExtensibleCollection}. provides: {#Sequence. #SubSequence. #Repetition}. collections addPrototype: #Sequence derivedFrom: {Collection. Mapping}. "Sequences are Mappings from a range of Integers starting from 0 to a final Integer, in a sequence, to arbitrary objects. The last address will be one less than the size." "Mapping compatibility methods." s@(Sequence traits) acceptsKey: n@(Integer traits) [n isPositive and: [n < s size]]. _@(Sequence traits) acceptsKey: _ [False]. s@(Sequence traits) keySet "Answers the keys of a Sequence as a Range; will not work until Range is installed." [ 0 below: s size ]. s@(Sequence traits) keysDo: block "Iterate over just the indices in the Sequence." [ 0 below: s size do: [| :index | block applyWith: index] ]. s@(Sequence traits) keysAndValuesDo: block [ s doWithIndex: [| :each :index | block applyWith: index with: each] ]. "Some commonly useful idioms." c@(Sequence traits) first [c at: 0]. c@(Sequence traits) second [c at: 1]. c@(Sequence traits) third [c at: 2]. c@(Sequence traits) fourth [c at: 3]. c@(Sequence traits) fifth [c at: 4]. c@(Sequence traits) sixth [c at: 5]. c@(Sequence traits) seventh [c at: 6]. c@(Sequence traits) eighth [c at: 7]. c@(Sequence traits) ninth [c at: 8]. c@(Sequence traits) tenth [c at: 9]. c@(Sequence traits) last [c at: c size - 1]. _@(Sequence traits) newSize: n "This is a general catch-all which is the core creation method to override." [overrideThis]. c@(Sequence traits) newEmpty [ c newSize: 0 ]. s@(Sequence traits) newWithAll: c@(Collection traits) [| newS index | newS: (s newSizeOf: c). index: 0. c do: [| :each | newS at: index put: each. index: index + 1]. newS ]. s@(Sequence traits) newWithAll: c@(Sequence traits) [| newS cs | cs: c size. newS: (s newSize: cs). newS replaceFrom: 0 to: cs - 1 with: c startingAt: 0. newS ]. s1@(Sequence traits) as: s2@(Sequence traits) [ s2 newWithAll: s1 ]. s@(Sequence traits) as: c@(ExtensibleCollection traits) [| newC | newC: (c newSizeOf: s). newC addAll: s. newC ]. c@(Sequence traits) arrayType "A generic protocol for returning a suitable Array prototype for holding the Sequence's objects. TODO: This is an internal, messy kind of detail that should be fixed with some parametrization on elementType." [Array]. c@(Sequence traits) after: obj ifAbsent: block [| index | (index: (c indexOf: obj)) ifNil: [block do] ifNotNil: [index = (c size - 1) ifTrue: [Nil] ifFalse: [c at: index + 1]] ]. c@(Sequence traits) after: obj [ c after: obj ifAbsent: [Nil] ]. c@(Sequence traits) allButFirst: n [ n < c size ifTrue: [c copyFrom: n to: c size - 1] ifFalse: [c newEmpty] ]. c@(Sequence traits) allButFirst [ c allButFirst: 1 ]. c@(Sequence traits) allButLast: n [ n < c size ifTrue: [c copyFrom: 0 to: c size - n - 1] ifFalse: [c newEmpty] ]. c@(Sequence traits) allButLast [ c allButLast: 1 ]. c@(Sequence traits) anyOne [ c first ]. c@(Sequence traits) acceptsKey: n@(Integer traits) "Note that this method is a temporal query: it answers about the 'now'." [ n >= 0 and: [n < c size] ]. _@(Sequence traits) acceptsKey: _@(Root traits) "Sequenceables are keyed by integers as indices only." [False]. c@(Sequence traits) at: index ifAbsent: block [ (index between: 0 and: c size - 1) ifTrue: [c at: index] ifFalse: [block do] ]. c@(Sequence traits) atAll: d@(Collection traits) "Returns a new Sequence of the elements corresponding to the indexes in the given Collection." [ d collectWithIndex: [| :each :_ | each] into: (c newSizeOf: d) ]. c@(Sequence traits) atAll: d@(Sequence traits) "Returns a new Sequence of the elements corresponding to the indexes in the given Sequence." [| newC | newC: (c newSizeOf: d). newC keysDo: [| :index | newC at: index put: (c at: (d at: index))]. newC ]. c@(Sequence traits) atAll: d put: obj [ d do: [| :index | c at: index put: obj]. obj ]. c@(Sequence traits) atAll: indices put: values [ indices with: values do: [| :index :value | c at: index put: value]. values ]. c@(Sequence traits) atAllPut: obj [| size | 0 below: size do: [| :index | c at: index put: obj]. c ]. c@(Sequence traits) = d@(Sequence traits) [ c == d or: [| size | (size: c size) = d size and: [0 below: size do: [| :index | (c at: index) = (d at: index) ifFalse: [^ False]]. True]] ]. c@(Sequence traits) hash [| hash | hash: c identityHash. c doWithIndex: [| :each :index | hash: (hash + each hash) hashMultiply]. hash ]. c@(Sequence traits) atPin: index "Return the indexed element, coercing index to the collection's range." [ c isEmpty ifFalse: [c at: (index min: c size - 1 max: 0)] ]. c@(Sequence traits) atWrap: index "Return the indexed element, wrapping the index around until it's in range." [ c at: index \\ c size ]. c@(Sequence traits) atWrap: index put: obj "Set the indexed element, wrapping the index around until it's in range." [ c at: index \\ c size put: obj ]. c@(Sequence traits) before: obj ifAbsent: block [| index | (index: (c indexOf: obj)) ifNil: [block do] ifNotNil: [index = 0 ifTrue: [Nil] ifFalse: [c at: index - 1]] ]. c@(Sequence traits) before: obj [ c before: obj ifAbsent: [Nil] ]. c@(Sequence traits) first: n [ c copyFrom: 0 to: n - 1 ]. c@(Sequence traits) identityIndexOf: obj ifAbsent: block [ 0 below: c size do: [| :index | (c at: index) == obj ifTrue: [^ index]]. block do ]. c@(Sequence traits) identityIndexOf: obj [ c identityIndexOf: obj ifAbsent: [Nil] ]. c@(Sequence traits) indexOf: obj startingAt: start ifAbsent: block "Returns the first occurrence of an element equal to the given object from the start-point. Execute and return the block's value if nothing is found." [ start below: c size do: [| :index | (c at: index) = obj ifTrue: [^ index]]. block do ]. c@(Sequence traits) indexOf: obj startingAt: start [ c indexOf: obj startingAt: start ifAbsent: [Nil] ]. c@(Sequence traits) indexOf: obj ifAbsent: block [ c indexOf: obj startingAt: 0 ifAbsent: block ]. c@(Sequence traits) indexOf: obj [ c indexOf: obj ifAbsent: [Nil] ]. c@(Sequence traits) indicesOf: obj "Answer all positions of the occurrence of the given element within the Sequence in the order that they occur." [| result position | result: ExtensibleArray newEmpty. position: 0. [(position: (c indexOf: obj startingAt: position)) isNil] whileFalse: [result addLast: position. position: position + 1]. result ]. c@(Sequence traits) includes: obj "Defined using indexOf: since Sequence is not hashed. Of course, this takes O(n) time in worst cases (most of them, when the element isn't found." [ (c indexOf: obj) isNotNil ]. c@(Sequence traits) indexOfSubSeq: subSeq startingAt: start ifAbsent: block [| first index | subSeq isEmpty ifTrue: [^ block do]. subSeq size = 1 ifTrue: [^ (c indexOf: subSeq first startingAt: start ifAbsent: block)]. first: subSeq first. start upTo: c size - subSeq size do: [| :startIndex | (c at: startIndex) = first ifTrue: [index: 1. [(c at: startIndex + index) = (subSeq at: index)] whileTrue: [index = subSeq size ifTrue: [^ startIndex]. index: index + 1]]]. block do ]. c@(Sequence traits) indexOfSubSeq: subSeq startingAt: start [ c indexOfSubSeq: subSeq startingAt: start ifAbsent: [Nil] ]. c@(Sequence traits) indexOfSubSeq: subSeq [ c indexOfSubSeq: subSeq startingAt: 0 ]. c@(Sequence traits) last: n "Answer the last N elements in the Sequence." [| size | c copyFrom: (size: c size) - n to: size - 1 ]. c@(Sequence traits) containsSubSeq: subSeq [ ]. c@(Sequence traits) lastIndexOf: obj startingAt: start ifAbsent: block "Answer the last index where an element equal to the object is found preceding the start index, executing the block if none." [ start downTo: 0 do: [| :index | (c at: index) = obj ifTrue: [^ index]]. block do ]. c@(Sequence traits) lastIndexOf: obj ifAbsent: block [ c lastIndexOf: obj startingAt: c size - 1 ifAbsent: block ]. c@(Sequence traits) lastIndexOf: obj "The last index where the object is found or Nil if none." [ c lastIndexOf: obj startingAt: c size - 1 ifAbsent: [Nil] ]. s@(Sequence traits) firstIndexOf: delims@(Collection traits) startingAt: start "Answer the first occurrence of an object in the delimiters, starting at start, returning size on failure." [ start below: s size do: [| :index | delims do: [| :obj | obj = (s at: index) ifTrue: [^ index]]]. s size ]. s@(Sequence traits) lastIndexOf: delims@(Collection traits) startingAt: start "Answer the last occurrence of an object in the delimiters, starting at start, returning -1 on failure." [ start above: 0 do: [| :index | delims do: [| :obj | obj = (s at: index) ifTrue: [^ index]]]. -1 ]. c@(Sequence traits) middle "Answer the element at the median index." [ c at: c size // 2 ]. c@(Sequence traits) replaceAll: obj with: newOne "Replace all elements equal to the given object with the replacement given." [| index | index: (c indexOf: obj startingAt: 0). [index isNil] whileFalse: [c at: index put: newOne. index: (c indexOf: obj startingAt: index)]. c ]. c@(Sequence traits) replaceFrom: start to: end with: replacement startingAt: repStart "This destructively modifies the collection." [| repOff | repOff: repStart - start. (c == replacement and: [start > repStart]) ifTrue: [end downTo: start do: [| :index | c at: index put: (replacement at: repOff + index)]] ifFalse: [start upTo: end do: [| :index | c at: index put: (replacement at: repOff + index)]]. c ]. c@(Sequence traits) swap: index1 with: index2 "Swaps the objects stored at the given indices." [| obj | obj: (c at: index1). c at: index1 put: (c at: index2). c at: index2 put: obj. c ]. c@(Sequence traits) ; d@(Sequence traits) "Concatenates the two Sequences, answering the result." [| cs | c copyReplaceFrom: (cs: c size) to: cs - 1 with: d ]. c@(Sequence traits) concatenatedTimes: n "Answer a Sequence the result of concatenating N copies of the original together." [| result | result: (c newSize: c size * n). 0 below: n by: c size do: [| :index | c doWithIndex: [| :each :srcIndex | result at: index + srcIndex put: each]]. result ]. c@(Sequence traits) copyAfter: obj "Answer a similar Sequence of all but the elements before the first matching the given object." [ c allButFirst: (c indexOf: obj ifAbsent: [^ c traits newEmpty]) ]. c@(Sequence traits) copyAfterLast: obj "Answer a similar Sequence of all but the elements before the last matching the given object." [ c allButFirst: (c lastIndexOf: obj ifAbsent: [^ c traits newEmpty]) ]. c@(Sequence traits) copyFrom: start to: end "Answer a similar Sequence with the elements from the start to the end indices, inclusive." [| newSize | (c newSize: (newSize: end - start + 1)) replaceFrom: 0 to: newSize - 1 with: c startingAt: start ]. c@(Sequence traits) copyFrom: start [c copyFrom: start to: c size - 1]. c@(Sequence traits) copyReplaceFrom: start to: end with: d "Copy with replacement, except if end < start, then this is instead an insertion. start = 0 and end = -1 inserts at the beginning; start = size appends at the end." [| newC ns endReplace ds | ns: c size - (end - start + 1) + (ds: d size). endReplace: start - 1 + ds. newC: (c newSize: ns). start > 0 ifTrue: [ newC replaceFrom: 0 to: start - 1 with: c startingAt: 0]. start <= endReplace ifTrue: [ newC replaceFrom: start to: endReplace with: d startingAt: 0]. endReplace < ns ifTrue: [ newC replaceFrom: endReplace + 1 to: ns - 1 with: c startingAt: end + 1]. newC ]. c@(Sequence traits) copyReplaceAll: seq with: replacement "Answer a copy with any occurrences of the (sub)sequence replaced with the given replacement." [| start result currentIndex end | start: 0. result: c. [(currentIndex: (result indexOfSubSeq: seq startingAt: start)) isPositive] whileTrue: [end: currentIndex + seq size - 1. (currentIndex = 0 and: [end = result size]) ifTrue: [result: (result copyReplaceFrom: currentIndex to: end with: replacement). start: currentIndex + replacement size] ifFalse: [start: currentIndex + replacement size]]. result ]. c@(Sequence traits) copyReplace: element with: obj "Answer a copy with any occurrences of the element replaced with the given object." [| newS | newS: c newSameSize. c doWithIndex: [| :each :index | newS at: index put: (each = element ifTrue: [obj] ifFalse: [each])]. newS ]. c@(Sequence traits) copyUpTo: obj [ c first: (c indexOf: obj ifAbsent: [^ c copy]) - 1 ]. c@(Sequence traits) copyUpToLast: obj [ c first: (c lastIndexOf: obj ifAbsent: [^ c copy]) - 1 ]. c@(Sequence traits) copyWith: obj "Non-destructively append an object." [| newC cs | (newC: (c newSize: (cs: c size) + 1)) replaceFrom: 0 to: cs - 1 with: c startingAt: 0. newC at: cs put: obj. newC ]. c@(Sequence traits) copyWithoutFirst [ c allButFirst ]. c@(Sequence traits) copyWithoutAt: index [| newC ns | newC: (c newSize: (ns: c size - 1)). newC replaceFrom: 0 to: index - 1 with: c startingAt: 0. newC replaceFrom: index to: ns - 1 with: c startingAt: index + 1. newC ]. s@(Sequence traits) splitWith: obj "Divides the Sequence up into subsequences as delimited by the given element." "NOTE: This has a forward reference to ExtensibleArray." [| subSeqs sepIndex nextSep | subSeqs: ExtensibleArray newEmpty. sepIndex: 0. [sepIndex < s size] whileTrue: [nextSep: (s indexOf: obj startingAt: sepIndex + 1 ifAbsent: [s size]). subSeqs addLast: (s copyFrom: sepIndex to: nextSep - 1). sepIndex: nextSep]. subSeqs ]. c@(Sequence traits) copy "An abstract Sequence copy." [ c copyFrom: 0 to: c size - 1. ]. s@(Sequence traits) copySize: n "Create a new Sequence of the same type and given size, filling in the values with repetitions of the source's contents throughout its length." [| result cs | result: (s newSize: n). cs: s size. result keysDo: [| :index | result at: index put: index // cs]. result ]. c@(Sequence traits) choose: k of: n into: workingArray do: block "Execute the block on all the combinations of size k out of the sequence. This uses a single array as an iterator object which should not be modified by the client code." [ n < k ifTrue: [^ c]. k = 0 ifTrue: [^ (block applyWith: workingArray)]. workingArray at: k put: (c at: n). c choose: k - 1 of: n - 1 into: workingArray do: block. c choose: k of: n - 1 into: workingArray do: block. ]. c@(Sequence traits) choose: n do: block "Execute the block on all the combinations of size N out of the sequence. This uses a single array as an iterator object which should not be modified by the client code." [| workingArray | workingArray: (Array newSize: n). c choose: n of: c size into: workingArray do: block ]. c@(Sequence traits) collect: block [ c collectWithIndex: [| :each :_ | block applyWith: each] into: c newSameSize ]. c@(Sequence traits) collect: block from: start to: end [| result size j | size: end - start + 1. result: (c newSize: size). j: start. result keysDo: [| :index | result at: index put: (block applyWith: (c at: j)). j: j + 1]. result ]. c@(Sequence traits) collectWithIndex: binBlock "binBlock should take :element and :index." [ c collectWithIndex: binBlock into: c newSameSize ]. c@(Sequence traits) do: block [ c isEmpty ifTrue: [^ c]. 0 below: c size do: [| :index | block applyWith: (c at: index)]. c ]. c@(Sequence traits) do: block separatedBy: sepBlock "Run the separator block between applying the block to each element." [ c isEmpty ifTrue: [^ c] ifFalse: [block applyWith: c first]. 1 below: c size do: [| :index | sepBlock do. block applyWith: (c at: index)]. c ]. c@(Sequence traits) do: block ifNotEqualTo: obj [ c do: [| :each | each = obj ifFalse: [block applyWith: each]]. c ]. c@(Sequence traits) allButFirst: n do: block "Apply the block to all elements but the first N in the Sequence." [ c from: n to: c size - 1 do: block ]. c@(Sequence traits) allButFirstDo: block [ c allButFirst: 1 do: block ]. c@(Sequence traits) allButLast: n do: block "Apply the block to all but the last N members of the Sequence." [ n >= c size ifTrue: [^ Nil]. c from: 0 to: c size - n - 1 do: block ]. c@(Sequence traits) allButLastDo: block [ c allButLast: 1 do: block ]. c@(Sequence traits) doWithIndex: binBlock "binBlock takes :each object and its :index." [ c isEmpty ifTrue: [^ c]. 0 below: c size do: [| :index | binBlock applyWith: (c at: index) with: index]. c ]. c@(Sequence traits) collectWithIndex: binBlock into: seq "Runs doWithIndex: on binBlock, collecting results implicitly into the other Sequence at the same locations as the arguments, and returning that result." [ c doWithIndex: [| :each :index | seq at: index put: (binBlock applyWith: each with: index)]. seq ]. c@(Sequence traits) do: block every: step "Invoke the block on every n'th argument." [ c do: block every: step startingAt: 0 ]. c@(Sequence traits) do: block every: step startingAt: start "Invoke the block on every n'th argument, starting at a particular index." [| index steps | c isEmpty ifTrue: [^ c]. index: start. steps: (c size - start) // step. steps timesRepeat: [| :iter | block applyWith: (c at: index). index: index + step]. c ]. c@(Sequence traits) do: block inGroupsOf: arity "Send the elements of the target to the block in the number of its arity. If fewer than that are remaining, abort and return." [ c do: block inGroupsOf: arity startingAt: 0 ]. c@(Sequence traits) do: block inGroupsOf: arity startingAt: start "Send the elements of the target to the block in the number of its arity, beginning with a given index. If fewer than that are remaining, abort and return." [| index steps | index: start. steps: (c size - start) // arity. steps timesRepeat: [ block applyTo: (c copyFrom: index to: index + arity - 1). index: index + arity]. c ]. c@(Sequence traits) indexOfFirstSatisfying: block "Find the index of the first occurrence of an object satisfying the block." [ c doWithIndex: [| :obj :index | (block applyWith: obj) ifTrue: [^ index]]. Nil ]. c@(Sequence traits) indexOfLastSatisfying: block "Find the index of the last occurrence of an object satisfying the block." [ c reverseDoWithIndex: [| :obj :index | (block applyWith: obj) ifTrue: [^ index]]. Nil ]. c@(Sequence traits) firstSatisfying: block "Answer the first occurrence of an object satisfying the block." [c at: ((c indexOfFirstSatisfying: block) ifNil: [^ Nil])]. c@(Sequence traits) lastSatisfying: block "Answer the last occurrence of an object satisfying the block." [c at: ((c indexOfLastSatisfying: block) ifNil: [^ Nil])]. c@(Sequence traits) from: start to: end do: block [ c isEmpty ifTrue: [^ c]. start to: end do: [| :index | block applyWith: (c at: index)]. c ]. c@(Sequence traits) reverseDoWithIndex: block "The reverse performance of doWithIndex: of course." [ c size - 1 downTo: 0 do: [| :index | block applyWith: (c at: index) with: index]. c ]. c@(Sequence traits) reverseDo: block "The reverse performance of do:." [ c size - 1 downTo: 0 do: [| :index | block applyWith: (c at: index)]. c ]. c@(Sequence traits) reverseWith: d do: block "The reverse performance of with:do:." [| cs | (cs: c size) ~= d size ifTrue: [^ Nil]. cs downTo: 0 do: [| :index | block applyWith: (c at: index) with: (d at: index)]. c ]. c@(Sequence traits) select: block [| result | result: c newSameSize. c doWithIndex: [| :each :index | (block applyWith: each) ifTrue: [result at: index put: each]]. result ]. c@(Sequence traits) with: d@(Sequence traits) collect: binBlock "Collect the result from applying the block to as many pairs of elements from each Sequence as possible." [| newC | newC: (c newSize: (c size min: d size)). newC keysDo: [| :index | newC at: index put: (binBlock applyWith: (c at: index) with: (d at: index))]. newC ]. c@(Sequence traits) with: d@(Sequence traits) do: binBlock "Apply the block to as many pairs of elements from each Sequence as possible." [| cs | 0 below: (c size min: d size) do: [| :index | binBlock applyWith: (c at: index) with: (d at: index)]. c ]. prefix@(Sequence traits) isPrefixOf: seq@(Sequence traits) "Answer whether the first elements of the Sequence match the potential prefix Sequence's elements in order." [ prefix size <= seq size ifFalse: [^ False]. prefix doWithIndex: [| :each :index | each = (seq at: index) ifFalse: [^ False]]. True ]. c@(Sequence traits) reversed "Answer a new Sequence with the element order reversed." [| cs newC srcIdx | cs: c size. newC: (c newSize: cs). srcIdx: cs. 0 below: cs do: [| :destIdx | newC at: destIdx put: (c at: (srcIdx: (srcIdx - 1)))]. newC ]. a@(Sequence traits) isSortedBy: block "Whether the elements in the Sequence are arranged in order by the block comparison." [| lastObj obj | a isEmpty ifTrue: [^ True]. lastObj: a first. 1 below: a size do: [| :index | obj: (a at: index). (block applyWith: lastObj with: obj) ifFalse: [^ False]. lastObj: obj]. True ]. s@(Sequence traits) sortFrom: start to: end by: block "Perform a quick-sort within the start/end bounds using the sort block." [| low high pivot | start >= end ifTrue: [^ s]. low: start. high: end. pivot: (s at: start). [low < high] whileTrue: [[low >= high or: [block applyWith: pivot with: (s at: low)]] whileFalse: [low: low + 1]. [low < high and: [block applyWith: pivot with: (s at: high)]] whileTrue: [high: high - 1]. low < high ifTrue: [s swap: low with: high]]. low > start ifTrue: [(block applyWith: (s at: low - 1) with: (s at: low)) ifFalse: [s swap: low with: low - 1]. s sortFrom: start to: low - 1]. low < end ifTrue: [(block applyWith: (s at: low + 1) with: (s at: low)) ifTrue: [s swap: low with: low + 1]. s sortFrom: low + 1 to: end]. s ]. a@(Sequence traits) sort: block "Sort the elements by a binary block comparison. Perform a quick-sort by default. The sense of the block is that it should return the equivalent of <=: whether the first element not greater than the second." [ a sortFrom: 0 to: a size - 1 by: block ]. a@(Sequence traits) sort "The default comparison given to sort the Sequence's elements." [ a sort: [| :x :y | x <= y] ]. x caseOf: cases@(Sequence traits) otherwise: block "A Sequence of Associations between Objects and Blocks is used as a control structure. Matching against the first argument causes the respective block to be evaluated and its result returned. If none match, an alternative block is provided." [ cases do: [| :assoc | assoc key = x ifTrue: [^ assoc value do]]. block do ]. x caseOf: cases@(Sequence traits) "Executes the case-switching logic with a null alternative block." [ x caseOf: cases otherwise: [] ]. c@(Collection traits) collect: block into: seq@(Sequence traits) "Specialized to handle sequences which are not Extensible. This returns a result of applying the block to each element, which may not be the given Sequence if it was not of the right size." [| result | result: (seq capacity = c size ifTrue: [seq] ifFalse: [seq newSizeOf: c]). c collectWithIndex: [| :each :_ | block applyWith: each] into: result ]. collections addPrototype: #SubSequence derivedFrom: {Sequence}. "Represents a section/slice of a Sequence without allocating a new Sequence." SubSequence addSlot: #start valued: 0. "The index within the source of the first element of the SubSequence." SubSequence addSlot: #end valued: 0. "The index within the source following the last element of the SubSequence." SubSequence addSlot: #sequence. "The source of the elements." c@(Sequence traits) sliceFrom: start below: end [| newSS | newSS: SubSequence clone. start <= end ifFalse: [error: 'This results in a negative size.']. newSS sequence: c. newSS start: start. newSS end: end. newSS ]. c@(Sequence traits) sliceFrom: start to: end "Slice the range from the start through the end index." [c sliceFrom: start below: end + 1]. c@(Sequence traits) sliceFrom: start "Slice the range from the start through the Sequence's end." [c sliceFrom: start below: c size]. c@(Sequence traits) sliceUpTo: end "Slice the beginning up to but not including the end index." [c sliceFrom: 0 below: end]. c@(Sequence traits) sliceEndAbove: end [c sliceFrom: c size - end]. ss@(SubSequence traits) size [ ss end - ss start ]. ss@(SubSequence traits) at: index [ ss sequence at: index + ss start ]. ss@(SubSequence traits) at: index put: obj [ ss sequence at: index + ss start put: obj ]. ss@(SubSequence traits) do: block [ ss start below: ss end do: [| :index | block applyWith: (ss sequence at: index)]. ss ]. ss@(SubSequence traits) reverseDo: block [ ss end - 1 downTo: ss start do: [| :index | block applyWith: (ss sequence at: index)]. ss ]. ss@(SubSequence traits) doWithIndex: binBlock [ ss start below: ss end do: [| :index | binBlock applyWith: (ss sequence at: index) with: index]. ss ]. ss@(SubSequence traits) ; seq "An override to provide correct concatenation behavior." [| newS midpt | midpt: ss size. newS: (seq newSize: midpt + seq size). newS replaceFrom: 0 to: midpt - 1 with: ss startingAt: 0. newS replaceFrom: midpt to: newS size - 1 with: seq startingAt: 0. newS ]. seq@(Sequence traits) ; ss@(SubSequence traits) [ss ; seq]. c@(SubSequence traits) copyFrom: start to: end [| newSize | (c arrayType newSize: (newSize: end - start + 1)) replaceFrom: 0 to: newSize - 1 with: c startingAt: start ]. collections addPrototype: #Repetition derivedFrom: {Sequence}. "A Repetition is a Sequence of the same element repeated over its length." Repetition addSlot: #number. "The number of times the element occurs." Repetition addSlot: #element. "The repeated element." r@(Repetition traits) newSize: n [| newR | newR: r clone. newR element: Nil. newR number: n. newR ]. r@(Repetition traits) newFor: obj sized: n [| newR | newR: r clone. newR element: obj. newR number: n. newR ]. obj@(Root traits) repeatedTimes: n "Convenient syntax to instantiate it." [Repetition newFor: obj sized: n]. r@(Repetition traits) size [ r number ]. r@(Repetition traits) at: index [ (index between: 0 and: r number) ifTrue: [r element] ]. r@(Repetition traits) at: index put: obj [ r element ifNil: [r element: obj] ifNotNil: [error: 'An attempt was made to modify a Repetition.'] ]. r@(Repetition traits) do: block [ r number timesRepeat: [block applyWith: r element] ].