graph: add edgeIndex's to Graph to speed up EdgeValues call
This commit is contained in:
parent
132a50039b
commit
91c0629377
@ -43,6 +43,46 @@ func (e Edge) id() string {
|
|||||||
return fmt.Sprintf("%q-%q->%q", e.Tail, e.Val, e.Head)
|
return fmt.Sprintf("%q-%q->%q", e.Tail, e.Val, e.Head)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// an edgeIndex maps valueIDs to a set of edgeIDs. Graph keeps two edgeIndex's,
|
||||||
|
// one for input edges and one for output edges.
|
||||||
|
type edgeIndex map[string]map[string]struct{}
|
||||||
|
|
||||||
|
func (ei edgeIndex) cp() edgeIndex {
|
||||||
|
if ei == nil {
|
||||||
|
return edgeIndex{}
|
||||||
|
}
|
||||||
|
ei2 := make(edgeIndex, len(ei))
|
||||||
|
for valID, edgesM := range ei {
|
||||||
|
edgesM2 := make(map[string]struct{}, len(edgesM))
|
||||||
|
for id := range edgesM {
|
||||||
|
edgesM2[id] = struct{}{}
|
||||||
|
}
|
||||||
|
ei2[valID] = edgesM2
|
||||||
|
}
|
||||||
|
return ei2
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ei edgeIndex) add(valID, edgeID string) {
|
||||||
|
edgesM, ok := ei[valID]
|
||||||
|
if !ok {
|
||||||
|
edgesM = map[string]struct{}{}
|
||||||
|
ei[valID] = edgesM
|
||||||
|
}
|
||||||
|
edgesM[edgeID] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ei edgeIndex) del(valID, edgeID string) {
|
||||||
|
edgesM, ok := ei[valID]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(edgesM, edgeID)
|
||||||
|
if len(edgesM) == 0 {
|
||||||
|
delete(ei, valID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Graph implements an immutable, unidirectional graph which can hold generic
|
// Graph implements an immutable, unidirectional graph which can hold generic
|
||||||
// values. All methods are thread-safe as they don't modify the Graph in any
|
// values. All methods are thread-safe as they don't modify the Graph in any
|
||||||
// way.
|
// way.
|
||||||
@ -53,11 +93,17 @@ func (e Edge) id() string {
|
|||||||
// Edges are in random order.
|
// Edges are in random order.
|
||||||
type Graph struct {
|
type Graph struct {
|
||||||
m map[string]Edge
|
m map[string]Edge
|
||||||
|
|
||||||
|
// these are indices mapping Value IDs to all the in/out edges for that
|
||||||
|
// Value in the Graph.
|
||||||
|
vIns, vOuts edgeIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g Graph) cp() Graph {
|
func (g Graph) cp() Graph {
|
||||||
g2 := Graph{
|
g2 := Graph{
|
||||||
m: make(map[string]Edge, len(g.m)),
|
m: make(map[string]Edge, len(g.m)),
|
||||||
|
vIns: g.vIns.cp(),
|
||||||
|
vOuts: g.vOuts.cp(),
|
||||||
}
|
}
|
||||||
for id, e := range g.m {
|
for id, e := range g.m {
|
||||||
g2.m[id] = e
|
g2.m[id] = e
|
||||||
@ -75,6 +121,8 @@ func (g Graph) AddEdge(e Edge) Graph {
|
|||||||
|
|
||||||
g2 := g.cp()
|
g2 := g.cp()
|
||||||
g2.m[id] = e
|
g2.m[id] = e
|
||||||
|
g2.vIns.add(e.Head.ID, id)
|
||||||
|
g2.vOuts.add(e.Tail.ID, id)
|
||||||
return g2
|
return g2
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,6 +136,8 @@ func (g Graph) DelEdge(e Edge) Graph {
|
|||||||
|
|
||||||
g2 := g.cp()
|
g2 := g.cp()
|
||||||
delete(g2.m, id)
|
delete(g2.m, id)
|
||||||
|
g2.vIns.del(e.Head.ID, id)
|
||||||
|
g2.vOuts.del(e.Tail.ID, id)
|
||||||
return g2
|
return g2
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,14 +171,14 @@ func (g Graph) Edges() []Edge {
|
|||||||
// ValueEdges returns all input (e.Head==v) and output (e.Tail==v) Edges
|
// ValueEdges returns all input (e.Head==v) and output (e.Tail==v) Edges
|
||||||
// for the given Value in the Graph.
|
// for the given Value in the Graph.
|
||||||
func (g Graph) ValueEdges(v Value) ([]Edge, []Edge) {
|
func (g Graph) ValueEdges(v Value) ([]Edge, []Edge) {
|
||||||
var in, out []Edge
|
in := make([]Edge, 0, len(g.vIns[v.ID]))
|
||||||
for _, e := range g.m {
|
for edgeID := range g.vIns[v.ID] {
|
||||||
if e.Tail.ID == v.ID {
|
in = append(in, g.m[edgeID])
|
||||||
out = append(out, e)
|
|
||||||
}
|
|
||||||
if e.Head.ID == v.ID {
|
|
||||||
in = append(in, e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out := make([]Edge, 0, len(g.vOuts[v.ID]))
|
||||||
|
for edgeID := range g.vOuts[v.ID] {
|
||||||
|
out = append(out, g.m[edgeID])
|
||||||
}
|
}
|
||||||
return in, out
|
return in, out
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user