! ========================================================================
! Copyright (C) by VMware, Inc. 1991-2011.  All Rights Reserved
!
! $Id: dict.gs,v 1.9 2008-01-09 22:50:10 stever Exp $
!
! Superclass Hierarchy:
!	Dictionary, AbstractDictionary, Collection, Object
!
! ========================================================================
expectvalue %String
run
^ AbstractDictionary _newKernelSubclass: 'Dictionary'
        instVarNames: #(  'count' 'tableSize' 'emptySlotHint' 'numEmptySlots' 
			  'unused' )
        classVars: #()
        classInstVars: #()
        poolDictionaries: #[]
        inDictionary: Globals
        constraints: #[ #[ #count, SmallInteger ],
                        #[ #tableSize, SmallInteger ],
                        #[ #emptySlotHint, SmallInteger ],
                        #[ #numEmptySlots, SmallInteger ]]
        instancesInvariant: false
        isModifiable: false
        reservedOop: 793
%

removeallmethods Dictionary
removeallclassmethods Dictionary

! ------------------- Class methods for Dictionary

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

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

txt := (GsDocText new) details:
'Dictionary is a concrete subclass of AbstractDictionary.  In each Dictionary,
 all keys should be of the same class.

 A Dictionary stores key-value pairs as instances of class Association, and is
 therefore a collection of Associations.  As a result, a Dictionary has two
 kinds of instance protocols:

 * Methods that view the Dictionary as key/value pairs.
 * Methods that involve the Association objects themselves.

 A Dictionary is also an equality-based collection.  That is, two keys or two
 values are considered to be the same if they are equivalent; they need not be
 identical to be the same.  Thus, if you add two key-value pairs to a Dictionary
 but the keys are equivalent, even if they are not identical, then the result is
 that the second pair overwrites the first one, because the keys are the same.

 Some other kinds of dictionaries do not store key-value pairs as Associations.
 Still other kinds are identity-based rather than equality-based.  These other
 kinds of dictionaries exhibit better performance than Dictionary and are to be
 preferred where they are appropriate.

 WARNING: do not implement subclasses of Dictionary that use the implementation
 of Dictionary and compare keys by Identity.  All identity based dictionary
 classes must be a subclass of IdentityKeyValueDictionary or IdentityDictionary
 in order for GemStone''s Symbol canonicalization to work properly.' .
doc documentClassWith: txt.

txt := (GsDocText new) details:
'A SmallInteger, the number of Associations in the instance.' .
doc documentInstVar: #count with: txt.

txt := (GsDocText new) details:
'A SmallInteger, the size of an internal table for storing elements.' .
doc documentInstVar: #tableSize with: txt.

txt := (GsDocText new) details:
'A SmallInteger, for GemStone internal use.' .
doc documentInstVar: #emptySlotHint with: txt.

txt := (GsDocText new) details:
'A SmallInteger, for GemStone internal use.' .
doc documentInstVar: #numEmptySlots with: txt.

self description: doc.
%

category: 'Instance Creation'
classmethod: Dictionary
new

"Returns a new instance of Dictionary."

^ self new: 5.
%

category: 'Instance Creation'
classmethod: Dictionary
new: count

"Returns a new instance of Dictionary.  The argument count provides a hint of
 the number of elements the instance should be designed to hold. 

 count should be a SmallInteger."

| dict size |

"The dictionary should have a certain minimum size and the size should 
 preferably be a prime number."
(count <= 7) 
  ifTrue: [size := 7]
  ifFalse: [size := Integer _selectedPrimeGreaterThan: count].

dict := self basicNew: (size * 3).
dict count: 0.
dict tableSize: size.
dict emptySlotHint: (size + 1).
dict numEmptySlots: size.

^ dict.
%

category: 'Instance Initialization'
method: Dictionary
_gciInitialize

"Private."

| size |

"The dictionary should have a certain minimum size and the size should
 preferably be a prime number."
size := 7.
self _basicSize: 0.
self _basicSize: (size * 3).
count := 0.
tableSize := size.
emptySlotHint := size + 1.
numEmptySlots := size.
%

! ------------------- Instance methods for Dictionary

category: 'Searching'
method: Dictionary
_idxOccurrencesOf: aValue

