prototypes ensureDelegatedNamespace: #collections. collections addPrototype: #Collection derivedFrom: {Cloneable}. "The abstract object type for Collections, objects which other objects can be added and removed and tested for as elements." "Some common idioms for testing collections." c@(Collection traits) isEmpty [c size = 0]. c@(Collection traits) isNotEmpty [c isEmpty not]. c@(Collection traits) isFull [c size = c capacity]. c@(Collection traits) newEmpty "By default, new collections should be spaced to hold a certain amount, which makes working with small collections frequently less of a pain." [ c newSize: 10 ]. c@(Collection traits) newSizeOf: x "A flexible method which uses the result of whatever size method the second argument defines." [ c newSize: x size ]. c@(Collection traits) newSameSize "Returns a new collection of the same size as the given one." [ c newSizeOf: c ]. c@(Collection traits) accepts: obj "Some collections are implemented so that certain types of objects cannot be encoded as elements, in which case, add: or at:put: would fail. Here's the default method." [ True ]. c@(Collection traits) as: d@(Collection traits) "The default conversion between collections uses this method which doesn't get overridden." [ d newWithAll: c ]. c@(Collection traits) newWithAll: d@(Collection traits) "Make a new collection of kind c and stuff in all of d's elements." [ ((c newSizeOf: d) writer ; d) contents ]. c@(Collection traits) anyOne "Return the first (any) element possible, not a random one." [ c emptyCheck. c do: [| :each | ^ each]. ]. c@(Collection traits) size "Tally up the number of elements in the Collection." [| tally | tally: 0. c do: [| :each | tally: tally + 1]. tally ]. c@(Collection traits) capacity "How much can it carry? This does not always equal size." [ c size ]. c@(Collection traits) 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." [| result | result: resend. c size <= 10 ifTrue: [c do: [| :each | result: (result bitXor: each hash)]]. result bitXor: c size hash ]. c@(Collection traits) contents "Answer c's elements. Provides compatibility with other collections with complex implementations." [ c ]. c@(Collection traits) do: block "Evaluate the block once for each element on that value." [overrideThis]. c@(Collection traits) inject: start into: block "Accumulate a running value starting with the input and running a block on it and each element of a collection in turn. The result of the block is implicitly the next value." [| result | result: start. c do: [| :element | result: (block applyWith: result with: element)]. result ]. c@(Collection traits) collect: block "Answer a new collection resulting from mapping the block onto each element. This returns a collection of the same kind." [| result | result: c newSameSize writer. c do: [| :each | result nextPut: (block applyWith: each)]. result contents ]. c@(Collection traits) count: test "Return the number of elements of the collection satisfying the test." [| sum | sum: 0. c do: [| :each | (test applyWith: each) ifTrue: [sum: sum + 1]]. sum ]. c@(Collection traits) detect: succeed ifNone: fail "Find an element satisfying a test. Conditionally execute a failure block." [ c do: [| :element | (succeed applyWith: element) ifTrue: [^ element]]. fail do ]. c@(Collection traits) detect: succeed "Supply a default failure block to detect:ifNone: which just answers Nil." [ c detect: succeed ifNone: [] ]. c@(Collection traits) anySatisfy: predicate "Answer whether any elements cause the input block to be True." [ c do: [| :element | (predicate applyWith: element) ifTrue: [^ True]]. False ]. c@(Collection traits) allSatisfy: predicate "Answer whether all elements cause the input block to be True." [ c do: [| :element | (predicate applyWith: element) ifFalse: [^ False]]. True ]. c@(Collection traits) noneSatisfy: predicate "Answer whether none of c's elements cause the input block to be True." [ c do: [| :element | (predicate applyWith: element) ifTrue: [^ False]]. True ]. c@(Collection traits) select: test into: result "Write the elements of c satisfying the test block into the given resulting collection." [| result | result: result writer. c do: [| :each | (test applyWith: each) ifTrue: [result nextPut: each]]. result contents ]. c@(Collection traits) select: test "Answer a subset of c containing those elements causing the input block to return True." [ c select: test into: c newEmpty ]. c@(Collection traits) select: test collect: block "An optimization for staged collect:'s on select: results." [| result | result: c newEmpty. c do: [| :each | (test applyWith: each) ifTrue: [result nextPut: (block applyWith: each)]]. result contents ]. c@(Collection traits) collect: block select: test "An optimization for staged select:'s on collect: results." [| result | result: c newEmpty writer. c do: [| :each tmp | tmp: (block applyWith: each). (test applyWith: tmp) ifTrue: [result nextPut: tmp]]. result contents ]. c@(Collection traits) reduce: binBlock ifEmpty: emptyBlock "Reduce works like inject except that the first element of the collection is used as the injected element for the rest of the collection. e.g. #{1. 2. 3 .4} reduce: [| :a :b | a + b] returns a sum of the elements." [| result | c isEmpty ifTrue: [^ emptyBlock do]. result: c first. c allButFirstDo: [| :each | result: (binBlock applyWith: result with: each) ]. result ]. c@(Collection traits) reduce: binBlock "Same as reduce:ifEmpty:, except doing nothing in the empty case." [ c reduce: binBlock ifEmpty: [] ]. c@(Collection traits) reject: test "Answer the complement of select:, a subset of the collection containing those elements causing the input block to return False." [ c select: [| :each | (test applyWith: each) not] ]. c@(Collection traits) copyWithout: obj "Return a new collection with all elements equal to the given ones removed." [ c reject: [| :each | each = obj] ]. c@(Collection traits) difference: d@(Collection traits) "Answer the subset of c that are not elements of d." [ c reject: [| :each | d includes: each] ]. c@(Collection traits) intersection: d@(Collection traits) "Answer a collection of kind c with elements that are common to both c and d." [ c select: [| :each | d includes: each] ]. c@(Collection traits) /\ d@(Collection traits) [ c intersection: d ]. c@(Collection traits) union: d@(Collection traits) "Answer a Set with elements from both input collections." [ ((c as: Set) writer ; d) collection ]. c@(Collection traits) \/ d@(Collection traits) [ c union: d ]. c@(Collection traits) includes: obj "Return whether some object equal to the input is in the collection." [ c anySatisfy: [| :each | each = obj] ]. c@(Collection traits) identityIncludes: obj "Return whether the input object is in the collection." [ c anySatisfy: [| :each | each == obj] ]. c@(Collection traits) includesAllOf: d "Return whether d is a subset of c. All elements of d are in c." [ d do: [| :each | (c includes: each) ifFalse: [^ False]]. True ]. c@(Collection traits) includesAnyOf: d "Return whether the collections have any common elements." [ d do: [| :each | (c includes: each) ifTrue: [^ True]]. False ]. c@(Collection traits) occurrencesOf: obj "Return how many times the input object occurs in the collection." [| tally | tally: 0. c do: [| :each | obj = each ifTrue: [tally: tally + 1]]. tally ].