! ========================================================================
! Copyright (C) by VMware, Inc. 1991-2011.  All Rights Reserved
!
! $Id: collect.gs,v 1.15.2.4 2008-03-04 19:03:19 dhenrich Exp $
!
! Class Hierarchy:
!	Collection, Object.
!
! ========================================================================

removeallmethods Collection
removeallclassmethods Collection

! ------------------- Class methods for Collection

category: 'For Documentation Installation only'
classmethod: Collection
installDocumentation

| doc txt |
doc := GsClassDocumentation newForClass: self.

txt := (GsDocText new) details:
'Collection is an abstract superclass for all classes whose instances represent
 a collection of other objects that are known as their elements.  It defines
 methods for operating upon the elements as a whole.

 You should not add elements to or remove elements from a Collection at the same
 time as you are iterating over all or part of the Collection.  Doing so may
 have unpredictable consequences.  For example, avoid changing a Collection
 within the block argument for methods like do:, collect:, select:, reject:, and
 their variants or extensions.' .
doc documentClassWith: txt.

self description: doc.
%

category: 'Instance Creation'
classmethod: Collection
with: aValue

"Returns an instance of the receiver containing the argument."

| inst |
inst := self new.
inst add: aValue.
^inst
%

category: 'Instance Creation'
classmethod: Collection
with: aValue with: val2

"Returns an instance of the receiver containing the arguments."

| inst |
inst := self new.
inst add: aValue; add: val2.
^inst
%

category: 'Instance Creation'
classmethod: Collection
with: aValue with: val2 with: val3

"Returns an instance of the receiver containing the arguments."

| inst |
inst := self new.
inst add: aValue; add: val2; add: val3.
^inst
%

category: 'Instance Creation'
classmethod: Collection
with: aValue with: val2 with: val3 with: val4

"Returns an instance of the receiver containing the arguments."

| inst |
inst := self new.
inst add: aValue; add: val2; add: val3; add: val4.
^inst
%

category: 'Instance Creation'
classmethod: Collection
withAll: aCollection

"Returns an instance of the receiver containing the elements of the argument."

| result |

result:= self new.
result addAll: aCollection.
^result
%

! ------------------- Instance methods for Collection

category: 'Error Handling'
method: Collection
_errorNotFound: anObject

"Sends an error message indicating that the expected object was not found."

^ self _error: #objErrNotInColl args: #[anObject]
%

category: 'Adding'
method: Collection
add: newObject

"Makes newObject one of the receiver's elements and returns newObject."

"Note: In GemStone 4.1, this method returned the receiver."

Collection subclassResponsibility: #add:
%

category: 'Adding'
method: Collection
addAll: aCollection

"Adds all of the elements of aCollection to the receiver and returns
 aCollection."

"Note: In GemStone 4.1, (1) this method returned the receiver and (2) if the
 argument was a kind of AbstractDictionary, this method added all the
 Associations of the key/value pairs stored in the argument."

(self == aCollection) ifTrue: [ ^ self addAll: (aCollection copy) ].
aCollection do: [:each | self add: each ].
^ aCollection.
%

category: 'Converting'
method: Collection
asArray

"Returns an Array with the contents of the receiver."

^Array withAll: self
%

category: 'Converting'
method: Collection
asByteArray

"Returns an Array with the contents of the receiver."

^ByteArray withAll: self
%

category: 'Converting'
method: Collection
asBag

"Returns a Bag with the contents of the receiver."

^Bag withAll: self
%

category: 'Converting'
method: Collection
asIdentityBag

"Returns an IdentityBag with the contents of the receiver."

^IdentityBag withAll: self
%

category: 'Converting'
method: Collection
asIdentitySet

"Returns an IdentitySet with the contents of the receiver."

^IdentitySet withAll: self
%

category: 'Converting'
method: Collection
asOrderedCollection

"Returns an OrderedCollection with the contents of the receiver."