"Dictionaries can contain only Associations."

^ 0
%

category: 'Backward Compatibility'
method: Dictionary
_indexOf: aKey

"This method used to return the numerical index (as found by _#at:) of the
 Association in the receiver with the given key.  With the new implementation of
 Dictionaries, this method does not make sense."

^ self shouldNotImplement: #_indexOf:
%

category: 'Searching'
method: Dictionary
_keysWithValue: aValue

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

| result |

result:= IdentityBag new.
self associationsDo: [ :anAssoc |
  (aValue = anAssoc value) ifTrue: [ result add: anAssoc key ].
  ].
^ result
%

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

"Creates a new Association with the given key and value and adds it to the
 receiver.  No checks are made to see if an Association with the given key
 exists or not.  Improper use could result in duplicate keys."

| hashVal anAssoc |

hashVal := self hashFunction: aKey.
anAssoc := self class associationClass newWithKey: aKey value: aValue.
self addNewAssociation: anAssoc hash: hashVal.
^ aValue
%

category: 'Adding'
method: Dictionary
add: anAssociation

"Adds the Association or 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."

| aKey hashVal anAssoc |

aKey := anAssociation key.
hashVal := self hashFunction: aKey.

anAssoc := self associationAtOrNil: aKey hash: hashVal.
(anAssoc == nil)
  ifTrue: [
    anAssociation assignToSegment: self segment.
    self addNewAssociation: anAssociation hash: hashVal.
    ^ anAssociation.
    ].

anAssoc value: (anAssociation value).
^ anAssociation.
%

category: 'Private'
method: Dictionary
addNewAssociation: anAssociation hash: aHashVal

"Adds a new Association to the Dictionary.  The hash value of the key is given
 by aHashVal.  Returns the receiver."

| anElement emptySlot emptySlot2 |

(anAssociation isKindOf: self class associationClass) 
  ifFalse: 
    [ ^ self _error: #objErrDictConstraintViolation 
                  args: #[anAssociation, self class associationClass, 
                          anAssociation class]
    ].

anElement := self _at: aHashVal.
 
