!=========================================================================
! Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved.
!
! $Id: obsdict.gs,v 1.8 2008-01-09 22:50:12 stever Exp $
!
! Superclass Hierarchy:
!   ObsoleteDictionary, IdentitySet, IdentityBag, UnorderedCollection, 
!   Collection, Object.
!
!=========================================================================

removeallmethods ObsoleteDictionary
removeallclassmethods ObsoleteDictionary

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

| doc txt |

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

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

self description: doc.
%

category: 'Error Handling'
method: ObsoleteDictionary
_errorKeyNotFound: aKey

"No Association with given key, aKey, was found."

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

!  _dictionaryKeys removed

category: 'Searching'
method: ObsoleteDictionary
_indexOf: aKey

"This method returns the numerical index (as found by _#at:) of the Association
 in the receiver with the given key.  If the key cannot be found, then returns
 nil.  The search is done on equality."

1 to: self size do: [ :i |
  aKey = (self _at: i) key
    ifTrue: [ ^i ]
].
^nil
%

category: 'Enumerating'
method: ObsoleteDictionary
keysDo: aBlock

"For each Association in the receiver, evaluates the one-argument block aBlock
 with the Association's key as the argument."

1 to: self size do: [ :j | aBlock value: ((self _at: j) key) ]
%

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

"For each Association in the receiver, evaluates the one-argument block aBlock
 with the Association's key as the argument."

^self keysDo: aBlock
%

category: 'Enumerating'
method: ObsoleteDictionary
valuesDo: aBlock

"For each Association in the receiver, evaluates the one-argument block aBlock
 with the Association's value as the argument."

1 to: self size do: [ :j | aBlock value: ((self _at: j) value) ]
%

category: 'Enumerating'
method: ObsoleteDictionary
doValues: aBlock

"For each Association in the receiver, evaluates the one-argument block aBlock
 with the Association's value as the argument."

^ self valuesDo: aBlock.
%

category: 'Enumerating'
method: ObsoleteDictionary
doAssociations: aBlock

"Evaluates the one-argument block aBlock with each of the receiver's
 Associations as the argument.  Compare with keysDo: and valuesDo:."

^ self do: aBlock
%
category: 'Enumerating'
method: ObsoleteDictionary
associationsDo: aBlock

"Evaluates the one-argument block aBlock with each of the receiver's
 Associations as the argument.  Compare with keysDo: and valuesDo:."

^ self do: aBlock
%
category: 'Enumerating'
method: ObsoleteDictionary
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.  Returns the receiver."

self do:[:anAssoc | aBlock value: anAssoc key value: anAssoc value ]
%

! added for 36675
category: 'Enumerating'
method: ObsoleteDictionary
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 ."

self do:[:anAssoc |  aBlock value: anObj value: anAssoc key value: anAssoc value].
%

category: 'Enumerating'
method: ObsoleteDictionary
doKeysAndValues: 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.  Returns the receiver."

^ self keysAndValuesDo: aBlock.
%

category: 'Removing'
method: ObsoleteDictionary
remove: anObject

"Disallowed.  Use removeKey: instead."

self shouldNotImplement: #remove:
%

category: 'Removing'
method: ObsoleteDictionary
remove: anObject ifAbsent: aBlock

"Disallowed.  Use removeKey:ifAbsent: instead."

self shouldNotImplement: #remove:ifAbsent:
%

category: 'Removing'
method: ObsoleteDictionary
removeAssociation: anAssociation

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

^ self removeAssociation: anAssociation
       ifAbsent: [^ self _errorNotFound: anAssociation]
%

category: 'Removing'
method: ObsoleteDictionary
removeAssociation: anAssociation ifAbsent: aBlock

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

^ super remove: anAssociation ifAbsent: aBlock
%

category: 'Removing'
method: ObsoleteDictionary
removeKey: aKey

"Removes the Association with key aKey from the receiver and returns the value
 of that Association.  Generates an error if no Association is present with key
 aKey."

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

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

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

| anAssoc |
anAssoc:= self associationAt: aKey
                    ifAbsent: [^ aBlock value].
self removeAssociation: anAssoc .
^ anAssoc value
%

category: 'Accessing'
method: ObsoleteDictionary
associationAt: aKey

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

