-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathCollections.cs
3844 lines (3030 loc) · 129 KB
/
Collections.cs
1
'From Pharo4.0 of 18 March 2013 [Latest update: #40152] on 7 August 2014 at 2:21:37.309017 pm'!Object subclass: #Collection instanceVariableNames: '' classVariableNames: 'MutexForPicking RandomForPicking' poolDictionaries: '' category: 'Collections-Abstract'!HashedCollection subclass: #Dictionary instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Collections-Unordered'!Collection class instanceVariableNames: ''!Dictionary class instanceVariableNames: ''!String subclass: #Symbol instanceVariableNames: '' classVariableNames: 'NewSymbols OneCharacterSymbols SymbolTable' poolDictionaries: '' category: 'Collections-Strings'!Symbol class instanceVariableNames: ''!SequenceableCollection subclass: #OrderedCollection instanceVariableNames: 'array firstIndex lastIndex' classVariableNames: '' poolDictionaries: '' category: 'Collections-Sequenceable'!OrderedCollection class uses: TSortable classTrait instanceVariableNames: ''!Object subclass: #Stream instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Collections-Streams'!Stream class instanceVariableNames: ''!!Collection methodsFor: '*metacello-core-scripting' stamp: 'dkh 9/5/2012 06:26:03.064'!execute: projectSpecBlock against: aScriptExecutor aScriptExecutor executeCollection: self do: projectSpecBlock! !!Collection methodsFor: 'testing' stamp: 'EstebanLorenzano 8/17/2012 16:40'!includesSubstringAnywhere: testString "Answer whether the receiver includes, anywhere in its nested structure, a string that has testString as a substring" self do: [:element | (element isString) ifTrue: [(element includesSubstring: testString) ifTrue: [^ true]]. (element isCollection) ifTrue: [(element includesSubstringAnywhere: testString) ifTrue: [^ true]]]. ^ false"#(first (second third) ((allSentMessages ('Elvis' includes:)))) includesSubstringAnywhere: 'lvi'"! !!Collection methodsFor: 'testing'!contains: aBlock "VW compatibility" ^self anySatisfy: aBlock! !!Collection methodsFor: 'testing' stamp: 'ClementBera 12/2/2013 12:41'!includesAllOf: aCollection self flag: 'use includesAll: instead'. ^ self includesAll: aCollection.! !!Collection methodsFor: 'testing' stamp: 'CamilloBruni 9/8/2011 14:18'!includesAny: aCollection "Answer whether any element of aCollection is one of the receiver's elements." aCollection do: [:elem | (self includes: elem) ifTrue: [^ true]]. ^ false! !!Collection methodsFor: 'testing' stamp: 'ls 3/27/2000 17:25'!identityIncludes: anObject "Answer whether anObject is one of the receiver's elements." self do: [:each | anObject == each ifTrue: [^true]]. ^false! !!Collection methodsFor: 'testing' stamp: 'StephaneDucasse 7/3/2010 22:15'!ifEmpty: aBlock "Evaluate the given block with the receiver as argument, answering its value if the receiver is empty, otherwise answer the receiver." "Note that the fact that this method returns its argument in case the receiver is not empty allows one to write expressions like the following ones: self classifyMethodAs: (myProtocol ifEmpty: ['As yet unclassified'])" ^ self isEmpty ifTrue: [ ^aBlock value ] ifFalse: [ self ]! !!Collection methodsFor: 'testing' stamp: 'HenrikSperreJohansen 6/28/2010 12:13'!ifEmpty: emptyBlock ifNotEmpty: notEmptyBlock "Evaluate emptyBlock if I'm empty, notEmptyBlock otherwise" " If the notEmptyBlock has an argument, eval with the receiver as its argument" self isEmpty ifTrue: [ ^emptyBlock value ]. ^notEmptyBlock cull: self! !!Collection methodsFor: 'testing' stamp: 'StephaneDucasse 7/3/2010 22:10'!ifNotEmpty: aBlock "Evaluate the given block with the receiver as argument, answering its value unless the receiver is empty, in which case answer the receiver If the block has an argument, eval with the receiver as its argument, but it might be better to use ifNotEmptyDo: to make the code easier to understand" "Note that the fact that this method returns its argument in case the receiver is empty allows one to write expressions like the following ones: self classifyMethodAs: (myProtocol ifEmpty: ['As yet unclassified']" ^self isEmpty ifTrue: [self] ifFalse: [aBlock cull: self]! !!Collection methodsFor: 'testing' stamp: 'ar 11/21/2009 00:36'!ifNotEmptyDo: aBlock "Evaluate the given block with the receiver as its argument." self isEmpty ifFalse: [^ aBlock value: self].! !!Collection methodsFor: 'testing' stamp: 'sma 5/12/2000 14:07'!includes: anObject "Answer whether anObject is one of the receiver's elements." ^ self anySatisfy: [:each | each = anObject]! !!Collection methodsFor: 'testing' stamp: 'ul 11/11/2009 16:24'!ifEmpty: emptyBlock ifNotEmptyDo: notEmptyBlock "Evaluate emptyBlock if I'm empty, notEmptyBlock otherwise" "Evaluate the notEmptyBlock with the receiver as its argument" self isEmpty ifTrue: [ ^emptyBlock value ]. ^notEmptyBlock value: self! !!Collection methodsFor: 'testing'!isEmpty "Answer whether the receiver contains any elements." ^self size = 0! !!Collection methodsFor: 'testing' stamp: 'bf 3/10/2000 09:29'!isEmptyOrNil "Answer whether the receiver contains any elements, or is nil. Useful in numerous situations where one wishes the same reaction to an empty collection or to nil" ^ self isEmpty! !!Collection methodsFor: 'testing'!occurrencesOf: anObject "Answer how many of the receiver's elements are equal to anObject." | tally | tally := 0. self do: [:each | anObject = each ifTrue: [tally := tally + 1]]. ^tally! !!Collection methodsFor: 'testing' stamp: 'di 11/6/1998 09:16'!isSequenceable ^ false! !!Collection methodsFor: 'testing' stamp: 'ul 11/11/2009 16:25'!ifNotEmptyDo: notEmptyBlock ifEmpty: emptyBlock "Evaluate emptyBlock if I'm empty, notEmptyBlock otherwise Evaluate the notEmptyBlock with the receiver as its argument" self isEmpty ifFalse: [ ^notEmptyBlock value: self ]. ^emptyBlock value! !!Collection methodsFor: 'testing' stamp: 'CamilloBruni 9/8/2011 14:20'!includesAnyOf: aCollection self flag: 'use includesAny: instead'. ^ self includesAny: aCollection. ! !!Collection methodsFor: 'testing' stamp: 'MarcusDenker 7/17/2013 13:15'!isNotEmpty "Answer whether the receiver contains any elements." ^ self isEmpty not! !!Collection methodsFor: 'testing' stamp: 'CamilloBruni 9/8/2011 14:18'!includesAll: aCollection "Answer whether all the elements of aCollection are in the receiver." aCollection do: [:elem | (self includes: elem) ifFalse: [^ false]]. ^ true! !!Collection methodsFor: 'testing' stamp: 'ar 8/17/1999 19:43'!isCollection "Return true if the receiver is some sort of Collection and responds to basic collection messages such as #size and #do:" ^true! !!Collection methodsFor: 'testing' stamp: 'MarcusDenker 7/17/2013 13:16'!notEmpty "Answer whether the receiver contains any elements." "use isNotEmpty for consistency with isEmpty" ^ self isEmpty not! !!Collection methodsFor: 'testing' stamp: 'HenrikSperreJohansen 6/28/2010 12:14'!ifNotEmpty: notEmptyBlock ifEmpty: emptyBlock "Evaluate emptyBlock if I'm empty, notEmptyBlock otherwise If the notEmptyBlock has an argument, eval with the receiver as its argument" self isEmpty ifFalse: [ ^notEmptyBlock cull: self ]. ^emptyBlock value! !!Collection methodsFor: '*Morphic-Base-Basic' stamp: 'CamilloBruni 10/21/2012 23:39'!asDraggableMorph ^ (String streamContents: [ :s| self do: [ :each | s print: each ] separatedBy: [ s space ]]) asStringMorph! !!Collection methodsFor: 'comparing' stamp: 'SqR 8/3/2000 13:36'!hash "Answer an integer hash value for the receiver such that, -- the hash value of an unchanged object is constant over time, and -- two equal objects have equal hash values" | hash | hash := self species hash. self size <= 10 ifTrue: [self do: [:elem | hash := hash bitXor: elem hash]]. ^hash bitXor: self size hash! !!Collection methodsFor: 'enumerating' stamp: 'CamilloBruni 3/23/2013 10:46'!reject: rejectBlock thenDo: doBlock "Utility method to improve readability." (self reject: rejectBlock) do: doBlock! !!Collection methodsFor: 'enumerating' stamp: 'SebastianTleye 6/25/2013 18:41'!flattened "Flattens a collection of collections (no matter how many levels of collections exist). Strings are considered atoms and, as such, won't be flattened Examples: #(1 #(2 3) #(4 (#5))) flattened returns #(1 2 3 4 5) #('string1' #('string2' 'string3')) flattened returns #('string1' 'string2' 'string3')" ^ Array streamContents: [ :stream | self flattenOn: stream].! !!Collection methodsFor: 'enumerating' stamp: 'nice 1/5/2010 15:59'!detectMin: aBlock "Evaluate aBlock with each of the receiver's elements as the argument. Answer the element for which aBlock evaluates to the lowest number. If collection empty, return nil." | minElement minValue | self do: [:each | | val | minValue == nil ifFalse: [ (val := aBlock value: each) < minValue ifTrue: [ minElement := each. minValue := val]] ifTrue: ["first element" minElement := each. minValue := aBlock value: each]. "Note that there is no way to get the first element that works for all kinds of Collections. Must test every one."]. ^ minElement! !!Collection methodsFor: 'enumerating' stamp: 'GabrielOmarCotelli 11/26/2013 17:15'!detect: aBlock ifNone: exceptionBlock "Evaluate aBlock with each of the receiver's elements as the argument. Answer the first element for which aBlock evaluates to true. If none evaluate to true, then evaluate the argument, exceptionBlock." ^ self detect: aBlock ifFound: [ :element | element ] ifNone: exceptionBlock! !!Collection methodsFor: 'enumerating' stamp: 'sma 5/12/2000 11:57'!do: elementBlock separatedBy: separatorBlock "Evaluate the elementBlock for all elements in the receiver, and evaluate the separatorBlock between." | beforeFirst | beforeFirst := true. self do: [:each | beforeFirst ifTrue: [beforeFirst := false] ifFalse: [separatorBlock value]. elementBlock value: each]! !!Collection methodsFor: 'enumerating' stamp: 'sma 4/30/2000 11:17'!anySatisfy: aBlock "Evaluate aBlock with the elements of the receiver. If aBlock returns true for any element return true. Otherwise return false." self do: [:each | (aBlock value: each) ifTrue: [^ true]]. ^ false! !!Collection methodsFor: 'enumerating' stamp: 'TudorGirba 3/20/2012 09:07'!intersection: aCollection "Answer the set theoretic intersection of two collections." | set outputSet | set := self asSet. outputSet := Set new. aCollection do: [ :each| ((set includes: each) and: [(outputSet includes: each) not]) ifTrue: [ outputSet add: each]]. ^ self species withAll: outputSet asArray! !!Collection methodsFor: 'enumerating' stamp: 'nice 12/9/2009 15:37'!findFirstInByteString: aByteString startingAt: start "Find the index of first character starting at start in aByteString that is included in the receiver. Default is to use a naive algorithm. Subclasses might want to implement a more efficient scheme" start to: aByteString size do: [:index | (self includes: (aByteString at: index)) ifTrue: [^ index]]. ^ 0! !!Collection methodsFor: 'enumerating' stamp: 'CamilloBruni 3/22/2013 22:09'!reject: rejectBlock thenCollect: collectBlock "Utility method to improve readability." ^ (self reject: rejectBlock) collect: collectBlock! !!Collection methodsFor: 'enumerating' stamp: 'sma 4/30/2000 11:17'!allSatisfy: aBlock "Evaluate aBlock with the elements of the receiver. If aBlock returns false for any element return false. Otherwise return true." self do: [:each | (aBlock value: each) ifFalse: [^ false]]. ^ true! !!Collection methodsFor: 'enumerating' stamp: 'CamilloBruni 3/22/2013 22:30'!collect: collectBlock thenReject: selectBlock "Utility method to improve readability." ^ (self collect: collectBlock) reject: selectBlock! !!Collection methodsFor: 'enumerating' stamp: 'StephaneDucasse 1/3/2010 20:15'!groupBy: keyBlock having: selectBlock "This message is deprecated. Please use groupedBy:having:. But we let it right now without warning because we are not sure to remove in the next iteration." ^ self groupedBy: keyBlock having: selectBlock ! !!Collection methodsFor: 'enumerating' stamp: 'StephaneDucasse 1/2/2012 21:08'!reduce: aBlock "Fold the result of the receiver into aBlock. The argument aBlock must take two or more arguments. It applies the argument, binaryBlock cumulatively to the elements of the receiver. For sequenceable collections the elements will be used in order, for unordered collections the order is unspecified." "#(1 2 3) asSet reduce: [ :a :b | a + b ] --> 1 + 2 + 3 = 6 #(1 2 3 4 5) asSet reduce: [ :a :b :c | a + b + c ] --> 1 + 2 + 3 + 4 + 5 = 15" ^self asOrderedCollection reduce: aBlock! !!Collection methodsFor: 'enumerating' stamp: 'CamilloBruni 3/22/2013 22:32'!reject: aBlock "Evaluate aBlock with each of the receiver's elements as the argument. Collect into a new collection like the receiver only those elements for which aBlock evaluates to false. Answer the new collection." ^self select: [ :element | (aBlock value: element) == false ]! !!Collection methodsFor: 'enumerating' stamp: 'jannik.laval 8/27/2010 15:54'!flatCollect: aBlock as: aCollectionClass "Evaluate aBlock for each of the receiver's elements and answer the list of all resulting values flatten one level. Assumes that aBlock returns some kind of collection for each element. Equivalent to the lisp's mapcan" | col | self isEmpty ifTrue: [^self copy ]. col := aCollectionClass new: self size. self do: [ :each | col addAll: (aBlock value: each) ]. ^col! !!Collection methodsFor: 'enumerating' stamp: 'ST 6/23/2013 11:33'!gather: aBlock "This method is kept for compatibility reasons, use flatCollect instead." ^ self flatCollect: aBlock.! !!Collection methodsFor: 'enumerating' stamp: 'TudorGirba 11/3/2013 12:12'!flatCollect: aBlock "Evaluate aBlock for each of the receiver's elements and answer the list of all resulting values flatten one level. Assumes that aBlock returns some kind of collection for each element. Equivalent to the lisp's mapcan" | stream | self isEmpty ifTrue: [ ^ self copy ]. stream := (self species new: 0) writeStream. self do: [ :each | stream nextPutAll: (aBlock value: each) ]. ^ stream contents! !!Collection methodsFor: 'enumerating'!detectSum: aBlock "Evaluate aBlock with each of the receiver's elements as the argument. Return the sum of the answers." | sum | sum := 0. self do: [:each | sum := (aBlock value: each) + sum]. ^ sum! !!Collection methodsFor: 'enumerating' stamp: 'AdrianKuhn 12/30/2009 09:37'!groupedBy: aBlock having: aSelectionBlock "Like in SQL operation - Split the recievers contents into collections of elements for which keyBlock returns the same results, and return those collections allowed by selectBlock." ^ (self groupedBy: aBlock) select: aSelectionBlock! !!Collection methodsFor: 'enumerating' stamp: 'CamilloBruni 9/7/2011 19:24'!\ aCollection ^ self difference: aCollection! !!Collection methodsFor: 'enumerating' stamp: 'BenComan 3/20/2014 00:00'!do: aBlock displayingProgress: aStringOrBlock every: msecs "Enumerate aBlock displaying progress information. If the argument is a string, use a static label for the process. If the argument is a block, evaluate it with the element to retrieve the label. The msecs argument ensures that updates happen at most every msecs. Example: Smalltalk allClasses do:[:aClass| (Delay forMilliseconds: 1) wait] displayingProgress:[:aClass| 'Processing ', aClass name] every: 0." | size labelBlock count oldLabel lastUpdate | self isEmpty ifTrue: [ ^ self ]. oldLabel := nil. count := lastUpdate := 0. size := self size. '' displayProgressFrom: 0 to: size during: [:bar | labelBlock := aStringOrBlock isString ifTrue: [ bar label: aStringOrBlock. [ :dummyItem | aStringOrBlock]] ifFalse: [aStringOrBlock]. self do: [:each| | newLabel | "Special handling for first and last element" (count = 0 or: [count+1 = size or: [(Time millisecondsSince: lastUpdate) >= msecs]]) ifTrue: [ bar current: count. oldLabel = (newLabel := (labelBlock cull: each) ifNil: [oldLabel]) ifFalse: [ bar label: newLabel. ProgressNotification signal: '' extra: (oldLabel := newLabel) ]. lastUpdate := Time millisecondClockValue ]. aBlock value: each. count := count + 1]]! !!Collection methodsFor: 'enumerating'!associationsDo: aBlock "Evaluate aBlock for each of the receiver's elements (key/value associations). If any non-association is within, the error is not caught now, but later, when a key or value message is sent to it." self do: aBlock! !!Collection methodsFor: 'enumerating' stamp: 'AdrianKuhn 12/30/2009 09:36'!groupedBy: aBlock "Answer a dictionary whose keys are the result of evaluating aBlock for all my elements, and the value for each key is the selection of my elements that evaluated to that key. Uses species." | groups | groups := PluggableDictionary integerDictionary. self do: [ :each | (groups at: (aBlock value: each) ifAbsentPut: [ OrderedCollection new ]) add: each ]. self species ~~ OrderedCollection ifTrue: [ groups associationsDo: [ :association | association value: (self species withAll: association value) ]]. ^ groups! !!Collection methodsFor: 'enumerating' stamp: 'ST 6/19/2013 18:29'!flattenOn: aStream self do: [ :each | (each isCollection and: [each isString not]) ifTrue: [each flattenOn: aStream] ifFalse: [aStream nextPut: each]].! !!Collection methodsFor: 'enumerating'!do: aBlock "Evaluate aBlock with each of the receiver's elements as the argument." self subclassResponsibility! !!Collection methodsFor: 'enumerating' stamp: 'GabrielOmarCotelli 11/26/2013 16:53'!detect: aBlock ifFound: foundBlock "Evaluate aBlock with each of the receiver's elements as the argument. If some element evaluates aBlock to true, then cull this element into foundBlock. If no element matches the criteria then do nothing. Always returns self to avoid misuse and a potential isNil check on the sender." self detect: aBlock ifFound: foundBlock ifNone: [ "Do nothing on purpose" ]! !!Collection methodsFor: 'enumerating' stamp: 'StephaneDucasse 2/4/2010 15:34'!do: aBlock displayingProgress: aStringOrBlock "Enumerate aBlock displaying progress information. If the argument is a string, use a static label for the process. If the argument is a block, evaluate it with the element to retrieve the label. Smalltalk allClasses do:[:aClass| (Delay forMilliseconds: 1) wait] displayingProgress: 'Processing...'. Smalltalk allClasses do:[:aClass| (Delay forMilliseconds: 1) wait] displayingProgress:[:aClass| 'Processing ', aClass name]. " ^self do: aBlock displayingProgress: aStringOrBlock every: 20! !!Collection methodsFor: 'enumerating' stamp: 'sma 5/12/2000 11:45'!collect: aBlock "Evaluate aBlock with each of the receiver's elements as the argument. Collect the resulting values into a collection like the receiver. Answer the new collection." | newCollection | newCollection := self species new. self do: [:each | newCollection add: (aBlock value: each)]. ^ newCollection! !!Collection methodsFor: 'enumerating' stamp: 'nice 1/5/2010 15:59'!detectMax: aBlock "Evaluate aBlock with each of the receiver's elements as the argument. Answer the element for which aBlock evaluates to the highest magnitude. If collection empty, return nil. This method might also be called elect:." | maxElement maxValue | self do: [:each | | val | maxValue == nil ifFalse: [ (val := aBlock value: each) > maxValue ifTrue: [ maxElement := each. maxValue := val]] ifTrue: ["first element" maxElement := each. maxValue := aBlock value: each]. "Note that there is no way to get the first element that works for all kinds of Collections. Must test every one."]. ^ maxElement! !!Collection methodsFor: 'enumerating' stamp: 'sma 5/12/2000 11:51'!collect: collectBlock thenSelect: selectBlock "Utility method to improve readability." ^ (self collect: collectBlock) select: selectBlock! !!Collection methodsFor: 'enumerating' stamp: 'CamilloBruni 9/7/2011 19:23'!& aCollection ^ self intersection: aCollection! !!Collection methodsFor: 'enumerating' stamp: 'CamilloBruni 3/22/2013 22:18'!collect: collectBlock thenDo: doBlock "Utility method to improve readability." ^ self do: [ :each| doBlock value: (collectBlock value: each)]! !!Collection methodsFor: 'enumerating' stamp: 'gh 9/18/2001 15:59'!noneSatisfy: aBlock "Evaluate aBlock with the elements of the receiver. If aBlock returns false for all elements return true. Otherwise return false" self do: [:item | (aBlock value: item) ifTrue: [^ false]]. ^ true! !!Collection methodsFor: 'enumerating' stamp: 'sma 5/12/2000 11:59'!select: selectBlock thenCollect: collectBlock "Utility method to improve readability." ^ (self select: selectBlock) collect: collectBlock! !!Collection methodsFor: 'enumerating' stamp: 'ul 11/21/2009 01:16'!collect: aBlock as: aClass "Evaluate aBlock with each of the receiver's elements as the argument. Collect the resulting values into an instance of aClass. Answer the resulting collection." ^(aClass new: self size) fillFrom: self with: aBlock! !!Collection methodsFor: 'enumerating' stamp: 'sma 5/12/2000 11:20'!detect: aBlock "Evaluate aBlock with each of the receiver's elements as the argument. Answer the first element for which aBlock evaluates to true." ^ self detect: aBlock ifNone: [self errorNotFound: aBlock]! !!Collection methodsFor: 'enumerating' stamp: 'GabrielOmarCotelli 11/26/2013 16:53'!detect: aBlock ifFound: foundBlock ifNone: exceptionBlock "Evaluate aBlock with each of the receiver's elements as the argument. If some element evaluates aBlock to true, then cull this element into foundBlock and answer the result of this evaluation. If none evaluate to true, then evaluate exceptionBlock." self do: [ :each | (aBlock value: each) ifTrue: [ ^ foundBlock cull: each ] ]. ^ exceptionBlock value ! !!Collection methodsFor: 'enumerating' stamp: 'StephaneDucasse 2/1/2011 07:34'!fold: binaryBlock "Evaluate the block with the first two elements of the receiver, then with the result of the first evaluation and the next element, and so on. Answer the result of the final evaluation. If the receiver is empty, raise an error. If the receiver has a single element, answer that element." "#('if' 'it' 'is' 'to' 'be' 'it' 'is' 'up' 'to' 'me') fold: [:a :b | a, ' ', b]" ^self reduce: binaryBlock! !!Collection methodsFor: 'enumerating' stamp: 'sma 5/12/2000 11:52'!count: aBlock "Evaluate aBlock with each of the receiver's elements as the argument. Answer the number of elements that answered true." | sum | sum := 0. self do: [:each | (aBlock value: each) ifTrue: [sum := sum + 1]]. ^ sum! !!Collection methodsFor: 'enumerating' stamp: 'sma 5/12/2000 11:59'!do: aBlock without: anItem "Enumerate all elements in the receiver. Execute aBlock for those elements that are not equal to the given item" ^ self do: [:each | anItem = each ifFalse: [aBlock value: each]]! !!Collection methodsFor: 'enumerating' stamp: 'CamilloBruni 9/7/2011 19:24'!| aCollection ^ self union: aCollection! !!Collection methodsFor: 'enumerating' stamp: 'StephaneDucasse 5/20/2012 18:50'!piecesCutWhere: binaryBlock do: pieceBlock "Evaluate pieceBlock with substrings of the receiver derived from cutting the receiver at points where binaryBlock answers true for adjacent elements." | size lastCut this next | (size := self size) <= 1 ifTrue: [size = 1 ifTrue: [pieceBlock value: self]. ^self]. lastCut := 1. this := self at: 1. 2 to: size do: [:i| next := self at: i. (binaryBlock value: this value: next) ifTrue: [pieceBlock value: (self copyFrom: lastCut to: i - 1). lastCut := i]. this := next]. pieceBlock value: (self copyFrom: lastCut to: size)! !!Collection methodsFor: 'enumerating' stamp: 'TudorGirba 3/20/2012 09:06'!union: aCollection "Answer the set theoretic union of two collections." | set | set := self asSet addAll: aCollection; yourself. ^ self species withAll: set asArray! !!Collection methodsFor: 'enumerating' stamp: 'TudorGirba 11/3/2013 12:12'!flatCollectAsSet: aBlock "Evaluate aBlock for each of the receiver's elements and answer the list of all resulting values flatten one level. Assumes that aBlock returns some kind of collection for each element. Equivalent to the lisp's mapcan" ^ self flatCollect: aBlock as: Set! !!Collection methodsFor: 'enumerating' stamp: 'CamilloBruni 3/22/2013 22:20'!piecesCutWhere: binaryBlock "Answer substrings of the receiver derived from cutting the receiver at points where binaryBlock answers true for adjacent elements." | pieces | pieces := OrderedCollection new. self piecesCutWhere: binaryBlock do: [ :piece | pieces add: piece ]. ^pieces "'Now is the time for all good people to come to the aid of the cause of world peace. It is just fine, even desirable, to love your country, if that means wanting it to play a beneficial role in the course of world events and be the best possible example of a good society. But if it means wanting dominion over the rest of the world, it is not love but defensiveness or self-glorification, and will lead only to oblivion.' piecesCutWhere: [:a :b| a = $. and: [b isSeparator]]"! !!Collection methodsFor: 'enumerating' stamp: 'hfm 2/12/2009 13:38'!select: selectBlock thenDo: doBlock "Utility method to improve readability. Do not create the intermediate collection." self do: [: each | ( selectBlock value: each ) ifTrue: [ doBlock value: each ] ].! !!Collection methodsFor: 'enumerating' stamp: 'ul 11/21/2009 01:16'!collect: aBlock into: aCollection "Evaluate aBlock with each of the receiver's elements as the argument. Collect the resulting values into aCollection. Answer aCollection." ^aCollection fillFrom: self with: aBlock! !!Collection methodsFor: 'enumerating' stamp: 'CamilloBruni 10/20/2012 21:50'!select: aBlock "Evaluate aBlock with each of the receiver's elements as the argument. Collect into a new collection like the receiver, only those elements for which aBlock evaluates to true. Answer the new collection." | newCollection | newCollection := self copyEmpty. self do: [ :each | (aBlock value: each) ifTrue: [ newCollection add: each ]]. ^newCollection! !!Collection methodsFor: 'enumerating'!inject: thisValue into: binaryBlock "Accumulate a running value associated with evaluating the argument, binaryBlock, with the current value of the argument, thisValue, and the receiver as block arguments. For instance, to sum the numeric elements of a collection, aCollection inject: 0 into: [:subTotal :next | subTotal + next]." | nextValue | nextValue := thisValue. self do: [:each | nextValue := binaryBlock value: nextValue value: each]. ^nextValue! !!Collection methodsFor: 'enumerating' stamp: 'StephaneDucasse 3/14/2014 20:54'!difference: aCollection "Answer the set theoretic difference of two collections." "#(a b c d e f) difference: #(a b z k) => #(#f #d #e #c) #(a b z k) difference: #(a b c d e f) => #(#k #z) " | set | set := self asSet. aCollection do: [ :each | set remove: each ifAbsent: [ ] ]. ^ self species withAll: set asArray! !!Collection methodsFor: '*metacello-mc' stamp: 'dkh 6/8/2012 14:04:22'!mergeIntoMetacelloRepositories: aMetacelloRepositoriesSpec self do: [:each | each mergeIntoMetacelloRepositories: aMetacelloRepositoriesSpec ]! !!Collection methodsFor: '*metacello-mc' stamp: 'dkh 6/8/2012 14:04:22'!removeFromMetacelloRepositories: aMetacelloRepositoriesSpec self do: [:each | each removeFromMetacelloRepositories: aMetacelloRepositoriesSpec ]! !!Collection methodsFor: '*metacello-mc' stamp: 'dkh 6/8/2012 14:04:22'!loadRequiredForMetacelloMCVersion: aMetacelloMCVersion ^aMetacelloMCVersion doLoadRequiredFromArray: self.! !!Collection methodsFor: '*metacello-mc' stamp: 'dkh 6/8/2012 14:04:22'!resolvePackageSpecsNamedForMetacelloMCVersion: aMetacelloMCVersion visited: visited ifAbsent: aBlock ^ aMetacelloMCVersion allPackagesForSpecs: (self collect: [ :ea | aMetacelloMCVersion packageNamed: ea ifAbsent: aBlock ]) visited: visited! !!Collection methodsFor: '*metacello-mc' stamp: 'dkh 6/8/2012 14:04:22'!recordRequiredForMetacelloMCVersion: aMetacelloMCVersion ^aMetacelloMCVersion doRecordRequiredFromArray: self.! !!Collection methodsFor: '*metacello-mc' stamp: 'dkh 6/8/2012 14:04:22'!fetchRequiredForMetacelloMCVersion: aMetacelloMCVersion ^aMetacelloMCVersion doFetchRequiredFromArray: self.! !!Collection methodsFor: '*metacello-mc' stamp: 'dkh 6/8/2012 14:04:22'!addToMetacelloRepositories: aMetacelloRepositoriesSpec self do: [:each | each addToMetacelloRepositories: aMetacelloRepositoriesSpec ]! !!Collection methodsFor: 'adding' stamp: 'sma 5/12/2000 17:23'!addIfNotPresent: anObject "Include anObject as one of the receiver's elements, but only if there is no such element already. Anwser anObject." (self includes: anObject) ifFalse: [self add: anObject]. ^ anObject! !!Collection methodsFor: 'adding' stamp: 'sma 5/12/2000 17:21'!add: newObject withOccurrences: anInteger "Add newObject anInteger times to the receiver. Answer newObject." anInteger timesRepeat: [self add: newObject]. ^ newObject! !!Collection methodsFor: 'adding'!add: newObject "Include newObject as one of the receiver's elements. Answer newObject. ArrayedCollections cannot respond to this message." self subclassResponsibility! !!Collection methodsFor: 'adding' stamp: 'sma 5/12/2000 17:26'!addAll: aCollection "Include all the elements of aCollection as the receiver's elements. Answer aCollection. Actually, any object responding to #do: can be used as argument." aCollection do: [:each | self add: each]. ^ aCollection! !!Collection methodsFor: 'adapting' stamp: 'di 11/6/1998 13:37'!adaptToString: rcvr andSend: selector "If I am involved in arithmetic with a String, convert it to a Number." ^ rcvr asNumber perform: selector with: self! !!Collection methodsFor: 'adapting' stamp: 'di 11/6/1998 13:37'!adaptToPoint: rcvr andSend: selector "If I am involved in arithmetic with a scalar, return a Collection of the results of each element combined with the scalar in that expression." ^ self collect: [:element | rcvr perform: selector with: element]! !!Collection methodsFor: 'adapting' stamp: 'di 11/9/1998 12:16'!adaptToNumber: rcvr andSend: selector "If I am involved in arithmetic with a scalar, return a Collection of the results of each element combined with the scalar in that expression." ^ self collect: [:element | rcvr perform: selector with: element]! !!Collection methodsFor: 'adapting' stamp: 'ClementBera 9/30/2013 10:59'!adaptToCollection: rcvr andSend: selector "If I am involved in arithmetic with another Collection, return a Collection of the results of each element combined with the scalar in that expression." (rcvr isSequenceable and: [ self isSequenceable ]) ifFalse: [self error: 'Only sequenceable collections may be combined arithmetically']. ^ rcvr with: self collect: [:rcvrElement :myElement | rcvrElement perform: selector with: myElement]! !!Collection methodsFor: 'printing' stamp: 'gk 1/14/2005 08:27'!asStringOn: aStream delimiter: delimString "Print elements on a stream separated with a delimiter String like: 'a, b, c' Uses #asString instead of #print:." self do: [:elem | aStream nextPutAll: elem asString] separatedBy: [aStream nextPutAll: delimString]! !!Collection methodsFor: 'printing' stamp: 'gk 1/14/2005 08:20'!asCommaStringAnd "Return collection printed as 'a, b and c' " ^String streamContents: [:s | self asStringOn: s delimiter: ', ' last: ' and '] ! !!Collection methodsFor: 'printing' stamp: 'gk 1/14/2005 08:27'!asStringOn: aStream delimiter: delimString last: lastDelimString "Print elements on a stream separated with a delimiter between all the elements and with a special one before the last like: 'a, b and c'. Uses #asString instead of #print: Note: Feel free to improve the code to detect the last element." | n sz | n := 1. sz := self size. self do: [:elem | n := n + 1. aStream nextPutAll: elem asString] separatedBy: [ aStream nextPutAll: (n = sz ifTrue: [lastDelimString] ifFalse: [delimString])]! !!Collection methodsFor: 'printing' stamp: 'sma 6/1/2000 09:41'!printNameOn: aStream super printOn: aStream! !!Collection methodsFor: 'printing' stamp: 'fbs 1/14/2005 10:54'!printOn: aStream delimiter: delimString last: lastDelimString "Print elements on a stream separated with a delimiter between all the elements and with a special one before the last like: 'a, b and c' Note: Feel free to improve the code to detect the last element." | n sz | n := 1. sz := self size. self do: [:elem | n := n + 1. aStream print: elem] separatedBy: [ n = sz ifTrue: [aStream print: lastDelimString] ifFalse: [aStream print: delimString]]! !!Collection methodsFor: 'printing'!storeOn: aStream "Refer to the comment in Object|storeOn:." | noneYet | aStream nextPutAll: '(('. aStream nextPutAll: self class name. aStream nextPutAll: ' new)'. noneYet := true. self do: [:each | noneYet ifTrue: [noneYet := false] ifFalse: [aStream nextPut: $;]. aStream nextPutAll: ' add: '. aStream store: each]. noneYet ifFalse: [aStream nextPutAll: '; yourself']. aStream nextPut: $)! !!Collection methodsFor: 'printing' stamp: 'apb 4/21/2006 09:37'!printElementsOn: aStream "The original code used #skip:, but some streams do not support that, and we don't really need it." aStream nextPut: $(. self do: [:element | aStream print: element] separatedBy: [aStream space]. aStream nextPut: $)! !!Collection methodsFor: 'printing' stamp: 'gk 1/14/2005 08:19'!asCommaString "Return collection printed as 'a, b, c' " ^String streamContents: [:s | self asStringOn: s delimiter: ', '] ! !!Collection methodsFor: 'printing' stamp: 'gk 1/14/2005 08:01'!printOn: aStream delimiter: delimString "Print elements on a stream separated with a delimiter String like: 'a, b, c' " self do: [:elem | aStream print: elem] separatedBy: [aStream print: delimString] ! !!Collection methodsFor: 'printing' stamp: 'sma 6/1/2000 09:41'!printOn: aStream "Append a sequence of characters that identify the receiver to aStream." self printNameOn: aStream. self printElementsOn: aStream! !!Collection methodsFor: '*zinc-resource-meta-core' stamp: 'SvenVanCaekenberghe 3/16/2013 20:24'!addedToZnUrl: url ^ url withPathSegments: self! !!Collection methodsFor: 'accessing' stamp: 'nice 4/19/2011 00:26'!atRandom: aGenerator "Answer a random element of the receiver. Uses aGenerator which should be kept by the user in a variable and used every time. Use this instead of #atRandom for better uniformity of random numbers because only you use the generator. Causes an error if self has no elements." | rand index | self emptyCheck. rand := aGenerator nextInt: self size. index := 1. self do: [:each | index = rand ifTrue: [^each]. index := index + 1]. ^ self errorEmptyCollection! !!Collection methodsFor: 'accessing' stamp: 'sma 5/12/2000 11:34'!size "Answer how many elements the receiver contains." | tally | tally := 0. self do: [:each | tally := tally + 1]. ^ tally! !!Collection methodsFor: 'accessing' stamp: 'sd 11/4/2003 22:05'!atRandom "Answer a random element of the receiver. Uses a shared random number generator owned by class Collection. If you use this a lot, define your own instance of Random and use #atRandom:. Causes an error if self has no elements." ^ self class mutexForPicking critical: [ self atRandom: self class randomForPicking ]"Examples: #('one' 'or' 'the' 'other') atRandom (1 to: 10) atRandom 'Just pick one of these letters at random' atRandom #(3 7 4 9 21) asSet atRandom (just to show it also works for Sets)"! !!Collection methodsFor: 'accessing' stamp: 'sma 5/12/2000 11:41'!capacity "Answer the current capacity of the receiver." ^ self size! !!Collection methodsFor: 'accessing' stamp: 'sma 5/12/2000 11:33'!anyOne "Answer a representative sample of the receiver. This method can be helpful when needing to preinfer the nature of the contents of semi-homogeneous collections." self emptyCheck. self do: [:each | ^ each]! !!Collection methodsFor: '*Fuel' stamp: 'MartinDias 5/19/2011 23:41'!addIfNotPresent: anObject ifPresentDo: aBlock "Include anObject as one of the receiver's elements and then value aBlock, but only if there is no such element already. Anwser anObject." (self includes: anObject) ifFalse: [ self add: anObject ] ifTrue: [ aBlock value ]. ^ anObject! !!Collection methodsFor: '*Keymapping-KeyCombinations' stamp: 'GuillermoPolito 6/28/2013 13:02'!asShortcut ^ self asKeyCombination! !!Collection methodsFor: '*Keymapping-KeyCombinations' stamp: 'GuillermoPolito 3/19/2013 19:12'!asKeyCombination | shortcut | self size = 1 ifTrue: [ ^self first asKeyCombination ]. shortcut := KMKeyCombinationSequence new. self do: [ :each | shortcut addShortcut: each asKeyCombination ]. ^shortcut.! !!Collection methodsFor: 'filter streaming' stamp: 'sma 5/12/2000 12:07'!contents ^ self! !!Collection methodsFor: 'filter streaming' stamp: 'sma 5/12/2000 12:07'!write: anObject ^ self add: anObject! !!Collection methodsFor: 'copying' stamp: 'ar 2/11/2001 01:55'!copyWithDependent: newElement "Answer a new collection with newElement added (as last element if sequenceable)." ^self copyWith: newElement! !!Collection methodsFor: 'copying' stamp: 'sma 5/12/2000 18:08'!copyWithoutAll: aCollection "Answer a copy of the receiver that does not contain any elements equal to those in aCollection." ^ self reject: [:each | aCollection includes: each]! !!Collection methodsFor: 'copying' stamp: 'CamilloBruni 10/20/2012 21:49'!copyEmpty ^ self species new! !!Collection methodsFor: 'copying' stamp: 'sma 5/12/2000 14:43'!copyWithout: oldElement "Answer a copy of the receiver that does not contain any elements equal to oldElement." ^ self reject: [:each | each = oldElement]"Examples: 'fred the bear' copyWithout: $e #(2 3 4 5 5 6) copyWithout: 5"! !!Collection methodsFor: 'copying' stamp: 'al 12/12/2003 14:31'!, aCollection ^self copy addAll: aCollection; yourself! !!Collection methodsFor: 'copying' stamp: 'sma 5/12/2000 14:41'!copyWith: newElement "Answer a new collection with newElement added (as last element if sequenceable)." ^ self copy add: newElement; yourself! !!Collection methodsFor: 'math functions' stamp: 'TAG 11/6/1998 16:00'!median ^ self asSortedCollection median! !!Collection methodsFor: 'math functions' stamp: 'TudorGirba 11/19/2013 21:37'!sumNumbers: aBlock "This is implemented using a variant of the normal inject:into: pattern that is specific to handling numbers. aBlock is expected to return a number for every element in the collection. Different from the sum: implementation, the default value is zero. While sum: is more general, sumNumbers: is meant to support the most often encountered use case of dealing with numbers." ^ self inject: 0 into: [ :sum :each | sum + (aBlock value: each) ]! !!Collection methodsFor: 'math functions' stamp: 'MarcusDenker 8/15/2010 11:01'!stdev | avg sample sum | avg := self average. "see comment in self sum" sample := self anyOne. sum := self inject: sample into: [:accum :each | accum + (each - avg) squared]. sum := sum - sample. ^ (sum / (self size - 1)) sqrt! !!Collection methodsFor: 'math functions' stamp: 'JuanVuletich 10/11/2010 20:15'!sum: aBlock "This is implemented using a variant of the normal inject:into: pattern. The reason for this is that it is not known whether we're in the normal number line, i.e. whether 0 is a good initial value for the sum. Consider a collection of measurement objects, 0 would be the unitless value and would not be appropriate to add with the unit-ed objects." | sum sample | sample := aBlock value: self anyOne. sum := self inject: sample into: [ :previousValue :each | previousValue + (aBlock value: each) ]. ^ sum - sample! !!Collection methodsFor: '*Tool-Explorer' stamp: 'yo 8/27/2008 23:29'!explorerContentsWithIndexCollect: twoArgBlock ^ self asOrderedCollection withIndexCollect: twoArgBlock! !!Collection methodsFor: '*Tool-Explorer' stamp: 'yo 8/27/2008 23:45'!explorerContents ^self explorerContentsWithIndexCollect: [:value :index | ObjectExplorerWrapper with: value name: index printString model: self]! !!Collection methodsFor: 'removing' stamp: 'nice 9/14/2009 20:30'!removeAll "Remove each element from the receiver and leave it empty. ArrayedCollections cannot respond to this message. There are two good reasons why a subclass should override this message: 1) the subclass does not support being modified while being iterated 2) the subclass provides a much faster way than iterating through each element" self do: [:each | self remove: each].! !!Collection methodsFor: 'removing' stamp: 'sma 5/12/2000 11:19'!removeAllSuchThat: aBlock "Evaluate aBlock for each element and remove all that elements from the receiver for that aBlock evaluates to true. Use a copy to enumerate collections whose order changes when an element is removed (i.e. Sets)." self copy do: [:each | (aBlock value: each) ifTrue: [self remove: each]]! !!Collection methodsFor: 'removing' stamp: 'nice 1/10/2009 00:01'!removeAll: aCollection "Remove each element of aCollection from the receiver. If successful for each, answer aCollection. Otherwise create an error notification. ArrayedCollections cannot respond to this message." aCollection == self ifTrue: [^self removeAll]. aCollection do: [:each | self remove: each]. ^ aCollection! !!Collection methodsFor: 'removing' stamp: 'sma 5/12/2000 11:22'!remove: oldObject "Remove oldObject from the receiver's elements. Answer oldObject unless no element is equal to oldObject, in which case, raise an error. ArrayedCollections cannot respond to this message." ^ self remove: oldObject ifAbsent: [self errorNotFound: oldObject]! !!Collection methodsFor: 'removing' stamp: 'sma 5/12/2000 11:14'!remove: oldObject ifAbsent: anExceptionBlock "Remove oldObject from the receiver's elements. If several of the elements are equal to oldObject, only one is removed. If no element is equal to oldObject, answer the result of evaluating anExceptionBlock. Otherwise, answer the argument, oldObject. ArrayedCollections cannot respond to this message." self subclassResponsibility! !!Collection methodsFor: 'removing' stamp: 'sma 5/12/2000 11:16'!removeAllFoundIn: aCollection "Remove each element of aCollection which is present in the receiver from the receiver. Answer aCollection. No error is raised if an element isn't found. ArrayedCollections cannot respond to this message." aCollection do: [:each | self remove: each ifAbsent: []]. ^ aCollection! !!Collection methodsFor: 'private' stamp: 'ul 11/21/2009 01:14'!fillFrom: aCollection with: aBlock "Evaluate aBlock with each of aCollections's elements as the argument. Collect the resulting values into self. Answer self." aCollection do: [ :each | self add: (aBlock value: each) ]! !!Collection methodsFor: 'private' stamp: 'SvenVanCaekenberghe 4/18/2011 14:37'!errorNotFound: anObject "Raise a NotFound exception." NotFound signalFor: anObject! !!Collection methodsFor: 'private' stamp: 'SvenVanCaekenberghe 4/18/2011 14:58'!errorNoMatch "Signal a SizeMismatch exception" SizeMismatch signal! !!Collection methodsFor: 'private'!toBraceStack: itsSize "Push receiver's elements onto the stack of thisContext sender. Error if receiver does not have itsSize elements or if receiver is unordered. Do not call directly: this is called by {a. b} := ... constructs." self size ~= itsSize ifTrue: [self error: 'Trying to store ', self size printString, ' values into ', itsSize printString, ' variables.']. thisContext sender push: itsSize fromIndexable: self! !!Collection methodsFor: 'private' stamp: 'SvenVanCaekenberghe 4/18/2011 14:59'!errorEmptyCollection "Signal a CollectionIsEmpty exception" CollectionIsEmpty signalWith: self! !!Collection methodsFor: 'private' stamp: 'yo 6/29/2004 13:14'!errorNotKeyed self error: ('Instances of {1} do not respond to keyed accessing messages.' translated format: {self class name})! !!Collection methodsFor: 'private'!emptyCheck self isEmpty ifTrue: [self errorEmptyCollection]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'raok 10/22/2002 00:20'!arcTan ^self collect: [:each | each arcTan]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'raok 10/22/2002 00:22'!tan ^self collect: [:each | each tan]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'TAG 11/6/1998 15:53'!reciprocal "Return the reciever full of reciprocated elements" ^ self collect: [:a | a reciprocal]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'TAG 11/6/1998 15:51'!ceiling ^ self collect: [:a | a ceiling]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'raok 10/22/2002 00:21'!ln ^self collect: [:each | each ln]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'TAG 11/6/1998 15:54'!truncated ^ self collect: [:a | a truncated]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'raok 10/22/2002 00:20'!arcCos ^self collect: [:each | each arcCos]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'raok 10/22/2002 00:20'!cos ^self collect: [:each | each cos]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'raok 10/22/2002 00:22'!sin ^self collect: [:each | each sin]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'raok 10/22/2002 00:21'!exp ^self collect: [:each | each exp]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'TAG 11/6/1998 15:53'!rounded ^ self collect: [:a | a rounded]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'TAG 11/6/1998 15:52'!log ^ self collect: [:each | each log]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'TAG 11/6/1998 15:53'!sqrt ^ self collect: [:each | each sqrt]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'TAG 11/6/1998 15:51'!abs "Absolute value of all elements in the collection" ^ self collect: [:a | a abs]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'raok 10/22/2002 00:20'!arcSin ^self collect: [:each | each arcSin]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'nk 12/30/2003 15:47'!roundTo: quantum ^self collect: [ :ea | ea roundTo: quantum ]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'TAG 11/6/1998 15:52'!negated "Negated value of all elements in the collection" ^ self collect: [:a | a negated]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'TAG 11/6/1998 15:53'!squared ^ self collect: [:each | each * each]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'raok 10/22/2002 00:23'!sign ^self collect: [:each | each sign]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'raok 10/22/2002 00:20'!degreeCos ^self collect: [:each | each degreeCos]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'TAG 11/6/1998 15:51'!floor ^ self collect: [:a | a floor]! !!Collection methodsFor: '*Collections-arithmetic-collectors' stamp: 'raok 10/22/2002 00:21'!degreeSin ^self collect: [:each | each degreeSin]! !!Collection methodsFor: '*metacello-core' stamp: 'dkh 6/6/2009 11:42'!removeFromMetacelloPackages: aMetacelloPackagesSpec self do: [:each | each removeFromMetacelloPackages: aMetacelloPackagesSpec ]! !!Collection methodsFor: '*metacello-core' stamp: 'dkh 9/8/2012 05:30'!asMetacelloAttributePath ^ MetacelloMethodSectionPath withAll: self! !!Collection methodsFor: '*metacello-core' stamp: 'dkh 6/6/2009 10:08'!setRequiresInMetacelloPackage: aMetacelloPackageSpec aMetacelloPackageSpec setRequires: self asArray.! !!Collection methodsFor: '*metacello-core' stamp: 'dkh 9/7/2012 13:10'!asMetacelloAttributeList ^ self! !!Collection methodsFor: '*metacello-core' stamp: 'dkh 9/5/2012 06:26:03.064'!setForVersion: aString withInMetacelloConfig: aMetacelloConstructore aMetacelloConstructore setFor: self version: aString! !!Collection methodsFor: '*metacello-core' stamp: 'dkh 6/6/2009 11:45'!addToMetacelloPackages: aMetacelloPackagesSpec self do: [:each | each addToMetacelloPackages: aMetacelloPackagesSpec ]! !!Collection methodsFor: '*metacello-core' stamp: 'dkh 6/8/2009 19:02'!setLoadsInMetacelloProject: aMetacelloPackageSpec aMetacelloPackageSpec setLoads: self asArray.! !!Collection methodsFor: '*metacello-core' stamp: 'dkh 6/6/2009 11:46'!mergeIntoMetacelloPackages: aMetacelloPackagesSpec self do: [:each | each mergeIntoMetacelloPackages: aMetacelloPackagesSpec ]! !!Collection methodsFor: '*metacello-core' stamp: 'dkh 9/5/2012 06:26:03.064'!setForDo: aBlock withInMetacelloConfig: aMetacelloConstructore aMetacelloConstructore setFor: self do: aBlock! !!Collection methodsFor: '*metacello-core' stamp: 'dkh 9/23/2009 08:46'!setIncludesInMetacelloPackage: aMetacelloPackageSpec aMetacelloPackageSpec setIncludes: self asArray.! !!Collection methodsFor: '*Collections-arithmetic' stamp: 'TAG 11/6/1998 15:57'!average ^ self sum / self size! !!Collection methodsFor: '*Collections-arithmetic' stamp: 'di 11/6/1998 13:53'!/ arg ^ arg adaptToCollection: self andSend: #/! !!Collection methodsFor: '*Collections-arithmetic' stamp: 'raok 10/22/2002 00:17'!raisedTo: arg ^ arg adaptToCollection: self andSend: #raisedTo:! !!Collection methodsFor: '*Collections-arithmetic' stamp: 'di 11/6/1998 13:54'!\\ arg ^ arg adaptToCollection: self andSend: #\\! !!Collection methodsFor: '*Collections-arithmetic' stamp: 'di 11/6/1998 13:53'!- arg ^ arg adaptToCollection: self andSend: #-! !!Collection methodsFor: '*Collections-arithmetic' stamp: 'di 11/6/1998 13:53'!+ arg ^ arg adaptToCollection: self andSend: #+! !!Collection methodsFor: '*Collections-arithmetic' stamp: 'G.C 10/23/2008 10:12'!* arg ^ arg adaptToCollection: self andSend: #*! !!Collection methodsFor: '*Collections-arithmetic' stamp: 'di 11/6/1998 13:54'!// arg ^ arg adaptToCollection: self andSend: #//! !!Collection methodsFor: '*Collections-arithmetic' stamp: 'TAG 11/6/1998 15:58'!max ^ self inject: self anyOne into: [:max :each | max max: each]! !!Collection methodsFor: '*Collections-arithmetic' stamp: 'TAG 11/6/1998 16:02'!sum "This is implemented using a variant of the normal inject:into: pattern. The reason for this is that it is not known whether we're in the normal number line, i.e. whether 0 is a good initial value for the sum. Consider a collection of measurement objects, 0 would be the unitless value and would not be appropriate to add with the unit-ed objects." | sum sample | sample := self anyOne. sum := self inject: sample into: [:accum :each | accum + each]. ^ sum - sample! !!Collection methodsFor: '*Collections-arithmetic' stamp: 'TAG 11/6/1998 16:00'!min ^ self inject: self anyOne into: [:min :each | min min: each]! !!Collection methodsFor: '*Collections-arithmetic' stamp: 'TAG 11/6/1998 16:00'!range ^ self max - self min! !!Collection methodsFor: 'sorting' stamp: 'LucFabresse 6/28/2013 12:58'!sorted "Return a new sequenceable collection which contains the same elements as self but its elements are sorted" ^self asArray sorted! !!Collection methodsFor: 'sorting' stamp: 'StephaneDucasse 3/28/2010 22:42'!sorted: aSortBlockOrNil "Return a new sequenceable collection which contains the same elements as self but its elements are sorted by aSortBlockOrNil. The block should take two arguments and return true if the first element should preceed the second one. If aSortBlock is nil then <= is used for comparison." ^self asArray sort: aSortBlockOrNil! !!Collection methodsFor: 'converting' stamp: 'sma 5/6/2000 20:22'!asArray "Answer an Array whose elements are the elements of the receiver. Implementation note: Cannot use ''Array withAll: self'' as that only works for SequenceableCollections which support the replacement primitive." | array index | array := Array new: self size. index := 0. self do: [:each | array at: (index := index + 1) put: each]. ^ array! !!Collection methodsFor: 'converting' stamp: 'StephaneDucasse 3/28/2010 22:39'!asSortedCollection "Answer a SortedCollection whose elements are the elements of the receiver. The sort order is the default less than or equal. Note that you should use #sorted: if you don't really need a SortedCollection, but a sorted collection." ^ self as: SortedCollection! !!Collection methodsFor: 'converting' stamp: 'sma 5/6/2000 20:29'!asSet "Answer a Set whose elements are the unique elements of the receiver." ^ Set withAll: self! !!Collection methodsFor: 'converting' stamp: 'sma 5/6/2000 20:26'!asCharacterSet "Answer a CharacterSet whose elements are the unique elements of the receiver. The reciever should only contain characters." ^ CharacterSet newFrom: self! !!Collection methodsFor: 'converting' stamp: 'StephaneDucasse 3/28/2010 22:41'!asSortedCollection: aSortBlock "Answer a SortedCollection whose elements are the elements of the receiver. The sort order is defined by the argument, aSortBlock. Note that this is better to use #sorted: if you don't really need a SortedCollection, but a sorted collection!!!!" | aSortedCollection | aSortedCollection := SortedCollection new: self size. aSortedCollection sortBlock: aSortBlock. aSortedCollection addAll: self. ^ aSortedCollection! !!Collection methodsFor: 'converting' stamp: 'sma 5/12/2000 17:43'!asOrderedCollection "Answer an OrderedCollection whose elements are the elements of the receiver. The order in which elements are added depends on the order in which the receiver enumerates its elements. In the case of unordered collections, the ordering is not necessarily the same for multiple requests for the conversion." ^ self as: OrderedCollection! !!Collection methodsFor: 'converting' stamp: 'sma 5/6/2000 20:22'!asByteArray "Answer a ByteArray whose elements are the elements of the receiver. Implementation note: Cannot use ''ByteArray withAll: self'' as that only works for SequenceableCollections which support the replacement primitive." | array index | array := ByteArray new: self size. index := 0. self do: [:each | array at: (index := index + 1) put: each]. ^ array! !!Collection methodsFor: 'converting' stamp: 'MarcusDenker 11/28/2009 11:40'!asDictionary ^ self as: Dictionary! !!Collection methodsFor: 'converting' stamp: 'ar 9/22/2000 10:12'!asIdentitySet ^(IdentitySet new: self size) addAll: self; yourself! !!Collection methodsFor: 'converting' stamp: 'sma 5/6/2000 20:10'!asBag "Answer a Bag whose elements are the elements of the receiver." ^ Bag withAll: self! !!Dictionary methodsFor: '*Fuel' stamp: 'MartinDias 2/25/2013 14:33'!fuelAfterMaterialization | class | "Since for Set and IdentitySet we are recreating the collection with #add: we do not need to rehash." class := self class. ^ (((class == Dictionary) or: [ class == IdentityDictionary ]) ) ifFalse: [ self rehash ] ifTrue: [ self ]! !!Dictionary methodsFor: '*Fuel' stamp: 'MarianoMartinezPeck 7/30/2012 23:16'!fuelAccept: aGeneralMapper | class | "Since we have subclasses of Dictionary that behave differently, we cannot use the visitDictionary: for all of them. We could also use MethodDictionary for this case, but its materialization is much slower with this cluster than with the default action." class := self class. ^ (((class == Dictionary) or: [class == IdentityDictionary ])) ifTrue: [ aGeneralMapper visitDictionary: self ] ifFalse: [ super fuelAccept: aGeneralMapper ] ! !!Dictionary methodsFor: 'adding'!add: anAssociation | index element | index := self findElementOrNil: anAssociation key. element := array at: index. element == nil ifTrue: [self atNewIndex: index put: anAssociation] ifFalse: [element value: anAssociation value]. ^ anAssociation! !!Dictionary methodsFor: 'adding' stamp: 'raok 12/17/2003 16:01'!addAll: aKeyedCollection aKeyedCollection == self ifFalse: [ aKeyedCollection keysAndValuesDo: [:key :value | self at: key put: value]]. ^aKeyedCollection! !!Dictionary methodsFor: 'private' stamp: 'nice 11/14/2009 16:33'!fixCollisionsFrom: start "The element at start has been removed and replaced by nil. This method moves forward from there, relocating any entries that had been placed below due to collisions with this one." | element index | index := start. [ (element := array at: (index := index \\ array size + 1)) == nil ] whileFalse: [ | newIndex | (newIndex := self findElementOrNil: element key) = index ifFalse: [ array swap: index with: newIndex ] ]! !!Dictionary methodsFor: 'private' stamp: 'CamilloBruni 8/1/2012 16:12'!noCheckAdd: anObject "Must be defined separately for Dictionary because (self findElementOrNil:) expects a key, not an association." array at: (self findElementOrNil: anObject key) put: anObject. tally := tally + 1! !!Dictionary methodsFor: 'private' stamp: 'SvenVanCaekenberghe 4/19/2011 19:41'!errorKeyNotFound: aKey KeyNotFound signalFor: aKey! !!Dictionary methodsFor: 'private' stamp: 'md 10/5/2005 15:42'!scanFor: anObject "Scan the key array for the first slot containing either a nil (indicating an empty slot) or an element that matches anObject. Answer the index of that slot or zero if no slot is found. This method will be overridden in various subclasses that have different interpretations for matching elements." | element start finish | finish := array size. start := (anObject hash \\ finish) + 1. "Search from (hash mod size) to the end." start to: finish do: [:index | ((element := array at: index) == nil or: [element key = anObject]) ifTrue: [^ index ]]. "Search from 1 to where we started." 1 to: start-1 do: [:index | ((element := array at: index) == nil or: [element key = anObject]) ifTrue: [^ index ]]. ^ 0 "No match AND no empty slot"! !!Dictionary methodsFor: 'private'!valueAtNewKey: aKey put: anObject atIndex: index declareFrom: aDictionary "Support for coordinating class variable and global declarations with variables that have been put in Undeclared so as to redirect all references to the undeclared variable." (aDictionary includesKey: aKey) ifTrue: [self atNewIndex: index put: ((aDictionary associationAt: aKey) value: anObject). aDictionary removeKey: aKey] ifFalse: [self atNewIndex: index put: (Association key: aKey value: anObject)]! !!Dictionary methodsFor: 'private' stamp: 'ul 11/21/2009 01:15'!fillFrom: aCollection with: aBlock "Evaluate aBlock with each of aCollections's elements as the argument. Collect the resulting values into self. Answer self." aCollection keysAndValuesDo: [ :key :value | self at: key put: (aBlock value: value) ]! !!Dictionary methodsFor: 'private' stamp: 'SvenVanCaekenberghe 4/19/2011 20:30'!errorValueNotFound: value ValueNotFound signalFor: value! !!Dictionary methodsFor: 'private'!rehash "Smalltalk rehash." | newSelf | newSelf := self species new: self size. self associationsDo: [:each | newSelf noCheckAdd: each]. array := newSelf array! !!Dictionary methodsFor: 'private' stamp: 'HenrikSperreJohansen 9/1/2010 23:17'!noCheckNoGrowFillFrom: anArray "Add the elements of anArray except nils to me assuming that I don't contain any of them, they are unique and I have more free space than they require." 1 to: anArray size do: [ :index | (anArray at: index) ifNotNil: [ :association | array at: (self scanForEmptySlotFor: association key) put: association ] ]! !!Dictionary methodsFor: 'enumerating' stamp: 'nice 10/5/2009 10:16'!select: aBlock "Evaluate aBlock with each of my values as the argument. Collect into a new dictionary, only those associations for which aBlock evaluates to true." | newCollection | newCollection := self copyEmpty. self associationsDo: [ :each | (aBlock value: each value) ifTrue: [ newCollection add: each copy ] ]. ^newCollection! !!Dictionary methodsFor: 'enumerating' stamp: 'MarianoMartinezPeck 8/24/2012 15:26'!keysAndValuesDo: aBlock ^self associationsDo:[:assoc| aBlock value: assoc key value: assoc value].! !!Dictionary methodsFor: 'enumerating' stamp: 'dtl 2/17/2003 09:40'!associationsSelect: aBlock "Evaluate aBlock with each of my associations as the argument. Collect into a new dictionary, only those associations for which aBlock evaluates to true." | newCollection | newCollection := self species new. self associationsDo: [:each | (aBlock value: each) ifTrue: [newCollection add: each]]. ^newCollection! !!Dictionary methodsFor: 'enumerating'!keysDo: aBlock "Evaluate aBlock for each of the receiver's keys." self associationsDo: [:association | aBlock value: association key]! !!Dictionary methodsFor: 'enumerating' stamp: 'ar 6/13/2008 00:16'!collect: aBlock "Evaluate aBlock with each of my values as the argument. Collect the resulting values into a collection that is like me. Answer with the new collection." | newCollection | newCollection := self species new. self associationsDo:[:each | newCollection at: each key put: (aBlock value: each value). ]. ^newCollection! !!Dictionary methodsFor: 'enumerating' stamp: 'CamilloBruni 9/9/2011 16:50'!difference: aCollection "Answer the set theoretic difference of two collections. This is a specialized version for Dictionaries keeping the keys of the objects. At a slightly higher price of an additional Set to track duplicates." | other result duplicates | other := aCollection asSet. duplicates := Set new. result := self class new: self size. self keysAndValuesDo: [ :key :value| ((other includes: value) not and: [ (duplicates includes: value) not ]) ifTrue: [ duplicates add: value. result at: key put: value]]. ^ result! !!Dictionary methodsFor: 'enumerating' stamp: 'TristanBourgois 5/10/2010 10:41'!associationsDo: aBlock "Evaluate aBlock for each of the receiver's elements (key/value associations)." tally = 0 ifTrue: [^ self]. array do: [:each | each ifNotNil: [aBlock value: each]]! !!Dictionary methodsFor: 'enumerating' stamp: 'MarcusDenker 7/2/2010 13:02'!do: aBlock ^self valuesDo: aBlock! !!Dictionary methodsFor: 'enumerating' stamp: 'SqR 11/7/2013 12:12'!valuesDo: aBlock "Evaluate aBlock for each of the receiver's values. Implemented with == checks merely for the sake of maximum efficiency" tally = 0 ifTrue: [ ^self ]. 1 to: array size do: [ :eachIndex | | eachAssociation | eachAssociation := array at: eachIndex. nil == eachAssociation ifFalse: [ aBlock value: eachAssociation value ] ]! !!Dictionary methodsFor: 'enumerating' stamp: 'ar 5/18/2003 20:33'!bindingsDo: aBlock ^self associationsDo: aBlock! !!Dictionary methodsFor: 'removing'!removeKey: key ifAbsent: aBlock "Remove key (and its associated value) from the receiver. If key is not in the receiver, answer the result of evaluating aBlock. Otherwise, answer the value externally named by key." | index assoc | index := self findElementOrNil: key. assoc := array at: index. assoc == nil ifTrue: [ ^ aBlock value ]. array at: index put: nil. tally := tally - 1. self fixCollisionsFrom: index. ^ assoc value! !!Dictionary methodsFor: 'removing'!removeUnreferencedKeys "Undeclared removeUnreferencedKeys" ^ self unreferencedKeys do: [:key | self removeKey: key].! !!Dictionary methodsFor: 'removing' stamp: 'MarcusDenker 10/9/2013 11:29'!unreferencedKeys "| uk | (Time millisecondsToRun: [uk := TextConstants unreferencedKeys]) -> uk" ^'Scanning for references . . .' displayProgressFrom: 0 to: Smalltalk globals classNames size * 2 during: [:bar | | currentClass n associations referencedAssociations | currentClass := nil. n := 0. associations := self associations asIdentitySet. referencedAssociations := IdentitySet new: associations size. self systemNavigation allMethodsSelect: [:m| m methodClass ~~ currentClass ifTrue: [currentClass := m methodClass. bar current: (n := n + 1)]. m literalsDo: [:l| (l isVariableBinding and: [associations includes: l]) ifTrue: [referencedAssociations add: l]]. false]. ((associations reject: [:assoc | referencedAssociations includes: assoc]) collect: [:assoc| assoc key]) asSet]! !!Dictionary methodsFor: 'removing' stamp: 'di 4/4/2000 11:47'!keysAndValuesRemove: keyValueBlock "Removes all entries for which keyValueBlock returns true." "When removing many items, you must not do it while iterating over the dictionary, since it may be changing. This method takes care of tallying the removals in a first pass, and then performing all the deletions afterward. Many places in the sytem could be simplified by using this method." | removals | removals := OrderedCollection new. self associationsDo: [:assoc | (keyValueBlock value: assoc key value: assoc value) ifTrue: [removals add: assoc key]]. removals do: [:aKey | self removeKey: aKey]! !!Dictionary methodsFor: 'removing' stamp: 'CamilloBruni 4/11/2011 13:30'!removeKey: key "Remove key from the receiver. If key is not in the receiver, notify an error." ^ self removeKey: key ifAbsent: [self errorKeyNotFound: key]! !!Dictionary methodsFor: 'removing'!remove: anObject self shouldNotImplement! !!Dictionary methodsFor: 'removing'!remove: anObject ifAbsent: exceptionBlock self shouldNotImplement! !!Dictionary methodsFor: 'copying' stamp: 'ul 9/22/2009 04:51'!postCopy "Must copy the associations, or later store will affect both theoriginal and the copy" array := array collect: [ :association | association ifNotNil: [ association copy ] ]! !!Dictionary methodsFor: 'printing'!storeOn: aStream | noneYet | aStream nextPutAll: '(('. aStream nextPutAll: self class name. aStream nextPutAll: ' new)'. noneYet := true. self associationsDo: [:each | noneYet ifTrue: [noneYet := false] ifFalse: [aStream nextPut: $;]. aStream nextPutAll: ' add: '. aStream store: each]. noneYet ifFalse: [aStream nextPutAll: '; yourself']. aStream nextPut: $)! !!Dictionary methodsFor: 'printing' stamp: 'apb 7/14/2004 12:48'!printElementsOn: aStream aStream nextPut: $(. self size > 100 ifTrue: [aStream nextPutAll: 'size '. self size printOn: aStream] ifFalse: [self keysSortedSafely do: [:key | aStream print: key; nextPutAll: '->'; print: (self at: key); space]]. aStream nextPut: $)! !!Dictionary methodsFor: 'comparing' stamp: 'cyrille.delaunay 7/17/2009 15:45'!= aDictionary "Two dictionaries are equal if (a) they are the same 'kind' of thing. (b) they have the same set of keys. (c) for each (common) key, they have the same value" self == aDictionary ifTrue: [ ^ true ]. (aDictionary isDictionary) ifFalse: [^false]. self size = aDictionary size ifFalse: [^false]. self associationsDo: [:assoc| (aDictionary at: assoc key ifAbsent: [^false]) = assoc value ifFalse: [^false]]. ^true! !!Dictionary methodsFor: '*monticellofiletree-core' stamp: 'dkh 4/6/2012 15:56:14'!writeCypressJsonForHtmlOn: aStream self writeCypressJsonOn: aStream forHtml: true indent: 0! !!Dictionary methodsFor: '*monticellofiletree-core' stamp: 'dkh 4/6/2012 15:56:14'!writeCypressJsonOn: aStream self writeCypressJsonOn: aStream forHtml: false indent: 0. aStream lf! !!Dictionary methodsFor: '*monticellofiletree-core' stamp: 'dkh 4/6/2012 15:56:14'!writeCypressJsonOn: aStream forHtml: forHtml indent: startIndent "by default ignore <forHtml> ... <forHtml> is used for Dictionary and Array, i.e., container objects and String which actually encodes itself differently for HTML" | indent keys | indent := startIndent. aStream nextPutAll: '{'; lf. indent := indent + 1. keys := self keys sort: [ :a :b | a <= b ]. 1 to: keys size do: [ :index | | key value | key := keys at: index. value := self at: key. aStream tab: indent. key writeCypressJsonOn: aStream forHtml: forHtml indent: indent. aStream nextPutAll: ' : '. value writeCypressJsonOn: aStream forHtml: forHtml indent: indent. index < self size ifTrue: [ aStream nextPutAll: ','; lf ] ]. self size = 0 ifTrue: [ aStream tab: indent ]. aStream nextPutAll: ' }'! !!Dictionary methodsFor: '*Tool-Explorer' stamp: 'yo 8/27/2008 23:16'!customizeExplorerContents ^ true.! !!Dictionary methodsFor: '*Tool-Explorer' stamp: 'yo 8/27/2008 23:44'!explorerContentsWithIndexCollect: twoArgBlock | sortedKeys | sortedKeys := self keys asSortedCollection: [:x :y | ((x isString and: [y isString]) or: [x isNumber and: [y isNumber]]) ifTrue: [x < y] ifFalse: [x class == y class ifTrue: [x printString < y printString] ifFalse: [x class name < y class name]]]. ^ sortedKeys collect: [:k | twoArgBlock value: (self at: k) value: k].! !!Dictionary methodsFor: 'kernel'!declare: key from: aDictionary "Add key to the receiver. If key already exists, do nothing. If aDictionary includes key, then remove it from aDictionary and use its association as the element of the receiver." (self includesKey: key) ifTrue: [^ self]. (aDictionary includesKey: key) ifTrue: [self add: (aDictionary associationAt: key). aDictionary removeKey: key] ifFalse: [self add: key -> nil]! !!Dictionary methodsFor: 'kernel' stamp: 'MarcusDenker 7/29/2014 16:08'!declareVariable: newGlobal from: aDictionary "Add aGlobal to the receiver. If key already exists, do nothing. If aDictionary includes key, then remove it from aDictionary and use its association as the element of the receiver." | globalName | globalName := newGlobal key. self associationAt: globalName ifPresent: [:existingGlobal | "need to take care to migrate existing variables to new global if class if different" (existingGlobal class == newGlobal class) ifTrue: [^self]. newGlobal value: existingGlobal value. self removeKey: globalName. self add: newGlobal. ]. (aDictionary includesKey: globalName) ifTrue: [ self add: ((aDictionary associationAt: globalName) primitiveChangeClassTo: ClassVariable new). aDictionary removeKey: globalName] ifFalse: [ self add: newGlobal]! !!Dictionary methodsFor: 'testing'!includes: anObject self do: [:each | anObject = each ifTrue: [^true]]. ^false! !!Dictionary methodsFor: 'testing' stamp: 'SvenVanCaekenberghe 10/26/2013 12:24'!includesKey: key "Answer whether the receiver has a key equal to the argument, key." ^ (array at: (self scanFor: key)) ~~ nil "We could use #notNil here, but ProtoObject doesn't understand it."! !!Dictionary methodsFor: 'testing' stamp: 'tween 9/13/2004 10:11'!hasBindingThatBeginsWith: aString "Answer true if the receiver has a key that begins with aString, false otherwise" self keysDo:[:each | (each beginsWith: aString) ifTrue:[^true]]. ^false! !!Dictionary methodsFor: 'testing' stamp: 'sw 3/23/2000 01:12'!keyForIdentity: anObject "If anObject is one of the values of the receive, return its key, else return nil. Contrast #keyAtValue: in which there is only an equality check, here there is an identity check" self associationsDo: [:assoc | assoc value == anObject ifTrue: [^ assoc key]]. ^ nil! !!Dictionary methodsFor: 'testing' stamp: 'StephaneDucasse 5/28/2011 14:01'!isHealthy "Test that object hashes match their positions stored in set's array, answer true if everything ok, false otherwise Dictionary allInstances select: [:dict | dict isHealthy not ] Dictionary allSubInstances select: [:dict | dict isHealthy not ] " array withIndexDo: [:elem :i | elem ifNotNil: [ (self scanFor: elem key) == i ifFalse: [ ^ false ] ] ]. ^ true! !!Dictionary methodsFor: 'testing' stamp: 'md 8/11/2005 16:49'!isDictionary ^true! !!Dictionary methodsFor: 'testing' stamp: 'sw 2/14/2000 14:34'!includesIdentity: anObject "Answer whether anObject is one of the values of the receiver. Contrast #includes: in which there is only an equality check, here there is an identity check" self do: [:each | anObject == each ifTrue: [^ true]]. ^ false! !!Dictionary methodsFor: 'testing' stamp: 'ab 9/17/2004 00:39'!includesAssociation: anAssociation ^ (self associationAt: anAssociation key ifAbsent: [ ^ false ]) value = anAssociation value! !!Dictionary methodsFor: 'accessing' stamp: 'MarcusDenker 8/18/2010 19:17'!at: key ifAbsent: aBlock "Answer the value associated with the key or, if key isn't found, answer the result of evaluating aBlock." ^((array at: (self findElementOrNil: key)) ifNil: [aBlock] ifNotNil: [:assoc | assoc]) value.! !!Dictionary methodsFor: 'accessing' stamp: 'SvenVanCaekenberghe 4/19/2011 20:31'!keyAtValue: value "Answer the key that is the external name for the argument, value. If there is none, signal an error." ^self keyAtValue: value ifAbsent: [self errorValueNotFound: value]! !!Dictionary methodsFor: 'accessing' stamp: 'CamilloBruni 4/11/2011 13:30'!at: key "Answer the value associated with the key." ^ self at: key ifAbsent: [self errorKeyNotFound: key]! !!Dictionary methodsFor: 'accessing' stamp: 'StephaneDucasse 5/13/2010 11:37'!at: key ifPresent: oneArgBlock ifAbsent: absentBlock "Lookup the given key in the receiver. If it is present, answer the value of evaluating the oneArgBlock with the value associated with the key, otherwise answer the value of absentBlock." self at: key ifPresent: [ :v | ^oneArgBlock value: v ]. ^absentBlock value! !!Dictionary methodsFor: 'accessing' stamp: 'StephaneDucasse 12/25/2009 12:12'!associations "Answer a Collection containing the receiver's associations." "Suggested by l. Uzonyi" ^Array new: self size streamContents: [ :stream | self associationsDo: [ :each | stream nextPut: each ] ]! !!Dictionary methodsFor: 'accessing' stamp: 'tk 2/18/97'!keyAtValue: value ifAbsent: exceptionBlock "Answer the key that is the external name for the argument, value. If there is none, answer the result of evaluating exceptionBlock. : Use =, not ==, so stings like 'this' can be found. Note that MethodDictionary continues to use == so it will be fast." self associationsDo: [:association | value = association value ifTrue: [^association key]]. ^exceptionBlock value! !!Dictionary methodsFor: 'accessing' stamp: 'nice 10/20/2009 23:20'!keys "Answer an Array containing the receiver's keys." ^Array new: self size streamContents: [:s| self keysDo: [:key| s nextPut: key]]! !!Dictionary methodsFor: 'accessing' stamp: 'SvenVanCaekenberghe 4/19/2011 20:31'!keyAtIdentityValue: value "Answer the key that is the external name for the argument, value. If there is none, answer nil. Note: There can be multiple keys with the same value. Only one is returned." ^self keyAtIdentityValue: value ifAbsent: [self errorValueNotFound: value]! !!Dictionary methodsFor: 'accessing' stamp: 'StephaneDucasse 12/25/2009 12:15'!keysSortedSafely "Answer an Array containing the receiver's keys." "Suggested by l. Uzonyi" | sortedKeys | sortedKeys := Array new: self size streamContents: [ :stream | self keysDo: [ :each | stream nextPut: each ] ]. sortedKeys sort: [ :x :y | "Should really be use <obj, string, num> compareSafely..." ((x isString and: [ y isString ]) or: [ x isNumber and: [ y isNumber ] ]) ifTrue: [ x < y ] ifFalse: [ x class == y class ifTrue: [ x printString < y printString ] ifFalse: [ x class name < y class name ] ] ]. ^sortedKeys! !!Dictionary methodsFor: 'accessing'!associationAt: key ifAbsent: aBlock "Answer the association with the given key. If key is not found, return the result of evaluating aBlock." | index assoc | index := self findElementOrNil: key. assoc := array at: index. nil == assoc ifTrue: [ ^ aBlock value ]. ^ assoc! !!Dictionary methodsFor: 'accessing' stamp: 'PeterHugossonMiller 9/3/2009 01:13'!values "Answer a Collection containing the receiver's values." | out | out := (Array new: self size) writeStream. self valuesDo: [:value | out nextPut: value]. ^ out contents! !!Dictionary methodsFor: 'accessing' stamp: 'ar 2/13/1999 21:16'!keyAtIdentityValue: value ifAbsent: exceptionBlock "Answer the key that is the external name for the argument, value. If there is none, answer the result of evaluating exceptionBlock. Note: There can be multiple keys with the same value. Only one is returned." self associationsDo: [:association | value == association value ifTrue: [^association key]]. ^exceptionBlock value! !!Dictionary methodsFor: 'accessing' stamp: 'CamilloBruni 4/11/2011 13:30'!associationAt: key ^ self associationAt: key ifAbsent: [self errorKeyNotFound: key]! !!Dictionary methodsFor: 'accessing' stamp: 'ar 5/17/2003 14:07'!bindingOf: varName ^self associationAt: varName ifAbsent:[nil]! !!Dictionary methodsFor: 'accessing' stamp: 'sma 5/12/2000 15:00'!at: key put: anObject "Set the value at key to be anObject. If key is not found, create a new entry for key and set is value to anObject. Answer anObject." | index assoc | index := self findElementOrNil: key. assoc := array at: index. assoc ifNil: [self atNewIndex: index put: (Association key: key value: anObject)] ifNotNil: [assoc value: anObject]. ^ anObject! !!Dictionary methodsFor: 'accessing' stamp: 'MarcusDenker 7/11/2014 18:34'!associationAt: key ifPresent: aBlock "Answer the association with the given key. If key is not found, return the result of evaluating aBlock." ^(array at: (self findElementOrNil: key)) ifNotNil: [:assoc | aBlock cull: assoc]! !!Dictionary methodsFor: 'accessing' stamp: 'sma 5/12/2000 15:01'!at: key ifAbsentPut: aBlock "Return the value at the given key. If key is not included in the receiver store the result of evaluating aBlock as new value." ^ self at: key ifAbsent: [self at: key put: aBlock value]! !!Dictionary methodsFor: 'accessing' stamp: 'nice 5/1/2011 18:29'!at: key ifPresent: aBlock "Lookup the given key in the receiver. If it is present, answer the value of evaluating the given block with the value associated with the key. Otherwise, answer nil." ^(array at: (self findElementOrNil: key)) ifNotNil: [:assoc | aBlock cull: assoc value]! !!Dictionary methodsFor: '*NewValueHolder' stamp: 'BenjaminVanRyseghem 1/24/2014 16:07'!asValueHolder ^ DictionaryValueHolder value: self! !!Collection class methodsFor: 'instance creation' stamp: 'sma 5/6/2000 20:07'!withAll: aCollection "Create a new collection containing all the elements from aCollection." ^ (self new: aCollection size) addAll: aCollection; yourself! !!Collection class methodsFor: 'instance creation' stamp: 'sma 5/6/2000 20:06'!with: firstObject with: secondObject with: thirdObject with: fourthObject with: fifthObject with: sixthObject "Answer an instance of me, containing the six arguments as the elements." ^ self new add: firstObject; add: secondObject; add: thirdObject; add: fourthObject; add: fifthObject; add: sixthObject; yourself! !!Collection class methodsFor: 'instance creation' stamp: 'sma 5/6/2000 20:06'!with: firstObject with: secondObject with: thirdObject with: fourthObject with: fifthObject "Answer an instance of me, containing the five arguments as the elements." ^ self new add: firstObject; add: secondObject; add: thirdObject; add: fourthObject; add: fifthObject; yourself! !!Collection class methodsFor: 'instance creation' stamp: 'sma 5/6/2000 20:01'!with: firstObject with: secondObject "Answer an instance of me containing the two arguments as elements." ^ self new add: firstObject; add: secondObject; yourself! !!Collection class methodsFor: 'instance creation' stamp: 'sma 5/6/2000 20:03'!with: firstObject with: secondObject with: thirdObject "Answer an instance of me containing the three arguments as elements." ^ self new add: firstObject; add: secondObject; add: thirdObject; yourself! !!Collection class methodsFor: 'instance creation' stamp: 'sma 5/6/2000 20:06'!with: firstObject with: secondObject with: thirdObject with: fourthObject "Answer an instance of me, containing the four arguments as the elements." ^ self new add: firstObject; add: secondObject; add: thirdObject; add: fourthObject; yourself! !!Collection class methodsFor: 'instance creation' stamp: 'sma 5/6/2000 19:58'!with: anObject "Answer an instance of me containing anObject." ^ self new add: anObject; yourself! !!Collection class methodsFor: '*Tools-Debugger' stamp: 'SeanDeNigris 5/28/2013 17:47'!canonicalArgumentName ^ 'aCollection'.! !!Collection class methodsFor: 'private' stamp: 'lr 11/4/2003 12:07'!initialize "Set up a Random number generator to be used by atRandom when the user does not feel like creating his own Random generator." RandomForPicking := Random new. MutexForPicking := Semaphore forMutualExclusion! !!Collection class methodsFor: 'private' stamp: 'lr 11/4/2003 12:08'!mutexForPicking ^ MutexForPicking! !!Collection class methodsFor: 'private' stamp: 'sma 5/12/2000 12:31'!randomForPicking ^ RandomForPicking! !!Collection class methodsFor: '*Polymorph-Widgets-Themes' stamp: 'YuriyTymchuk 12/20/2013 11:17'!systemIcon ^ Smalltalk ui icons iconNamed: #collectionIcon! !!Dictionary class methodsFor: '*Spec-Inspector' stamp: 'cb 6/25/2013 13:43'!inspectorClass ^ EyeDictionaryInspector! !!Dictionary class methodsFor: 'instance creation'!newFrom: aDict "Answer an instance of me containing the same associations as aDict. Error if any key appears twice." | newDictionary | newDictionary := self new: aDict size. aDict associationsDo: [:x | (newDictionary includesKey: x key) ifTrue: [self error: 'Duplicate key: ', x key printString] ifFalse: [newDictionary add: x]]. ^ newDictionary" NewDictionary newFrom: {1->#a. 2->#b. 3->#c} {1->#a. 2->#b. 3->#c} as: NewDictionary NewDictionary newFrom: {1->#a. 2->#b. 1->#c} {1->#a. 2->#b. 1->#c} as: NewDictionary"! !!Dictionary class methodsFor: 'instance creation' stamp: 'bgf 10/25/2006 17:08'!newFromPairs: anArray "Answer an instance of me associating (anArray at:i) to (anArray at: i+i) for each odd i. anArray must have an even number of entries." | newDictionary | newDictionary := self new: (anArray size/2). 1 to: (anArray size-1) by: 2 do: [ :i| newDictionary at: (anArray at: i) put: (anArray at: i+1). ]. ^ newDictionary " Dictionary newFromPairs: {'Red' . Color red . 'Blue' . Color blue . 'Green' . Color green}. "! !!Symbol methodsFor: 'printing' stamp: 'BenjaminVanRyseghem 11/24/2010 14:43'!storeOn: aStream aStream nextPut: $#. (self isLiteralSymbol) ifTrue: [aStream nextPutAll: self] ifFalse: [super storeOn: aStream]! !!Symbol methodsFor: 'printing' stamp: 'sw 8/19/1999 11:30'!isOrientedFill "Needs to be implemented here because symbols can occupy 'color' slots of morphs." ^ false! !!Symbol methodsFor: '*metacello-core' stamp: 'DaleHenrichs 12/21/2010 13:55'!setPreLoadDoItInMetacelloSpec: aMetacelloSpec self precedence == 0 ifTrue: [ self error: 'Invalid selector' ]. aMetacelloSpec setPreLoadDoIt: (aMetacelloSpec project valueHolderSpec value: self; yourself)! !!Symbol methodsFor: '*metacello-core' stamp: 'dkh 9/5/2012 06:26:03.064'!setForVersion: aString withInMetacelloConfig: aMetacelloConstructore aMetacelloConstructore setFor: {self} version: aString! !!Symbol methodsFor: '*metacello-core' stamp: 'dkh 9/7/2012 13:44'!asMetacelloAttributePath ^ MetacelloMethodSectionPath with: {self}! !!Symbol methodsFor: '*metacello-core' stamp: 'dkh 9/5/2012 06:26:03.064'!setForDo: aBlock withInMetacelloConfig: aMetacelloConstructore aMetacelloConstructore setFor: {self} do: aBlock! !!Symbol methodsFor: '*metacello-core' stamp: 'dkh 9/7/2012 13:11'!asMetacelloAttributeList ^ {self}! !!Symbol methodsFor: '*metacello-core' stamp: 'DaleHenrichs 12/21/2010 13:54'!setPostLoadDoItInMetacelloSpec: aMetacelloSpec self precedence == 0 ifTrue: [ self error: 'Invalid selector' ]. aMetacelloSpec setPostLoadDoIt: (aMetacelloSpec project valueHolderSpec value: self; yourself)! !!Symbol methodsFor: '*Slot' stamp: 'MarcusDenker 6/26/2014 13:37'!asSlot ^ InstanceVariableSlot named: self.! !!Symbol methodsFor: '*Slot' stamp: 'MarcusDenker 7/13/2014 11:56'!=> aVariable aVariable isBehavior ifTrue: [ ^ aVariable named: self]. ^ aVariable name: self; yourself! !!Symbol methodsFor: '*Slot' stamp: 'MartinDias 8/7/2012 01:31'!isPseudovariableName "Answer true if I am a pseudo-variable name. #self isPseudovariableName -> true " ^ self class pseudovariablesNames includes: self! !!Symbol methodsFor: '*opalcompiler-core' stamp: 'MarcusDenker 6/21/2012 11:18'!asOneArgSelector ^ String streamContents: [:str| | parts | parts := (self findTokens: ':)'). str nextPutAll: parts first. parts allButFirst do: [:each | str nextPutAll: each capitalized] . str nextPutAll: ':']! !!Symbol methodsFor: '*opalcompiler-core' stamp: 'MarcusDenker 10/11/2013 10:21'!asMethodPreamble self numArgs = 0 ifTrue: [ ^self asString]. ^ String streamContents: [ :str | self keywords doWithIndex: [ :each :index | str nextPutAll: each; nextPutAll: ' var' , index asString ] ]! !!Symbol methodsFor: 'evaluating' stamp: 'HenrikSperreJohansen 2/18/2010 14:58'!cull: anObject ^anObject perform: self.! !!Symbol methodsFor: 'evaluating' stamp: 'md 3/24/2006 12:09'!value: anObject ^anObject perform: self.! !!Symbol methodsFor: 'copying' stamp: 'tk 8/19/1998 16:05'!veryDeepCopyWith: deepCopier "Return self. I am immutable in the Morphic world. Do not record me."! !!Symbol methodsFor: 'copying'!copy "Answer with the receiver, because Symbols are unique."! !!Symbol methodsFor: 'copying'!shallowCopy "Answer with the receiver, because Symbols are unique."! !!Symbol methodsFor: 'sorting' stamp: 'DamienCassou 8/27/2013 21:06'!sorted: aSortBlockOrNil "Return a new sequenceable collection which contains the same elements as self but its elements are sorted by aSortBlockOrNil. The block should take two arguments and return true if the first element should preceed the second one. If aSortBlock is nil then <= is used for comparison. We convert the symbol to an array because symbols can't be changed." ^self asArray sort: aSortBlockOrNil! !!Symbol methodsFor: 'system primitives' stamp: 'CamilloBruni 9/7/2011 16:21'!numArgs: n "Answer a string that can be used as a selector with n arguments. TODO: need to be extended to support shrinking and for selectors like #+ " | selector numArgs offs | selector := self. (numArgs := selector numArgs) >= n ifTrue: [ ^ self ]. ^ self class new: 16 streamContents: [ :stream| stream nextPutAll: self. (numArgs = 0) ifTrue: [ stream nextPut: $:. offs := 0] ifFalse: [ offs := 1 ]. 2 to: n - numArgs + offs do: [:i | stream nextPutAll: 'with:' ]]. ! !!Symbol methodsFor: 'system primitives' stamp: 'MarcusDenker 2/29/2012 11:18'!flushCache "Tell the interpreter to remove all entries with this symbol as a selector from its method lookup cache, if it has one. This primitive must be called whenever a method is redefined or removed. NOTE: Only one of the two selective flush methods (Symbol or CompiledMethod) needs to be used." <primitive: 119>! !!Symbol methodsFor: 'announcements' stamp: 'StephaneDucasse 2/22/2013 18:21'!handlesAnnouncement: anAnnouncement "Anything else than the announcement identifier (in the case of symbol i.e. #foo for ... on: #foo send: #bar to: nil) will not be handled." "Announcer new on: #FOO send: #bar to: nil; announce: #FOO should raise DNU bar" ^ anAnnouncement == self! !!Symbol methodsFor: 'testing' stamp: 'StephaneDucasse 5/28/2011 13:42'!isUnary "Answer whether the receiver is an unary message selector." ^ self precedence = 1! !!Symbol methodsFor: 'testing' stamp: 'md 1/20/2006 16:16'!includesKey: sym ^self == sym.! !!Symbol methodsFor: 'testing' stamp: 'md 8/27/2005 16:33'!isDoIt ^ (self == #DoIt) or: [self == #DoItIn:].! !!Symbol methodsFor: 'testing' stamp: 'StephaneDucasse 5/28/2011 13:45'!isInfix "Answer whether the receiver is an infix message selector." ^ self precedence = 2! !!Symbol methodsFor: 'testing' stamp: 'md 4/30/2003 15:31'!isSymbol ^ true ! !!Symbol methodsFor: 'testing' stamp: 'StephaneDucasse 5/28/2011 13:45'!isBinary "Answer whether the receiver is a binary message selector." ^ self precedence = 2! !!Symbol methodsFor: 'testing' stamp: 'StephaneDucasse 5/28/2011 13:47'!isKeyword "Answer whether the receiver is a message keyword." ^ self precedence = 3! !!Symbol methodsFor: 'converting' stamp: 'st 11/22/2004 17:26'!asMutator "Return a setter message from a getter message. For example, #name asMutator returns #name:" ^ (self copyWith: $:) asSymbol! !!Symbol methodsFor: 'converting'!asSymbol "Refer to the comment in String|asSymbol."! !!Symbol methodsFor: 'converting' stamp: 'ar 4/10/2005 22:42'!asString "Refer to the comment in String|asString." | newString | newString := self species new: self size. newString replaceFrom: 1 to: newString size with: self startingAt: 1. ^newString! !!Symbol methodsFor: 'converting' stamp: 'MarcusDenker 10/11/2013 10:07'!separateKeywords "#'foo:zork:' separateKeywords -> 'foo: zork:'" self isKeyword ifFalse: [ ^ self ]. ^ String streamContents: [ :stream | (self findTokens: $:) do: [ :each | stream nextPutAll: each; nextPut: $: ] separatedBy: [ stream nextPutAll: ' ' ] ]! !!Symbol methodsFor: 'converting' stamp: 'md 8/10/2004 10:54'!withFirstCharacterDownshifted "Answer an object like the receiver but with first character downshifted if necesary" ^self asString withFirstCharacterDownshifted asSymbol.! !!Symbol methodsFor: 'converting' stamp: 'StephaneDucasse 2/22/2013 18:18'!asAnnouncement ^ self! !!Symbol methodsFor: 'converting' stamp: 'sw 1/28/98 18:18'!capitalized ^ self asString capitalized asSymbol! !!Symbol methodsFor: '*System-Support' stamp: 'MarcusDenker 7/17/2014 19:07'!implementors ^SystemNavigation new allImplementorsOf: self! !!Symbol methodsFor: '*System-Support' stamp: 'MarcusDenker 7/17/2014 19:11'!senders ^SystemNavigation new allSendersOf: self! !!Symbol methodsFor: 'accessing'!replaceFrom: start to: stop with: replacement startingAt: repStart self errorNoModification! !!Symbol methodsFor: 'accessing'!at: anInteger put: anObject "You cannot modify the receiver." self errorNoModification! !!Symbol methodsFor: 'accessing' stamp: 'sma 2/5/2000 12:32'!precedence "Answer the receiver's precedence, assuming it is a valid Smalltalk message selector or 0 otherwise. The numbers are 1 for unary, 2 for binary and 3 for keyword selectors." self size = 0 ifTrue: [^ 0]. self first isLetter ifFalse: [^ 2]. self last = $: ifTrue: [^ 3]. ^ 1! !!Symbol methodsFor: 'comparing' stamp: 'ar 4/10/2005 23:45'!= aSymbol "Compare the receiver and aSymbol." self == aSymbol ifTrue: [^ true]. self class == aSymbol class ifTrue: [^ false]. "Use String comparison otherwise" ^ super = aSymbol! !!Symbol methodsFor: 'private'!string: aString 1 to: aString size do: [:j | super at: j put: (aString at: j)]. ^self ! !!Symbol methodsFor: 'private'!errorNoModification self error: 'symbols can not be modified.'! !!Symbol class methodsFor: 'initialization' stamp: 'RAA 5/29/2001 14:35'!allSymbolTablesDo: aBlock after: aSymbol NewSymbols do: aBlock after: aSymbol. SymbolTable do: aBlock after: aSymbol.! !!Symbol class methodsFor: 'initialization' stamp: 'RAA 5/29/2001 09:04'!initialize "Symbol initialize" Symbol rehash. OneCharacterSymbols := nil. OneCharacterSymbols := (1 to: 256) collect: [ :i | (i - 1) asCharacter asSymbol]. Smalltalk addToShutDownList: self.! !!Symbol class methodsFor: 'initialization' stamp: 'RAA 5/29/2001 08:21'!allSymbolTablesDo: aBlock NewSymbols do: aBlock. SymbolTable do: aBlock.! !!Symbol class methodsFor: 'initialization' stamp: 'RAA 12/17/2000 18:05'!compactSymbolTable "Reduce the size of the symbol table so that it holds all existing symbols + 25% (changed from 1000 since sets like to have 25% free and the extra space would grow back in a hurry)" | oldSize | Smalltalk garbageCollect. oldSize := SymbolTable array size. SymbolTable growTo: SymbolTable size * 4 // 3 + 100. ^oldSize printString,' ',(oldSize - SymbolTable array size) printString, ' slot(s) reclaimed'! !!Symbol class methodsFor: 'accessing' stamp: 'CamilloBruni 9/5/2011 15:22'!streamSpecies ^ String! !!Symbol class methodsFor: 'instance creation' stamp: 'MarcusDenker 7/23/2014 13:17'!findInterned: aString self hasInterned:aString ifTrue:[:symbol| ^symbol]. ^nil.! !!Symbol class methodsFor: 'instance creation' stamp: 'BenjaminVanRyseghem 11/24/2010 14:44'!with: aCharacter ^self newFrom: aCharacter asOrderedCollection! !!Symbol class methodsFor: 'instance creation' stamp: 'CamilloBruni 9/9/2011 12:57'!withAll: aCollection ^ self newFrom: aCollection! !!Symbol class methodsFor: 'instance creation' stamp: 'ar 4/10/2005 23:04'!internCharacter: aCharacter aCharacter asciiValue > 256 ifTrue:[^self intern: aCharacter asString]. OneCharacterSymbols ifNil: [^self intern: aCharacter asString]. ^OneCharacterSymbols at: aCharacter asciiValue + 1! !!Symbol class methodsFor: 'instance creation'!newFrom: aCollection "Answer an instance of me containing the same elements as aCollection." ^ (aCollection as: String) asSymbol" Symbol newFrom: {$P. $e. $n} {$P. $e. $n} as: Symbol"! !!Symbol class methodsFor: 'instance creation' stamp: 'RAA 5/29/2001 08:09'!lookup: aStringOrSymbol ^(SymbolTable like: aStringOrSymbol) ifNil: [ NewSymbols like: aStringOrSymbol ]! !!Symbol class methodsFor: 'instance creation' stamp: 'SheridanMahoney 11/12/2009 22:04'!new: aSize self shouldNotImplement .! !!Symbol class methodsFor: 'instance creation' stamp: 'MarcusDenker 5/18/2013 15:44'!readFrom: strm "Symbol readFromString: '#abc'" strm peek = $# ifFalse: [self error: 'Symbols must be introduced by #']. ^ strm contents parseLiterals first. ! !!Symbol class methodsFor: 'instance creation' stamp: 'SheridanMahoney 11/17/2009 13:23'!intern: aStringOrSymbol ^(self lookup: aStringOrSymbol) ifNil:[ | aClass aSymbol | aStringOrSymbol isSymbol ifTrue:[ aSymbol := aStringOrSymbol. ] ifFalse:[ aClass := aStringOrSymbol isOctetString ifTrue:[ByteSymbol] ifFalse:[WideSymbol]. aSymbol := aClass basicNew: aStringOrSymbol size. aSymbol string: aStringOrSymbol. ]. NewSymbols add: aSymbol. aSymbol].! !!Symbol class methodsFor: 'private' stamp: 'RAA 5/29/2001 09:04'!shutDown: aboutToQuit SymbolTable addAll: NewSymbols. NewSymbols := WeakSet new.! !!Symbol class methodsFor: 'private' stamp: 'MarcusDenker 10/9/2013 10:42'!hasInterned: aString ifTrue: symBlock "Answer with false if aString hasnt been interned (into a Symbol), otherwise supply the symbol to symBlock and return true." ^ (self lookup: aString) ifNil: [ false ] ifNotNil: [ :symbol | symBlock value: symbol. true ]! !!Symbol class methodsFor: 'private' stamp: 'ar 9/27/2005 20:01'!rehash "Symbol rehash" "Rebuild the hash table, reclaiming unreferenced Symbols." SymbolTable := WeakSet withAll: self allSubInstances. NewSymbols := WeakSet new.! !!Symbol class methodsFor: 'private' stamp: 'nice 1/5/2010 15:59'!possibleSelectorsFor: misspelled "Answer an ordered collection of possible corrections for the misspelled selector in order of likelyhood" | numArgs candidates lookupString best binary short long first | lookupString := misspelled asLowercase. "correct uppercase selectors to lowercase" numArgs := lookupString numArgs. (numArgs < 0 or: [lookupString size < 2]) ifTrue: [^ OrderedCollection new: 0]. first := lookupString first. short := lookupString size - (lookupString size // 4 max: 3) max: 2. long := lookupString size + (lookupString size // 4 max: 3). "First assemble candidates for detailed scoring" candidates := OrderedCollection new. self allSymbolTablesDo: [:s | | ss | (((ss := s size) >= short "not too short" and: [ss <= long "not too long" or: [(s at: 1) = first]]) "well, any length OK if starts w/same letter" and: [s numArgs = numArgs]) "and numArgs is the same" ifTrue: [candidates add: s]]. "Then further prune these by correctAgainst:" best := lookupString correctAgainst: candidates. ((misspelled last ~~ $:) and: [misspelled size > 1]) ifTrue: [ binary := misspelled, ':'. "try for missing colon" Symbol hasInterned: binary ifTrue: [:him | best addFirst: him]]. ^ best! !!Symbol class methodsFor: 'cleanup' stamp: 'StephaneDucasse 3/9/2010 22:17'!cleanUp "Flush caches" self compactSymbolTable.! !!Symbol class methodsFor: 'stream creation' stamp: 'CamilloBruni 9/5/2011 15:35'!new: size streamContents: aBlock ^ (super new: size streamContents: aBlock) asSymbol! !!Symbol class methodsFor: 'access' stamp: 'tween 9/13/2004 10:09'!thatStartsCaseSensitive: leadingCharacters skipping: skipSym "Same as thatStarts:skipping: but caseSensitive" | size firstMatch key | size := leadingCharacters size. size = 0 ifTrue: [^skipSym ifNil: [#''] ifNotNil: [nil]]. firstMatch := leadingCharacters at: 1. size > 1 ifTrue: [key := leadingCharacters copyFrom: 2 to: size]. self allSymbolTablesDo: [:each | each size >= size ifTrue: [ ((each at: 1) == firstMatch and: [key == nil or: [(each findString: key startingAt: 2 caseSensitive: true) = 2]]) ifTrue: [^each] ] ] after: skipSym. ^nil! !!Symbol class methodsFor: 'access' stamp: 'StephaneDucasse 5/28/2011 13:45'!selectorsContaining: aString "Answer a list of selectors that contain aString within them. Case-insensitive. Does return symbols that begin with a capital letter." | size selectorList ascii | selectorList := OrderedCollection new. (size := aString size) = 0 ifTrue: [^selectorList]. aString size = 1 ifTrue: [ ascii := aString first asciiValue. ascii < 128 ifTrue: [selectorList add: (OneCharacterSymbols at: ascii+1)] ]. (aString first isAlphaNumeric) ifFalse: [ aString size = 2 ifTrue: [Symbol hasInterned: aString ifTrue: [:s | selectorList add: s]]. ^selectorList ]. selectorList := selectorList copyFrom: 2 to: selectorList size. self allSymbolTablesDo: [:each | each size >= size ifTrue: [(each findSubstring: aString in: each startingAt: 1 matchTable: CaseInsensitiveOrder) > 0 ifTrue: [selectorList add: each]]]. ^selectorList reject: [:each | "reject non-selectors, but keep ones that begin with an uppercase" each numArgs < 0 and: [each asString withFirstCharacterDownshifted numArgs < 0]]."Symbol selectorsContaining: 'scon'"! !!Symbol class methodsFor: 'access' stamp: 'ar 4/10/2005 22:49'!allSymbols "Answer all interned symbols" ^Array streamContents:[:s| s nextPutAll: NewSymbols. s nextPutAll: OneCharacterSymbols. s nextPutAll: SymbolTable. ].! !!Symbol class methodsFor: 'access' stamp: 'RAA 5/29/2001 14:35'!thatStarts: leadingCharacters skipping: skipSym "Answer a selector symbol that starts with leadingCharacters. Symbols beginning with a lower-case letter handled directly here. Ignore case after first char. If skipSym is not nil, it is a previous answer; start searching after it. If no symbols are found, answer nil. Used by Alt-q (Command-q) routines" | size firstMatch key | size := leadingCharacters size. size = 0 ifTrue: [^skipSym ifNil: [#''] ifNotNil: [nil]]. firstMatch := leadingCharacters at: 1. size > 1 ifTrue: [key := leadingCharacters copyFrom: 2 to: size]. self allSymbolTablesDo: [:each | each size >= size ifTrue: [ ((each at: 1) == firstMatch and: [key == nil or: [(each findString: key startingAt: 2 caseSensitive: false) = 2]]) ifTrue: [^each] ] ] after: skipSym. ^nil"Symbol thatStarts: 'sf' skipping: nil""Symbol thatStarts: 'sf' skipping: #sfpGetFile:with:with:with:with:with:with:with:with:""Symbol thatStarts: 'candidate' skipping: nil"! !!Symbol class methodsFor: '*Slot' stamp: 'MartinDias 8/7/2012 01:18'!pseudovariablesNames ^#('self' 'true' 'false' 'nil' 'thisContext' 'super')! !!OrderedCollection methodsFor: '*GroupManager' stamp: 'BenjaminVanRyseghem 4/14/2012 12:08'!removeDuplicates | iterator | "Remove the copies of elements, but keep the same order" self ifEmpty: [ ^ self ]. iterator := 1. [ iterator <= self size ] whileTrue: [ | each newIndex | each := self at: iterator. [ newIndex := (self indexOf: each startingAt: iterator+1). newIndex > 0 ] whileTrue: [ self removeAt: newIndex ]. iterator := iterator + 1. ]! !!OrderedCollection methodsFor: '*Fuel' stamp: 'MarianoMartinezPeck 7/26/2012 17:42'!fuelAccept: aGeneralMapper "Since we have subclasses of OrderedCollection that behave differently, we cannot use the visitSimpleCollection: for all of them." ^ (self class == OrderedCollection ) ifTrue: [ aGeneralMapper visitSimpleCollection: self ] ifFalse: [ super fuelAccept: aGeneralMapper ] ! !!OrderedCollection methodsFor: 'adding'!add: newObject after: oldObject "Add the argument, newObject, as an element of the receiver. Put it in the sequence just succeeding oldObject. Answer newObject." | index | index := self find: oldObject. self insert: newObject before: index + 1. ^newObject! !!OrderedCollection methodsFor: 'adding' stamp: 'ar 7/15/2008 23:05'!add: newObject beforeIndex: index "Add the argument, newObject, as an element of the receiver. Put it in the sequence just before index. Answer newObject." (index between: 1 and: self size+1) ifFalse:[^self errorSubscriptBounds: index]. self insert: newObject before: firstIndex + index - 1. ^ newObject! !!OrderedCollection methodsFor: 'adding'!add: newObject ^self addLast: newObject! !!OrderedCollection methodsFor: 'adding' stamp: 'CamilloBruni 4/12/2011 13:52'!add: newObject afterIndex: index "Add the argument, newObject, as an element of the receiver. Put it in the sequence just after index. Answer newObject." (index between: 0 and: self size) ifFalse:[^self errorSubscriptBounds: index]. self insert: newObject before: firstIndex + index. ^ newObject! !!OrderedCollection methodsFor: 'adding' stamp: 'sma 5/12/2000 11:26'!addAll: aCollection "Add each element of aCollection at my end. Answer aCollection." ^ self addAllLast: aCollection! !!OrderedCollection methodsFor: 'adding'!addAllFirst: anOrderedCollection "Add each element of anOrderedCollection at the beginning of the receiver. Answer anOrderedCollection." anOrderedCollection reverseDo: [:each | self addFirst: each]. ^anOrderedCollection! !!OrderedCollection methodsFor: 'adding' stamp: 'StephaneDucasse 12/25/2009 12:13'!addAllLast: aCollection "Add each element of aCollection at the end of the receiver. Answer aCollection." aCollection do: [:each | self addLast: each]. ^aCollection! !!OrderedCollection methodsFor: 'adding' stamp: 'sw 3/1/2001 11:03'!addAllFirstUnlessAlreadyPresent: anOrderedCollection "Add each element of anOrderedCollection at the beginning of the receiver, preserving the order, but do not add any items that are already in the receiver. Answer anOrderedCollection." anOrderedCollection reverseDo: [:each | (self includes: each) ifFalse: [self addFirst: each]]. ^ anOrderedCollection! !!OrderedCollection methodsFor: 'adding'!addFirst: newObject "Add newObject to the beginning of the receiver. Answer newObject." firstIndex = 1 ifTrue: [self makeRoomAtFirst]. firstIndex := firstIndex - 1. array at: firstIndex put: newObject. ^ newObject! !!OrderedCollection methodsFor: 'adding'!add: newObject before: oldObject "Add the argument, newObject, as an element of the receiver. Put it in the sequence just preceding oldObject. Answer newObject." | index | index := self find: oldObject. self insert: newObject before: index. ^newObject! !!OrderedCollection methodsFor: 'adding' stamp: 'ajh 5/22/2003 12:03'!at: index ifAbsentPut: block "Return value at index, however, if value does not exist (nil or out of bounds) then add block's value at index (growing self if necessary)" | v | index <= self size ifTrue: [ ^ (v := self at: index) ifNotNil: [v] ifNil: [self at: index put: block value] ]. [self size < index] whileTrue: [self add: nil]. ^ self at: index put: block value! !!OrderedCollection methodsFor: 'adding'!addLast: newObject "Add newObject to the end of the receiver. Answer newObject." lastIndex = array size ifTrue: [self makeRoomAtLast]. lastIndex := lastIndex + 1. array at: lastIndex put: newObject. ^ newObject! !!OrderedCollection methodsFor: 'accessing' stamp: 'sma 5/12/2000 11:39'!size "Answer how many elements the receiver contains." ^ lastIndex - firstIndex + 1! !!OrderedCollection methodsFor: 'accessing' stamp: 'sma 5/12/2000 11:42'!capacity "Answer the current capacity of the receiver." ^ array size! !!OrderedCollection methodsFor: 'accessing' stamp: 'CamilloBruni 4/11/2011 15:39'!at: anInteger put: anObject "Put anObject at element index anInteger. at:put: cannot be used to append, front or back, to an ordered collection; it is used by a knowledgeable client to replace an element." self ensureBoundsFrom: anInteger to: anInteger. ^array at: anInteger + firstIndex - 1 put: anObject! !!OrderedCollection methodsFor: 'accessing' stamp: 'CamilloBruni 4/11/2011 15:36'!at: anInteger "Answer my element at index anInteger. at: is used by a knowledgeable client to access an existing element" self ensureBoundsFrom: anInteger to: anInteger. ^ array at: anInteger + firstIndex - 1! !!OrderedCollection methodsFor: 'removing'!remove: oldObject ifAbsent: absentBlock | index | index := firstIndex. [index <= lastIndex] whileTrue: [oldObject = (array at: index) ifTrue: [self removeIndex: index. ^ oldObject] ifFalse: [index := index + 1]]. ^ absentBlock value! !!OrderedCollection methodsFor: 'removing'!removeFirst "Remove the first element of the receiver and answer it. If the receiver is empty, create an error notification." | firstObject | self emptyCheck. firstObject := array at: firstIndex. array at: firstIndex put: nil. firstIndex := firstIndex + 1. ^ firstObject! !!OrderedCollection methodsFor: 'removing' stamp: 'ar 5/22/2000 12:19'!removeAt: index | removed | removed := self at: index. self removeIndex: index + firstIndex - 1. ^removed! !!OrderedCollection methodsFor: 'removing' stamp: 'cmm 10/25/2010 22:26'!removeAll "remove all the elements from this collection. Keep same amount of storage" self setCollection: (self class arrayType new: array size)! !!OrderedCollection methodsFor: 'removing'!removeLast "Remove the last element of the receiver and answer it. If the receiver is empty, create an error notification." | lastObject | self emptyCheck. lastObject := array at: lastIndex. array at: lastIndex put: nil. lastIndex := lastIndex - 1. ^ lastObject! !!OrderedCollection methodsFor: 'removing' stamp: 'StephaneDucasse 10/18/2010 14:51'!removeAllSuchThat: aBlock "Remove each element of the receiver for which aBlock evaluates to true. The method in Collection is O(N^2), this is O(N)." | n | n := firstIndex. firstIndex to: lastIndex do: [:index | (aBlock value: (array at: index)) ifFalse: [ array at: n put: (array at: index). n := n + 1]]. array from: n to: lastIndex put: nil. lastIndex := n - 1! !!OrderedCollection methodsFor: 'removing' stamp: 'cmm 10/25/2010 22:26'!removeFirst: n "Remove first n object into an array" | list | list := self class arrayType new: n. 1 to: n do: [ : i | list at: i put: self removeFirst ]. ^ list! !!OrderedCollection methodsFor: 'removing' stamp: 'ul 2/24/2011 14:33'!reset "Quickly remove all elements. The objects will be still referenced, but will not be accessible." self resetTo: 1! !!OrderedCollection methodsFor: 'removing' stamp: 'cmm 10/25/2010 22:26'!removeLast: n "Remove last n object into an array with last in last position" | list | list := self class arrayType new: n. n to: 1 by: -1 do: [ : i | list at: i put: self removeLast ]. ^ list! !!OrderedCollection methodsFor: 'enumerating' stamp: 'CamilloBruni 3/22/2013 23:51'!reject: rejectBlock thenCollect: collectBlock " Optimized version of Collection>>#reject:thenCollect: " | newCollection | newCollection := self copyEmpty. firstIndex to: lastIndex do: [ :index | | element | element := array at: index. (rejectBlock value: element) ifFalse: [ newCollection addLast: (collectBlock value: element) ]]. ^ newCollection! !!OrderedCollection methodsFor: 'enumerating' stamp: 'CamilloBruni 3/22/2013 23:51'!select: selectBlock "Optimized version of Collection>>#select: " | newCollection element | newCollection := self copyEmpty. firstIndex to: lastIndex do: [ :index | (selectBlock value: (element := array at: index)) ifTrue: [ newCollection addLast: element ]]. ^ newCollection! !!OrderedCollection methodsFor: 'enumerating'!reverseDo: aBlock "Override the superclass for performance reasons." | index | index := lastIndex. [index >= firstIndex] whileTrue: [aBlock value: (array at: index). index := index - 1]! !!OrderedCollection methodsFor: 'enumerating' stamp: 'di 8/31/1999 13:13'!with: otherCollection collect: twoArgBlock "Collect and return the result of evaluating twoArgBlock with corresponding elements from this collection and otherCollection." | result | otherCollection size = self size ifFalse: [self error: 'otherCollection must be the same size']. result := self species new: self size. 1 to: self size do: [:index | result addLast: (twoArgBlock value: (self at: index) value: (otherCollection at: index))]. ^ result! !!OrderedCollection methodsFor: 'enumerating' stamp: 'CamilloBruni 3/22/2013 23:52'!reject: rejectBlock "Optimized version of Collection>>#reject:" | newCollection element | newCollection := self copyEmpty. firstIndex to: lastIndex do: [ :index | (rejectBlock value: (element := array at: index)) ifFalse: [ newCollection addLast: element ]]. ^ newCollection! !!OrderedCollection methodsFor: 'enumerating' stamp: 'CamilloBruni 3/22/2013 23:52'!collect: collectBlock thenSelect: selectBlock "Optimized version Collection>>#collect:thenSelect:" | newCollection newElement | newCollection := self copyEmpty. firstIndex to: lastIndex do: [ :index | newElement := collectBlock value: (array at: index). (selectBlock value: newElement) ifTrue: [ newCollection addLast: newElement ]]. ^ newCollection! !!OrderedCollection methodsFor: 'enumerating' stamp: 'bf 5/16/2000 16:30'!withIndexCollect: elementAndIndexBlock "Just like with:collect: except that the iteration index supplies the second argument to the block. Override superclass in order to use addLast:, not at:put:." | newCollection | newCollection := self species new: self size. firstIndex to: lastIndex do: [:index | newCollection addLast: (elementAndIndexBlock value: (array at: index) value: index - firstIndex + 1)]. ^ newCollection! !!OrderedCollection methodsFor: 'enumerating' stamp: 'sma 2/5/2000 15:22'!collect: aBlock "Evaluate aBlock with each of my elements as the argument. Collect the resulting values into a collection that is like me. Answer the new collection. Override superclass in order to use addLast:, not at:put:." | newCollection | newCollection := self species new: self size. firstIndex to: lastIndex do: [:index | newCollection addLast: (aBlock value: (array at: index))]. ^ newCollection! !!OrderedCollection methodsFor: 'enumerating'!do: aBlock "Override the superclass for performance reasons." | index | index := firstIndex. [index <= lastIndex] whileTrue: [aBlock value: (array at: index). index := index + 1]! !!OrderedCollection methodsFor: 'enumerating' stamp: 'CamilloBruni 3/22/2013 23:52'!select: selectBlock thenCollect: collectBlock " Optimized version Collection>>#select:thenCollect: " | newCollection element | newCollection := self copyEmpty. firstIndex to: lastIndex do: [ :index | element := array at: index. (selectBlock value: element) ifTrue: [ newCollection addLast: (collectBlock value: element) ]]. ^ newCollection! !!OrderedCollection methodsFor: 'enumerating' stamp: 'CamilloBruni 4/11/2011 15:34'!collect: aBlock from: fromIndex to: toIndex "Override superclass in order to use addLast:, not at:put:." | result | self ensureBoundsFrom: fromIndex to: toIndex. result := self species new: toIndex - fromIndex + 1. firstIndex + fromIndex - 1 to: firstIndex + toIndex - 1 do: [:index | result addLast: (aBlock value: (array at: index))]. ^ result! !!OrderedCollection methodsFor: 'enumerating' stamp: 'pmm 3/13/2010 11:33'!sort: aSortBlock "Sort this array using aSortBlock. The block should take two arguments and return true if the first element should preceed the second one." self size <= 1 ifTrue: [^ self]. "nothing to do" array mergeSortFrom: firstIndex to: lastIndex src: array shallowCopy dst: array by: aSortBlock! !!OrderedCollection methodsFor: 'testing' stamp: 'md 8/13/2008 21:40'!hasContentsInExplorer ^self notEmpty! !!OrderedCollection methodsFor: 'converting' stamp: 'stephane.ducasse 8/8/2009 10:48'!asArray ^ (Array new: self size) replaceFrom: 1 to: self size with: array startingAt: firstIndex.! !!OrderedCollection methodsFor: 'splitjoin' stamp: 'onierstrasz 4/12/2009 19:44'!join: aCollection | result | result := self class new. aCollection do: [:each | each appendTo: result] separatedBy: [self appendTo: result]. ^ result! !!OrderedCollection methodsFor: 'private'!collector "Private" ^ array! !!OrderedCollection methodsFor: 'private'!errorConditionNotSatisfied self error: 'no element satisfies condition'! !!OrderedCollection methodsFor: 'private' stamp: 'MarianoMartinezPeck 8/3/2011 14:37'!makeRoomAtFirst "Make some empty slots at the front of the array. If we have more than 50% free space, then just move the elements, so that the first 50% of the slots are free, otherwise add new free slots to the front by growing. Precondition: firstIndex = 1" | tally newFirstIndex newLastIndex | tally := self size. tally * 2 >= array size ifTrue: [ ^self growAtFirst ]. tally = 0 ifTrue: [ ^self resetTo: array size + 1 ]. newFirstIndex := array size // 2 + 1. newLastIndex := newFirstIndex - firstIndex + lastIndex. 0 to: tally - 1 do: [ :offset | array at: newLastIndex - offset put: (array at: lastIndex - offset) ]. array from: firstIndex to: newFirstIndex - 1 put: nil. firstIndex := newFirstIndex. lastIndex := newLastIndex! !!OrderedCollection methodsFor: 'private' stamp: 'CamilloBruni 4/11/2011 15:34'!ensureBoundsFrom: fromIndex to: toIndex (fromIndex < 1) ifTrue: [^self errorSubscriptBounds: fromIndex]. (toIndex + firstIndex - 1 > lastIndex) ifTrue: [^self errorSubscriptBounds: toIndex].! !!OrderedCollection methodsFor: 'private' stamp: 'cmm 10/25/2010 22:27'!growAtFirst "Add new empty slots to the front of array, while keeping the empty slots at the end." | newArray newFirstIndex newLastIndex | newArray := self class arrayType new: (array size * 2 max: 1). newFirstIndex := newArray size - array size + firstIndex. newLastIndex := newFirstIndex + lastIndex - firstIndex. newArray replaceFrom: newFirstIndex to: newLastIndex with: array startingAt: firstIndex. array := newArray. firstIndex := newFirstIndex. lastIndex := newLastIndex! !!OrderedCollection methodsFor: 'private' stamp: 'BG 1/9/2004 12:28'!removeIndex: removedIndex " removedIndex is an index in the range firstIndex .. lastIndex, such an index is not known from outside the collection. Never use this method in your code, it is meant for private use by OrderedCollection only. The method for public use is: #removeAt: " array replaceFrom: removedIndex to: lastIndex - 1 with: array startingAt: removedIndex+1. array at: lastIndex put: nil. lastIndex := lastIndex - 1.! !!OrderedCollection methodsFor: 'private' stamp: 'MarianoMartinezPeck 8/3/2011 14:37'!makeRoomAtLast "Make some empty slots at the end of the array. If we have more than 50% free space, then just move the elements, so that the last 50% of the slots are free, otherwise add new free slots to the end by growing. Precondition: lastIndex = array size" | tally newFirstIndex newLastIndex | tally := self size. tally * 2 >= lastIndex ifTrue: [ ^self growAtLast ]. tally = 0 ifTrue: [ ^self resetTo: 1 ]. newLastIndex := lastIndex // 2. newFirstIndex := newLastIndex - lastIndex + firstIndex. array replaceFrom: newFirstIndex to: newLastIndex with: array startingAt: firstIndex. array from: newLastIndex + 1 to: lastIndex put: nil. firstIndex := newFirstIndex. lastIndex := newLastIndex! !!OrderedCollection methodsFor: 'private' stamp: 'BG 1/9/2004 12:26'!find: oldObject " This method answers an index in the range firstIndex .. lastIndex, which is meant for internal use only. Never use this method in your code, the methods for public use are: #indexOf: #indexOf:ifAbsent: " | index | index := firstIndex. [index <= lastIndex] whileTrue: [(array at: index) = oldObject ifTrue: [^ index]. index := index + 1]. self errorNotFound: oldObject! !!OrderedCollection methodsFor: 'private' stamp: 'cmm 10/25/2010 22:27'!growAtLast "Add new empty slots to the end of array, while keeping the empty slots at the front." | newArray | newArray := self class arrayType new: (array size * 2 max: 1). newArray replaceFrom: firstIndex to: lastIndex with: array startingAt: firstIndex. array := newArray! !!OrderedCollection methodsFor: 'private' stamp: 'ar 4/16/1999 07:59'!resetTo: index firstIndex := index. lastIndex := firstIndex - 1! !!OrderedCollection methodsFor: 'private' stamp: 'BG 1/9/2004 12:29'!insert: anObject before: spot " spot is an index in the range firstIndex .. lastIndex, such an index is not known from outside the collection. Never use this method in your code, it is meant for private use by OrderedCollection only. The methods for use are: #add:before: to insert an object before another object #add:beforeIndex: to insert an object before a given position. " | "index" delta spotIndex| spotIndex := spot. delta := spotIndex - firstIndex. firstIndex = 1 ifTrue: [self makeRoomAtFirst. spotIndex := firstIndex + delta]. firstIndex := firstIndex - 1. array replaceFrom: firstIndex to: spotIndex - 2 with: array startingAt: firstIndex + 1. array at: spotIndex - 1 put: anObject." index := firstIndex := firstIndex - 1. [index < (spotIndex - 1)] whileTrue: [array at: index put: (array at: index + 1). index := index + 1]. array at: index put: anObject." ^ anObject! !!OrderedCollection methodsFor: 'private' stamp: 'di 11/14/97 12:54'!setCollection: anArray array := anArray. self reset! !!OrderedCollection methodsFor: 'private' stamp: 'apb 10/15/2000 18:10'!setContents: anArray array := anArray. firstIndex := 1. lastIndex := array size.! !!OrderedCollection methodsFor: 'copying'!copyEmpty "Answer a copy of the receiver that contains no elements." ^self species new! !!OrderedCollection methodsFor: 'copying' stamp: 'sw 1/26/96'!reversed "Answer a copy of the receiver with element order reversed. " | newCol | newCol := self species new. self reverseDo: [:elem | newCol addLast: elem]. ^ newCol"#(2 3 4 'fred') reversed"! !!OrderedCollection methodsFor: 'copying'!copyReplaceFrom: start to: stop with: replacementCollection "Answer a copy of the receiver with replacementCollection's elements in place of the receiver's start'th to stop'th elements. This does not expect a 1-1 map from replacementCollection to the start to stop elements, so it will do an insert or append." | newOrderedCollection delta startIndex stopIndex | "if start is less than 1, ignore stop and assume this is inserting at the front. if start greater than self size, ignore stop and assume this is appending. otherwise, it is replacing part of me and start and stop have to be within my bounds. " delta := 0. startIndex := start. stopIndex := stop. start < 1 ifTrue: [startIndex := stopIndex := 0] ifFalse: [startIndex > self size ifTrue: [startIndex := stopIndex := self size + 1] ifFalse: [(stopIndex < (startIndex - 1) or: [stopIndex > self size]) ifTrue: [self errorOutOfBounds]. delta := stopIndex - startIndex + 1]]. newOrderedCollection := self species new: self size + replacementCollection size - delta. 1 to: startIndex - 1 do: [:index | newOrderedCollection add: (self at: index)]. 1 to: replacementCollection size do: [:index | newOrderedCollection add: (replacementCollection at: index)]. stopIndex + 1 to: self size do: [:index | newOrderedCollection add: (self at: index)]. ^newOrderedCollection! !!OrderedCollection methodsFor: 'copying'!copyWith: newElement "Answer a copy of the receiver that is 1 bigger than the receiver and includes the argument, newElement, at the end." | newCollection | newCollection := self copy. newCollection add: newElement. ^newCollection! !!OrderedCollection methodsFor: 'copying' stamp: 'nice 10/5/2009 08:50'!postCopy array := array copy! !!OrderedCollection methodsFor: 'copying' stamp: 'nice 10/5/2009 10:18'!copyFrom: startIndex to: endIndex "Answer a copy of the receiver that contains elements from position startIndex to endIndex." ^self shallowCopy postCopyFrom: startIndex to: endIndex! !!OrderedCollection methodsFor: 'copying' stamp: 'nice 5/28/2008 21:02'!postCopyFrom: startIndex to: endIndex "finish copying the array in a certain range." endIndex < startIndex ifFalse: [ "Because actual size of the array may be greater than used size, postCopyFrom:to: may fail to fail and answer an incorrect result if this sanity check were not applied" (startIndex between: 1 and: self size) ifFalse: [^self error: 'startIndex is out of bounds']. (endIndex between: 1 and: self size) ifFalse: [^self error: 'endIndex is out of bounds']]. "Add a protection that lacks in Array>>postcopy" array := array copyFrom: startIndex + firstIndex - 1 to: (endIndex max: startIndex - 1) + firstIndex - 1. firstIndex := 1. lastIndex := array size! !!OrderedCollection class methodsFor: 'instance creation' stamp: 'cmm 10/25/2010 22:28'!new: anInteger withAll: anObject ^ self basicNew setContents: (self arrayType new: anInteger withAll: anObject)! !!OrderedCollection class methodsFor: 'instance creation' stamp: 'cmm 10/25/2010 22:27'!new: anInteger ^ self basicNew setCollection: (self arrayType new: anInteger)! !!OrderedCollection class methodsFor: 'instance creation' stamp: 'sma 5/12/2000 17:41'!new ^ self new: 10! !!OrderedCollection class methodsFor: 'instance creation' stamp: 'apb 10/15/2000 22:02'!ofSize: n "Create a new collection of size n with nil as its elements. This method exists because OrderedCollection new: n creates an empty collection, not one of size n." | collection | collection := self new: n. collection setContents: (collection collector). ^ collection! !!OrderedCollection class methodsFor: 'instance creation'!newFrom: aCollection "Answer an instance of me containing the same elements as aCollection." | newCollection | newCollection := self new: aCollection size. newCollection addAll: aCollection. ^newCollection" OrderedCollection newFrom: {1. 2. 3} {1. 2. 3} as: OrderedCollection {4. 2. 7} as: SortedCollection"! !!OrderedCollection class methodsFor: 'private' stamp: 'cmm 10/25/2010 22:26'!arrayType ^ Array! !!OrderedCollection class methodsFor: 'accessing' stamp: 'CamilloBruni 9/5/2011 15:38'!streamSpecies ^ Array! !!OrderedCollection class methodsFor: 'stream creation' stamp: 'CamilloBruni 9/5/2011 15:48'!new: size streamContents: aBlock ^ self withAll: (super new: size streamContents: aBlock)! !!Stream methodsFor: 'accessing' stamp: 'nk 4/29/2004 10:40'!openReadOnly ^self! !!Stream methodsFor: 'accessing' stamp: 'HenrikSperreJohansen 8/17/2012 11:30'!basicNext: anAmount putAll: aCollection startingAt: startIndex ^ self next: anAmount putAll: aCollection startingAt: startIndex.! !!Stream methodsFor: 'accessing' stamp: 'yo 8/30/2002 17:13'!basicNextPutAll: aCollection ^ self nextPutAll: aCollection.! !!Stream methodsFor: 'accessing'!nextMatchAll: aColl "Answer true if next N objects are the ones in aColl, else false. Advance stream of true, leave as was if false." | save | save := self position. aColl do: [:each | (self next) = each ifFalse: [ self position: save. ^ false] ]. ^ true! !!Stream methodsFor: 'accessing' stamp: 'yo 8/30/2002 17:13'!basicNextPut: anObject ^ self nextPut: anObject! !!Stream methodsFor: 'accessing' stamp: 'HenrikSperreJohansen 8/17/2012 11:30'!next: anInteger putAll: aCollection startingAt: startIndex "Store the next anInteger elements from the given collection." (startIndex = 1 and:[anInteger = aCollection size]) ifTrue:[^self nextPutAll: aCollection]. ^self nextPutAll: (aCollection copyFrom: startIndex to: startIndex+anInteger-1)! !!Stream methodsFor: 'accessing' stamp: 'MarianoMartinezPeck 8/24/2012 15:30'!upToEnd "answer the remaining elements in the string" | elements | elements := OrderedCollection new. [ self atEnd ] whileFalse: [ elements add: self next ]. ^elements! !!Stream methodsFor: 'accessing'!next: anInteger put: anObject "Make anObject be the next anInteger number of objects accessible by the receiver. Answer anObject." anInteger timesRepeat: [self nextPut: anObject]. ^anObject! !!Stream methodsFor: 'accessing' stamp: 'MarianoMartinezPeck 8/24/2012 15:59'!next "Answer the next object accessible by the receiver." self subclassResponsibility ! !!Stream methodsFor: 'accessing' stamp: 'MarianoMartinezPeck 8/24/2012 15:30'!next: anInteger "Answer the next anInteger number of objects accessible by the receiver." | aCollection | aCollection := OrderedCollection new. anInteger timesRepeat: [aCollection addLast: self next]. ^aCollection! !!Stream methodsFor: 'accessing' stamp: 'MarianoMartinezPeck 8/24/2012 15:59'!flush "Do nothing by default" ! !!Stream methodsFor: 'accessing' stamp: 'MarianoMartinezPeck 8/24/2012 15:59'!nextPut: anObject "Insert the argument, anObject, as the next object accessible by the receiver. Answer anObject." self subclassResponsibility ! !!Stream methodsFor: 'accessing' stamp: 'MarianoMartinezPeck 8/24/2012 15:59'!binary "do nothing" ^self ! !!Stream methodsFor: 'accessing' stamp: 'yo 8/30/2002 17:13'!basicNext ^ self next.! !!Stream methodsFor: 'accessing'!contents "Answer all of the contents of the receiver." self subclassResponsibility! !!Stream methodsFor: 'accessing' stamp: 'MarianoMartinezPeck 8/24/2012 15:29'!nextPutAll: aCollection "Append the elements of aCollection to the sequence of objects accessible by the receiver. Answer aCollection." aCollection do: [:v | self nextPut: v]. ^aCollection! !!Stream methodsFor: 'accessing' stamp: 'nk 4/29/2004 10:41'!readOnly ^self! !!Stream methodsFor: 'accessing' stamp: 'nk 4/29/2004 10:38'!localName ^'a stream'! !!Stream methodsFor: 'accessing'!nextMatchFor: anObject "Gobble the next object and answer whether it is equal to the argument, anObject." ^anObject = self next! !!Stream methodsFor: 'filter streaming' stamp: 'MPW 1/1/1901 00:48'!write:encodedObject ^encodedObject putOn:self.! !!Stream methodsFor: '*Monticello' stamp: 'cwp 8/9/2003 12:02'!isMessageStream ^ false! !!Stream methodsFor: 'printing' stamp: 'sma 6/1/2000 09:56'!print: anObject "Have anObject print itself on the receiver." anObject printOn: self! !!Stream methodsFor: 'enumerating'!do: aBlock "Evaluate aBlock for each of the objects accessible by receiver." [self atEnd] whileFalse: [aBlock value: self next]! !!Stream methodsFor: 'file open/close' stamp: 'MarianoMartinezPeck 8/24/2012 15:59'!close "Presumably sets the status of the receiver to be closed. This message does nothing at this level, but is included for FileStream compatibility." ^self ! !!Stream methodsFor: 'readability' stamp: 'kph 9/27/2007 21:53'!<< items items putOn: self. ^ self! !!Stream methodsFor: 'testing' stamp: 'MarcusDenker 7/15/2012 15:43'!isBinary ^false! !!Stream methodsFor: 'testing' stamp: 'ar 12/23/1999 15:43'!isStream "Return true if the receiver responds to the stream protocol" ^true! !!Stream methodsFor: 'testing' stamp: 'MarianoMartinezPeck 8/24/2012 15:59'!atEnd "Answer whether the receiver can access any more objects." self subclassResponsibility ! !!Stream methodsFor: 'testing' stamp: 'ab 8/28/2003 18:30'!closed ^ false! !!Stream methodsFor: 'testing' stamp: 'ClementBera 9/30/2013 10:56'!nextWordsPutAll: aCollection "Write the argument a word-like object in big endian format on the receiver. May be used to write other than plain word-like objects (such as ColorArray)." (aCollection class isPointers or: [ aCollection class isWords not ]) ifTrue: [ ^ self error: aCollection class name,' is not word-like']. 1 to: aCollection basicSize do: [ :i | self nextNumber: 4 put: (aCollection basicAt: i) ]. ^ aCollection! !!Stream methodsFor: '*Fuel' stamp: 'MartinDias 8/13/2011 14:29'!nextBytesPutAll: aCollection "Append the bytes of aCollection to the sequence of bytes accessible by the receiver. Answer aCollection." ^self nextPutAll: aCollection! !!Stream class methodsFor: 'instance creation' stamp: 'MarianoMartinezPeck 8/24/2012 15:59'!new self error: 'Streams are created with on: and with:'! !Symbol initialize!Collection initialize!