Skip to content

Commit

Permalink
[VirtualTree] Add insert method for FlatTree
Browse files Browse the repository at this point in the history
  • Loading branch information
hyazinthh committed Sep 19, 2023
1 parent adba7b0 commit 7bee1ea
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 20 deletions.
28 changes: 21 additions & 7 deletions src/Scratch/31 - VirtualTree/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,35 @@ let main argv =
// FlatTree.ofHierarchy getChildren 11
// |> FlatTree.delete 15

//Log.line "\n\nReplace 9 with %A" repl
//let tree = tree |> FlatTree.replace 9 repl
//Log.line "\n\nReplace 3 with %A" repl
//let tree = tree |> FlatTree.replace 3 repl

//Log.line "%A" tree
//Log.line "Count: %A" (FlatTree.count tree)
//Log.line "Path from 14: %A" (tree |> FlatTree.rootPath 14)
//Log.line "Parent of 13: %A" (tree |> FlatTree.parent 13)

//Log.line "Insert 42 as child of 9"
//let tree = tree |> FlatTree.insert 9 42

////Log.line "Delete 9"
//Log.line "%A" tree
//Log.line "Count: %A" (FlatTree.count tree)
//Log.line "Path from 42: %A" (tree |> FlatTree.rootPath 42)
//Log.line "Path from 10: %A" (tree |> FlatTree.rootPath 10)
//Log.line "Path from 5: %A" (tree |> FlatTree.rootPath 5)

//Log.line "Insert 43 as child of 1"
//let tree = tree |> FlatTree.insert 1 43

////let cut = tree |> FlatTree.delete 9
////Log.line "Deleted: %A" cut
////Log.line "%A" (cut |> FlatTree.rootPath 10)
////Log.line "%A" (cut |> FlatTree.rootPath 8)
//Log.line "%A" tree
//Log.line "Path from 43: %A" (tree |> FlatTree.rootPath 43)
//Log.line "Descendants of 4: %A" (tree |> FlatTree.descendantCount 4)

//Log.line "Insert 44 as child of 43"
//let tree = tree |> FlatTree.insert 43 44

//Log.line "%A" tree
//Log.line "Path from 44: %A" (tree |> FlatTree.rootPath 44)

//Environment.Exit 0

Expand Down
71 changes: 58 additions & 13 deletions src/Scratch/31 - VirtualTree/VirtualTree/FlatTree.fs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ type FlatTree<'T> internal (nodes : ArraySegment<FlatNode>, values : ArraySegmen
internal new (nodes : FlatNode[], values : 'T[], indices : Dict<'T, int>) =
FlatTree(ArraySegment nodes, ArraySegment values, indices)

internal new (nodes : ArraySegment<FlatNode>, values : ArraySegment<'T>) =
let indices = Dict(initialCapacity = values.Count)
for i = 0 to values.Count - 1 do
indices.Add(values.[i], i)
FlatTree(nodes, values, indices)

internal new (nodes : FlatNode[], values : 'T[]) =
FlatTree(ArraySegment nodes, ArraySegment values)

member private _.Nodes = nodes
member private _.Values = values

Expand Down Expand Up @@ -219,13 +228,49 @@ type FlatTree<'T> internal (nodes : ArraySegment<FlatNode>, values : ArraySegmen
replacement.Values.CopyTo(values', countLeft)
values.Slice(startRight).CopyTo(values', countLeft + replacement.Count)

// Compute indices
let indices' = Dict(initialCapacity = countTotal)
FlatTree(nodes', values')

/// Inserts the given value as the last child of the given parent node.
member x.Insert(parent : 'T, value : 'T) =
match indices.TryFindV parent with
| ValueNone -> x
| ValueSome parentIndex ->
let node = nodes.[parentIndex]
let index = parentIndex + node.Count
let countRight = nodes.Count - index
let countTotal = nodes.Count + 1

// Compute new nodes
let nodes' = Array.zeroCreate countTotal

// Count of nodes on the root path of the inserted node have to be adjusted
nodes.Slice(0, index).CopyTo(nodes')

for i = 0 to countTotal - 1 do
indices'.Add(values'.[i], i)
let mutable i = parentIndex
for _ = 0 to node.Depth do
let n = nodes.[i]
nodes'.[i] <- FlatNode(n.Count + 1, n.Depth, n.Offset)
i <- i - n.Offset

FlatTree(nodes', values', indices')
nodes'.[index] <- FlatNode(1, node.Depth + 1, node.Count)

// Parent offsets of nodes right of the inserted node have to be adjusted
// if the parent of that node is on the root path of the inserted node
for i = 0 to countRight - 1 do
let n = nodes.[index + i]

if n.Offset <= i then
nodes'.[index + i + 1] <- n
else
nodes'.[index + i + 1] <- FlatNode(n.Count, n.Depth, n.Offset + 1)

// Copy values
let values' = Array.zeroCreate countTotal
values.Slice(0, index).CopyTo(values')
values'[index] <- value
values.Slice(index).CopyTo(values', index + 1)

FlatTree(nodes', values')

/// Deletes the given node and its descendants.
member inline x.Delete(value : 'T) =
Expand Down Expand Up @@ -294,11 +339,7 @@ type FlatTree<'T> internal (nodes : ArraySegment<FlatNode>, values : ArraySegmen
k <- k + nodes.[k].Count
inc &j

let indices = Dict(initialCapacity = count)
for i = 0 to count - 1 do
indices.Add(values'.[i], i)

FlatTree(nodes', values', indices)
FlatTree(nodes', values')

result.Add <| struct (values.[i], subtree)

Expand Down Expand Up @@ -338,7 +379,8 @@ type FlatTree<'T> internal (nodes : ArraySegment<FlatNode>, values : ArraySegmen
d <- di

if x.Count > 1 then
sb.Append " ]" |> ignore
let cb = String.replicate d "]"
sb.Append $" {cb} " |> ignore

sb.ToString()

Expand All @@ -354,8 +396,7 @@ module FlatTree =
let singleton (value : 'T) =
FlatTree<'T>(
[| FlatNode(count = 1, depth = 0, offset = 0) |],
[| value |],
Dict [| KeyValuePair(value, 0) |]
[| value |]
)

/// Returns whether the given tree is empty.
Expand Down Expand Up @@ -448,6 +489,10 @@ module FlatTree =
let inline replace (value : 'T) (replacement : FlatTree<'T>) (tree : FlatTree<'T>) =
tree.Replace(value, replacement)

/// Inserts the given value as the last child of the given parent node.
let inline insert (parent : 'T) (value : 'T) (tree : FlatTree<'T>) =
tree.Insert(parent, value)

/// Returns the subtree with the given value as root.
let inline subTree (value : 'T) (tree : FlatTree<'T>) =
tree.SubTree value
Expand Down

0 comments on commit 7bee1ea

Please sign in to comment.