^ self associationAt: aKey
       ifAbsent: [^ self _errorKeyNotFound: aKey]
%

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

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

| anAssoc |
1 to: self size do: [ :j |
  anAssoc := self _at: j .
  (aKey = anAssoc key) ifTrue: [ ^ anAssoc ]
].
^ aBlock value
%

category: 'Accessing'
method: ObsoleteDictionary
at: aKey

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

| anAssoc |
1 to: self size do: [ :j |
  anAssoc := self _at: j .
  aKey = anAssoc key ifTrue: [ ^ anAssoc value ]
] .

"if continuing execution with default result provided by an Exception,
  the default result must be an Association"

anAssoc := self _errorKeyNotFound: aKey .
^ anAssoc value
%

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

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

| anAssoc |
1 to: self size do: [ :j |
  anAssoc := self _at: j .
  aKey = anAssoc key ifTrue: [ ^ anAssoc value ]
] .
^ aBlock value
%

category: 'Accessing'
method: ObsoleteDictionary
keys

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

| result|

result:= IdentitySet new.
1 to: self size do:[:j| result add: (self _at: j) key ].
^result
%

category: 'Accessing'
method: ObsoleteDictionary
values

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

|result|
result:=  OrderedCollection new.
1 to: self size do:[:j| result add: (self _at: j) value ].
^result
%

category: 'Updating'
method: ObsoleteDictionary
_privAt: aKey put: aValue

"Returns aValue.  Does not check to see if receiver already contains given key.
 Adds new Association containing key and value.  Use with extreme caution since
 you may get multiple occurrences of a key!"

super _basicAdd: ((self class varyingConstraint) new key: aKey value: aValue).
^ aValue
%

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

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

| theAssoc |
1 to: self size do: [ :j |
  theAssoc := self _at: j .
  (aKey = theAssoc key) ifTrue: [
     theAssoc value: aValue .
     ^ aValue
     ]
  ].
"not found so add a new Association"
super add: ((self class varyingConstraint) new key: aKey value: aValue).
^ aValue
%

category: 'Searching'
method: ObsoleteDictionary
collectAssociations: aBlock

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

^ super collect: aBlock
%

category: 'Searching'
method: ObsoleteDictionary
detectAssociations: 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.  Uses associative access when the
 argument is a SelectionBlock."

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

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

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

^ super detect: aBlock ifNone: exceptionBlock
%

category: 'Searching'
method: ObsoleteDictionary
includesValue: aValue

"Returns true if any Association in the receiver has the value aValue.  Returns
 false otherwise."

1 to: self size do: [ :j |
   (aValue == (self _at: j) value)
   ifTrue: [ ^true ]
   ].
^ false
%

category: 'Searching'
method: ObsoleteDictionary
includesAssociation: anAssociation

"Returns true if the argument anAssociation is an element of the receiver.
 Returns false otherwise."

^ super includesIdentical: anAssociation
%

category: 'Searching'
method: ObsoleteDictionary
includesKey: aKey

"Returns true if the receiver contains an Association whose key
 is equal to aKey.  Returns false otherwise."

1 to: self size do: [ :j |
  (aKey = (self _at: j) key)
    ifTrue: [ ^ true ]
].
^ false
%

category: 'Searching'
method: ObsoleteDictionary
occurrencesOf: aValue

"Returns the number of Associations in the receiver with value aValue."

|result|

result:= 0.
1 to: self size do: [ :j |
  (aValue == ((self _at: j) value))
    ifTrue: [ result := result + 1 ]
].
^result
%

category: 'Searching'
method: ObsoleteDictionary
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."

^ super reject: aBlock
%

category: 'Searching'
method: ObsoleteDictionary
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."

^ super select: aBlock
%

category: 'Searching'
method: ObsoleteDictionary
_keysWithValue: aValue

"Returns a (possibly empty set) of keys associated with the value, aValue."

| result |

result:= IdentitySet new.  "a Set, since we should not have duplicate keys"
self do: [:assoc |
            (assoc value = aValue)
            ifTrue:
               [result add: assoc key]
         ].
^ result
%

category: 'Searching'
method: ObsoleteDictionary
_detect: aBlock ifNone: errBlock

"Provided for access to Bag|detect:ifNone:"

