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

removeallmethods StringKeyValueDictionary
removeallclassmethods StringKeyValueDictionary

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

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

txt := (GsDocText new) details:
'A StringKeyValueDictionary is a KeyValueDictionary in which the keys are
 Strings or DoubleByteStrings.  The hash function treats the strings as
 case-sensitive.

 The hashing algorithm is described in

 Pearson, Peter K.,
 "Fast Hashing of Variable-Length Text Strings,"
 Communications of the ACM, 33:6 (June 1990), 667-680.

 The implementation employs two modifications:

 * The hash function uses at most 2008 bytes of the string.  Strings that are
   identical within this range have the same hash value.

 * In his paper, Pearson describes a technique for producing a larger number of
   hash values by always computing the hash function to 24 bits.  The hash
   value is the result of this function modulo the table size.  Therefore,
   there is no value in specifying a table size greater than 2 to the 24th
   power.' .
doc documentClassWith: txt.

self description: doc.
%

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

"Returns the value that corresponds to aKey.  If no such key/value pair
 exists, returns the result of evaluating the zero-argument block aBlock."

^self _stringAt: aKey caseSensitive: true ifAbsent: aBlock
%

category: 'Accessing'
method: StringKeyValueDictionary
name

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

| hashKey hashValue collisionBkt |
1 to: tableSize do: [ :tableIndex |
  hashKey := self keyAt: tableIndex.
  hashValue := self valueAt: tableIndex.
  (hashKey == nil)
    ifTrue: [ collisionBkt := hashValue.
              (collisionBkt == nil)
                 ifFalse: [ 1 to: collisionBkt numElements do: [ :i |
                            ((collisionBkt valueAt: i) == self)
                              ifTrue: [ ^collisionBkt keyAt: i ] ] ] ]
    ifFalse: [ (hashValue == self)
                  ifTrue: [ ^hashKey ] ]
  ].
^nil
%

category: 'Accessing'
method: StringKeyValueDictionary
_stringAt: aKey caseSensitive: aBoolean ifAbsent: aBlock

"Performs a search of the receiver for the key aKey.
 Returns the value if found."

<primitive: 83>
aBlock _validateClass: BlockClosure.
^aBlock value
%

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

"Stores the aKey/aValue pair in the receiver.  Rebuilds the hash table if the
 addition caused the number of collisions to exceed the limit allowed.
 Returns aValue.

 If aKey is being added for the first time, an invariant copy of it is stored
 as the key."

self _stringAt: aKey put: aValue caseSensitive: true.
(numCollisions > collisionLimit)
  ifTrue: [self rebuildTable: tableSize * 2].
^aValue
%

category: 'Updating'
method: StringKeyValueDictionary
_stringAt: aKey put: aValue caseSensitive: aBoolean

"Stores the aKey/aValue pair in the hash dictionary."

<primitive: 256>
self _primitiveFailed: #_stringAt:put:caseSensitive: .
self _uncontinuableError
%

category: 'Accessing'
method: StringKeyValueDictionary
_stringAt: aKey caseSensitive: aBoolean otherwise: aValue

"Performs a search of the receiver for the key aKey.
 Returns the value if found."

<primitive: 83>
^aValue
%

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

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

^self _stringAt: aKey caseSensitive: true otherwise: aValue
%

category: 'Private'
method: StringKeyValueDictionary
_buildWeakRefSet

"Adds the leaf objects to the hiddenSet."

| hashKey hashValue collisionBkt systm |
systm := System .
1 to: tableSize do: [ :tableIndex |
  hashKey := self keyAt: tableIndex.
  hashValue := self valueAt: tableIndex.
  (hashKey == nil)
    ifTrue: [ collisionBkt := hashValue.
              (collisionBkt == nil)
                 ifFalse: [ systm _add: collisionBkt to: 35]]
  ].
^nil
%