^OrderedCollection withAll: self
%

category: 'Converting'
method: Collection
asSet

"Returns a Set with the contents of the receiver."

^Set withAll: self
%

category: 'Converting'
method: Collection
asSortedCollection

"Returns a SortedCollection with the contents of the receiver."

^SortedCollection withAll: self
%

category: 'Converting'
method: Collection
asSortedCollection: sortBlock

"Returns a SortedCollection with the contents of the receiver, using the
 given sort block."

| coll |
coll := SortedCollection sortBlock: sortBlock.
coll addAll: self.
^coll
%

category: 'Converting'
method: Collection
asSortedOrderedCollection

"Returns an OrderedCollection that has been sorted with a SortedCollection
 and having the contents of the receiver."

^OrderedCollection withAll: (SortedCollection withAll: self)
%

category: 'Clustering'
method: Collection
clusterDepthFirst

"This method clusters the receiver and its named and unnamed instance variables
 in depth-first order.  Returns true if the receiver has already been clustered
 during the current transaction; returns false otherwise."

self cluster
  ifTrue: [ ^ true ]
  ifFalse:[ 
    1 to: self class instSize do: [ :i | (self instVarAt: i) clusterDepthFirst ].
    self do: [ :each | each clusterDepthFirst ].
    ^ false 
    ].
%

category: 'Enumerating'
method: Collection
collect: aBlock

"Evaluates aBlock with each of the receiver's elements as the argument.
 Collects the resulting values into a collection of class specified by
 sending #speciesForCollect message to the receiver. Returns the new 
 collection. The argument aBlock must be a one-argument block.

 For SequenceableCollections, the result preserves the ordering of the
 receiver.  That is, if element a comes before element b in the receiver,
 then element a is guaranteed to come before b in the result."

|result|

result := self speciesForCollect new .
self do: [ :each | result add: (aBlock value: each) ].
^ result
%

category: 'Enumerating'
method: Collection
detect: aBlock

"Evaluates aBlock repeatedly, with elements of the receiver as the argument.
 Returns the first element for which aBlock evaluates to true.  If none of the
 receiver's elements evaluates to true, generates an error.  The argument
 aBlock must be a one-argument block."

