Kernel-Dag.st 3.9 KB

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