github.com/igggame/nebulas-go@v2.1.0+incompatible/common/dag/dag.go (about)

     1  // This file is part of the go-nebulas library.
     2  //
     3  // the go-nebulas library is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU General Public License as published by
     5  // the Free Software Foundation, either version 3 of the License, or
     6  // (at your option) any later version.
     7  //
     8  // the go-nebulas library is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU General Public License
    14  // along with the go-nebulas library.  If not, see <http://www.gnu.org/licenses/>.
    15  //
    16  
    17  package dag
    18  
    19  import (
    20  	"encoding/json"
    21  	"errors"
    22  
    23  	"github.com/gogo/protobuf/proto"
    24  	"github.com/nebulasio/go-nebulas/common/dag/pb"
    25  )
    26  
    27  // Node struct
    28  type Node struct {
    29  	key           interface{}
    30  	index         int
    31  	children      []*Node
    32  	parentCounter int
    33  }
    34  
    35  // Errors
    36  var (
    37  	ErrKeyNotFound       = errors.New("not found")
    38  	ErrKeyIsExisted      = errors.New("already existed")
    39  	ErrInvalidProtoToDag = errors.New("Protobuf message cannot be converted into Dag")
    40  	ErrInvalidDagToProto = errors.New("Dag cannot be converted into Protobuf message")
    41  )
    42  
    43  // NewNode new node
    44  func NewNode(key interface{}, index int) *Node {
    45  	return &Node{
    46  		key:           key,
    47  		index:         index,
    48  		parentCounter: 0,
    49  		children:      make([]*Node, 0),
    50  	}
    51  }
    52  
    53  // Index return node index
    54  func (n *Node) Index() int {
    55  	return n.index
    56  }
    57  
    58  // Dag struct
    59  type Dag struct {
    60  	nodes  map[interface{}]*Node
    61  	index  int
    62  	indexs map[int]interface{}
    63  }
    64  
    65  // ToProto converts domain Dag into proto Dag
    66  func (dag *Dag) ToProto() (proto.Message, error) {
    67  
    68  	nodes := make([]*dagpb.Node, len(dag.nodes))
    69  
    70  	for idx, key := range dag.indexs {
    71  		v, ok := dag.nodes[key]
    72  		if !ok {
    73  			return nil, ErrInvalidDagToProto
    74  		}
    75  
    76  		node := new(dagpb.Node)
    77  		node.Index = int32(v.index)
    78  		//node.Key = v.Key.(string)
    79  		node.Children = make([]int32, len(v.children))
    80  		for i, child := range v.children {
    81  			node.Children[i] = int32(child.index)
    82  		}
    83  
    84  		nodes[idx] = node
    85  	}
    86  
    87  	return &dagpb.Dag{
    88  		Nodes: nodes,
    89  	}, nil
    90  }
    91  
    92  // FromProto converts proto Dag to domain Dag
    93  func (dag *Dag) FromProto(msg proto.Message) error {
    94  	if msg, ok := msg.(*dagpb.Dag); ok {
    95  		if msg != nil {
    96  			for _, v := range msg.Nodes {
    97  				dag.addNodeWithIndex(int(v.Index), int(v.Index))
    98  			}
    99  
   100  			for _, v := range msg.Nodes {
   101  				for _, child := range v.Children {
   102  					dag.AddEdge(int(v.Index), int(child))
   103  				}
   104  			}
   105  			return nil
   106  		}
   107  		return ErrInvalidProtoToDag
   108  	}
   109  	return ErrInvalidProtoToDag
   110  }
   111  
   112  // String
   113  func (dag *Dag) String() string {
   114  	msg, err := dag.ToProto()
   115  	if err != nil {
   116  		return string("")
   117  	}
   118  	j, _ := json.Marshal(msg)
   119  	return string(j)
   120  }
   121  
   122  // NewDag new dag
   123  func NewDag() *Dag {
   124  	return &Dag{
   125  		nodes:  make(map[interface{}]*Node, 0),
   126  		index:  0,
   127  		indexs: make(map[int]interface{}, 0),
   128  	}
   129  }
   130  
   131  // Len Dag len
   132  func (dag *Dag) Len() int {
   133  	return len(dag.nodes)
   134  }
   135  
   136  // GetNode get node by key
   137  func (dag *Dag) GetNode(key interface{}) *Node {
   138  	if v, ok := dag.nodes[key]; ok {
   139  		return v
   140  	}
   141  	return nil
   142  }
   143  
   144  // GetChildrenNodes get children nodes with key
   145  func (dag *Dag) GetChildrenNodes(key interface{}) []*Node {
   146  	if v, ok := dag.nodes[key]; ok {
   147  		return v.children
   148  	}
   149  
   150  	return nil
   151  }
   152  
   153  // GetRootNodes get root nodes
   154  func (dag *Dag) GetRootNodes() []*Node {
   155  	nodes := make([]*Node, 0)
   156  	for _, node := range dag.nodes {
   157  		if node.parentCounter == 0 {
   158  			nodes = append(nodes, node)
   159  		}
   160  	}
   161  	return nodes
   162  }
   163  
   164  // GetNodes get all nodes
   165  func (dag *Dag) GetNodes() []*Node {
   166  	nodes := make([]*Node, 0)
   167  	for _, node := range dag.nodes {
   168  		nodes = append(nodes, node)
   169  	}
   170  	return nodes
   171  }
   172  
   173  // AddNode add node
   174  func (dag *Dag) AddNode(key interface{}) error {
   175  	if _, ok := dag.nodes[key]; ok {
   176  		return ErrKeyIsExisted
   177  	}
   178  
   179  	dag.nodes[key] = NewNode(key, dag.index)
   180  	dag.indexs[dag.index] = key
   181  	dag.index++
   182  	return nil
   183  }
   184  
   185  // addNodeWithIndex add node
   186  func (dag *Dag) addNodeWithIndex(key interface{}, index int) error {
   187  	if _, ok := dag.nodes[key]; ok {
   188  		return ErrKeyIsExisted
   189  	}
   190  
   191  	dag.nodes[key] = NewNode(key, index)
   192  	dag.indexs[index] = key
   193  	dag.index = index
   194  	return nil
   195  }
   196  
   197  // AddEdge add edge fromKey toKey
   198  func (dag *Dag) AddEdge(fromKey, toKey interface{}) error {
   199  	var from, to *Node
   200  	var ok bool
   201  
   202  	if from, ok = dag.nodes[fromKey]; !ok {
   203  		return ErrKeyNotFound
   204  	}
   205  
   206  	if to, ok = dag.nodes[toKey]; !ok {
   207  		return ErrKeyNotFound
   208  	}
   209  
   210  	for _, childNode := range from.children {
   211  		if childNode == to {
   212  			return ErrKeyIsExisted
   213  		}
   214  	}
   215  
   216  	dag.nodes[toKey].parentCounter++
   217  	dag.nodes[fromKey].children = append(from.children, to)
   218  
   219  	return nil
   220  }
   221  
   222  //IsCirclular a->b-c->a
   223  func (dag *Dag) IsCirclular() bool {
   224  
   225  	visited := make(map[interface{}]int, len(dag.nodes))
   226  	rootNodes := make(map[interface{}]*Node)
   227  	for key, node := range dag.nodes {
   228  		visited[key] = 0
   229  		rootNodes[key] = node
   230  	}
   231  
   232  	for _, node := range rootNodes {
   233  		if dag.hasCirclularDep(node, visited) {
   234  			return true
   235  		}
   236  	}
   237  
   238  	for _, count := range visited {
   239  		if count == 0 {
   240  			return true
   241  		}
   242  	}
   243  	return false
   244  }
   245  
   246  func (dag *Dag) hasCirclularDep(current *Node, visited map[interface{}]int) bool {
   247  
   248  	visited[current.key] = 1
   249  	for _, child := range current.children {
   250  		if visited[child.key] == 1 {
   251  			return true
   252  		}
   253  
   254  		if dag.hasCirclularDep(child, visited) {
   255  			return true
   256  		}
   257  	}
   258  	visited[current.key] = 2
   259  	return false
   260  }