! ========================================================================
! Copyright (C) by VMware, Inc. 1991-2011.  All Rights Reserved
!
! $Id: abstractdictionary.gs,v 1.18 2008-01-09 22:50:07 stever Exp $
!
! Superclass Hierarchy
!	AbstractDictionary, Collection, Object.
!
! ========================================================================

removeallmethods AbstractDictionary 
removeallclassmethods AbstractDictionary 


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

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

txt := (GsDocText new) details:
'AbstractDictionary is an abstract class that provides the protocol for
 collections whose elements can be accessed by an associated lookup key.
 Concrete classes of AbstractDictionary store the key-value pairs either
 directly or as Associations.  See the documentation for the Dictionary and
 KeyValueDictionary classes for more information.'.
doc documentClassWith: txt.

txt := (GsDocText new) details:
'Methods in this category are obsolete and are provided only for compatibility
 with earlier releases of GemStone.  They will be removed in a future release.'.
doc documentCategory: #'Backward Compatibility' with: txt.

self description: doc.
%

! ------------------- Class methods for AbstractDictionary

category: 'Instance Creation'
classmethod: AbstractDictionary
new

"(Subclass responsibility.)  Returns a new instance of AbstractDictionary."

^ self subclassResponsibility: #new

%
category: 'Instance Creation'
classmethod: AbstractDictionary
new: count

"(Subclass responsibility.) Returns a new instance of AbstractDictionary. The 
 argument count provides a hint of the number of elements the instance should 
 be designed to hold."

^ self subclassResponsibility: #new:
%

! ------------------- Instance methods for AbstractDictionary

! edited to fix 37666
category: 'Private'
method: AbstractDictionary
_asCollectionForSorting

"Creates a new collection that can be easily indexed for sorting."

| result |

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

category: 'Private'
method: AbstractDictionary
_errorKeyNotFound: aKey

"No Association or key-value pair with given key, aKey, was found."

^ self _error: #rtErrKeyNotFound args: #[aKey]
%

category: 'Adding'
method: AbstractDictionary
add: anAssociation

"Adds the Association or the key-value pair contained in anAssociation to the
 receiver.  If the receiver already includes an Association/key-value pair 
 whose key is equal to that of anAssociation, then this method redefines the 
 value portion of that Association/key-value pair. Returns anAssociation."

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

self at: anAssociation key put: anAssociation value.
^ anAssociation.
%

! changed with fix 36675
category: 'Adding'
method: AbstractDictionary
addAll: aCollection

"Adds to the receiver all the Associations or key-value pairs contained in
 aCollection.  aCollection must be a collection of Associations or a dictionary.
 Returns the argument, aCollection."

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

(aCollection isKindOf: AbstractDictionary) ifTrue: [
  aCollection inject: self 
    keysAndValuesInto:[ :rcvr :aKey :aVal| rcvr at: aKey put: aVal ]. 
] ifFalse: [
  aCollection do: [ :anAssociation | self add: anAssociation ]
].
^ aCollection.
%

category: 'Enumerating'
method: AbstractDictionary
associationsDo: aBlock

"Iteratively evaluates the one argument block, aBlock, using each Association
 in the receiver as the argument to the block. If the receiver stores the 
 key-value pairs directly, new Associations are created for the key-value pairs
 and used as the arguments to aBlock.  Returns the receiver."

^ self subclassResponsibility: #associationsDo:
%

category: 'Searching'
method: AbstractDictionary
includesAssociation: anAssociation

"Returns true if anAssociation is equal to one of the Associations of the 
 receiver.  Returns false otherwise."

self associationsDo: [ :assoc | (anAssociation = assoc) ifTrue: [ ^true ]].
^false
%

category: 'Searching'
method: AbstractDictionary
includesIdenticalAssociation: anAssociation

"Returns true if anAssociation is identical to one of the Associations of the
 receiver.  Returns false otherwise."

self associationsDo: [ :assoc | (anAssociation == assoc) ifTrue: [ ^true ]].
^false
%

category: 'Enumerating'
method: AbstractDictionary
associationsDetect: aBlock

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

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

category: 'Enumerating'
method: AbstractDictionary
associationsDetect: aBlock ifNone: exceptionBlock

