clean tree struct code

This commit is contained in:
Xiang Li 2013-07-08 21:20:50 -07:00
parent 67a06ecca5
commit 55146c3ece

View File

@ -6,138 +6,149 @@ import (
"sort" "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 { type tree struct {
Root *treeNode Root *treeNode
} }
// A treeNode wraps a Node. It has a hashmap to keep records of its children treeNodes.
type treeNode struct { type treeNode struct {
InternalNode Node
Value Node Dir bool
Dir bool //for clearity
NodeMap map[string]*treeNode NodeMap map[string]*treeNode
} }
// TreeNode with its key. We use it when we need to sort the treeNodes.
type tnWithKey struct{ type tnWithKey struct{
key string key string
tn *treeNode tn *treeNode
} }
// Define type and functions to match sort interface
type tnWithKeySlice []tnWithKey type tnWithKeySlice []tnWithKey
func (s tnWithKeySlice) Len() int { return len(s) } 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) 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] } 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} var emptyNode = Node{".", PERMANENT, nil}
// set the key to value, return the old value if the key exists //------------------------------------------------------------------------------
//
// Methods
//
//------------------------------------------------------------------------------
// 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 { func (t *tree) set(key string, value Node) bool {
key = "/" + key
key = path.Clean(key)
nodes := strings.Split(key, "/") nodesName := split(key)
nodes = nodes[1:]
//fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes))
nodeMap := t.Root.NodeMap nodeMap := t.Root.NodeMap
i := 0 i := 0
newDir := false 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 { if newDir {
node := &treeNode{emptyNode, true, make(map[string]*treeNode)} tn := &treeNode{emptyNode, true, make(map[string]*treeNode)}
nodeMap[nodes[i]] = node nodeMap[nodesName[i]] = tn
nodeMap = node.NodeMap nodeMap = tn.NodeMap
continue continue
} }
node, ok := nodeMap[nodes[i]] // get the node from the nodeMap of the current level
// add new dir tn, ok := nodeMap[nodesName[i]]
if !ok { if !ok {
//fmt.Println("TreeStore: Add a dir ", nodes[i]) // add a new directory and set newDir to true
newDir = true newDir = true
node := &treeNode{emptyNode, true, make(map[string]*treeNode)} tn := &treeNode{emptyNode, true, make(map[string]*treeNode)}
nodeMap[nodes[i]] = node nodeMap[nodesName[i]] = tn
nodeMap = node.NodeMap 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 return false
} else { } else {
//fmt.Println("TreeStore: found dir ", nodes[i]) // update the nodeMap to next level
nodeMap = node.NodeMap nodeMap = tn.NodeMap
} }
} }
// add the last node and value // Add the last node
node, ok := nodeMap[nodes[i]] tn, ok := nodeMap[nodesName[i]]
if !ok { if !ok {
node := &treeNode{value, false, nil} // we add a new treeNode
nodeMap[nodes[i]] = node tn := &treeNode{value, false, nil}
//fmt.Println("TreeStore: Add a new Node ", key, "=", value) nodeMap[nodesName[i]] = tn
} else { } else {
node.Value = value // we change the value of a old Treenode
//fmt.Println("TreeStore: Update a Node ", key, "=", value, "[", oldValue, "]") tn.InternalNode = value
} }
return true 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) { func (t *tree)internalGet(key string) (*treeNode, bool) {
key = "/" + key nodesName := split(key)
key = path.Clean(key)
nodes := strings.Split(key, "/")
nodes = nodes[1:]
//fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes))
nodeMap := t.Root.NodeMap nodeMap := t.Root.NodeMap
var i int var i int
for i = 0; i < len(nodes) - 1; i++ { for i = 0; i < len(nodesName) - 1; i++ {
node, ok := nodeMap[nodes[i]] node, ok := nodeMap[nodesName[i]]
if !ok || !node.Dir { if !ok || !node.Dir {
return nil, false return nil, false
} }
nodeMap = node.NodeMap nodeMap = node.NodeMap
} }
treeNode, ok := nodeMap[nodes[i]] tn, ok := nodeMap[nodesName[i]]
if ok { if ok {
return treeNode, ok return tn, ok
} else { } else {
return nil, ok return nil, ok
} }
} }
// get the node of the key // get the internalNode of the key
func (t *tree) get(key string) (Node, bool) { func (t *tree) get(key string) (Node, bool) {
treeNode, ok := t.internalGet(key) tn, ok := t.internalGet(key)
if ok { if ok {
return treeNode.Value, ok return tn.InternalNode, ok
} else { } else {
return emptyNode, ok return emptyNode, ok
} }
} }
// return the nodes under the directory // return the nodes information under the directory
func (t *tree) list(prefix string) ([]Node, []string, []string, bool) { func (t *tree) list(directory string) ([]Node, []string, []string, bool) {
treeNode, ok := t.internalGet(prefix) treeNode, ok := t.internalGet(directory)
if !ok { if !ok {
return nil, nil, nil, ok return nil, nil, nil, ok
@ -149,7 +160,7 @@ func (t *tree) list(prefix string) ([]Node, []string, []string, bool) {
i := 0 i := 0
for key, node := range treeNode.NodeMap { for key, node := range treeNode.NodeMap {
nodes[i] = node.Value nodes[i] = node.InternalNode
keys[i] = key keys[i] = key
if node.Dir { if node.Dir {
dirs[i] = "d" 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 { func (t *tree) delete(key string) bool {
key = "/" + key nodesName := split(key)
key = path.Clean(key)
nodes := strings.Split(key, "/")
nodes = nodes[1:]
//fmt.Println("TreeStore: Nodes ", nodes, " length: ", len(nodes))
nodeMap := t.Root.NodeMap nodeMap := t.Root.NodeMap
var i int var i int
for i = 0; i < len(nodes) - 1; i++ { for i = 0; i < len(nodesName) - 1; i++ {
node, ok := nodeMap[nodes[i]] node, ok := nodeMap[nodesName[i]]
if !ok || !node.Dir { if !ok || !node.Dir {
return false return false
} }
nodeMap = node.NodeMap nodeMap = node.NodeMap
} }
node, ok := nodeMap[nodes[i]] node, ok := nodeMap[nodesName[i]]
if ok && !node.Dir{ if ok && !node.Dir{
delete(nodeMap, nodes[i]) delete(nodeMap, nodesName[i])
return true return true
} }
return false return false
} }
// traverse wrapper
func (t *tree) traverse(f func(string, *Node), sort bool) { func (t *tree) traverse(f func(string, *Node), sort bool) {
if sort { if sort {
sortDfs("", t.Root, f) 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)) { func dfs(key string, t *treeNode, f func(string, *Node)) {
// base case // base case
if len(t.NodeMap) == 0{ if len(t.NodeMap) == 0{
f(key, &t.Value) f(key, &t.InternalNode)
// recursion // recursion
} else { } else {
for nodeKey, _treeNode := range t.NodeMap { for tnKey, tn := range t.NodeMap {
newKey := key + "/" + nodeKey tnKey := key + "/" + tnKey
dfs(newKey, _treeNode, f) 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)) { func sortDfs(key string, t *treeNode, f func(string, *Node)) {
// base case // base case
if len(t.NodeMap) == 0{ if len(t.NodeMap) == 0{
f(key, &t.Value) f(key, &t.InternalNode)
// recursion // recursion
} else { } else {
@ -227,9 +238,9 @@ func sortDfs(key string, t *treeNode, f func(string, *Node)) {
i := 0 i := 0
// copy // copy
for nodeKey, _treeNode := range t.NodeMap { for tnKey, tn := range t.NodeMap {
newKey := key + "/" + nodeKey tnKey := key + "/" + tnKey
s[i] = tnWithKey{newKey, _treeNode} s[i] = tnWithKey{tnKey, tn}
i++ 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
}