package diagram import ( "errors" "fmt" "sync" "modelRT/constant" "modelRT/network" "github.com/gofrs/uuid" ) // Graph represents a topological structure using an adjacency list type Graph struct { sync.RWMutex // 根节点 RootVertex uuid.UUID // 游离节点 FreeVertexs map[string]struct{} VerticeLinks map[string][]uuid.UUID // 存储多个上级节点同时指向同一下级节点的情况,key为下级节点,value为上级节点集合 BackLinks map[string][]uuid.UUID } // NewGraph creates a new graph func NewGraph(root uuid.UUID) *Graph { return &Graph{ RootVertex: root, FreeVertexs: make(map[string]struct{}), VerticeLinks: make(map[string][]uuid.UUID), BackLinks: make(map[string][]uuid.UUID), } } // AddNode adds a node to the graph func (g *Graph) AddNode(vertex string) { if _, exists := g.VerticeLinks[vertex]; !exists { g.VerticeLinks[vertex] = []uuid.UUID{} } } // CreateBackLink adds a node to the graph func (g *Graph) CreateBackLink(vertex string) { if _, exists := g.BackLinks[vertex]; !exists { g.BackLinks[vertex] = []uuid.UUID{} } } // AddEdge adds an edge between two verticeLinks // TODO 在添加拓扑信息时是否考虑过滤重复节点 func (g *Graph) AddEdge(from, to uuid.UUID) { g.Lock() defer g.Unlock() fromKey := from.String() toKey := to.String() g.CreateBackLink(toKey) g.BackLinks[toKey] = append(g.BackLinks[toKey], from) g.AddNode(fromKey) g.AddNode(toKey) g.VerticeLinks[fromKey] = append(g.VerticeLinks[fromKey], to) // 创建新的拓扑信息时,如果被链接的点已经存在于游离节点中 // 则将其移除 if _, exist := g.FreeVertexs[toKey]; exist { delete(g.FreeVertexs, toKey) } } // DelNode delete a node to the graph func (g *Graph) DelNode(vertex string) error { childNodes, exists := g.VerticeLinks[vertex] if exists { if len(childNodes) > 1 { return errors.New("delete node failed,that vertex contains more than one child node") } delete(g.VerticeLinks, vertex) } parentNodes, exists := g.BackLinks[vertex] if exists { if len(parentNodes) > 1 { return errors.New("delete node failed,that vertex contains more than one parent node") } delete(g.BackLinks, vertex) } else { return errors.New("that vertex don't have parent node") } return nil } // DelEdge delete an edge between two verticeLinks func (g *Graph) DelEdge(from, to uuid.UUID) error { g.Lock() defer g.Unlock() toKey := to.String() var fromKeys []uuid.UUID if _, exist := g.BackLinks[toKey]; exist { fromKeys = g.BackLinks[toKey] } else { fromKeys = []uuid.UUID{from} } // Process the situation where the to node is taken as the parent node while deleting edges childvertex := g.VerticeLinks[toKey] err := g.DelNode(toKey) if err != nil { return fmt.Errorf("delete edge failed: %w", err) } fmt.Println("fromKeys:", fromKeys) for _, fromUUID := range fromKeys { fromKey := fromUUID.String() var delIndex int for index, vertex := range g.VerticeLinks[fromKey] { if vertex == to { delIndex = index } } vertex := g.VerticeLinks[fromKey] if len(vertex) == 1 { g.DelNode(fromKey) } else { copy(vertex[delIndex:], vertex[delIndex+1:]) vertex = vertex[:len(vertex)-1] g.VerticeLinks[fromKey] = vertex } } fromKey := from.String() g.VerticeLinks[fromKey] = append(g.VerticeLinks[fromKey], childvertex...) return nil } // PrintGraph prints the graph in adjacency list format func (g *Graph) PrintGraph() { g.RLock() // 读锁 defer g.RUnlock() for vertex, edges := range g.VerticeLinks { fmt.Printf("%s -> %v\n", vertex, edges) } } // UpdateEdge update edge link info between two verticeLinks func (g *Graph) UpdateEdge(changeInfo network.TopologicUUIDChangeInfos) error { if changeInfo.ChangeType == constant.UUIDFromChangeType || changeInfo.ChangeType == constant.UUIDToChangeType { g.DelEdge(changeInfo.OldUUIDFrom, changeInfo.OldUUIDTo) g.AddEdge(changeInfo.NewUUIDFrom, changeInfo.NewUUIDTo) } else { g.AddEdge(changeInfo.NewUUIDFrom, changeInfo.NewUUIDTo) } return nil }