VERSION 1.0 CLASS BEGIN MultiUse = -1 'True END Attribute VB_Name = "CDS_Graph" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = False Attribute VB_PredeclaredId = False Attribute VB_Exposed = False ' ====== Class Module for Graph management ======== ' Shared module version: 20210419 ' Tested in: TestCommons ' Depends on: ex_Collection, CDS_Edge, CDS_Node ' Required reference: Scripting ' Warning: node data should be basic type and be convertible to String (VBA.CStr) Option Explicit Public nodes_ As Scripting.Dictionary Public edges_ As Scripting.Dictionary Private Sub Class_Initialize() Call Clear End Sub Public Function Clear() Set nodes_ = New Scripting.Dictionary Set edges_ = New Scripting.Dictionary End Function Public Property Get Size() As Long Size = nodes_.Count End Property Public Property Get Nodes() As Collection Set Nodes = New Collection Dim vData As Variant For Each vData In nodes_ Call Nodes.Add(vData) Next vData End Property Public Function AddNode(vNode As Variant) Call InternalAddNode(vNode) End Function Public Function HasNode(vNode As Variant) As Boolean HasNode = nodes_.Exists(vNode) End Function Public Function AddEdge(vSource As Variant, vDestination As Variant) As CDS_Edge Call AddNode(vSource) Call AddNode(vDestination) Dim newEdge As New CDS_Edge: Call newEdge.Init(vSource, vDestination) Dim sEdge$: sEdge = newEdge.ID If edges_.Exists(sEdge) Then _ Exit Function Call edges_.Add(sEdge, newEdge) Call nodes_(vSource).outputs_.Add(vDestination) Call nodes_(vDestination).inputs_.Add(vSource) Set AddEdge = newEdge End Function Public Function HasEdge(vSource As Variant, vDestination As Variant) As Boolean Dim newEdge As New CDS_Edge: Call newEdge.Init(vSource, vDestination) Dim sEdge$: sEdge = newEdge.ID HasEdge = edges_.Exists(sEdge) End Function Public Function ExpandOutputs(ByRef target As Scripting.Dictionary) Dim nCount& Do While True nCount = target.Count Call ExpandOutsOnce(target) If nCount = target.Count Then _ Exit Function Loop End Function Public Function ExpandInputs(ByRef target As Scripting.Dictionary) Dim nCount& Do While True nCount = target.Count Call ExpandInsOnce(target) If nCount = target.Count Then _ Exit Function Loop End Function Public Function ExpandBiderctional(ByRef target As Scripting.Dictionary) Dim nCount& Do While True nCount = target.Count Call ExpandBiderctionalOnce(target) If nCount = target.Count Then _ Exit Function Loop End Function Public Function ExpandOutsOnce(ByRef target As Scripting.Dictionary) Dim nCount&: nCount = target.Count Dim aKey As Variant Dim vChild As Variant For Each aKey In target For Each vChild In nodes_(aKey).outputs_ If Not target.Exists(vChild) Then _ Call target.Add(vChild, 0) Next vChild nCount = nCount - 1 If nCount = 0 Then _ Exit Function Next aKey End Function Public Function ExpandInsOnce(ByRef target As Scripting.Dictionary) Dim nCount&: nCount = target.Count Dim aKey As Variant Dim vChild As Variant For Each aKey In target For Each vChild In nodes_(aKey).inputs_ If Not target.Exists(vChild) Then _ Call target.Add(vChild, 0) Next vChild nCount = nCount - 1 If nCount = 0 Then _ Exit Function Next aKey End Function Public Function ExpandBiderctionalOnce(ByRef target As Scripting.Dictionary, Optional nStart& = 1) Dim nCount&: nCount = target.Count Dim aKey As Variant Dim vChild As Variant For Each aKey In target For Each vChild In nodes_(aKey).inputs_ If Not target.Exists(vChild) Then _ Call target.Add(vChild, 0) Next vChild For Each vChild In nodes_(aKey).outputs_ If Not target.Exists(vChild) Then _ Call target.Add(vChild, 0) Next vChild nCount = nCount - 1 If nCount = 0 Then _ Exit Function Next aKey End Function Public Function FilterInternalEdges(iNodes As Scripting.Dictionary) As Collection Dim iEdges As New Collection Dim anEdge As CDS_Edge Dim aKey As Variant For Each aKey In edges_ Set anEdge = edges_(aKey) If iNodes.Exists(anEdge.source_) And iNodes.Exists(anEdge.dest_) Then _ Call iEdges.Add(anEdge) Next aKey Set FilterInternalEdges = iEdges End Function ' ============== Private Function InternalAddNode(vNode As Variant) If nodes_.Exists(vNode) Then _ Exit Function Dim newNode As New CDS_Node newNode.data_ = vNode Call nodes_.Add(vNode, newNode) End Function