!=========================================================================
! Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved.
!
! $Id: obssymbollistdict.gs,v 1.9 2008-01-09 22:50:13 stever Exp $
!
! Superclass Hierarchy:
!   ObsoleteSymbolListDictionary, KeyValueDictionary, 
!   AbstractDictionary, Collection, Object.
!
!=========================================================================

removeallmethods ObsoleteSymbolListDictionary
removeallclassmethods ObsoleteSymbolListDictionary

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

| doc txt |

doc := GsClassDocumentation _newForObsoleteGsClass: self asOfGsVersion: '5.0'.

txt := (GsDocText new) details:
'Existing instances should be migrated to SymbolDictionary or otherwise
 processed as required, and then should be removed.' .
doc documentClassWith: txt.

self description: doc.
%

category: 'Accessing'
method: ObsoleteSymbolListDictionary
associationAt: aKey

"Returns the ObsoleteSymbolAssociation with key aKey.  Generates an error if
 no such ObsoleteSymbolAssociation exists."

| anAssoc |

anAssoc :=  self associationAt: aKey otherwise: nil.
anAssoc == nil ifTrue:[ anAssoc := self _errorKeyNotFound: aKey] .
^ anAssoc
%

category: 'Accessing'
method: ObsoleteSymbolListDictionary
associationAt: aKey ifAbsent: aBlock

"Returns the ObsoleteSymbolAssociation with key aKey.  If no such 
 ObsoleteSymbolAssociation
 exists, returns the result of evaluating the zero-argument block aBlock."

^ super at: aKey ifAbsent: aBlock.
%

category: 'Accessing'
method: ObsoleteSymbolListDictionary
at: aKey

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

| anAssoc |
anAssoc:= self associationAt: aKey otherwise: nil .
anAssoc == nil ifTrue:[ anAssoc := self _errorKeyNotFound: aKey ].
^anAssoc value
%

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

"Returns the value of the ObsoleteSymbolAssociation with key aKey.  If no such
 ObsoleteSymbolAssociation exists, returns the result of evaluating the
 zero-argument block aBlock."

| symAssoc |
symAssoc := super at: aKey ifAbsent: [nil].
symAssoc ~~ nil ifTrue: [ ^ symAssoc value ].
^ aBlock value.
%

category: 'Accessing'
method: ObsoleteSymbolListDictionary
associationAt: aKey otherwise: defaultValue

"Returns the ObsoleteSymbolAssociation with key aKey.  If no such ObsoleteSymbolAssociation
 exists, returns the given default value."

^ super at: aKey otherwise: defaultValue.
%

category: 'Accessing'
method: ObsoleteSymbolListDictionary
at: aKey otherwise: aValue

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

| anAssoc |
aKey == nil ifTrue:[ ^aValue ] .
anAssoc := self associationAt: aKey otherwise: nil .
anAssoc == nil ifTrue:[ ^ aValue] .
^ anAssoc value
%

category: 'Accessing'
method: ObsoleteSymbolListDictionary
name

"Returns the key of a ObsoleteSymbolAssociation whose value is the receiver.  If the
 receiver contains no such ObsoleteSymbolAssociation, returns nil."

^self keyAtValue: self ifAbsent: [^nil]
%

category: 'Adding'
method: ObsoleteSymbolListDictionary
add: aSymAssoc

"Requires a ObsoleteSymbolAssociation as the argument.  If the receiver already
 includes a ObsoleteSymbolAssociation whose key is equal to that of aSymAssoc, this
 method redefines the value portion of that ObsoleteSymbolAssociation."

| anAssoc aKey |
aKey:= aSymAssoc key.
anAssoc:= self associationAt: aKey otherwise: nil .
anAssoc == nil ifTrue:[ super at: aKey put: aSymAssoc.
                      ^self ].
anAssoc value: (aSymAssoc value).
^self
%

