Example #1
0
        internal ImmutableStack <RopeCacheEntry> FindNodeUsingCache(int index)
        {
            Debug.Assert(index >= 0 && index < this.Length);

            // thread safety: fetch stack into local variable
            ImmutableStack <RopeCacheEntry> stack    = lastUsedNodeStack;
            ImmutableStack <RopeCacheEntry> oldStack = stack;

            if (stack == null)
            {
                stack = ImmutableStack <RopeCacheEntry> .Empty.Push(new RopeCacheEntry(root, 0));
            }
            while (!stack.PeekOrDefault().IsInside(index))
            {
                stack = stack.Pop();
            }
            while (true)
            {
                RopeCacheEntry entry = stack.PeekOrDefault();
                // check if we've reached a leaf or function node
                if (entry.node.height == 0)
                {
                    if (entry.node.contents == null)
                    {
                        // this is a function node - go down into its subtree
                        entry = new RopeCacheEntry(entry.node.GetContentNode(), entry.nodeStartIndex);
                        // entry is now guaranteed NOT to be another function node
                    }
                    if (entry.node.contents != null)
                    {
                        // this is a node containing actual content, so we're done
                        break;
                    }
                }
                // go down towards leaves
                if (index - entry.nodeStartIndex >= entry.node.left.length)
                {
                    stack = stack.Push(new RopeCacheEntry(entry.node.right, entry.nodeStartIndex + entry.node.left.length));
                }
                else
                {
                    stack = stack.Push(new RopeCacheEntry(entry.node.left, entry.nodeStartIndex));
                }
            }

            // write back stack to volatile cache variable
            // (in multithreaded access, it doesn't matter which of the threads wins - it's just a cache)
            if (oldStack != stack)
            {
                // no need to write when we the cache variable didn't change
                lastUsedNodeStack = stack;
            }

            // this method guarantees that it finds a leaf node
            Debug.Assert(stack.Peek().node.contents != null);
            return(stack);
        }