^ self detect: aBlock
       ifNone: [^ self _error: #assocErrNoElementsDetected args: #[aBlock]]
%

category: 'Enumerating'
method: Collection
detect: aBlock ifNone: exceptionBlock

"Evaluates aBlock repeatedly, with elements of the receiver as the argument.
 Returns the first element for which aBlock evaluates to true.  If none of the
 receiver's elements evaluates to true, this evaluates the argument
 exceptionBlock and returns its value.  The argument aBlock must be a
 one-argument block, and exceptionBlock must be a zero-argument block."

self do: [:each| (aBlock value: each) ifTrue: [^each]].
^exceptionBlock value
%

category: 'Enumerating'
method: Collection
do: aBlock

"Evaluates the one-argument block aBlock using each element of the
 receiver in order.  Returns the receiver."

"Must be reimplemented in subclasses such as Dictionary which have different 
 format or implementation."

1 to: self size do: [:i | 
  aBlock value: (self at: i) ].

^ self
%

category: 'Error Handling'
method: Collection
errorDifferentSizeCollections

"Reports an error indicating that the size of the receiver collection is 
 different from the size of the argument collection."

^ self _error: #objErrDiffSizeColl 
%

category: 'Error Handling'
method: Collection
errorInvalidArgClass: argument classes: classArray

"Reports an error indicating that the class of argument is not one of those
 specified in classArray."

^ self _error: #rtErrInvalidArgClass args: #[ argument, classArray]. 
%

category: 'Searching'
method: Collection
identicalOccurrencesOf: anObject

"Returns the number of the receiver's elements that are identical (==) to
 anObject."

| result |

result := 0.
self do: [ :element | 
  (anObject == element) ifTrue: [ result := result + 1 ]
  ].
^result
%

category: 'Searching'
method: Collection
includes: anObject

"Returns true if anObject is equal to one of the elements of the receiver. 
 Returns false otherwise."

"Note: In GemStone 4.1, this method returned true only if one of the elements of
 the receiver was identical to anObject. For functionality similar to that 
 provided by GemStone 4.1, use #includesIdentical:."

self do: [ :element | (anObject = element) ifTrue: [ ^true ]].
^false
%

category: 'Searching'
method: Collection
includesIdentical: anObject

"Returns true if anObject is identical to one of the elements of the receiver. 
 Returns false otherwise."

self do: [ :element | (anObject == element) ifTrue: [ ^true ]].
^false
%

category: 'Searching'
method: Collection
includesValue: anObject

"Returns true if anObject is equal to one of the elements of the receiver. 
 Returns false otherwise."

"Note: This method is the same as #includes:"

^ self includes: anObject.
%

category: 'Enumerating'
method: Collection
inject: aValue into: aBlock

"Accumulates a running value associated with evaluating the argument,
 aBlock, with the current value and the each element of the receiver
 as block arguments.  The initial value is the value of the argument, aValue.
 For example: total := #(1 2 3 4) inject: 0 into: [:sum:int | sum + int]"

| val |

val := aValue.
self do: [:element | val := aBlock value: val value: element ].
^val
%

category: 'Testing'
method: Collection
isEmpty

"Returns true if the receiver is empty.  Returns false otherwise."

^self size == 0
%

category: 'Testing'
method: Collection
notEmpty

"Returns true if the receiver is not empty.  Returns false otherwise."

^self size > 0
%

category: 'Searching'
method: Collection
occurrencesOf: anObject

"Returns the number of the receiver's elements that are equal to anObject."

"Note: In GemStone 4.1, this method returned the number of elements that were
 identical to anObject. For functionality similar to that provided in 
 GemStone 4.1, use #identicalOccurrencesOf:"

| count |

count := 0.
self do: [ :element| (anObject = element) ifTrue: [count := count + 1]].
^count.
%

category: 'Formatting'
method: Collection
printOn: aStream

"Puts a displayable representation of the receiver on the given stream."

| count sz |
super printOn: aStream .
aStream nextPutAll: '( ' .
count := 1 .
sz := self size .
self do:[:anElement | 
  aStream position > 700 ifTrue:[
    "prevent infinite recursion when printing cyclic structures, and 
     limit the size of result when printing large collections."
    aStream nextPutAll: '...)' .
    ^ self 
    ] .
  anElement printOn: aStream .
  count < sz ifTrue:[ aStream nextPutAll: ', ' ].
  count := count + 1 .
  ].
aStream nextPut: $) .
%

category: 'Enumerating'
method: Collection
reject: aBlock

"Evaluates aBlock with each of the receiver's elements as the argument.  Stores
 the values for which aBlock is false into a collection of the same class as
 the receiver, and returns the new collection.  The argument aBlock must be a
 one-argument block.

 For SequenceableCollections, the result preserves the ordering of the
 receiver.  That is, if element a comes before element b in the receiver,
 then element a is guaranteed to come before b in the result."

|result|
result := self speciesForSelect new.
self do: [:each|
  (aBlock value: each) ifFalse: [result add: each]
  ].

^ result
%

category: 'Removing'
method: Collection
remove: oldObject

"Removes from the receiver an object that is equivalent to oldObject and
 returns oldObject.  If several elements of the receiver are equivalent to 
 oldObject, only one instance is removed.  If oldObject has no equivalent 
 elements in the receiver, raises an error."

"Note: In GemStone 4.1, this method returned the receiver."

^ self remove: oldObject ifAbsent: [self _errorNotFound: oldObject]
%

category: 'Removing'
method: Collection
removeIdentical: oldObject

