!=========================================================================
! Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved.
!
! $Id: rccollbkt.gs,v 1.4 2008-01-09 22:50:13 stever Exp $
!
! Superclass Hierarchy:
!   RcCollisionBucket, CollisionBucket, Array, SequenceableCollection,
!   Collection, Object.
!
!=========================================================================

! Create the class RcCollisionBucket, if it does not already exist

expectvalue %String
run
  CollisionBucket _newKernelSubclass: 'RcCollisionBucket'
    instVarNames: #()
    classVars: #()
    classInstVars: #()
    poolDictionaries: #[]
    inDictionary: Globals
    constraints: #[  ]
    instancesInvariant: false
    isModifiable: false
    reservedOop: 897
%

removeallmethods RcCollisionBucket
removeallclassmethods RcCollisionBucket

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

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

txt := (GsDocText new) details:
'An RcCollisionBucket is a CollisionBucket that is used in an
 RcKeyValueDictionary to store a collection of key/value pairs for which the
 keys hash to the same value.  It provides support for the reduced-conflict
 properties of RcKeyValueDictionaries.' .
doc documentClassWith: txt.

self description: doc.
%

! ------------------- Class methods for RcCollisionBucket
! ------------------- Instance methods for RcCollisionBucket
category: 'Accessing'
method: RcCollisionBucket
keyAt: index

"Returns the key at the specified index."

^ self _rcAt: (2 * index - 1)
%

category: 'Updating'
method: RcCollisionBucket
reset

"Reset all entries to nil and the number of elements to zero."

self _deleteNoShrinkFrom: 1 to: self _basicSize.
numElements := 0.
System _addEntireObjectToRcReadSet: self
%

category: 'Accessing'
method: RcCollisionBucket
valueAt: index

"Returns the value at the specified index."

^ self _rcAt: (2 * index)
%

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

"Stores the aKey/aValue pair in the RcCollisionBucket.  If the key already
 exists, returns the old value, otherwise, returns nil."

| emptySlotIndex startTableSize thisKey oldVal |
startTableSize := self tableSize .
aKey == nil
    ifTrue:[ ^ self _error: #rtErrNilKey ].

" search for aKey, or for the first empty slot "
1 to: startTableSize do: [ :index |
  thisKey := self keyAt: index.
  ( nil == emptySlotIndex _and: [ nil == thisKey ] )
    ifTrue:[ emptySlotIndex := index ]
    ifFalse: [
      (self compareKey: aKey with: thisKey)
        ifTrue:[ "Key found.  Store given value"
          oldVal := self valueAt: index.
          self at: index putValue: aValue.
          ^ oldVal
        ]
    ]
] .

" key not found so add key and value"
emptySlotIndex == nil
    ifTrue:[ " bucket is full so grow it "
        self size: (self _basicSize + 8 ) . "accommodate 4 more key,value pairs"
        emptySlotIndex := startTableSize + 1 .
    ] .

numElements := numElements + 1.
self at: emptySlotIndex putKey: aKey.
self at: emptySlotIndex putValue: aValue.
^ nil
%

category: 'Private'
method: RcCollisionBucket
_addToWriteSet

"Make a benign modification to the receiver so that it is placed in 
 the write set."

numElements := numElements
%

