Kernel-Dag.st 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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'
  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. !PathDagVisitor methodsFor: 'initialization'!
  56. initialize
  57. super initialize.
  58. path := #()
  59. ! !
  60. !PathDagVisitor methodsFor: 'visiting'!
  61. visit: aNode
  62. | oldPath result |
  63. result := aNode.
  64. oldPath := path.
  65. [
  66. path := path, {aNode}.
  67. result := super visit: aNode
  68. ] ensure: [ path := oldPath ].
  69. ^ result
  70. !
  71. visitDagNodeVariantRedux: aNode
  72. | newNode |
  73. newNode := super visitDagNodeVariantRedux: aNode.
  74. aNode == newNode ifFalse: [ path at: path size put: newNode ].
  75. ^ newNode
  76. ! !
  77. Object subclass: #DagNode
  78. instanceVariableNames: ''
  79. package: 'Kernel-Dag'!
  80. !DagNode commentStamp!
  81. I am the abstract root class of any directed acyclic graph.
  82. Concrete classes should implement `dagChildren` and `dagChildren:`
  83. to get / set direct successor nodes (aka child nodes / subnodes).!
  84. !DagNode methodsFor: 'accessing'!
  85. allDagChildren
  86. | allNodes |
  87. allNodes := self dagChildren asSet.
  88. self dagChildren do: [ :each |
  89. allNodes addAll: each allDagChildren ].
  90. ^ allNodes
  91. !
  92. dagChildren
  93. self subclassResponsibility
  94. !
  95. dagChildren: aCollection
  96. self subclassResponsibility
  97. ! !
  98. !DagNode methodsFor: 'testing'!
  99. isDagNode
  100. ^ true
  101. ! !
  102. !DagNode methodsFor: 'visiting'!
  103. acceptDagVisitor: aVisitor
  104. ^ aVisitor visitDagNode: self
  105. ! !
  106. DagNode subclass: #DagParentNode
  107. instanceVariableNames: 'nodes'
  108. package: 'Kernel-Dag'!
  109. !DagParentNode commentStamp!
  110. I am `DagNode` that stores a collection of its children,
  111. lazy initialized to empty array.
  112. I can `addDagChild:` to add a child.!
  113. !DagParentNode methodsFor: 'accessing'!
  114. addDagChild: aDagNode
  115. self dagChildren add: aDagNode
  116. !
  117. dagChildren
  118. ^ nodes ifNil: [ nodes := Array new ]
  119. !
  120. dagChildren: aCollection
  121. nodes := aCollection
  122. ! !
  123. DagNode subclass: #DagSink
  124. instanceVariableNames: 'nodes'
  125. package: 'Kernel-Dag'!
  126. !DagSink commentStamp!
  127. I am `DagNode` with no direct successors.
  128. Sending `dagChildren:` with empty collection is legal.!
  129. !DagSink methodsFor: 'accessing'!
  130. dagChildren
  131. ^ #()
  132. !
  133. dagChildren: aCollection
  134. aCollection ifNotEmpty: [ self error: 'A DagSink cannot have children.' ]
  135. ! !
  136. !Object methodsFor: '*Kernel-Dag'!
  137. isDagNode
  138. ^ false
  139. ! !