Beispiel #1
0
        void InsertNode(PathTreeNode node, PathTreeNode parentNode, PathTreeNode previousNode)
        {
            parentNode.ChildrenCount += 1;

            node.Parent = parentNode;
            if (previousNode == null)
            {
                // We're inserting at the beginning.
                var insertBefore = parentNode.FirstChild;

                node.Next = insertBefore;
                if (insertBefore != null)
                {
                    insertBefore.Previous = node;
                }
                parentNode.FirstChild = node;
                return;
            }

            // We are appending inbetween other nodes
            var next = previousNode.Next;

            previousNode.Next = node;
            node.Previous     = previousNode;

            node.Next = next;
            if (next != null)
            {
                next.Previous = node;
            }
        }
Beispiel #2
0
        static void PrettyPrint(StringBuilder builder, PathTreeNode node, string indent)
        {
            builder.Append(indent);
            if (node.Next == null)
            {
                builder.Append("\\-");
                indent += "  ";
            }
            else
            {
                builder.Append("|-");
                indent += "| ";
            }

            builder.Append(node.Segment);
            if (node.IdCount != 0)
            {
                builder.AppendFormat(" ({0})", node.IdCount);
            }

            node = node.FirstChild;
            while (node != null)
            {
                builder.AppendLine();
                PrettyPrint(builder, node, indent);
                node = node.Next;
            }
        }
Beispiel #3
0
        bool IsDeadSubtree(PathTreeNode node)
        {
            // We do a DFS here, looking for any live node in a tree.
            // We know that leaves are live, so DFS works better here.
            var stack = new Stack <PathTreeNode> ();

            stack.Push(node);

            while (stack.Count != 0)
            {
                node = stack.Pop();
                if (node.IsLive)
                {
                    return(false);
                }

                var child = node.FirstChild;

                while (child != null)
                {
                    stack.Push(child);
                    child = child.Next;
                }
            }
            return(true);
        }
Beispiel #4
0
        internal static (PathTreeNode root, PathTreeNode leaf) CreateSubTree(string path, int start)
        {
            PathTreeNode lastNode = null, rootNode = null;

            while (start < path.Length)
            {
                var nextSep = path.IndexOf(Path.DirectorySeparatorChar, start);
                int length  = nextSep == -1 ? path.Length - start : nextSep - start;

                if (length != 0)
                {
                    var node = new PathTreeNode(path, start, length);

                    if (lastNode != null)
                    {
                        lastNode.FirstChild    = node;
                        node.Parent            = lastNode;
                        lastNode.ChildrenCount = 1;
                    }
                    else
                    {
                        rootNode = node;
                    }

                    lastNode = node;
                }

                start = start + length + 1;
            }

            return(rootNode, lastNode);
        }
Beispiel #5
0
        bool TryFind(string path, out PathTreeNode result, out PathTreeNode parent, out PathTreeNode previousNode, out int lastIndex)
        {
            lastIndex = 0;

            parent = rootNode;
            var currentNode = parent.FirstChild;

            previousNode = null;

            var remainingSegments = path.AsSpan().TrimEnd(Path.DirectorySeparatorChar);

            while (currentNode != null)
            {
                var currentSegment = currentNode.GetSegment();

                // Chunk by directory separator
                int currentIndex = remainingSegments.IndexOf(Path.DirectorySeparatorChar);

                int segmentLength = currentIndex == -1 ? remainingSegments.Length : currentIndex;

                var toAddSegment = remainingSegments.Slice(0, segmentLength);

                int comparisonResult = currentSegment.CompareTo(toAddSegment, FilePath.PathComparison);
                // We need to insert in this node's position.
                if (comparisonResult > 0)
                {
                    break;
                }

                // Keep searching if we still have items.
                if (comparisonResult < 0)
                {
                    previousNode = currentNode;
                    currentNode  = currentNode.Next;
                    continue;
                }

                // We found this segment in the tree.
                remainingSegments = remainingSegments.Slice(Math.Min(currentIndex + 1, remainingSegments.Length));
                lastIndex        += currentIndex + 1;

                // We found the node already, register the ID.
                if (currentIndex == -1 || remainingSegments.Length == 0)
                {
                    result = currentNode;
                    return(true);
                }

                // We go to the first child of this segment and repeat the algorithm.
                parent       = currentNode;
                previousNode = null;
                currentNode  = parent.FirstChild;
            }

            result = null;
            return(false);
        }
Beispiel #6
0
 public PathTree()
 {
     rootNode = new PathTreeNode("", 0, 1);
     if (!Platform.IsWindows)
     {
         rootNode.FirstChild = new PathTreeNode("/", 0, 0)
         {
             Parent = rootNode,
         };
         rootNode.ChildrenCount = 1;
     }
 }