"Evaluates aBlock repeatedly, with the Associations of the receiver as the 
 argument.  Returns the first Association for which aBlock evaluates to true 
 when the Association is used as the argument to the block.  If none of the
 receiver's Associations evaluates to true, this method 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 associationsDo: [ :anAssoc| 
  (aBlock value: anAssoc) ifTrue: [ ^anAssoc ].
  ].

^ exceptionBlock value.
%

category: 'Accessing'
method: AbstractDictionary
at: aKey

"Returns the value of the Association with key aKey.  Generates an error if no 
 such key exists."

    | sentinel result |
    sentinel := Object new.
    (result := self at: aKey otherwise: sentinel) == sentinel ifTrue:
        [^self _errorKeyNotFound: aKey].
    ^result
%

category: 'Accessing'
method: AbstractDictionary
at: aKey ifAbsent: aBlock

"Returns the value associated with key aKey.  If no such key/value pair or
 Association exists, returns the result of evaluating the zero-argument block
 aBlock."

^ self subclassResponsibility: #at:ifAbsent.
%

category: 'Accessing'
method: AbstractDictionary
at: aKey ifAbsentPut: aBlock

"Returns the value associated with key aKey. If no such key/value pair or
 Association exists, returns the result of evaluating the zero-argument block
 aBlock. In the latter case, the result of  evaluating the block aBlock is 
 also stored in the receiver using the key aKey."

| known existing value |

known := 'a'.
existing := self at: aKey otherwise: known.
existing == known 
  ifTrue: [
    value := aBlock value.
    self at: aKey put: value.
    ^value 
    ].
^existing
%

category: 'Accessing'
method: AbstractDictionary
at: aKey otherwise: value

"Returns the value that corresponds to aKey.  If no such key/value pair or
 Association exists, returns the given alternate value."

    ^self at: aKey ifAbsent: [value]
%

category: 'Updating'
method: AbstractDictionary
at: aKey put: aValue

"Creates a new Association with the given key and value and adds it to the
 receiver or adds the key-value pair to the receiver depending on the class of
 the receiver.  If the receiver already contains an Association or key-value
 pair with the given key, this method makes aValue the value of that 
 Association or key-value pair.  Returns aValue."

^ self subclassResponsibility: #at:put:
%

category: 'Enumerating'
method: AbstractDictionary
collect: aBlock

"Evaluates aBlock with each of the receiver's values as the argument and
 collects the resulting values into the appropriate Dictionary at the
 corresponding key values."

| result |

result := self speciesForCollect new: (self size).
self keysAndValuesDo: [ :aKey :aValue |
  result at: aKey put: (aBlock value: aValue).
  ].

^ result. 
%

category: 'Enumerating'
method: AbstractDictionary
collectAssociations: aBlock

"Evaluates aBlock with each of the receiver's Associations (or Associations 
 created using the key-value pairs) as the argument and collects the resulting 
 values into an Array. Returns the newly created Array."

| anArray index |

anArray := Array new: (self size).
index := 0.
self associationsDo: [ :anAssoc |
  index := index + 1.     
  anArray at: index put: (aBlock value: anAssoc).
  ].

^ anArray. 
%

category: 'Backward Compatibility'
method: AbstractDictionary
collectValues: aBlock

"Obsolete in GemStone 5.0.  Use the collect: method instead."

^ self collect: aBlock.
%

category: 'Enumerating'
method: AbstractDictionary
collectValuesAsArray: aBlock

"Evaluates aBlock with each of the receiver's values as the argument and
 collects the resulting values into an Array. Returns the new Array."

| result |
result := Array new.
self valuesDo: [ :aValue |
  result add: (aBlock value: aValue).
  ].
^ result. 
%

category: 'Backward Compatibility'
method: AbstractDictionary
detectValues: aBlock 

"Obsolete in GemStone 5.0.  Use the keysAndValuesDo: method instead."

^ self detectValues: aBlock ifNone: [ ^ self errorNoElementDetected: aBlock ].
%

category: 'Backward Compatibility'
method: AbstractDictionary
detectValues: aBlock ifNone: exceptionBlock

"Obsolete in GemStone 5.0.  Use the keysAndValuesDo: method instead."

self keysAndValuesDo: [ :aKey :aValue |
  (aBlock value: aValue) ifTrue: [ ^ aKey ].
  ].