category: 'Enumerating'
method: ObsoleteSymbolListDictionary
associationsDo: aBlock

"Evaluates aBlock with each of the receiver's Associations as the
 argument. The argument aBlock must be a one-argument block.  Returns 
 the receiver."

super keysAndValuesDo: [ :aKey :aSymAssoc | aBlock value: aSymAssoc ].
^self
%

category: 'Enumerating'
method: ObsoleteSymbolListDictionary
keysAndValuesDo: aBlock

"Evaluates aBlock with each of the receiver's key/value pairs as the arguments.
 The argument aBlock must be a two-argument block.  The first argument is the
 key and the second argument is the value of each key/value pair."

super keysAndValuesDo: [:aKey :aSymAssoc |
   aBlock value: aKey value: aSymAssoc value].
^self
%
! added for 36675
category: 'Enumerating'
method: ObsoleteSymbolListDictionary
inject: anObj keysAndValuesInto: aBlock

"Evaluates aBlock with each of the receiver's key/value pairs as the
 2nd and 3rd arguments.
 aBlock must be a 3 argument block, with arguments anObj, key value ."

super keysAndValuesDo: [ :aKey :aSymAssoc | 
  aBlock value: anObj value: aKey value: aSymAssoc value  
].
%

category: 'Enumerating'
method: ObsoleteSymbolListDictionary
do: aBlock

"Evaluates aBlock with each of the receiver's ObsoleteSymbolAssociations as the
 argument.  The argument aBlock must be a one-argument block."

super do: [:aSymAssoc | aBlock value: (aSymAssoc value)].
^ self
%

category: 'Hashing'
method: ObsoleteSymbolListDictionary
rebuildTable: newSize

"Rebuilds the receiver to be a new size specified by newSize."

"Reimplemented to ensure that the identity of the receiver's keys and values
 are preserved."

| saveArray index saveCollLimit|

collisionLimit == 536870911 ifTrue:[
  ^ self "prevent recursive rebuild"
  ].

saveArray := Array new: (self numElements).
index:= 1.
self associationsDo: [ :aSymAssoc | saveArray at: index put: aSymAssoc.
                        index:= index + 1 ].
self tableSize: newSize.
saveCollLimit := collisionLimit .
collisionLimit := 536870911 . "prevent recursive rebuild"

1 to: saveArray size do: [ :i | self add: (saveArray at: i)].

collisionLimit := saveCollLimit .
^self
%

category: 'Removing'
method: ObsoleteSymbolListDictionary
removeAssociation: aSymAssoc

"Removes aSymAssoc from the receiver, and returns the receiver.
 If aSymAssoc is absent, generates an error."

^self removeAssociation: aSymAssoc ifAbsent: [
  ^ self _errorNotFound: aSymAssoc
].
%

category: 'Removing'
method: ObsoleteSymbolListDictionary
removeAssociation: aSymAssoc ifAbsent: aBlock

"Removes aSymAssoc from the receiver.  If aSymAssoc is absent, evaluates the
 zero-argument block aBlock and returns the result of that evaluation."

"We must remove this particular ObsoleteSymbolAssociation (aSymAssoc), not
 just any ObsoleteSymbolAssociation with the same key as aSymAssoc"

|object|
object:= self associationAt: (aSymAssoc key) otherwise: nil .
object == nil ifTrue:[ ^aBlock value ].
(object == aSymAssoc)
   ifTrue: [ self removeKey: aSymAssoc key ]
   ifFalse:[ ^aBlock value].
^self
%

category: 'Removing'
method: ObsoleteSymbolListDictionary
removeKey: aKey

"Removes the key/value pair that corresponds to aKey."

|anAssoc|
anAssoc:= super removeKey: aKey ifAbsent: nil.
^anAssoc value
%

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

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

|anAssoc|
anAssoc:= super removeKey: aKey ifAbsent: [^aBlock value].
^anAssoc value
%