"Removes from the receiver an object that is identical to oldObject, and
 returns oldObject.  If several elements of the receiver are identical to 
 oldObject, only one instance is removed.  If oldObject is not present in
 the receiver, raises an error."

^ self removeIdentical: oldObject ifAbsent: [self _errorNotFound: oldObject]
%

category: 'Removing'
method: Collection
remove: oldObject ifAbsent: anExceptionBlock

"Removes from the receiver an object that is equivalent to oldObject and
 returns oldObject.  If several elements of the receiver are equivalent to 
 oldObject, only one instance is removed.  If oldObject has no equivalent 
 elements in the receiver, anExceptionBlock is evaluated and the result of the
 evaluation is returned."

"Note: In GemStone 4.1, this method returned the receiver." 

^ self subclassResponsibility: #remove:ifAbsent:
%

category: 'Removing'
method: Collection
removeIdentical: oldObject ifAbsent: anExceptionBlock

"Removes from the receiver an object that is identical to oldObject and
 returns oldObject.  If several elements of the receiver are identical to 
 oldObject, only one instance is removed.  If oldObject is not present in
 the receiver, anExceptionBlock is evaluated and the result of the
 evaluation is returned."

^ self subclassResponsibility: #removeIdentical:ifAbsent:
%

category: 'Removing'
method: Collection
removeAll: aCollection

"For each element in aCollection, removes from the receiver one element that is
 equivalent to the element in aCollection.  Returns aCollection if successful."

"Note: In GemStone 4.1, this method returned the receiver."

aCollection == self ifTrue:[ 
  self size: 0 .
  ^ aCollection
  ].
aCollection do: [ :element | self remove: element ].
^ aCollection.
%

category: 'Removing'
method: Collection
removeAllIdentical: aCollection

"For each element in aCollection, removes from the receiver one element that is
 identical to the element in aCollection.  Returns aCollection if successful."

aCollection do: [ :element | self removeIdentical: element ].
^ aCollection.
%

category: 'Enumerating'
method: Collection
select: aBlock

"Evaluates aBlock with each of the receiver's elements as the argument.
 Stores the values for which aBlock is true into a collection of the
 same class as the receiver, and returns the new collection.
 The argument aBlock must be a one-argument block.

 For SequenceableCollections, the result preserves the ordering of the
 receiver.  That is, if element a comes before element b in the receiver,
 then element a is guaranteed to come before b in the result.

 The new collection that this method returns does not retain any indexes of the
 receiver.  If you want to perform indexed selections on the new collection,
 you must build all of the necessary indexes.  For more information, see the
 GemStone Programming Guide."

| result |

result:= self speciesForSelect new.
self do: [ :each | (aBlock value: each) ifTrue: [result add: each]].
^result
%

category: 'Enumerating'
method: Collection
speciesForCollect

"Returns a class, an instance of which should be used as the result of
 collect: or other projections applied to the receiver."

"Collection returns a default: its own class.  Most subclasses of Collection
 reimplement this method."

^ self class
%

category: 'Sorting'
method: Collection
sortAscending

"Returns an Array containing the elements of the receiver sorted in ascending
 order."

^ self sortAscending: '' persistentRoot: nil.
%

category: 'Sorting'
method: Collection
sortDescending

"Returns an Array containing the elements of the receiver sorted in descending
 order."

^ self sortDescending: '' persistentRoot: nil.
%

category: 'Sorting'
method: Collection
sortAscending: aSortSpec persistentRoot: persistentArrayOrNil

"Returns an Array containing the elements of the receiver, sorted in ascending
 order, as determined by the values of the instance variables represented by
 aSortSpec.  The argument aSortSpec must be either a String representing a
 single path, or an Array holding up to 16 such Strings (each representing a
 path).  If aSortSpec is an Array, the first path in the Array is the primary
 sort key, and the remaining paths are taken in order as subordinate keys.

 Each path in aSortSpec must follow the rules for equality indexes.
 In addition, if any path in aSortSpec is an empty path (that is, a zero-length
 String), the sort is performed upon the elements of the receiver itself,
 rather than upon the instance variables of those elements."

