home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 3 / CDPDIII.bin / pd / programming / gnusmalltalk / identitydictionary.st < prev    next >
Text File  |  1992-02-15  |  8KB  |  307 lines

  1. "======================================================================
  2. |
  3. |   IdentityDictionary Method Definitions
  4. |
  5.  ======================================================================"
  6.  
  7.  
  8. "======================================================================
  9. |
  10. | Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
  11. | Written by Steve Byrne.
  12. |
  13. | This file is part of GNU Smalltalk.
  14. |
  15. | GNU Smalltalk is free software; you can redistribute it and/or modify it
  16. | under the terms of the GNU General Public License as published by the Free
  17. | Software Foundation; either version 1, or (at your option) any later version.
  18. | GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
  19. | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  20. | FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
  21. | details.
  22. | You should have received a copy of the GNU General Public License along with
  23. | GNU Smalltalk; see the file COPYING.  If not, write to the Free Software
  24. | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  
  25. |
  26.  ======================================================================"
  27.  
  28.  
  29. "
  30. |     Change Log
  31. | ============================================================================
  32. | Author       Date       Change 
  33. | sbb         28 Jul 91      Fixed #= to check argument class.  Converted to use
  34. |              cascaded printing.
  35. |
  36. | sbb         16 Mar 91      Class creation now separate statement.
  37. |
  38. | sbyrne     25 Apr 89      created.
  39. |
  40. "
  41.  
  42. Dictionary variableSubclass: #IdentityDictionary
  43.        instanceVariableNames: 'values'
  44.        classVariableNames: ''
  45.        poolDictionaries: ''
  46.        category: nil
  47. !
  48.  
  49. IdentityDictionary comment:
  50. 'I am similar to dictionary, except that my representation is
  51. different, and I use the object identity comparision message == to
  52. determine equivalence of indices.' !
  53.  
  54. !IdentityDictionary class methodsFor: 'instance creation'!
  55.  
  56. new
  57.     ^self new: 4
  58. !
  59.  
  60. new: anInteger
  61.     ^(super new: anInteger) initValues
  62.  
  63. !!
  64.  
  65.  
  66.  
  67. !IdentityDictionary methodsFor: 'accessing'!
  68.  
  69. add: anAssociation
  70.     self at: anAssociation key put: anAssociation value.
  71.     ^anAssociation
  72. !
  73.  
  74. at: key put: value
  75.     | index |
  76.     index _ self findKeyIndex: key.
  77.     (self basicAt: index) isNil
  78.         ifTrue: [ tally _ tally + 1 ].
  79.     self basicAt: index put: key.
  80.     values basicAt: index put: value.
  81.     ^value
  82. !
  83.  
  84. at: key ifAbsent: aBlock
  85.     | index |
  86.     index _ self findKeyIndex: key.
  87.     (self basicAt: index) isNil
  88.         ifTrue: [ ^aBlock value ].
  89.     ^values basicAt: index
  90. !    
  91.     
  92. associationAt: key ifAbsent: aBlock
  93.     | index assoc|
  94.     ^Association key: key
  95.          value: (self at: key
  96.                       ifAbsent: [ ^aBlock value ])
  97. !
  98.  
  99. keyAtValue: value ifAbsent: exceptionBlock
  100.     self indicesDo:
  101.         [ :i | value = (values basicAt: i)
  102.                  ifTrue: [ ^self basicAt: i] ].
  103.     ^exceptionBlock value
  104. !!
  105.  
  106.  
  107.  
  108. !IdentityDictionary methodsFor: 'dictionary testing'!
  109.  
  110. includesAssociation: anAssociation
  111.     | index |
  112.     index _ self findKeyIndex: anAssociation key.
  113.     ^(self basicAt: index) notNil
  114.         and: [ (values basicAt: index) = anAssociation value ]
  115. !
  116.  
  117. includesKey: key
  118.     ^(self basicAt: (self findKeyIndex: key)) notNil
  119. !!
  120.  
  121.  
  122.  
  123. !IdentityDictionary methodsFor: 'dictionary removing'!
  124.  
  125. removeKey: key ifAbsent: aBlock
  126.     | index value|
  127.     index _ self findKeyIndexNoGrow: key ifAbsent: [ ^aBlock value ].
  128.     value _ values basicAt: index.
  129.     self basicAt: index put: nil.
  130.     values basicAt: index put: nil.
  131.     tally _ tally - 1.
  132.     self rehashObjectsAfter: index.
  133.     ^ value
  134. !!
  135.  
  136.  
  137.  
  138. !IdentityDictionary methodsFor: 'dictionary enumerating'!
  139.  
  140. associationsDo: aBlock
  141.     self indicesDo:
  142.         [ :i | aBlock value: (Association key: (self basicAt: i)
  143.                                       value: (values basicAt: i)) ]
  144. !
  145.  
  146. "These could be implemented more efficiently by 
  147.  doing the explicit scanning of the dictionary by hand"
  148. keysDo: aBlock
  149.     self indicesDo: [ :i | aBlock value: (self basicAt: i) ]
  150. !
  151.  
  152. do: aBlock
  153.     self indicesDo: [ :i | aBlock value: (values basicAt: i) ]
  154. !
  155.  
  156. select: aBlock
  157.     | newDict |
  158.     newDict _ self species new.
  159.     self indicesDo:
  160.         [ :i | (aBlock value: (values basicAt: i))
  161.                  ifTrue: [ newDict add: (Association key: (self basicAt: i)
  162.                                             value: (values basicAt: i))] ].
  163.     ^newDict
  164. !!
  165.  
  166.  
  167.  
  168. !IdentityDictionary methodsFor: 'misc math methods'!
  169.  
  170. = aDictionary
  171.     self class == aDictionary class
  172.     ifFalse: [ ^false ].
  173.     tally ~= aDictionary size ifTrue: [ ^false ].
  174.     self indicesDo:
  175.         [ :i | (values basicAt: i) = (aDictionary at: (self basicAt: i)
  176.                                               ifAbsent: [ ^false ])
  177.                  ifFalse: [ ^false ] ].
  178.     ^true
  179. !
  180.  
  181. hash
  182.     | hashValue |
  183.     hashValue _ tally.
  184.     self indicesDo:
  185.         [ :i | hashValue _ hashValue + (self basicAt: i) hash.
  186.            hashValue _ hashValue + (values basicAt: i) hash ].
  187.     ^hashValue
  188. !!
  189.  
  190.  
  191.  
  192. !IdentityDictionary methodsFor: 'printing'!
  193.  
  194. printOn: aStream
  195.     aStream nextPutAll: self class name , ' (' ; nl.
  196.     self indicesDo:
  197.         [ :i | aStream tab;
  198.            print: (self basicAt: i);
  199.            nextPutAll: '->';
  200.            print: (values basicAt: i);
  201.            nl ].
  202.     aStream nextPut: $)
  203. !!
  204.  
  205.  
  206.  
  207. !IdentityDictionary methodsFor: 'storing'!
  208.  
  209. storeOn: aStream
  210.     | hasElements |
  211.     aStream nextPutAll: '(', self class name , ' new'.
  212.     hasElements _ false.
  213.     self indicesDo:
  214.         [ :i | aStream nextPutAll: ' at: ';
  215.            store: (self basicAt: i);
  216.            nextPutAll: ' put: ';
  217.            store: (values basicAt: i);
  218.            nextPut: $;.
  219.            hasElements _ true ].
  220.     hasElements ifTrue: [ aStream nextPutAll: ' yourself' ].
  221.     aStream nextPut: $)
  222. !!
  223.  
  224.  
  225.  
  226. !IdentityDictionary methodsFor: 'private methods'!
  227.  
  228. initValues
  229.     values _ Array new: self basicSize
  230. !
  231.  
  232. indicesDo: aBlock
  233.     "Invokes aBlock with all the indices of the set that have valid keys"
  234.     1 to: self basicSize do:
  235.         [ :i | (self basicAt: i) notNil
  236.               ifTrue: [ aBlock value: i ] ]
  237. !    
  238.  
  239. rehashObjectsAfter: index
  240.     "### rehash bug needs to be fixed!!!!"
  241.     "Rehashes all the objects in the collection after index to see if any of
  242.     them hash to index.  If so, that object is copied to index, and the
  243.     process repeats with that object's index, until a nil is encountered."
  244.     | i size count key |
  245.     i _ index.
  246.     size _ self basicSize.
  247.     count _ size.
  248.     [ count > 0 ]
  249.         whileTrue:
  250.         [ i _ i \\ size + 1.
  251.               key _ self basicAt: i.
  252.           key isNil ifTrue: [ ^self ].
  253.               ((key hash \\ size) + 1) = index
  254.               ifTrue: [ self basicAt: index put: key.
  255.                   values basicAt: index put: (values basicAt: i).
  256.                   self basicAt: i put: nil.  "Be tidy"
  257.               values basicAt: i put: nil."Be tidy"
  258.               index _ i ].
  259.               count _ count - 1 ]
  260. !
  261.  
  262. findKeyIndex: aKey ifFull: aBlock
  263.     "Tries to see if aKey exists as the key of an indexed variable (which is an
  264.     association).  If it's searched the entire dictionary and the key is 
  265.     not to be found, aBlock is evaluated and it's value is returned."
  266.     | index count size key |
  267.     size _ self basicSize.
  268.     index _ aKey hash \\ size + 1.
  269.     count _ size.
  270.     [ count > 0 ]
  271.         whileTrue:
  272.         [ key _ self basicAt: index.
  273.               (key isNil or: [ key == aKey ])
  274.             ifTrue: [ ^index ].
  275.           index _ index \\ size + 1.
  276.           count _ count - 1. ].
  277.     ^aBlock value
  278. !
  279.         
  280. findKeyIndex: aKey
  281.     "Finds an association with the given key in the dictionary and returns its
  282.     index.  If the dictionary doesn't contain the object and there is no nil
  283.     element, the dictionary is grown and then the index of where the object
  284.     would go is returned."
  285.     ^self findKeyIndex: aKey
  286.            ifFull: [ self grow.
  287.                 self findKeyIndexNoGrow: aKey
  288.                   ifAbsent: [ ^self error: 'failed to grow a new empty element!!!' ] ]
  289. !
  290.  
  291. grow
  292.     | newDict |
  293.     newDict _ self species new: self basicSize + self growSize.
  294.     self indicesDo: [ :i | newDict at: (self basicAt: i)
  295.                    put: (values basicAt: i) ].
  296.     ^self become: newDict
  297. !
  298.  
  299. growSize
  300.     ^32
  301.  
  302. !!
  303.  
  304.  
  305.