category: 'Searching'
method: ObsoleteSymbolListDictionary
select: aBlock

"Evaluates aBlock with each of the receiver's ObsoleteSymbolAssociations 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."

|result|
result:= self class new.
self associationsDo: [:aSymAssoc | (aBlock value: aSymAssoc)
                       ifTrue: [result add: aSymAssoc]
         ].
^result
%

category: 'Searching'
method: ObsoleteSymbolListDictionary
detect: aBlock

"Evaluates aBlock repeatedly, with the ObsoleteSymbolAssociations of the receiver as
 the argument.  Returns the first ObsoleteSymbolAssociation 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 associationsDo: [:aSymAssoc | (aBlock value: aSymAssoc)
                       ifTrue: [^aSymAssoc]
         ].
^ self _error: #assocErrNoElementsDetected args: #[aBlock] .
%

category: 'Searching'
method: ObsoleteSymbolListDictionary
reject: aBlock

"Evaluates aBlock with each of the receiver's ObsoleteSymbolAssociations 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."

|result|
result:= self class new.
self associationsDo: [:aSymAssoc | (aBlock value: aSymAssoc)
                       ifFalse: [result add: aSymAssoc]
         ].
^result
%

category: 'Searching'
method: ObsoleteSymbolListDictionary
selectValues: aBlock

"Evaluates aBlock with each of the receiver's values as the argument.  Returns
 an instance of the class of the receiver containing the values for which
 aBlock is true.  The argument aBlock must be a one-argument block."

| result |
result:= self class new.
self associationsDo: [:aSymAssoc | (aBlock value: (aSymAssoc value))
                       ifTrue: [ result add: aSymAssoc ]].
^result
%

category: 'Searching'
method: ObsoleteSymbolListDictionary
detectValues: aBlock ifNone: exceptionBlock

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

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

category: 'Searching'
method: ObsoleteSymbolListDictionary
rejectValues: aBlock

"Evaluates aBlock with each of the receiver's ObsoleteSymbolAssociations as the
 argument.  Returns an instance of the class of the receiver containing the
 values for which aBlock is false.  The argument aBlock must be a one-argument
 block."

| result |
result:= self class new.
self associationsDo: [:aSymAssoc | (aBlock value: (aSymAssoc value))
                       ifFalse: [ result add: aSymAssoc ]].
^result
%

category: 'Private'
method: ObsoleteSymbolListDictionary
atHash: hashIndex putKey: aKey

"Updates the hash table by storing aKey at the specified hashIndex."

^super atHash: hashIndex putKey: aKey.
%

category: 'Private'
method: ObsoleteSymbolListDictionary
atHash: hashIndex putValue: aValue

"Updates the hash table by storing aValue at the specified hashIndex."
^super atHash: hashIndex putValue: aValue.
%

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

"If the receiver already contains a ObsoleteSymbolAssociation with the given key, this
 makes aValue the value of that ObsoleteSymbolAssociation.  Otherwise, this creates a
 new ObsoleteSymbolAssociation with the given key and value and adds it to the
 receiver.  Returns aValue."

| tempKey anAssoc |

(aKey _isSymbol)
  ifTrue: [ tempKey := aKey ]
  ifFalse: [ tempKey := ObsoleteSymbol withAll: aKey ].

anAssoc:= self associationAt: aKey otherwise: nil .
anAssoc == nil 
  ifTrue:[ | newAssoc |
    (tempKey _isSymbol)
      ifTrue: [ 
        newAssoc := SymbolAssociation newWithKey: tempKey value: aValue
	]
      ifFalse: [
        newAssoc := ObsoleteSymbolAssociation newWithKey: tempKey value: aValue
        ].
     super at: tempKey put: newAssoc.
     ^aValue
    ].

anAssoc value: aValue.
^aValue
%

category: 'Searching'
method: ObsoleteSymbolListDictionary
collectAssociations: aBlock

