Kernel-Dag.st 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. Smalltalk createPackage: 'Kernel-Dag'!
  2. Object subclass: #AbstractDagVisitor
  3. slots: {}
  4. package: 'Kernel-Dag'!
  5. !AbstractDagVisitor commentStamp!
  6. I am base class of `DagNode` visitor.
  7. Concrete classes should implement `visitDagNode:`,
  8. they can reuse possible variants of implementation
  9. offered directly: `visitDagNodeVariantSimple:`
  10. and `visitDagNodeVariantRedux:`.!
  11. !AbstractDagVisitor methodsFor: 'evaluating'!
  12. value: anObject
  13. ^ self visit: anObject
  14. ! !
  15. !AbstractDagVisitor methodsFor: 'visiting'!
  16. visit: aNode
  17. ^ aNode acceptDagVisitor: self
  18. !
  19. visitAll: aCollection
  20. ^ aCollection collect: [ :each | self visit: each ]
  21. !
  22. visitAllChildren: aDagNode
  23. ^ self visitAll: aDagNode dagChildren
  24. !
  25. visitDagNode: aNode
  26. self subclassResponsibility
  27. !
  28. visitDagNodeVariantRedux: aNode
  29. "Immutable-guarded implementation of visitDagNode:.
  30. Visits all children and checks if there were changes.
  31. If not, returns aNode.
  32. If yes, returns copy of aNode with new children."
  33. | newChildren oldChildren |
  34. oldChildren := aNode dagChildren.
  35. newChildren := self visitAllChildren: aNode.
  36. oldChildren = newChildren
  37. ifTrue: [ ^ aNode ]
  38. ifFalse: [ ^ aNode copy dagChildren: newChildren; yourself ]
  39. !
  40. visitDagNodeVariantSimple: aNode
  41. "Simple implementation of visitDagNode:.
  42. Visits children, then returns aNode"
  43. self visitAllChildren: aNode.
  44. ^ aNode
  45. ! !
  46. AbstractDagVisitor subclass: #PathDagVisitor
  47. slots: {#path}
  48. package: 'Kernel-Dag'!
  49. !PathDagVisitor commentStamp!
  50. I am base class of `DagNode` visitor.
  51. I hold the path of ancestors up to actual node
  52. in `self path`.!
  53. !PathDagVisitor methodsFor: 'accessing'!
  54. path
  55. ^ path
  56. ! !
  57. !PathDagVisitor methodsFor: 'initialization'!
  58. initialize
  59. super initialize.
  60. path := #()
  61. ! !
  62. !PathDagVisitor methodsFor: 'visiting'!
  63. visit: aNode
  64. | oldPath result |
  65. result := aNode.
  66. oldPath := path.
  67. [
  68. path := path, {aNode}.
  69. result := super visit: aNode
  70. ] ensure: [ path := oldPath ].
  71. ^ result
  72. !
  73. visitDagNodeVariantRedux: aNode
  74. | newNode |
  75. newNode := super visitDagNodeVariantRedux: aNode.
  76. aNode == newNode ifFalse: [ path at: path size put: newNode ].
  77. ^ newNode
  78. ! !
  79. Object subclass: #DagNode
  80. slots: {}
  81. package: 'Kernel-Dag'!
  82. !DagNode commentStamp!
  83. I am the abstract root class of any directed acyclic graph.
  84. Concrete classes should implement `dagChildren` and `dagChildren:`
  85. to get / set direct successor nodes (aka child nodes / subnodes).!
  86. !DagNode methodsFor: 'accessing'!
  87. allDagChildren
  88. | allNodes |
  89. allNodes := self dagChildren asSet.
  90. self dagChildren do: [ :each |
  91. allNodes addAll: each allDagChildren ].
  92. ^ allNodes
  93. !
  94. dagChildren
  95. self subclassResponsibility
  96. !
  97. dagChildren: aCollection
  98. self subclassResponsibility
  99. ! !
  100. !DagNode methodsFor: 'testing'!
  101. isDagNode
  102. ^ true
  103. ! !
  104. !DagNode methodsFor: 'visiting'!
  105. acceptDagVisitor: aVisitor
  106. ^ aVisitor visitDagNode: self
  107. ! !
  108. DagNode subclass: #DagParentNode
  109. slots: {#nodes}
  110. package: 'Kernel-Dag'!
  111. !DagParentNode commentStamp!
  112. I am `DagNode` that stores a collection of its children,
  113. lazy initialized to empty array.
  114. I can `addDagChild:` to add a child.!
  115. !DagParentNode methodsFor: 'accessing'!
  116. addDagChild: aDagNode
  117. self dagChildren add: aDagNode
  118. !
  119. dagChildren
  120. ^ nodes ifNil: [ nodes := Array new ]
  121. !
  122. dagChildren: aCollection
  123. nodes := aCollection
  124. ! !
  125. DagNode subclass: #DagSink
  126. slots: {}
  127. package: 'Kernel-Dag'!
  128. !DagSink commentStamp!
  129. I am `DagNode` with no direct successors.
  130. Sending `dagChildren:` with empty collection is legal.!
  131. Trait named: #TDagSink
  132. package: 'Kernel-Dag'!
  133. !TDagSink methodsFor: 'accessing'!
  134. dagChildren
  135. ^ #()
  136. !
  137. dagChildren: aCollection
  138. aCollection ifNotEmpty: [ self error: 'A DagSink cannot have children.' ]
  139. ! !
  140. Trait named: #TDerivedDagChildren
  141. package: 'Kernel-Dag'!
  142. !TDerivedDagChildren methodsFor: 'accessing'!
  143. addDagChild: aDagNode
  144. self error: 'Cannot add child for a TDerivedChildren.'
  145. !
  146. dagChildren
  147. self subclassResponsibility
  148. !
  149. dagChildren: aCollection
  150. self error: 'Cannot set children of a TDerivedChildren.'
  151. ! !
  152. Trait named: #TSingleDagChild
  153. package: 'Kernel-Dag'!
  154. !TSingleDagChild methodsFor: 'accessing'!
  155. dagChild
  156. self subclassResponsibility
  157. !
  158. dagChildren
  159. ^ { self dagChild }
  160. ! !
  161. TDagSink setTraitComposition: {TDerivedDagChildren} asTraitComposition!
  162. TSingleDagChild setTraitComposition: {TDerivedDagChildren} asTraitComposition!
  163. DagSink setTraitComposition: {TDagSink} asTraitComposition!
  164. ! !
  165. !Object methodsFor: '*Kernel-Dag'!
  166. isDagNode
  167. ^ false
  168. ! !