^ exceptionBlock value.
%

category: 'Backward Compatibility'
method: AbstractDictionary
detectAssociations: aBlock 

"Obsolete in GemStone 5.0.  Use the associationsDetect: method instead."

^ self associationsDetect: aBlock 
%

category: 'Backward Compatibility'
method: AbstractDictionary
detectAssociations: aBlock ifNone: exceptionBlock

"Obsolete in GemStone 5.0.  Use the associationsDetect:ifNone: method instead."

^ self associationsDetect: aBlock ifNone: exceptionBlock
%

category: 'Backward Compatibility'
method: AbstractDictionary
doAssociations: aBlock

"Obsolete in GemStone 5.0.  Use the associationsDo: method instead."

^ self associationsDo: aBlock.
%

category: 'Backward Compatibility'
method: AbstractDictionary
doKeys: aBlock

"Obsolete in GemStone 5.0.  Use the keysDo: method instead."

^ self keysDo: aBlock.
%

category: 'Backward Compatibility'
method: AbstractDictionary
doKeysAndValues: aBlock

"Obsolete in GemStone 5.0.  Use the keysAndValuesDo: method instead."

^ self keysAndValuesDo: aBlock.
%

category: 'Backward Compatibility'
method: AbstractDictionary
doValues: aBlock

"Obsolete in GemStone 5.0.  Use the valuesDo: method instead."

^ self valuesDo: aBlock
%

category: 'Private'
method: AbstractDictionary
errorKeyNotFound: aKey

"No Association or key/value pair with the given key, aKey was found."

^ self _error: #rtErrKeyNotFound args: #[aKey]
%

category: 'Private'
method: AbstractDictionary
errorNilKey

"A nil key was provided as an argument."

^ self _error: #rtErrNilKey.
%

category: 'Private'
method: AbstractDictionary
errorNoElementDetected: aBlock

"Private."

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

category: 'Private'
method: AbstractDictionary
tableSize

"Returns the size of hash table used for storing the entries."

^ self subclassResponsibility: #tableSize.
%

category: 'Accessing'
method: AbstractDictionary
size

"Returns the number of elements (Associations/key-value pairs) contained in the
 receiver."

^ self subclassResponsibility: #size.
%

category: 'Updating'
method: AbstractDictionary
size: newSize

"Disallowed.  You should not change the size of a dictionary explicitly."

self shouldNotImplement: #size: .
%

category: 'Hashing'
method: AbstractDictionary
hashFunction: aKey

"The hash function should perform some operation on the value of the
 key (aKey) which returns a value in the range 1..tableSize."

^(aKey hash \\  self tableSize) + 1
%

category: 'Searching'
method: AbstractDictionary
includes: aValue

"Returns true if the receiver contains a value that is equal to aValue.
 Returns false otherwise."

self valuesDo: [ :element | (aValue = element) ifTrue: [ ^true ]].
^ false.
%

category: 'Searching'
method: AbstractDictionary
includesIdentical: aValue

"Returns true if the receiver contains a value that is identical to aValue.
 Returns false otherwise."

self valuesDo: [ :element | (aValue == element) ifTrue: [ ^true ]].
^ false.
%

category: 'Searching'
method: AbstractDictionary
includesKey: aKey

"Returns true if the receiver contains an Association or a key-value pair whose
 key is equal to aKey.  Returns false otherwise."

self at: aKey ifAbsent: [ ^false ].
^ true.
%

category: 'Backward Compatibility'
method: AbstractDictionary
includesValue: aValue

"Obsolete in GemStone 5.0.  Use the includes: method instead."

^ self includes: aValue.
%

category: 'Accessing'
method: AbstractDictionary
keyAtValue: anObject

"Returns the key of the first value equal to anObject. If no match is found, 
 runtime error objErrNotInColl is signaled."

"Note: In some implementations of Smalltalk, nil is returned if a match is 
 not found."

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

category: 'Accessing'
method: AbstractDictionary
keyAtValue: anObject ifAbsent: aBlock

"Returns the key of the first value equal to the given object, anObject.  
 If no match is found, evaluates and returns the result of the block aBlock."

^ self subclassResponsibility: #keyAtValue:ifAbsent: 
%