^super detect: aBlock ifNone: errBlock
%

category: 'Adding'
method: ObsoleteDictionary
add: anAssociation

"Requires an Association as the argument.  If the receiver already includes an
 Association whose key is equal to that of anAssociation, then this method
 redefines the value portion of that Association."

| aKey existingAssoc |

aKey := anAssociation key.
existingAssoc := self associationAt: aKey
                      ifAbsent:[ ^ super add: anAssociation ] .
existingAssoc value: anAssociation value
%

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

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

| anAssoc |
1 to: self size do: [ :j |
    anAssoc := self _at: j .
    (aKey = anAssoc key) ifTrue: [ ^anAssoc ]
    ].
^defaultValue
%

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

"Returns the value of the Association with key aKey.  If no such Association
 exists, returns the given value."

^ self at: aKey ifAbsent:[ aValue ]
%

category: 'Accessing'
method: ObsoleteDictionary
keyAtValue: anObject

"Returns the key of the first value matching the given object, anObject.
 If no match is found, runtime error objErrNotInColl is signaled."

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

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

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

1 to: self size do: [:i |
  anObject == ((self _at: i) value) ifTrue: [
    ^(self _at: i) key
  ]
].
^aBlock value
%

category: 'Removing'
method: ObsoleteDictionary
removeKeys: keys

"Removes each of the given keys from the receiver.  Does not generate
 an error if the keys do not exist."

| assn removals |
1 to: self size do: [:i |
  assn := self _at: i.
  (keys includesValue: assn key) ifTrue: [
    removals == nil ifTrue: [ removals := IdentitySet new ].
    removals add: assn
  ].
].
1 to: removals size do: [:j |
  super remove: (removals _at: j)
].
%

category: 'Searching'
method: ObsoleteDictionary
_idxOccurrencesOf: aValue

"Dictionaries can contain only Associations."

^ 0
%

category: 'Storing and Loading'
classmethod: ObsoleteDictionary
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: Dictionary
%

category: 'Storing and Loading'
method: ObsoleteDictionary
basicLoadFromNoRead: passiveObj size: varyingSize newResult: newDict

""

varyingSize = 0 ifTrue: [
  "Old NSC format had no named instance variable section.  A zero-length NSC in
   the old format might read instance variables from an enclosing object if
   there were not a special delimiter that could be reliably found."
  passiveObj checkForBagMark ifFalse: [
    passiveObj checkForInstVarMark ifFalse: [
      ^self
    ].
  ].
].
(passiveObj readNamedIV) ifTrue: [
  "not old NSC format with no named instance variables"
  newDict loadNamedIVsFrom: passiveObj.
  ].
newDict loadVaryingFrom: passiveObj size: varyingSize.
%

category: 'Storing and Loading'
classmethod: ObsoleteDictionary
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 newResult: newDict .
].
^ newDict
%

category: 'Repository Conversion'
method: ObsoleteDictionary
convertPoolDictionary

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

<primitive: 901> "enter protected mode"
| newSymDict anArray |

((self _class == ObsoleteDictionary) _or: 
[ self _class == ObsoleteSymbolDictionary ]) ifFalse: [ 
  System _disableProtectedMode.
  ^ self 
].

anArray := Array new.

self doAssociations: [ :anAssoc |
  anAssoc convertTo5 .
  anArray add: anAssoc.
  ].

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

System _disableProtectedMode.
^ self.
%

category: 'Repository Conversion'
method: ObsoleteDictionary
rehashForConversion

"Private. Converts the receiver to an instance of Dictionary. Only done if 
 the receiver is an instance of ObsoleteDictionary. Instances of subclasses
 of ObsoleteDictionary are not converted. Returns the receiver."

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

self _class == ObsoleteDictionary ifFalse: [ 
  System _disableProtectedMode.
  ^ self 
  ].

newDict := Dictionary new: (self size).
newDict assignToSegment: self segment.
self associationsDo: [ :anAssoc | newDict add: anAssoc ].
newDict _primitiveBecome: self.
System _disableProtectedMode.
^ self.
%

category: 'Repository Conversion'
classmethod: ObsoleteDictionary
_correspondingNewClass

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

(self == ObsoleteDictionary)
  ifTrue: [ ^ Dictionary ].

^ self.
%