anElement == nil
  ifTrue: [
    self basicAt: aHashVal put: anAssociation.
    count := count + 1.
    ((numEmptySlots < (tableSize // 3)) _and: [numEmptySlots < 200])
      ifTrue: [self rebuild]. 
    ^ self
    ].

(anElement _isSmallInteger)
  ifTrue: [
    emptySlot := self findEmptySlot.
    self basicAt: emptySlot put: anAssociation.
    self basicAt: (emptySlot + 1) put: anElement.
    self basicAt: aHashVal put: emptySlot.
    count := count + 1.
    ((numEmptySlots < (tableSize // 3)) _and: [numEmptySlots < 200])
      ifTrue: [self rebuild]. 
    ^ self.
    ].

emptySlot := self findEmptySlot.
self basicAt: emptySlot put: anElement.
self basicAt: (emptySlot + 1) put: nil.

emptySlot2 := self findEmptySlot.
self basicAt: emptySlot2 put: anAssociation.
self basicAt: (emptySlot2 + 1) put: (emptySlot).
count := count + 1.

self basicAt: aHashVal put: emptySlot2.

((numEmptySlots < (tableSize // 3)) _and: [numEmptySlots < 200])
  ifTrue: [self rebuild]. 
^ self.
%

category: 'Accessing'
classmethod: Dictionary
associationClass

"Returns the class Associations for this class are constrained to be."

^ Association
%

category: 'Obsolete'
method: Dictionary
constraint

"Returns the class Associations are constrained to be."

^ self class associationClass
%

category: 'Accessing'
method: Dictionary
associationAt: aKey

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

| assoc |

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

category: 'Accessing'
method: Dictionary
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."

| assoc |
assoc := self associationAt: aKey otherwise: nil .
assoc == nil ifTrue:[
  aBlock == nil ifTrue:[^ nil ].
  ^aBlock value
  ].
^ assoc
%

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

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

| index anAssoc |

aKey == nil ifTrue:[ ^ defaultValue ] .

index := self hashFunction: aKey.
anAssoc := self _at: index.

(anAssoc == nil) ifTrue:[^ defaultValue ].

(anAssoc _isSmallInteger)
  "There is a collision. Follow the chain."
  ifTrue: [
    index := anAssoc.
    [index ~~ nil]
    whileTrue: [
      anAssoc := self _at: index.
      (anAssoc key = aKey)
        ifTrue: [^ anAssoc]
        ifFalse: [index := self _at: (index + 1)].
      ].
    ^ defaultValue
    ].

(anAssoc key = aKey)
  ifTrue: [ ^ anAssoc ].

^ defaultValue
%

category: 'Private'
method: Dictionary
associationAtOrNil: aKey hash: aHashVal

"Returns the Association with key aKey.  If no such Association exists, returns
 nil.  The search is only done in the hash chain that corresponds to aHashVal."

| index anAssoc |

anAssoc := self _at: aHashVal.

(anAssoc == nil) ifTrue: [ ^ nil ].

(anAssoc _isSmallInteger)
  "There is a collision. Follow the chain."
  ifTrue: [
    index := anAssoc.
    [nil ~~ index]
    whileTrue: [
      anAssoc := self _at: index.
      (anAssoc key = aKey)
        ifTrue: [^ anAssoc]
        ifFalse: [index := self _at: (index + 1)].
      ].
    ^ nil.
    ].

(anAssoc key = aKey)
  ifTrue: [ ^ anAssoc ].

^ nil.
%

category: 'Enumerating'
method: Dictionary
associationsDo: aBlock

"(R) Iteratively evaluates the one argument block, aBlock, using each
 Association in the receiver as the argument to the block.  Returns the
 receiver."

| anAssoc |

"First iterate through the first section of the Dictionary where Associations
 are directly hashed."
1 to: tableSize do: [ :i|
  anAssoc := self _at: i.
  (anAssoc isKindOf: Association)
    "anAssoc could be nil, a SmallInteger, or an Association"
    ifTrue: [ aBlock value: anAssoc ].
  ].

"Now iterate through the collision section of the Dictionary"
(tableSize + 1) to: (self _basicSize) by: 2 do: [ :i|
  anAssoc := self _at: i.
  (anAssoc ~~ nil)
    "anAssoc can only be nil or a valid Association in this section."
    ifTrue: [ aBlock value: anAssoc].
  ].

^ self.
%

category: 'Accessing'
method: Dictionary
at: aKey

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

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

category: 'Accessing'
method: Dictionary
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 |
anAssoc := self associationAt: aKey otherwise: nil .
anAssoc == nil ifTrue:[
  aBlock == nil ifTrue:[^ nil ].
  ^aBlock value
  ].
^ anAssoc value.
%

category: 'Accessing'
method: Dictionary
at: aKey otherwise: defaultValue

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

| anAssoc |

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

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

"(R) 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."

| hashVal anAssoc |

(aKey == nil) ifTrue: [ self errorNilKey ].
hashVal := self hashFunction: aKey.

anAssoc := self associationAtOrNil: aKey hash: hashVal.
(anAssoc == nil)
  ifTrue: [ 
    anAssoc := self class associationClass newWithKey: aKey value: aValue.
    anAssoc assignToSegment: self segment.
    self addNewAssociation: anAssoc hash: hashVal.
    ^ aValue
    ].

anAssoc value: aValue.
^ aValue
%

category: 'Private'
method: Dictionary
count

"Return the value of the instance variable 'count'."

^ count
%

category: 'Private'
method: Dictionary
count: newValue

"Modify the value of the instance variable 'count'."

count := newValue
%

category: 'Enumerating'
method: Dictionary
do: aBlock

"(R) Iteratively evaluates the one argument block, aBlock, using the value part
 of each Association as the argument of the block. Returns the receiver."
 
| anAssoc |
"First iterate through the first section of the Dictionary where Associations
 are directly hashed."
1 to: tableSize do: [ :i|
  anAssoc := self _at: i.
  (anAssoc isKindOf: Association)
    "anAssoc could be nil, a SmallInteger, or an Association"
    ifTrue: [ aBlock value: (anAssoc value) ].
  ].

"Now iterate through the collision section of the Dictionary"
(tableSize + 1) to: (self _basicSize) by: 2 do: [ :i|
  anAssoc := self _at: i.
  (anAssoc ~~ nil)
    "anAssoc can only be nil or a valid Association in this section."
    ifTrue: [ aBlock value: (anAssoc value) ].
  ].

^ self.
%

category: 'Private'
method: Dictionary
emptySlotHint

"Return the value of the instance variable 'emptySlotHint'."

^emptySlotHint
%

category: 'Private'
method: Dictionary
emptySlotHint: newValue

"Modify the value of the instance variable 'emptySlotHint'."

emptySlotHint := newValue
%

category: 'Private'
method: Dictionary
errorKeyNotFound: aKey

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

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

category: 'Private'
method: Dictionary
findEmptySlot

"Returns an empty slot from the collision part of the Dictionary structure."

| index |

"It is assumed that at this point at least one slot is empty.  Hence this
 cannot loop infinitely"
index := emptySlotHint.
[(self _at: index) ~~ nil]
  whileTrue: [
    index := index + 2.
    (index > (self _basicSize)) ifTrue: [index := tableSize + 1]
    ].

emptySlotHint := index + 2.
(emptySlotHint > (self _basicSize)) ifTrue: [emptySlotHint := tableSize + 1].

numEmptySlots := numEmptySlots - 1.

^ index.
%

category: 'Accessing'
method: Dictionary
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."

"Note: In GemStone 4.1, this method checked for a value identical to anObject 
 as opposed to checking for equality."

self keysAndValuesDo: [
  :key :value | (anObject = value) ifTrue: [^ key]
  ].

aBlock == nil ifTrue:[ ^ nil ].
^aBlock value
%

category: 'Enumerating'
method: Dictionary
keysAndValuesDo: aBlock

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

| anAssoc |

"First iterate through the first section of the Dictionary where Associations
 are directly hashed."
1 to: tableSize do: [ :i|
  anAssoc := self _at: i.
  (anAssoc isKindOf: Association)
    "anAssoc could be nil, a SmallInteger, or an Association"
    ifTrue: [ aBlock value: (anAssoc key) value: (anAssoc value) ].
  ].

"Now iterate through the collision section of the Dictionary"
(tableSize + 1) to: (self _basicSize) by: 2 do: [ :i|
  anAssoc := self _at: i.
  (anAssoc ~~ nil)
    "anAssoc can only be nil or a valid Association in this section."
    ifTrue: [ aBlock value: (anAssoc key) value: (anAssoc value) ].
  ].

^ self.
%

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

| anAssoc |
"First iterate through the first section of the Dictionary where Associations
 are directly hashed."
1 to: tableSize do: [ :i|
  anAssoc := self _at: i.
  (anAssoc isKindOf: Association)
    "anAssoc could be nil, a SmallInteger, or an Association"
    ifTrue: [ aBlock value: anObj value: (anAssoc key) value: (anAssoc value) ].
  ].

"Now iterate through the collision section of the Dictionary"
(tableSize + 1) to: (self _basicSize) by: 2 do: [ :i|
  anAssoc := self _at: i.
  (anAssoc ~~ nil)
    "anAssoc can only be nil or a valid Association in this section."
    ifTrue: [ aBlock value: anObj value: (anAssoc key) value: (anAssoc value) ].
  ].
%


category: 'Enumerating'
method: Dictionary
keysDo: aBlock

"(R) Iteratively evaluates the two argument block, aBlock, using each key
 of the receiver as the argument to the block.  Returns the receiver."

| anAssoc |

"First iterate through the first section of the Dictionary where Associations
 are directly hashed."
1 to: tableSize do: [ :i|
  anAssoc := self _at: i.
  (anAssoc isKindOf: Association)
    "anAssoc could be nil, a SmallInteger, or an Association"
    ifTrue: [ aBlock value: (anAssoc key) ].
  ].

"Now iterate through the collision section of the Dictionary"
(tableSize + 1) to: (self _basicSize) by: 2 do: [ :i|
  anAssoc := self _at: i.
  (anAssoc ~~ nil)
    "anAssoc can only be nil or a valid Association in this section."
    ifTrue: [ aBlock value: (anAssoc key) ].
  ].

^ self.
%

category: 'Enumerating'
method: Dictionary
valuesDo: aBlock

"(R) Iteratively evaluates the two argument block, aBlock, using each
 value of the receiver as the argument to the block.  Returns the receiver."

| anAssoc |

"First iterate through the first section of the Dictionary where Associations
 are directly hashed."
1 to: tableSize do: [ :i|
  anAssoc := self _at: i.
  (anAssoc isKindOf: Association)
    "anAssoc could be nil, a SmallInteger, or an Association"
    ifTrue: [ aBlock value: (anAssoc value) ].
  ].

"Now iterate through the collision section of the Dictionary"
(tableSize + 1) to: (self _basicSize) by: 2 do: [ :i|
  anAssoc := self _at: i.
  (anAssoc ~~ nil)
    "anAssoc can only be nil or a valid Association in this section."
    ifTrue: [ aBlock value: (anAssoc value) ].
  ].

^ self.
%

category: 'Private'
method: Dictionary
numEmptySlots

"Return the value of the instance variable 'numEmptySlots'."

^numEmptySlots
%

category: 'Private'
method: Dictionary
numEmptySlots: newValue

"Modify the value of the instance variable 'numEmptySlots'."

numEmptySlots := newValue
%

category: 'Private'
method: Dictionary
rebuild

"Rebuilds the hash dictionary so that it can accommodate more elements."

| newSize tempTable i |

"If it is a small dictionary, just double the overflow area every alternate
 time. Otherwise clear out the receiver, increase it in size, etc."
(tableSize < 650)
  ifTrue: [
    (self _basicSize <= (tableSize * 3))
      ifTrue: [ 
        self _basicSize: (self _basicSize + (tableSize * 2)).
        numEmptySlots := numEmptySlots + tableSize.
        ^ self.
        ].
    ].

"Until a table size of 650, double the size every time the dictionary
 needs to grow. After that, grow 650 entries each time. A tableSize of
 650 should occupy almost a whole page."

(tableSize < 650)
  ifTrue: [newSize := Integer _selectedPrimeGreaterThan: (tableSize * 2)]
  ifFalse: [newSize := Integer _selectedPrimeGreaterThan: (tableSize + 650)].

tempTable := Array new: count.
i := 1.
self associationsDo: [ :anAssn |
  tempTable at: i put: anAssn.
  i := i + 1
  ].

self _basicSize: 0.
self _basicSize: (newSize * 3).
"This grows the object and initializes the whole object with nils."

tableSize := newSize.
numEmptySlots := newSize.
emptySlotHint := newSize + 1.
count := 0.

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

^ self.
%

category: 'Removing'
method: Dictionary
removeAssociation: anAssociation

"Removes an element from the receiver equal to anAssociation and returns
 anAssociation. If no such element is present, this method generates an error."

"Note: In GemStone 4.1, this method checked for an element identical to 
 anAssociation. Also, it returned the receiver."

| assoc |
assoc := self removeKey: anAssociation key otherwise: nil .
assoc == nil ifTrue:[ ^ self _errorNotFound: anAssociation ].
^ assoc
%

category: 'Removing'
method: Dictionary
removeAssociation: anAssociation otherwise: defaultValue

"Removes an element from the receiver equal to anAssociation and returns 
 anAssociation.  If an element equal to anAssociation is not present, 
 returns defaultValue."

"Note: In GemStone 4.1, this method checked for an element identical to 
 anAssociation. Also, it returned the receiver."

| prevIndex index anElement |

index := self hashFunction: (anAssociation key).
anElement := self _at: index.

(anElement == nil) ifTrue: [^ defaultValue ].

(anElement _isSmallInteger)
  ifTrue: [
    "Need to follow the collision chains."
    prevIndex := index.
    index := anElement.
    [index ~~ nil]
    whileTrue: [
      anElement := self _at: index.
      (anElement = anAssociation) 
        ifTrue: [ 
           self basicAt: prevIndex put: (self _at: (index + 1)).
           self basicAt: index put: nil.
           self basicAt: (index + 1) put: nil.
           count := count - 1.
           ^ anAssociation.
           ]
        ifFalse: [
          "Go to the next one."
          prevIndex := index + 1.
          index := self _at: (index + 1)
          ].
      ].
    ^ defaultValue
    ].

(anElement = anAssociation)
  ifTrue: [ 
    self basicAt: index put: nil.
    count := count - 1.
    ^ anAssociation.
    ].

^ defaultValue
%

category: 'Removing'
method: Dictionary
removeKey: aKey otherwise: defaultValue

"Removes an element from the receiver with key aKey and returns an Association.
 If an element with key aKey is not present, returns defaultValue."

"Note: In GemStone 4.1, this method checked for an element identical to 
 anAssociation. Also, it returned the receiver."

| prevIndex index anAssociation |

index := self hashFunction: aKey .
anAssociation := self _at: index.

(anAssociation == nil) ifTrue: [^ defaultValue ].

(anAssociation _isSmallInteger)
  ifTrue: [
    "Need to follow the collision chains."
    prevIndex := index.
    index := anAssociation.
    [index ~~ nil]
    whileTrue: [
      anAssociation := self _at: index.
      (anAssociation key = aKey) 
        ifTrue: [
           self basicAt: prevIndex put: (self _at: (index + 1)).
           self basicAt: index put: nil.
           self basicAt: (index + 1) put: nil.
           count := count - 1.
           ^ anAssociation.
           ]
        ifFalse: [
          "Go to the next one."
          prevIndex := index + 1.
          index := self _at: (index + 1)
          ].
      ].
    ^ defaultValue
    ].

(anAssociation key = aKey) ifTrue:[
  self basicAt: index put: nil.
  count := count - 1.
  ^ anAssociation.
  ].
^ defaultValue 
%

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

"(R) Removes the Association with key equal to aKey from the receiver and
 returns the value of that Association.  If no Association 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."

| anAssoc |
anAssoc:= self removeKey: aKey otherwise: nil .
anAssoc == nil ifTrue:[ 
  aBlock == nil ifTrue:[^ nil ].
  ^aBlock value
  ].
^ anAssoc value
%

! delete resize;  rebuild is the correct method

category: 'Private'
method: Dictionary
tableSize

"Return the value of the instance variable 'tableSize'."

^tableSize
%

category: 'Private'
method: Dictionary
tableSize: newValue

"Modify the value of the instance variable 'tableSize'."

tableSize := newValue
%

category: 'Accessing'
method: Dictionary
size

"Returns the number of Associations in the receiver."

^ count
%

category: 'Accessing the Class Format'
classmethod: Dictionary
firstPublicInstVar

"Returns the index of the first user-visible instance variable defined in this
 class, regardless of whether or not this class actually has user-visible
 instance variables."

^ 6
%

category: 'Storing and Loading'
method: Dictionary
loadVaryingFrom: passiveObj size: varyingSize

"Reads the varying part of the receiver from the given passive object.
 Does not record the receiver as having been read.  Does not read the
 receiver's named instance variables, if any."

1 to: varyingSize do: [:i |
  self add: passiveObj readObject"anAssociation"
].
%

category: 'Storing and Loading'
method: Dictionary
basicWriteTo: passiveObj

"Converts the receiver to its passive form and writes that information on
 passiveObj."

| s cls ivs c |
  cls := self class.
  passiveObj writeClass: cls.

  ivs := cls _instVarNames .

  passiveObj writeSize: (s := self size) .

  cls firstPublicInstVar to: cls instSize do: [:i |
    (self shouldWriteInstVar: (ivs at: i)) ifTrue: [
      passiveObj writeObject: (self instVarAt: i) named: (ivs at: i)
    ].
  ].

  passiveObj endNamedInstVars.

  c := 0.
  self associationsDo:[ :anAssoc | 
    passiveObj writeObject: anAssoc .
    c := c + 1.
    c > 99 ifTrue: [
      passiveObj lf.
      c := 0.
      ].
    ].

  passiveObj cr
%

category: 'Private'
method: Dictionary
_deferredGciUpdateWith: valueArray

"Private."

1 to: valueArray size do:[:j |
  self add: (valueArray at: j)
  ].
%

category: 'Repository Conversion'
method: Dictionary
rehashForConversion

"This is a new class in 5.0. Return the receiver."

^ self.
%