category: 'Accessing'
method: AbstractDictionary
keys

"Returns a Set containing the receiver's keys."

| aSet |

aSet := Set new.
self keysDo: [ :key | aSet add: key ].
^ aSet
%

category: 'Enumerating'
method: AbstractDictionary
do: aBlock

"Iteratively evaluates the one argument block, aBlock, using the value part of
 each Association or key-value pair as the argument of the block.  Returns the 
 receiver."

^ self subclassResponsibility: #do.
%

category: 'Enumerating'
method: AbstractDictionary
keysAndValuesDo: aBlock

"Iteratively evaluates the two argument block, aBlock, using each key and value
 of the receiver as the argument to the block.  Returns the receiver."

^ self subclassResponsibility: #keysAndValuesDo:.
%

category: 'Enumerating'
method: AbstractDictionary
inject: anObj keysAndValuesInto: aBlock

"Iteratively evaluates the threee argument block, aBlock, 
 using anObj, each key and each value
 of the receiver as the arguments to the block.  Returns the receiver."

^ self subclassResponsibility: #inject:keysAndValuesInto: .
%


category: 'Enumerating'
method: AbstractDictionary
keysDo: aBlock

"Iteratively evaluates the one argument block, aBlock, using each key of
 the receiver as the argument to the block. Returns the receiver."

^ self subclassResponsibility: #keysDo:.
%

category: 'Enumerating'
method: AbstractDictionary
valuesDo: aBlock

"Iteratively evaluates the one argument block, aBlock, using each value of
 the receiver as the argument to the block. Returns the receiver."

"Note: This method has the same behavior as #do:."

^ self subclassResponsibility: #valuesDo:.
%

category: 'Searching'
method: AbstractDictionary
occurrencesOf: aValue

"Returns the number of Associations or key-value pairs in the receiver with 
 value equal to 'aValue'."

"Note: In GemStone 4.1, this method returned the number of Associations or 
 key-value pairs where the value was identical to aValue. Use the method 
 #occurrencesOfIdentical: for similar behavior."

| numOccurrences |

numOccurrences := 0.
self valuesDo: [ :aVal |  
  aValue = aVal ifTrue: [ numOccurrences := numOccurrences + 1 ]
  ].

^ numOccurrences
%

category: 'Searching'
method: AbstractDictionary
occurrencesOfIdentical: aValue

"Returns the number of Associations or key-value pairs in the receiver with 
 a value that is identical to aValue."

| numOccurrences |

numOccurrences := 0.
self valuesDo: [ :aVal |  
  aValue == aVal ifTrue: [ numOccurrences := numOccurrences + 1 ]
  ].

^ numOccurrences
%

category: 'Backward Compatibility'
method: AbstractDictionary
occurrencesOfValue: aValue

"Obsolete in GemStone 5.0.  Use the occurrencesOf: method instead."

^ self occurrencesOf: aValue.
%

category: 'Enumerating'
method: AbstractDictionary
reject: aBlock

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

| result |

result := self speciesForSelect new: (self size).
self keysAndValuesDo: [ :aKey :aValue |
  (aBlock value: aValue) ifFalse: [result at: aKey put: aValue]
  ].

^ result.
%

category: 'Backward Compatibility'
method: AbstractDictionary
rejectValues: aBlock

"Obsolete in GemStone 5.0.  Use the reject: method instead."

^ self reject: aBlock.
%

category: 'Enumerating'
method: AbstractDictionary
rejectValuesAsArray: aBlock

"Evaluates aBlock with each of the receiver's values as the argument and
 returns an Array containing the values for which aBlock evaluates false."

| result |
result := Array new.
self valuesDo: [ :aValue |
  (aBlock value: aValue) ifFalse: [result add: aValue].
  ].

^ result. 
%

category: 'Removing'
method: AbstractDictionary
remove: anObject

"Disallowed.  Use #removeKey: instead."

self shouldNotImplement: #remove:
%

category: 'Removing'
method: AbstractDictionary
removeIdentical: anObject

"Disallowed."

self shouldNotImplement: #removeIdentical:
%

category: 'Removing'
method: AbstractDictionary
remove: anObject ifAbsent: anExceptionBlock

"Disallowed.  Use #removeKey:ifAbsent: instead."

