Skip to content

Commit

Permalink
*: clean up interface
Browse files Browse the repository at this point in the history
  • Loading branch information
gyuho committed Mar 28, 2016
1 parent 7ccee81 commit 3075cfa
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 226 deletions.
124 changes: 42 additions & 82 deletions graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,45 @@ import (
"fmt"
"io"
"sync"
"sync/atomic"
)

// ID is unique identifier.
type ID uint64
type ID interface {
// String returns the string ID.
String() string
}

const NoID ID = 0
type StringID string

func (s StringID) String() string {
return string(s)
}

// Node is vertex. The ID must be unique within the graph.
type Node interface {
// ID returns the ID.
ID() ID

// String returns the string ID.
String() string
}

type node struct {
name string
id uint64
id string
}

var nodeCnt uint64

func NewNode(name string) Node {
val := atomic.AddUint64(&nodeCnt, 1)
func NewNode(id string) Node {
return &node{
name: name,
id: val,
id: id,
}
}

func (n *node) ID() ID {
return ID(n.id)
return StringID(n.id)
}

func (n *node) String() string {
return n.name
return n.id
}

// Edge connects between two Nodes.
Expand Down Expand Up @@ -98,24 +99,17 @@ type Graph interface {
// Init initializes a Graph.
Init()

// GetNodes returns a map from node ID to
// empty struct value. Graph does not allow duplicate
// node ID or name.
GetNodes() map[ID]Node

// GetNodeCount returns the total number of nodes.
GetNodeCount() int

// GetNode finds the Node. It returns nil if the Node
// does not exist in the graph.
GetNode(name string) Node

// GetNodeByID finds the Node. It returns nil if the Node
// does not exist in the graph.
GetNodeByID(id ID) Node
GetNode(id ID) Node

// GetID finds the Node ID.
GetID(name string) ID
// GetNodes returns a map from node ID to
// empty struct value. Graph does not allow duplicate
// node ID or name.
GetNodes() map[ID]Node

// AddNode adds a node to a graph, and returns false
// if the node already existed in the graph.
Expand Down Expand Up @@ -156,9 +150,6 @@ type Graph interface {
type graph struct {
mu sync.RWMutex // guards the following

// nameToID records used ids.
nameToID map[string]ID

// idToNodes stores all nodes.
idToNodes map[ID]Node

Expand All @@ -172,7 +163,6 @@ type graph struct {
// newGraph returns a new graph.
func newGraph() *graph {
return &graph{
nameToID: make(map[string]ID),
idToNodes: make(map[ID]Node),
nodeToSources: make(map[ID]map[ID]float64),
nodeToTargets: make(map[ID]map[ID]float64),
Expand All @@ -195,60 +185,33 @@ func (g *graph) Init() {
// (X) *g = *newGraph()
// assignment copies lock value

g.nameToID = make(map[string]ID)
g.idToNodes = make(map[ID]Node)
g.nodeToSources = make(map[ID]map[ID]float64)
g.nodeToTargets = make(map[ID]map[ID]float64)
}

func (g *graph) GetNodes() map[ID]Node {
g.mu.RLock()
defer g.mu.RUnlock()

return g.idToNodes
}

func (g *graph) GetID(name string) ID {
g.mu.RLock()
defer g.mu.RUnlock()

v, ok := g.nameToID[name]
if !ok {
return NoID
}
return v
}

func (g *graph) GetNodeCount() int {
g.mu.RLock()
defer g.mu.RUnlock()

return len(g.idToNodes)
}

func (g *graph) GetNode(name string) Node {
func (g *graph) GetNode(id ID) Node {
g.mu.RLock()
defer g.mu.RUnlock()

return g.idToNodes[g.nameToID[name]]
return g.idToNodes[id]
}

func (g *graph) GetNodeByID(id ID) Node {
func (g *graph) GetNodes() map[ID]Node {
g.mu.RLock()
defer g.mu.RUnlock()

return g.idToNodes[id]
}

func (g *graph) unsafeExist(nd Node) bool {
_, ok := g.nameToID[nd.String()]
return ok
return g.idToNodes
}

func (g *graph) unsafeExistID(id ID) bool {
if id == NoID {
return false
}
_, ok := g.idToNodes[id]
return ok
}
Expand All @@ -257,12 +220,11 @@ func (g *graph) AddNode(nd Node) bool {
g.mu.Lock()
defer g.mu.Unlock()

if g.unsafeExist(nd) {
if g.unsafeExistID(nd.ID()) {
return false
}

id := nd.ID()
g.nameToID[nd.String()] = id
g.idToNodes[id] = nd
return true
}
Expand All @@ -275,8 +237,6 @@ func (g *graph) DeleteNode(id ID) bool {
return false
}

delete(g.nameToID, g.idToNodes[id].String())

delete(g.idToNodes, id)

delete(g.nodeToTargets, id)
Expand All @@ -297,10 +257,10 @@ func (g *graph) AddEdge(id1, id2 ID, weight float64) error {
defer g.mu.Unlock()

if !g.unsafeExistID(id1) {
return fmt.Errorf("%s does not exist in the graph.", g.idToNodes[id1])
return fmt.Errorf("%s does not exist in the graph.", id1)
}
if !g.unsafeExistID(id2) {
return fmt.Errorf("%s does not exist in the graph.", g.idToNodes[id2])
return fmt.Errorf("%s does not exist in the graph.", id2)
}

if _, ok := g.nodeToTargets[id1]; ok {
Expand Down Expand Up @@ -334,10 +294,10 @@ func (g *graph) ReplaceEdge(id1, id2 ID, weight float64) error {
defer g.mu.Unlock()

if !g.unsafeExistID(id1) {
return fmt.Errorf("%s does not exist in the graph.", g.idToNodes[id1])
return fmt.Errorf("%s does not exist in the graph.", id1)
}
if !g.unsafeExistID(id2) {
return fmt.Errorf("%s does not exist in the graph.", g.idToNodes[id2])
return fmt.Errorf("%s does not exist in the graph.", id2)
}

if _, ok := g.nodeToTargets[id1]; ok {
Expand All @@ -362,10 +322,10 @@ func (g *graph) DeleteEdge(id1, id2 ID) error {
defer g.mu.Unlock()

if !g.unsafeExistID(id1) {
return fmt.Errorf("%s does not exist in the graph.", g.idToNodes[id1])
return fmt.Errorf("%s does not exist in the graph.", id1)
}
if !g.unsafeExistID(id2) {
return fmt.Errorf("%s does not exist in the graph.", g.idToNodes[id2])
return fmt.Errorf("%s does not exist in the graph.", id2)
}

if _, ok := g.nodeToTargets[id1]; ok {
Expand All @@ -386,26 +346,26 @@ func (g *graph) GetWeight(id1, id2 ID) (float64, error) {
defer g.mu.RUnlock()

if !g.unsafeExistID(id1) {
return 0, fmt.Errorf("%s does not exist in the graph.", g.idToNodes[id1])
return 0, fmt.Errorf("%s does not exist in the graph.", id1)
}
if !g.unsafeExistID(id2) {
return 0, fmt.Errorf("%s does not exist in the graph.", g.idToNodes[id2])
return 0, fmt.Errorf("%s does not exist in the graph.", id2)
}

if _, ok := g.nodeToTargets[id1]; ok {
if v, ok := g.nodeToTargets[id1][id2]; ok {
return v, nil
}
}
return 0.0, fmt.Errorf("there is no edge from %s to %s", g.idToNodes[id1], g.idToNodes[id2])
return 0.0, fmt.Errorf("there is no edge from %s to %s", id1, id2)
}

func (g *graph) GetSources(id ID) (map[ID]Node, error) {
g.mu.RLock()
defer g.mu.RUnlock()

if !g.unsafeExistID(id) {
return nil, fmt.Errorf("%s does not exist in the graph.", g.idToNodes[id])
return nil, fmt.Errorf("%s does not exist in the graph.", id)
}

rs := make(map[ID]Node)
Expand All @@ -422,7 +382,7 @@ func (g *graph) GetTargets(id ID) (map[ID]Node, error) {
defer g.mu.RUnlock()

if !g.unsafeExistID(id) {
return nil, fmt.Errorf("%s does not exist in the graph.", g.idToNodes[id])
return nil, fmt.Errorf("%s does not exist in the graph.", id)
}

rs := make(map[ID]Node)
Expand All @@ -443,7 +403,7 @@ func (g *graph) String() string {
nmap, _ := g.GetTargets(id1)
for id2, nd2 := range nmap {
weight, _ := g.GetWeight(id1, id2)
fmt.Fprintf(buf, "%s -- %.3f --> %s\n", nd1, weight, nd2)
fmt.Fprintf(buf, "%s -- %.3f - %s\n", nd1, weight, nd2)
}
}
return buf.String()
Expand Down Expand Up @@ -519,18 +479,18 @@ func NewGraphFromJSON(rd io.Reader, graphID string) (Graph, error) {
gmap := js[graphID]

g := newGraph()
for name1, mm := range gmap {
nd1 := g.GetNode(name1)
for id1, mm := range gmap {
nd1 := g.GetNode(StringID(id1))
if nd1 == nil {
nd1 = NewNode(name1)
nd1 = NewNode(id1)
if ok := g.AddNode(nd1); !ok {
return nil, fmt.Errorf("%s already exists", nd1)
}
}
for name2, weight := range mm {
nd2 := g.GetNode(name2)
for id2, weight := range mm {
nd2 := g.GetNode(StringID(id2))
if nd2 == nil {
nd2 = NewNode(name2)
nd2 = NewNode(id2)
if ok := g.AddNode(nd2); !ok {
return nil, fmt.Errorf("%s already exists", nd2)
}
Expand Down
Loading

0 comments on commit 3075cfa

Please sign in to comment.