"Evaluates aBlock with each of the receiver's Associations as the argument.
 Collects the resulting values into a new hash dictionary and returns that
 dictionary.  The argument aBlock must be a one-argument block."

|result|

result:= self speciesForCollect new: self tableSize.
super doKeysAndValues: [:aKey :aSymAssoc |
  result at: aKey put: ( aBlock value: aSymAssoc )
  ] .
^ result
%

category: 'Searching'
method: ObsoleteSymbolListDictionary
detectAssociations: 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 detect: aBlock
%

category: 'Searching'
method: ObsoleteSymbolListDictionary
detectAssociations: aBlock ifNone: exceptionBlock

"Same function as in class Collection, renamed to make it clear that the
 operations are on Associations."

^ self detect: aBlock ifNone: exceptionBlock
%

category: 'Searching'
method: ObsoleteSymbolListDictionary
rejectAssociations: aBlock

"Same function as in class Collection, renamed to make it clear that the
 operations are on Associations."

^ self reject: aBlock
%

category: 'Searching'
method: ObsoleteSymbolListDictionary
selectAssociations: aBlock

"Same function as in class Collection, renamed to make it clear that the
 operations are on Associations."

^ self select: aBlock
%

category: 'Locking Support'
method: ObsoleteSymbolListDictionary
_lockableValues

"Returns an Array of the receiver's Associations."

| result |

result := Array new .
super keysAndValuesDo: [:aKey :aSymAssoc | result add: aSymAssoc] .
^ result
%

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

"Returns the key of the first value matching the given object, anObject.  If no
 match is found, this method evaluates the block aBlock and returns its
 result."

"Reimplemented for improved performance"

| aKey collisionBkt |

aBlock _validateClass: BlockClosure.

1 to: tableSize * 2 by: 2 do: [ :tableIndex |
  (aKey := self _at: tableIndex) == nil ifTrue: [
    (collisionBkt := self _at: (tableIndex + 1)) == nil ifFalse: [
      1 to: collisionBkt _basicSize by: 2 do: [ :j |
        (aKey := collisionBkt _at: j) == nil ifFalse: [
          anObject == (collisionBkt _at: j + 1) value ifTrue: [
            ^ aKey
            ].
          ].
        ].
      ].
    ]
  ifFalse: [
    anObject == (self _at: tableIndex + 1) value ifTrue: [
      ^ aKey
      ].
    ].
  ].

^aBlock value.
%

category: 'Browser Methods'
method: ObsoleteSymbolListDictionary
_classAndVersionStrings

"For all Behaviors in the receiver, returns an OrderedCollection of Strings
 showing the class name and version.  This method is used as an optimization by
 the GemBuilder for Smalltalk browser."

| result |
result := OrderedCollection new .
self do: [ :anAssoc | | each |
  each := anAssoc value.
  each isBehavior
  ifTrue: [ result add:
              ( each classHistory size = 1
                 ifTrue: [ each name asString ]
                 ifFalse: [ each name + ' [ ' +
                      ( each classHistory indexOf: each ) printString + ' ]' ]
               )
    ]
  ].
^result
%

category: 'Repository Conversion'
method: ObsoleteSymbolListDictionary
convertTo5

"Returns a new instance of SymbolDictionary containing the contents of the
 receiver."

| newDict anArray |

(self _class == ObsoleteSymbolListDictionary) ifFalse: [ ^ self ].
"Cannot convert user defined subclasses of ObsoleteSymbolListDictionary"

anArray := Array new.
self associationsDo: [ :anObsSymAssoc | 
  anObsSymAssoc convertTo5.
  anArray add: anObsSymAssoc .
  ].

newDict := SymbolDictionary new .
newDict assignToSegment: self segment.
self _primitiveBecome: newDict .
anArray do: [ :anAssoc | self add: anAssoc ].

^ self
%

category: 'Repository Conversion'
method: ObsoleteSymbolListDictionary
convertPoolDictionary

