2
0

Kernel-Dag.st 3.7 KB

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