Browse Source

clean tree struct code

Xiang Li 12 years ago
parent
commit
55146c3ece
1 changed files with 94 additions and 73 deletions
  1. 94 73
      store/tree.go

+ 94 - 73
store/tree.go

@@ -6,138 +6,149 @@ import (
 	"sort"
 	)
 
+//------------------------------------------------------------------------------
+//
+// Typedefs
+//
+//------------------------------------------------------------------------------
+
+// A file system like tree structure. Each non-leaf node of the tree has a hashmap to 
+// store its children nodes. Leaf nodes has no hashmap (a nil pointer)
 type tree struct {
 	Root *treeNode
 }
 
+// A treeNode wraps a Node. It has a hashmap to keep records of its children treeNodes.
 type treeNode struct {
-
-	Value Node
-
-	Dir bool //for clearity
-
+	InternalNode Node
+	Dir bool 
 	NodeMap map[string]*treeNode
-
 }
 
+// TreeNode with its key. We use it when we need to sort the treeNodes.
 type tnWithKey struct{
 	key string
 	tn  *treeNode
 }
 
+// Define type and functions to match sort interface
 type tnWithKeySlice []tnWithKey
 
 func (s tnWithKeySlice) Len() int           { return len(s) }
 func (s tnWithKeySlice) Less(i, j int) bool { return s[i].key < s[j].key }
 func (s tnWithKeySlice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
 
+// CONSTANT VARIABLE
 
-
+// Represent an empty node
 var emptyNode = Node{".", PERMANENT, nil}
 
-// set the key to value, return the old value if the key exists 
-func (t *tree) set(key string, value Node) bool {
-	key = "/" + key
-	key = path.Clean(key)
+//------------------------------------------------------------------------------
+//
+// Methods
+//
+//------------------------------------------------------------------------------
 
-	nodes := strings.Split(key, "/")
-	nodes = nodes[1:]
+// Set the key to the given value, return true if success
+// If any intermidate path of the key is not a directory type, it will fail
+// For example if the /foo = Node(bar) exists, set /foo/foo = Node(barbar)
+// will fail.
+func (t *tree) set(key string, value Node) bool {
 
-	//fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes))
+	nodesName := split(key)
 
 	nodeMap := t.Root.NodeMap
 
 	i := 0
 	newDir := false
 
-	for i = 0; i < len(nodes) - 1; i++ {
+	// go through all the path
+	for i = 0; i < len(nodesName) - 1; i++ {
 
+		// if we meet a new directory, all the directory after it must be new
 		if newDir {
-			node := &treeNode{emptyNode, true, make(map[string]*treeNode)}
-			nodeMap[nodes[i]] = node
-			nodeMap = node.NodeMap
+			tn := &treeNode{emptyNode, true, make(map[string]*treeNode)}
+			nodeMap[nodesName[i]] = tn
+			nodeMap = tn.NodeMap
 			continue
 		}
 
-		node, ok := nodeMap[nodes[i]]
-		// add new dir
+		// get the node from the nodeMap of the current level
+		tn, ok := nodeMap[nodesName[i]]
+	
 		if !ok {
-			//fmt.Println("TreeStore: Add a dir ", nodes[i])
+			// add a new directory and set newDir to true
 			newDir = true
-			node := &treeNode{emptyNode, true, make(map[string]*treeNode)}
-			nodeMap[nodes[i]] = node
-			nodeMap = node.NodeMap
+			tn := &treeNode{emptyNode, true, make(map[string]*treeNode)}
+			nodeMap[nodesName[i]] = tn
+			nodeMap = tn.NodeMap
 
-		} else if ok && !node.Dir {
+		} else if ok && !tn.Dir {
 
+			// if we meet a non-directory node, we cannot set the key 
 			return false
 		} else {
 
-			//fmt.Println("TreeStore: found dir ", nodes[i])
-			nodeMap = node.NodeMap
+			// update the nodeMap to next level
+			nodeMap = tn.NodeMap
 		}
 
 	}
 
-	// add the last node and value
-	node, ok := nodeMap[nodes[i]]
+	// Add the last node
+	tn, ok := nodeMap[nodesName[i]]
 
 	if !ok {
-		node := &treeNode{value, false, nil}
-		nodeMap[nodes[i]] = node
-		//fmt.Println("TreeStore: Add a new Node ", key, "=", value)
+		// we add a new treeNode
+		tn := &treeNode{value, false, nil}
+		nodeMap[nodesName[i]] = tn
+	
 	} else {
-		node.Value = value
-		//fmt.Println("TreeStore: Update a Node ", key, "=", value, "[", oldValue, "]")
+		// we change the value of a old Treenode
+		tn.InternalNode = value
 	}
 	return true
 
 }
 
-// use internally to get the internal tree node 
+// Get the tree node of the key 
 func (t *tree)internalGet(key string) (*treeNode, bool) {
-	key = "/" + key
-	key = path.Clean(key)
-
-	nodes := strings.Split(key, "/")
-	nodes = nodes[1:]
-
-	//fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes))
+	nodesName := split(key)
 
 	nodeMap := t.Root.NodeMap
 		
 	var i int
 
-	for i = 0; i < len(nodes) - 1; i++ {
-		node, ok := nodeMap[nodes[i]]
+	for i = 0; i < len(nodesName) - 1; i++ {
+		node, ok := nodeMap[nodesName[i]]
 		if !ok || !node.Dir {
 			return nil, false
 		}
 		nodeMap = node.NodeMap
 	}
 
-	treeNode, ok := nodeMap[nodes[i]]
+	tn, ok := nodeMap[nodesName[i]]
 	if ok {
-		return treeNode, ok
+		return tn, ok
 	} else {
 		return nil, ok
 	}
 } 
 
-// get the node of the key
+// get the internalNode of the key
 func (t *tree) get(key string) (Node, bool) {
-	treeNode, ok := t.internalGet(key)
+	tn, ok := t.internalGet(key)
 
 	if ok {
-		return treeNode.Value, ok
+		return tn.InternalNode, ok
 	} else {
 		return emptyNode, ok
 	}
 }
 
-// return the nodes under the directory
-func (t *tree) list(prefix string) ([]Node, []string, []string, bool) {
-	treeNode, ok := t.internalGet(prefix)
+// return the nodes information under the directory
+func (t *tree) list(directory string) ([]Node, []string, []string, bool) {
+	treeNode, ok := t.internalGet(directory)
 
 	if !ok {
 		return nil, nil, nil, ok
@@ -149,7 +160,7 @@ func (t *tree) list(prefix string) ([]Node, []string, []string, bool) {
 		i := 0
 
 		for key, node := range treeNode.NodeMap {
-			nodes[i] = node.Value
+			nodes[i] = node.InternalNode
 			keys[i] = key
 			if node.Dir {
 				dirs[i] = "d"
@@ -163,36 +174,31 @@ func (t *tree) list(prefix string) ([]Node, []string, []string, bool) {
 	}
 }
 
-// delete the key, return the old value if the key exists
+// delete the key, return true if success
 func (t *tree) delete(key string) bool {
-	key = "/" + key
-	key = path.Clean(key)
-
-	nodes := strings.Split(key, "/")
-	nodes = nodes[1:]
-
-	//fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes))
+	nodesName := split(key)
 
 	nodeMap := t.Root.NodeMap
 		
 	var i int
 
-	for i = 0; i < len(nodes) - 1; i++ {
-		node, ok := nodeMap[nodes[i]]
+	for i = 0; i < len(nodesName) - 1; i++ {
+		node, ok := nodeMap[nodesName[i]]
 		if !ok || !node.Dir {
 			return false
 		}
 		nodeMap = node.NodeMap
 	}
 
-	node, ok := nodeMap[nodes[i]]
+	node, ok := nodeMap[nodesName[i]]
 	if ok && !node.Dir{
-		delete(nodeMap, nodes[i])
+		delete(nodeMap, nodesName[i])
 		return true
 	}
 	return false
 }
 
+// traverse wrapper
 func (t *tree) traverse(f func(string, *Node), sort bool) {
 	if sort {
 		sortDfs("", t.Root, f)
@@ -201,24 +207,29 @@ func (t *tree) traverse(f func(string, *Node), sort bool) {
 	}
 }
 
+// deep first search to traverse the tree 
+// apply the func f to each internal node
 func dfs(key string, t *treeNode, f func(string, *Node)) {
+
 	// base case
 	if len(t.NodeMap) == 0{
-		f(key, &t.Value)
+		f(key, &t.InternalNode)
 
 	// recursion
 	} else {
-		for nodeKey, _treeNode := range t.NodeMap {
-			newKey := key + "/" + nodeKey
-			dfs(newKey, _treeNode, f)
+		for tnKey, tn := range t.NodeMap {
+			tnKey := key + "/" + tnKey
+			dfs(tnKey, tn, f)
 		}
 	}
 }
 
+// sort deep first search to traverse the tree
+// apply the func f to each internal node
 func sortDfs(key string, t *treeNode, f func(string, *Node)) {
 	// base case
 	if len(t.NodeMap) == 0{
-		f(key, &t.Value)
+		f(key, &t.InternalNode)
 
 	// recursion
 	} else {
@@ -227,9 +238,9 @@ func sortDfs(key string, t *treeNode, f func(string, *Node)) {
 		i := 0
 
 		// copy
-		for nodeKey, _treeNode := range t.NodeMap {
-			newKey := key + "/" + nodeKey
-			s[i] = tnWithKey{newKey, _treeNode}
+		for tnKey, tn := range t.NodeMap {
+			tnKey := key + "/" + tnKey
+			s[i] = tnWithKey{tnKey, tn}
 			i++
 		}
 
@@ -243,4 +254,14 @@ func sortDfs(key string, t *treeNode, f func(string, *Node)) {
 	}
 }
 
+// split the key by '/', get the intermediate node name
+func split(key string) []string {
+	key = "/" + key
+	key = path.Clean(key)
 
+	// get the intermidate nodes name
+	nodesName := strings.Split(key, "/")
+	// we do not need the root node, since we start with it
+	nodesName = nodesName[1:]
+	return nodesName
+}