"Converts a pool dictionary to a new SymbolDictionary.  Retains the same 
 OOP."

^self convertTo5
%

category: 'Repository Conversion'
method: ObsoleteSymbolListDictionary
asGsMethodDictionary

"Convert an instance of ObsoleteSymbolListDictionary to an instance of 
 GsMethodDictionary."

| newGsDict |

newGsDict := GsMethodDictionary new.
self associationsDo: [ :anObsSymAssoc | 
  newGsDict addAssociation: (anObsSymAssoc convertTo5) 
  ].
newGsDict assignToSegment: self segment .
^ newGsDict.
%
category: 'Storing and Loading'
classmethod: ObsoleteSymbolListDictionary
loadFrom: passiveObj

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

^ self loadFrom: passiveObj mappingToClass: SymbolDictionary
%

category: 'Storing and Loading'
classmethod: ObsoleteSymbolListDictionary
loadFrom: passiveObj mappingToClass: newClass

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

| newDict oldDict size |
(passiveObj version >= 500 _or:[ newClass == self]) ifTrue:[ 
  size := passiveObj readSize.
  newDict := self new.
  newDict loadFrom: passiveObj size: size.
  ]
ifFalse:[
  "handle activation of objects written by 4.1.3"

  (self instSize - self firstPublicInstVar) > 
  (newClass instSize - newClass firstPublicInstVar) ifTrue:[
    self _halt:'Unable to map subclass of ' + self name +
               ' to class ' + newClass name .
    ].
  newDict := newClass new .
  passiveObj hasRead: newDict .
  size := passiveObj readSize. 
  oldDict := self new .
  oldDict basicLoadFromNoRead: passiveObj size: size .
  oldDict associationsDo:[:assoc | newDict addAssociation: assoc ].
  oldDict initialize: 1 .
].
^ newDict
%

category: 'Repository Conversion'
method: ObsoleteSymbolListDictionary
convertToSymbolDict

"Private. Converts the receiver to be an instance of SymbolDictionary."

<primitive: 483>
self _primitiveFailed: #convertToSymbolDict
%

category: 'Repository Conversion'
method: ObsoleteSymbolListDictionary
containsOnlySymbols

"Private. Checks to see if all its keys are Symbols (and not ObsoleteSymbols)"

self keysDo: [ :aKey | 
  (aKey _isSymbol) ifFalse: [ ^ false ]
  ].

^ true.
%

category: 'Repository Conversion'
method: ObsoleteSymbolListDictionary
rehashForConversion

"Private. Rehashes the receiver because the hash values of some of its keys
 may have changed."

<primitive: 901> "enter protected mode"
| newSize newDict |

(self _class == ObsoleteSymbolListDictionary) 
  ifFalse: [
    newSize := (Integer _selectedPrimeGreaterThan: numElements) max: tableSize.
    self rebuildTable: newSize.
    System _disableProtectedMode.
    ^ self
    ].

(self containsOnlySymbols)
  ifFalse: [ | anArray |
    anArray := Array new.
    self doAssociations: [ :anAssoc | anArray add: anAssoc ].
    newDict := Dictionary new: (self size).

    newDict assignToSegment: self segment.
    newDict _primitiveBecome: self.

    anArray do: [ :anAssoc |
      self add: anAssoc.
      ].
    System _disableProtectedMode.
    ^ self.
    ].

self convertToSymbolDict.
newSize := (Integer _selectedPrimeGreaterThan: numElements) max: tableSize.
self rebuildTable: newSize.
System _disableProtectedMode.
^ self
%

category: 'Repository Conversion'
classmethod: ObsoleteSymbolListDictionary
_correspondingNewClass

"The class all instances of receiver are converted to during conversion."

(self == ObsoleteSymbolListDictionary)
  ifTrue: [ ^ SymbolDictionary ].

^ self.
%