self shouldNotImplement: #remove:ifAbsent.
%

category: 'Removing'
method: AbstractDictionary
removeIdentical: anObject ifAbsent: anExceptionBlock

"Disallowed."

self shouldNotImplement: #removeIdentical:ifAbsent.
%

category: 'Removing'
method: AbstractDictionary
removeAll: aCollection

"Disallowed.  Use #removeAllKeys: instead."

self shouldNotImplement: #removeAll:
%

category: 'Removing'
method: AbstractDictionary
removeAllIdentical: aCollection

"Disallowed."

self shouldNotImplement: #removeAllIdentical:
%

category: 'Removing'
method: AbstractDictionary
removeAllKeys: keys

"Removes all the keys equal to the given keys from the receiver. An error is not
 generated if keys equal to any of the specified keys are not present. Returns
 the collection keys."

^ keys do: [ :aKey | self removeKey: aKey ifAbsent: [nil] ].
%

category: 'Removing'
method: AbstractDictionary
removeAllKeys: keys ifAbsent: aBlock

"Removes all the keys equal to the given keys from the receiver and returns the
 collection keys. For any key which is not a valid key of the receiver, aBlock 
 is evaluated with the key as the argument."

^ keys do: [ :aKey | self removeKey: aKey ifAbsent: [aBlock value: aKey] ].
%

category: 'Removing'
method: AbstractDictionary
removeKey: aKey

"Removes the Association or key-value pair with key equal to aKey from the 
 receiver and returns the value portion of that Association or key-value pair
 respectively. If no Association is present with key equal to aKey, reports an 
 error."

"Note: In GemStone 4.1, this method checked for a key identical to aKey."

^ self removeKey: aKey ifAbsent: [self _errorKeyNotFound: aKey ].
%

category: 'Removing'
method: AbstractDictionary
removeKey: aKey ifAbsent: aBlock

"Removes the Association or key-value pair with key equal to aKey from the 
 receiver and returns the value associated with the Association or the key-value
 pair.  If no Association or key-value pair is present with key equal to
 aKey, evaluates the zero-argument block aBlock and returns the result of that 
 evaluation."

"Note: In GemStone 4.1, this method checked for a key identical to aKey."

^ self subclassResponsibility: #removeKey:ifAbsent.
%

! added for 36675
category: 'Removing'
method: AbstractDictionary
removeKey: aKey otherwise: notFoundValue

"Removes the Association or key-value pair with key equal to aKey from the
 receiver and returns the value associated with the Association or the key-value
 pair.  If no Association or key-value pair is present with key equal to
 aKey, returns notFoundValue .

 KeyValueDictionary has an optimized implementation.
"

^ self removeKey: aKey ifAbsent:[ notFoundValue ]
%

category: 'Backward Compatibility'
method: AbstractDictionary
removeKeys: keys

"Obsolete in GemStone 5.0.  Use the removeAllKeys: method instead."

"Note: In GemStone 4.1, this method removed keys identical to the given keys.
 It also returned the receiver."

^ self removeAllKeys: keys
%

category: 'Private'
method: AbstractDictionary
_reportKeyNotFound: aKey with: aBlock

"Returns the value of aBlock if aBlock is not nil.  Otherwise, raises an error."

aBlock == nil ifTrue:[^ self _errorKeyNotFound: aKey ] .
^aBlock value
%

category: 'Enumerating'
method: AbstractDictionary
select: aBlock

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

|result|

result := self speciesForSelect new.
self keysAndValuesDo: [ :aKey :aValue |
  (aBlock value: aValue) ifTrue: [result at: aKey put: aValue]
  ].

^ result.
%

category: 'Backward Compatibility'
method: AbstractDictionary
selectValues: aBlock

"Obsolete in GemStone 5.0.  Use the select: method instead."

^ self select: aBlock.
%

category: 'Backward Compatibility'
method: AbstractDictionary
selectValuesAsArray: aBlock

"Obsolete in GemStone 5.0."

"Evaluates aBlock with each of the receiver's values as the argument and
 returns an Array containing the values for which aBlock evaluates true."

| result index |
result := Array new: (self size).
index := 1.
self valuesDo: [ :aValue |
  (aBlock value: aValue) 
    ifTrue: [result at: index put: aValue].
  index := index + 1.
  ].