| arg |

arg := Array new.

(aSortSpec isKindOf: CharacterCollection)
  ifTrue: [ arg add: aSortSpec ; add: #ASCENDING ]
  ifFalse: [ aSortSpec do: [ :each | arg add: each ; add: #ASCENDING ]].

^ self sortWith: arg persistentRoot: persistentArrayOrNil
%

category: 'Sorting'
method: Collection
sortAscending: aSortSpec

"Returns an Array containing the elements of the receiver, sorted in ascending
 order, as determined by the values of the instance variables represented by
 aSortSpec.  The argument aSortSpec must be either a String representing a
 single path, or an Array holding up to 16 such Strings (each representing a
 path).  If aSortSpec is an Array, the first path in the Array is the primary
 sort key, and the remaining paths are taken in order as subordinate keys.

 Each path in aSortSpec must follow the rules for equality indexes.
 In addition, if any path in aSortSpec is an empty path (that is, a zero-length
 String), the sort is performed upon the elements of the receiver itself,
 rather than upon the instance variables of those elements."

^self sortAscending: aSortSpec persistentRoot: nil
%

category: 'Sorting'
method: Collection
sortDescending: aSortSpec persistentRoot: persistentArrayOrNil

"Returns an Array containing the elements of the receiver, sorted in descending
 order, as determined by the values of the instance variables represented by
 aSortSpec.  The argument aSortSpec must be either a String representing a
 single path, or an Array holding up to 16 such Strings (each representing a
 path).  If aSortSpec is an Array, the first path in the Array is the primary
 sort key, and the remaining paths are taken in order as subordinate keys.

 Each path in aSortSpec must follow the rules for equality indexes.
 In addition, if any path in aSortSpec is an empty path (that is, a zero-length
 String), the sort is performed upon the elements of the receiver itself,
 rather than upon the instance variables of those elements."

| arg |

arg := Array new.

(aSortSpec isKindOf: CharacterCollection)
  ifTrue: [ arg add: aSortSpec ; add: #DESCENDING ]
  ifFalse: [ aSortSpec do: [ :each | arg add: each ; add: #DESCENDING ]].

^ self sortWith: arg persistentRoot: persistentArrayOrNil
%

category: 'Sorting'
method: Collection
sortDescending: aSortSpec

"Returns an Array containing the elements of the receiver, sorted in descending
 order, as determined by the values of the instance variables represented by
 aSortSpec.  The argument aSortSpec must be either a String representing a
 single path, or an Array holding up to 16 such Strings (each representing a
 path).  If aSortSpec is an Array, the first path in the Array is the primary
 sort key, and the remaining paths are taken in order as subordinate keys.

 Each path in aSortSpec must follow the rules for equality indexes.
 In addition, if any path in aSortSpec is an empty path (that is, a zero-length
 String), the sort is performed upon the elements of the receiver itself,
 rather than upon the instance variables of those elements."

^ self sortDescending: aSortSpec persistentRoot: nil
%

category: 'Sorting'
method: Collection
sortWith: aSortPairArray persistentRoot: persistentArrayOrNil

"Returns an Array containing the elements of the receiver, sorted according to
 the contents of aSortPairArray.  The argument aSortPairArray is an Array of
 Strings that represent path/direction pairs, in the following form:

 aCollection sortWith: #('a.b' 'ASCENDING' 'a.c' 'DESCENDING' ...)

 That Array may contain up to 16 path/direction pairs.  The first path in the
 Array is the primary sort key, and the remaining paths are taken in order as
 subordinate keys.

 In aSortPairArray, each path String must follow the rules for equality
 indexes.  Each direction String must be either 'ASCENDING' or
 'DESCENDING' (case-insensitive); otherwise, an error is generated.

 In addition, if any path in aSortPairArray is an empty path (that is, a
 zero-length String), the sort is performed upon the elements of the receiver
 itself, rather than upon the instance variables of those elements.

 If persistentArrayOrNil is notNil, then it is expected to be an empty persistent array and
 the array will be used to persist large temporary data structures created during
 the sorting operation. IndexManager>>autoCommit must be true in order for periodic
 commits to  be made during the sorting operation. When the sort operation is complete
 the persistent array will be emptied and a final commit performed. The persistentArrayOrNil 
 and  IndexManager>>autoCommit should be used when a collection is so large that it 
 isn't practical to allocate enough temporary memory."

| paths booleans thePath directionStr directionSym directionBool result |

paths := Array new.
booleans := Array new.

(aSortPairArray size even) & (aSortPairArray size > 0)
    ifFalse: [ ^ aSortPairArray _error: #assocErrSortOddLengthArray ].

1 to: aSortPairArray size by: 2 do: [ :i |
    thePath := aSortPairArray at: i.
    thePath _class == String ifFalse:[
      thePath _validateClasses: #[String, DoubleByteString].
      ].
    directionStr := (aSortPairArray at: i + 1) .
    directionBool := true .
    directionStr == #ASCENDING 
      ifFalse:[
        (directionStr == #DESCENDING )
          ifTrue:[ directionBool := false ]
          ifFalse:[
            directionSym := directionStr asUppercase asSymbol .
            directionSym == #ASCENDING 
              ifFalse:[
                directionSym == #DESCENDING 
                  ifTrue: [ directionBool := false ]
                  ifFalse: [ directionStr _error: #assocErrBadDirection ].
                ].
            ].
         ].
    paths add: thePath.
    booleans add: directionBool .
].
result := self _sortPaths: paths directions: booleans persistentRoot: persistentArrayOrNil.
^ result
%

category: 'Sorting'
method: Collection
sortWith: aSortPairArray

"Returns an Array containing the elements of the receiver, sorted according to
 the contents of aSortPairArray.  The argument aSortPairArray is an Array of
 Strings that represent path/direction pairs, in the following form:

 aCollection sortWith: #('a.b' 'ASCENDING' 'a.c' 'DESCENDING' ...)

 That Array may contain up to 16 path/direction pairs.  The first path in the
 Array is the primary sort key, and the remaining paths are taken in order as
 subordinate keys.

 In aSortPairArray, each path String must follow the rules for equality
 indexes.  Each direction String must be either 'ASCENDING' or
 'DESCENDING' (case-insensitive); otherwise, an error is generated.

 In addition, if any path in aSortPairArray is an empty path (that is, a
 zero-length String), the sort is performed upon the elements of the receiver
 itself, rather than upon the instance variables of those elements."

^ self sortWith: aSortPairArray persistentRoot: nil
%

category: 'Sorting'
method: Collection
_sortPaths: thePaths directions: theBooleans persistentRoot: persistentArrayOrNil

""

| thePath pathArrays indexObjs result |

pathArrays := Array new: thePaths size.

" do some error checking "
1 to: thePaths size do: [ :i |
    thePath := thePaths at: i.
    " check the string size "
    thePath size > 1024 ifTrue: [ ^ thePath _error: #assocErrPathTooLong ].

    " set-valued pathTerms disallowed in asArrayOfPathTerms "
    pathArrays at: i put: thePath asArrayOfPathTerms
    ].

indexObjs := self _indexObjectsFor: pathArrays.

result := (indexObjs at: 1) _sortOn: indexObjs directions: theBooleans persistentRoot: persistentArrayOrNil.
^ result
%

category: 'Sorting'
method: Collection
_sortPaths: thePaths directions: theBooleans

""

^ self _sortPaths: thePaths directions: theBooleans  persistentRoot: nil
%

category: 'Private'
method: Collection
_indexedPaths

"Returns the indexed paths for the receiver.  This is a private method that
 should only be used for sorting/indexing."

"This method should be reimplemented for classes where _indexedPaths is 
 defined."

^ nil
%

category: 'Private'
method: Collection
_indexObjectsFor: pathArrays

"Returns an Array of index objects (either PathEvaluators or
 RangeEqualityIndexes) that correspond to the paths described
 in the pathArrays (each element is an Array of Strings)."

| pathArray indexObj indexObjs k sz |

indexObjs := Array new.
1 to: pathArrays size do: [ :i |
  pathArray := pathArrays at: i.

  indexObj := self _findRangeIndexWithPath: pathArray.
  indexObj == nil
  ifTrue: [
    indexObj := PathEvaluator new nsc: self.

    1 to: pathArray size do: [ :j |
      indexObj addLast: (pathArray at: j)
      ].
    indexObj asMostSpecificType.

    indexObjs isEmpty
      ifTrue: [ indexObjs add: indexObj ]
      ifFalse: [
        " don't add a duplicate path "
        k := 1.
        sz := indexObjs size.
        [ k <= sz _and:
        [ (indexObj hasSamePathAs: (indexObjs at: k)) not ] ] whileTrue: [
          k := k + 1.
          ].
        k > sz ifTrue: [ indexObjs add: indexObj ].
    ]
  ]
  ifFalse: [ indexObjs add: indexObj ]
].

^ indexObjs
%

category: 'Private'
method: Collection
_findRangeIndexWithPath: pathArray

"Redefine this method for classes that support indexes."

^ nil
%

category: 'Private'
method: Collection
_asCollectionForSorting

"Redefine this method for classes that understand _at: or have different 
 semantics for the do: method."

| result |

result := Array new.
self do: [ :element | result add: element ].
^ result.
%

category: 'Private'
method: Collection
_deepCopyWith: copiedObjDict

""

| copy myClass firstInstVar lastInstVar |

copy := copiedObjDict at: self otherwise: nil.
copy ~~ nil ifTrue: [ ^ copy ].

myClass := self _class.
copy := self _class new.
copiedObjDict at: self put: copy.

firstInstVar := myClass _firstGciPublicInstVar.
lastInstVar := myClass instSize.
firstInstVar to: lastInstVar do: [ :i |
  copy instVarAt: i put: ((self instVarAt: i) _deepCopyWith: copiedObjDict).
  ].

self do: [ :anElement | 
  copy add: (anElement _deepCopyWith: copiedObjDict)
  ].

^ copy.
%

category: 'Comparing'
method: Collection
= aCollection

"Returns true if all of the following conditions are true:

 1.  The receiver and aCollection are of the same class.
 2.  The two collections are of the same size.
 3.  The corresponding elements of the receiver and aCollection are equal."

(self == aCollection)
  ifTrue: [ ^ true ].

(self _class == aCollection _class)
  ifFalse: [ ^ false ].

(self size == aCollection size)
  ifFalse: [ ^ false ].

self do: [ :anElement |
  (aCollection includes: anElement)
    ifFalse: [ ^ false ].
  ].

^ true.
%

category: 'Comparing'
method: Collection
hash

"Returns a numeric hash key for the receiver."

| hashValue |

hashValue := (97133 bitXor: (self size)) bitXor: (self _class asOop).
"For large collections, the hash value is just a function of its size
 and class"
(self size > 64) ifTrue: [ ^ hashValue abs ].

self do: [ :anElement |
  (anElement isKindOf: Collection)
    ifTrue: [ hashValue := hashValue bitXor: anElement size ]
    ifFalse: [ hashValue := hashValue bitXor: anElement hash ].
  ].
^ hashValue abs.
%

! sortWithBlock:   added during BlockSorter.gs
! sortWithBlock:persistentRoot:     added during BlockSorter.gs
