This program implements a data type for a buffer in a text editor. The buffer supports the following operations:

  • void Insert(char c) - Inserts c at the cursor position.
  • char Get() - Returns a character at the cursor position.
  • char Delete() - Deletes and returns the character at the cursor position.
  • void Left(int k) - Moves the cursor k positions to the left.
  • void Right(int k) - Moves the cursor k positions to the right.
  • int ¬†Size() - Returns the number of characters in the buffer.

The buffer is implemented using two stacks.

using System;
using System.Text;

namespace ConsoleTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Buffer b = new Buffer();
            b.Insert('A');
            b.Insert('B');
            b.Insert('C');
            b.Insert('D');
            b.Insert('E');
            b.Insert('F');
            b.ShowItems();

            b.Left(4);
            b.ShowItems();

            b.Right(3);
            b.ShowItems();

            b.Right(1);
            b.ShowItems();

            b.Right(1); // try to move cursor beyond the last element
            b.ShowItems();

            b.Left(3);
            b.ShowItems();

            b.Right(10); // try to move cursor beyond the last element
            b.ShowItems();

            b.Left(4);
            b.ShowItems();

            b.Left(1);
            b.ShowItems();

            b.Left(1); // try to move cursor before the first element
            b.ShowItems();

            b.Right(3);
            b.ShowItems();

            b.Left(15); // try to move cursor before the first element
            b.ShowItems();

            Console.WriteLine("\nDelete " + b.Delete());
            b.ShowItems();

            b.Right(2);
            b.ShowItems();

            Console.WriteLine("\nDelete " + b.Delete());
            b.ShowItems();

            Console.WriteLine("\nCurrent " + b.Get());
            b.ShowItems();

            b.Right(1);

            Console.WriteLine("\nCurrent " + b.Get());
            b.ShowItems();

            b.Left(10);

            Console.WriteLine("\nCurrent " + b.Get());
            b.ShowItems();

            Console.WriteLine("\nDelete " + b.Delete());
            b.ShowItems();

            b.Right(10);

            Console.WriteLine("\nCurrent " + b.Get());
            b.ShowItems();

            Console.WriteLine("\nDelete " + b.Delete());
            b.ShowItems();

            Console.WriteLine("\nDelete " + b.Delete());
            b.ShowItems();

            Console.WriteLine("\nDelete " + b.Delete());
            b.ShowItems();

            Console.WriteLine("\nDelete " + b.Delete()); // ignored; the buffer is empty
            b.ShowItems();

            Console.ReadKey();
        }

        class Buffer
        {
            private int N; // buffer size

            // The top of s refers the current cursor position.
            private Stack s;

            // The tmp stack contains items on the right from the cursor.
            private Stack tmp;

            public bool IsEmpty { get { return N == 0; } }
            public int Size { get { return N; } }

            public Buffer()
            {
                N = 0;
                s = new Stack();
                tmp = new Stack();
            }

            public void Insert(T item)
            {
                s.Push(item);
                ++N;
            }

            public T Get()
            {
                if (N == 0)
                    return default(T);

                return s.Peek();
            }

            public T Delete()
            {
                if (N == 0)
                    return default(T);

                T item = s.Pop();

                // If there is any element on the right of the cursor
                // move it before the cursor.
                if (tmp.Size > 0)
                    s.Push(tmp.Pop());

                --N;
                return item;
            }

            public void Left(int k)
            {
                if (N == 0)
                    return;

                // Determine the number of positions the cursor has to be moved
                // in a special case when it is requested to be moved before
                // the first element.
                if (tmp.Size + k + 1 > N) // we need to add one as there is always one element left on the s stack
                {
                    if (s.Size > 1)
                        k = s.Size - 1; // move the cursor to the beginning
                    else
                        return; // don't do anything; the cursor is already at the beginning
                }

                for (int i = 0; i < k; ++i)
                    tmp.Push(s.Pop());
            }

            public void Right(int k)
            {
                if (N == 0)
                    return;

                // Determine the number of positions the cursor has to be moved
                // in a special case when it is requested to be moved after
                // the last element.
                if (s.Size + k > N)
                {
                    if (tmp.Size > 1)
                        k = tmp.Size; // move the cursor to the end
                    else
                        return; // don't do anything; the cursor is already at the end
                }

                for (int i = 0; i < k; ++i)
                    s.Push(tmp.Pop());
            }

            public void ShowItems()
            {
                s.ShowBottomUp(); // bottom - A - B - C - top (cursor)
                Console.Write("^ "); // cursor
                tmp.ShowTopDown(); // bottom - F - E - D - top

                Console.WriteLine();
            }

            private int Min(int a, int b)
            {
                return (a < b ? a : b);
            }
        }

        class Stack
        {
            private Node first; // the top of stack (most recently added node)
            private int N; // stack size (the number of items in the linked list)

            public bool IsEmpty { get { return first == null; } } // the same as N == 0
            public int Size { get { return N; } }

            public Stack() { }

            public void Push(T item)
            {
                // Add item to the top of stack i.e., insert the item at the beginning of the linked list.
                Node oldFirst = first;
                first = new Node();
                first.Item = item;
                first.Next = oldFirst;

                ++N;
            }

            public T Pop()
            {
                // Remove item from the top of stack i.e., remove the item from the beginning of the linked list.
                T item = first.Item;
                first = first.Next;

                --N;

                return item;
            }

            // Returns the element at the top of the stack without removing it.
            public T Peek()
            {
                return first.Item;
            }

            public void ShowBottomUp()
            {
                StringBuilder sb = new StringBuilder();
                for (Node node = first; node != null; node = node.Next)
                {
                    sb.Insert(0, node.Item.ToString() + " ");
                }
                Console.Write(sb.ToString());
            }

            public void ShowTopDown()
            {
                StringBuilder sb = new StringBuilder();
                for (Node node = first; node != null; node = node.Next)
                {
                    sb.Append(node.Item.ToString() + " ");
                }
                Console.Write(sb.ToString());
            }

            private class Node
            {
                public T Item { get; set; }
                public Node Next { get; set; }

                public override string ToString() { return (Item == null ? "null" : Item.ToString()); }
            }
        }
    }
}

Output:

A B C D E F ^
A B ^ C D E F
A B C D E ^ F
A B C D E F ^
A B C D E F ^
A B C ^ D E F
A B C D E F ^
A B ^ C D E F
A ^ B C D E F
A ^ B C D E F
A B C D ^ E F
A ^ B C D E F

Delete A
B ^ C D E F
B C D ^ E F

Delete D
B C E ^ F

Current E
B C E ^ F

Current F
B C E F ^

Current B
B ^ C E F

Delete B
C ^ E F

Current F
C E F ^

Delete F
C E ^

Delete E
C ^

Delete C
^

Delete
^