^ result. 
%

category: 'Enumerating'
method: AbstractDictionary
speciesForCollect

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

^ self class
%

category: 'Enumerating'
method: AbstractDictionary
speciesForSelect

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

^ self class
%

category: 'Formatting'
method: AbstractDictionary
printOn: aStream

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

| count sz myCls |

myCls := self class .
aStream nextPutAll: myCls name describeClassName .
(myCls whichClassIncludesSelector: #associationsDo:) == AbstractDictionary
  ifTrue:[ ^ self "can't safely execute associationsDo: " ].

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

category: 'Accessing'
method: AbstractDictionary
values

"Returns an OrderedCollection containing the receiver's values."

|result|
result:= OrderedCollection new. 
self valuesDo: [ :value | result add: value ].
^ result.
%

category: 'Sorting'
method: AbstractDictionary
sortAscending: aSortSpec

"Returns an Array containing Associations constructed from the receiver, 
 sorted in ascending order, as determined by the values of the instance 
 variables represented by aSortSpec.

 See UnorderedCollection | sortAscending: for further documentation."

| aSet result |

aSet := IdentitySet new .
self associationsDo:[:anAssoc | aSet add: anAssoc ].
result := aSet sortAscending: aSortSpec .
				"deleted   'reduce garbage' code"
^ result 
%

category: 'Sorting'
method: AbstractDictionary
sortDescending: aSortSpec

"Returns an Array containing Associations constructed from the receiver, 
 sorted in descending order, as determined by the values of the instance 
 variables represented by aSortSpec.

 See UnorderedCollection | sortDescending: for further documentation."

| aSet result |

aSet := IdentitySet new .
self associationsDo:[:anAssoc | aSet add: anAssoc ].
result := aSet sortDescending: aSortSpec .
				"deleted   'reduce garbage' code"
^ result 
%

category: 'Sorting'
method: AbstractDictionary
sortWith: aSortPairArray

"Returns an Array containing Associations constructed from the receiver, 
 sorted according to the contents of aSortPairArray.

 See Collection | sortWith: for further documentation."

| aSet result |

aSet := IdentitySet new .
self associationsDo:[:anAssoc | aSet add: anAssoc ].
result := aSet sortWith: aSortPairArray .
				"deleted   'reduce garbage' code"
^ result 
%

! delete duplicates

category: 'Enumerating'
method: AbstractDictionary
rejectAssociations: 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.  Uses associative access when the argument is a
 SelectionBlock."

| newCollection |

newCollection := self species new.
self associationsDo: [ :element | 
  (aBlock value: element) ifFalse: [ newCollection add: element ].
  ].

^ newCollection.
%

category: 'Enumerating'
method: AbstractDictionary
selectAssociations: 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.  Uses associative access when the argument is a
 SelectionBlock."

| newCollection |

newCollection := self species new.
self associationsDo: [ :element | 
  (aBlock value: element) ifTrue: [ newCollection add: element ].
  ].

^ newCollection.
%

! gemstone64, I added selectAssociationsAsArray: and associationsAsArray
!  because I could not find a convienent way to get these results.  these methods
!  make it easy to get a listing of the contents of a Dictionary by doing
!  a level 2 display of the result in topaz .   		Allen

category: 'Enumerating'
method: AbstractDictionary
selectAssociationsAsArray: aBlock

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

| newCollection |

newCollection := Array new .
self associationsDo: [ :element | 
  (aBlock value: element) ifTrue: [ newCollection add: element ].
  ].

^ newCollection.
%

category: 'Enumerating'
method: AbstractDictionary
associationsAsArray

"Returns an Array containing all of the receiver's Associations"

^ self selectAssociationsAsArray: [ :assoc| true ]
%

category: 'Storing and Loading'
method: AbstractDictionary
loadFrom: passiveObj size: varyingSize

"Reads from passiveObj the passive form of an object.  Converts the object to
 its active form by loading the information into the receiver."

"This method is similar to loadFrom:, but is used for objects whose size
 is not known when they are first instantiated (such as an IdentitySet)."

^self basicLoadFrom: passiveObj size: varyingSize
%

category: 'Storing and Loading'
classmethod: AbstractDictionary
loadFrom: passiveObj

"Reads from passiveObj the passive form of an object.  Converts the object to
 its active form by loading the information into a new instance of the receiver.
 Returns the new instance."

| size inst |
size := passiveObj readSize.
inst := self new.
inst loadFrom: passiveObj size: size.
^inst
%

category: 'Private'
method: AbstractDictionary
_deferredGciUpdateWith: valueArray

""

^ self subclassResponsibility: #_deferredGciUpdateWith:
%

category: 'Private'
method: AbstractDictionary
_deepCopyWith: copiedObjDict

""

| copy myClass firstInstVar lastInstVar |

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

myClass := self _class.
copy := myClass new: (self size).
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 keysAndValuesDo: [ :aKey :aValue |
  copy at: (aKey _deepCopyWith: copiedObjDict)
       put: (aValue _deepCopyWith: copiedObjDict).
  ].
  
^ copy.
%

category: 'Comparing'
method: AbstractDictionary
= anAbstractDictionary

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

 1.  The receiver and anAbstractDictionary are of the same class.
 2.  The two dictionaries are of the same size.
 3.  The corresponding keys and values of the receiver and anAbstractDictionary
     are equal."

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

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

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

self keysAndValuesDo: [ :aKey :aValue |
  (aValue = (anAbstractDictionary at: aKey otherwise: nil))
    ifFalse: [ ^ false ]
  ].

^ true.
%

category: 'Comparing'
method: AbstractDictionary
hash

"Returns a numeric hash key for the receiver."

| hashValue |

hashValue := 97633 bitXor: (self size).
"For large dictionaries, the hash value is just a function of its size"
(self size > 64) ifTrue: [ ^ hashValue abs ].
self keysDo: [ :aKey |
   "Skip if the key is a dictionary."
   (aKey isKindOf: AbstractDictionary)
     ifFalse: [
       hashValue := hashValue bitXor: aKey hash 
       ]
     ].
^ hashValue abs
%

category: 'Printing'
method: AbstractDictionary
asReportString

"Returns a String that lists the key-value pairs, one on each line."

| result |
result := String new.
self keysAndValuesDo: [ :key :val |
  result add: key printString; 
    add: Character tab;
    add: val printString;
    add: Character lf ].
^ result
%

! deleted _canonicalizeSymbolAt: offset oldSymbol: oldSym newSymbol: newSym

! deleted _resetParentRef, moved it to Object

category: 'Instance Migration'
method: AbstractDictionary
migrateIndexable: anotherObject myClass: cls otherClass: othercls

"For dictionaries, we need to reconstruct the indexable component rather
 than just copy it over (in case the new class uses a different structure)."

anotherObject keysAndValuesDo: [ :key :value |
    self at: key put: value ].

%

category: 'Updating'
method: AbstractDictionary
changeToSegment: segment

"Assigns the receiver and all its components to the given segment. Returns
 the receiver."

self assignToSegment: segment.
self associationsDo: [ :anAssoc |
  anAssoc assignToSegment: segment
  ].
^ self.
%

category: 'Repository Conversion'
method: AbstractDictionary
fixRefsAfterConversion

"Default Dictionary method for fixing references LargePositiveInteger and 
 LargeNegativeInteger instances that can now be represented as a 
 SmallInteger and Floats and SmallFloats which can now be represented as
 a SmallDouble."

|myClass array|

(System _testIf: self isIn: 45)
	ifTrue:[^false]. "already fixed this one"

"Fix inst var refs first"
self fixInstVarRefsAfterConversion.

"now handle keys and values"
array := Array new.
self keysAndValuesDo:[:k :v|
	(k needsFixingAfterConversion _or:[v needsFixingAfterConversion])
		ifTrue:[array add: k; add: v.].
	].
1 to: array size by: 2 do:[:n| |k v newKey newValue|
	k := array at: n.
	v := array at: (n + 1).
	self removeKey: k.
	k needsFixingAfterConversion
		ifTrue:[newKey := k + 0]
		ifFalse:[newKey := k].
	v needsFixingAfterConversion
		ifTrue:[newValue := v + 0]
		ifFalse:[newValue := v].
	self at: newKey put: newValue.
].
System _add: self to: 45.
^true
%