Beispiel #7
0
        bool TryFind(string path, out PathTreeNode result, out PathTreeNode parent, out PathTreeNode previousNode, out int lastIndex)
        {
            lastIndex = 0;

            parent = rootNode;
            var currentNode = parent.FirstChild;

            previousNode = null;

            while (currentNode != null)
            {
                int currentIndex     = path.IndexOf(Path.DirectorySeparatorChar, lastIndex);
                int comparisonResult = string.Compare(currentNode.FullPath, currentNode.Start, path, lastIndex, currentNode.Length);

                // We need to insert in this node's position.
                if (comparisonResult > 0)
                {
                    break;
                }

                // Keep searching.
                if (comparisonResult < 0)
                {
                    previousNode = currentNode;
                    currentNode  = currentNode.Next;
                    continue;
                }

                // We found this segment in the tree.
                lastIndex = currentIndex + 1;

                // We found the node already, register the ID.
                if (currentIndex == -1 || lastIndex == path.Length)
                {
                    result = currentNode;
                    return(true);
                }

                // We go to the first child of this segment and repeat the algorithm.
                parent       = currentNode;
                previousNode = null;
                currentNode  = parent.FirstChild;
            }

            result = null;
            return(false);
        }
        public void CreateSubTree(string sep)
        {
            var path = MakePath("a", "b", "c") + sep;

            var(first, leaf) = PathTreeNode.CreateSubTree(path, 0);

            PathTreeNode a;

            if (Platform.IsWindows)
            {
                AssertPathTreeSubtree(first, "C:");
                Assert.AreEqual(1, first.ChildrenCount);

                a = first.FirstChild;
                Assert.AreSame(first, a.Parent);
            }
            else
            {
                a = first;
            }

            AssertPathTreeSubtree(a, "a");
            Assert.AreEqual(1, a.ChildrenCount);

            var b = a.FirstChild;

            Assert.AreSame(a, b.Parent);
            AssertPathTreeSubtree(b, "b");
            Assert.AreEqual(1, b.ChildrenCount);

            var c = b.FirstChild;

            Assert.AreSame(b, c.Parent);
            AssertPathTreeSubtree(c, "c");
            Assert.AreEqual(0, c.ChildrenCount);
            Assert.AreSame(c, leaf);

            Assert.IsNull(c.FirstChild);

            void AssertPathTreeSubtree(PathTreeNode node, string segment)
            {
                Assert.AreEqual(segment, node.Segment);
                Assert.IsNull(node.Next);
                Assert.AreSame(node.FirstChild, node.LastChild);
            }
        }
Beispiel #9
0
        public PathTreeNode AddNode(string path, object id, out bool isModified)
        {
            if (TryFind(path, out var result, out var parent, out var previousNode, out var lastIndex))
            {
                isModified = !result.IsLive;
                result.RegisterId(id);
                return(result);
            }

            // At this point, we need to create a new node.
            isModified       = true;
            var(first, leaf) = PathTreeNode.CreateSubTree(path, lastIndex);
            leaf.RegisterId(id);

            InsertNode(first, parent, previousNode);

            return(leaf);
        }
Beispiel #10
0
        public PathTreeNode AddNode(string path, object id)
        {
            if (TryFind(path, out var result, out var parent, out var previousNode, out var lastIndex))
            {
                result.RegisterId(id);
                return(result);
            }

            // At this point, we need to create a new node.
            var(first, leaf) = PathTreeNode.CreateSubTree(path, lastIndex);
            if (id != null)
            {
                leaf.RegisterId(id);
            }

            InsertNode(first, parent, previousNode);

            return(leaf);
        }
Beispiel #11
0
        internal PathTreeNode RemoveNode(PathTreeNode result, object id, out bool isModified)
        {
            var parent = result.Parent;

            isModified = result.UnregisterId(id) && !result.IsLive;
            if (isModified)
            {
                var nodeToRemove = result;
                var lastToRemove = pathRoot;

                while (nodeToRemove != lastToRemove && IsDeadSubtree(nodeToRemove))
                {
                    parent.ChildrenCount -= 1;

                    if (parent.FirstChild == nodeToRemove)
                    {
                        parent.FirstChild = nodeToRemove.Next;
                    }

                    if (nodeToRemove.Previous != null)
                    {
                        nodeToRemove.Previous.Next = nodeToRemove.Next;
                    }

                    if (nodeToRemove.Next != null)
                    {
                        nodeToRemove.Next.Previous = nodeToRemove.Previous;
                    }

                    nodeToRemove.Next     = null;
                    nodeToRemove.Previous = null;
                    nodeToRemove.Parent   = null;

                    nodeToRemove = parent;
                    parent       = nodeToRemove.Parent;
                }
            }

            return(result);
        }
 [TestCase(1)]          // Should not crash
 public void EmptySubTrie(int startIndex)
 {
     var(node, leaf) = PathTreeNode.CreateSubTree(string.Empty, startIndex);
     Assert.IsNull(node);
     Assert.IsNull(leaf);
 }
 public void JustSlash()
 {
     var(node, leaf) = PathTreeNode.CreateSubTree(Path.DirectorySeparatorChar.ToString(), 0);
     Assert.IsNull(node);
     Assert.IsNull(leaf);
 }