AVL tree/Managed C++

From Rosetta Code

Code

 
// AVL in Managed C++

using namespace System;
using namespace System::Collections;
using namespace System::Collections::Generic;
using namespace System::Threading;
using namespace System::Runtime::Serialization;

namespace Calculus
{

public enum class State
{
 Header,
 LeftHigh,
 Balanced,
 RightHigh
};

public enum class Direction { FromLeft, FromRight };

public ref struct Node
{
 Node^ Left;
 Node^ Right;
 Node^ Parent;
 State Balance;

 Node()
 {
  Left = this;
  Right = this;
  Parent = nullptr;
  Balance = State::Header;
 }

 Node(Node^ p)
 {
  Left = nullptr;
  Right = nullptr;
  Parent = p;
  Balance = State::Balanced;
 }

 property Boolean IsHeader
 { Boolean get() { return Balance == State::Header; } }
};

generic <typename T>
public delegate void TypeFound(Object^ O, T type);

generic <typename T>
public delegate void TypeAdded(Object^ O, T type);

generic <typename T>
public delegate void TypeRemoved(Object^ O, T type);

generic <typename T>
public delegate void TypeUpdated(Object^ O, T before, T after);

generic<typename T>
public interface struct IHasher
{
 int GetHashCode(T t);
};

generic<typename T>
[Serializable]
public ref class Hasher abstract : IHasher<T>
{
 public:

  static property Hasher<T>^ Default { Hasher<T>^ get(); }

  virtual int GetHashCode(T t) = 0;
};

generic<typename T>
[Serializable]
public ref class DefaultHasher : Hasher<T>
{
 public:

 virtual int GetHashCode(T t) override
 {
  return t->GetHashCode();
 }
};

generic<typename T>
Hasher<T>^ Hasher<T>::Default::get() { return gcnew DefaultHasher<T>(); }


generic<typename T>
 public interface struct ICloneable
 {
  T Clone();
 };

generic<typename T>
public interface class ICloner  {  T Clone(T t); };

generic<typename T>
[Serializable]
 public ref struct Cloner abstract : ICloner<T>
{
 static property Cloner<T>^ Default { Cloner<T>^ get(); }

 static property Cloner<T>^ Invisible { Cloner<T>^ get(); }

 virtual T Clone(T t) = 0;
};

generic<typename T>
[Serializable]
public ref struct DefaultCloner1 : Cloner<T>
{
 virtual T Clone(T t) override
 {
  ICloneable<T>^ copier = (ICloneable<T>^)t;
  return copier->Clone();
 }
};

generic<typename T>
[Serializable]
public ref struct DefaultCloner2 : Cloner<T>
{
 virtual T Clone(T t) override
 {
  ICloneable<T>^ copier = (ICloneable<T>^)t;
  return (T)copier->Clone();
 }
};

generic<typename T>
[Serializable]
public ref struct DefaultNoCloner : Cloner<T>
{
 virtual T Clone(T t) override
 {
  return t;
 }
};

generic<typename T>
Cloner<T>^ Cloner<T>::Default::get()
{
   Type^ TypeT = T::typeid;
   Type^ TypeIC1 = ICloneable<T>::typeid;
   Type^ TypeIC2 = ICloneable::typeid;
   if (TypeIC1->IsAssignableFrom(TypeT))
     return gcnew DefaultCloner1<T>();
   else if (TypeIC2->IsAssignableFrom(TypeT))
     return gcnew DefaultCloner2<T>();
   else
     return gcnew DefaultNoCloner<T>();
}

 generic<typename T>
 Cloner<T>^ Cloner<T>::Invisible::get() { return gcnew DefaultNoCloner<T>(); } 

    public ref struct OutOfKeyOrderException : public Exception
    {
        static String^ message = gcnew String("A tree was found to be out of key order.");

        OutOfKeyOrderException() : Exception(message)
        {
            HelpLink = gcnew String("Benedict@NNcNannara.net");
            Source = gcnew String("Calculus Subsystem");
        }
    };

    public ref struct TreeInvalidParentException : public Exception
    {
        static String^ message = gcnew String("The validation routines detected that the parent structure of a tree is invalid.");

        TreeInvalidParentException() : Exception(message)
        {
            HelpLink = gcnew String("Benedict@NNcNannara.net");
            Source = gcnew String("Calculus Subsystem");
        }
    };

    public ref struct TreeOutOfBalanceException : public Exception
    {
        static String^ message = gcnew String("The validation routines detected that the tree is out of balance.");

        TreeOutOfBalanceException() : Exception(message)
        {
            HelpLink = gcnew String("Benedict@NNcNannara.net");
            Source = gcnew String("Calculus Subsystem");
        }
    };

    public ref struct InvalidEmptyTreeException : public Exception
    {
        static String^ message = gcnew String("The validation routines detected that an empty tree is invalid.");

        InvalidEmptyTreeException() : Exception(message)
        {
            HelpLink = gcnew String("Benedict@NNcNannara.net");
            Source = gcnew String("Calculus Subsystem");
        }
    };


    public ref struct InvalidEndItemException : public Exception
    {
        static String^ message = gcnew String("The validation routines detected that the end item of a tree is invalid.");

        InvalidEndItemException() : Exception(message)
        {
            HelpLink = gcnew String("Benedict@NNcNannara.net");
            Source = gcnew String("Calculus Subsystem");
        }
    };

     public ref struct EntryAlreadyExistsException : public Exception
    {
        static String^ message = gcnew String("An entry already exists in the collection.");

        EntryAlreadyExistsException() : Exception(message)
        {
            HelpLink = gcnew String("Benedict@NNcNannara.net");
            Source = gcnew String("Calculus Subsystem");
        }
    };

    public ref struct DifferentKeysException : public Exception
    {
        static String^ message = gcnew String("The specified items have different keys.");

        DifferentKeysException() : Exception(message)
        {
            HelpLink = gcnew String("Benedict@NNcNannara.net");
            Source = gcnew String("Calculus Subsystem");
        }
    };

    public ref struct AddSubTreeFailedException : public Exception
    {
        static String^ message = gcnew String("Subtree creation failed.");

        AddSubTreeFailedException() : Exception(message)
        {
            HelpLink = gcnew String("Benedict@NNcNannara.net");
            Source = gcnew String("Calculus Subsystem");
        }
    };

    public ref struct IsEndItemException : public Exception
    {
        static String^ message = gcnew String("The requested action cannot be performed on an end item.");

        IsEndItemException() : Exception(message)
        {
            HelpLink = gcnew String("Benedict@NNcNannara.net");
            Source = gcnew String("Calculus Subsystem");
        }
    };

    public ref struct EntryNotFoundException : public Exception
    {
        static String^ message = gcnew String("The requested entry could not be located in the specified collection.");

        EntryNotFoundException() : Exception(message)
        {
            HelpLink = gcnew String("Benedict@NNcNannara.net");
            Source = gcnew String("Calculus Subsystem");
        }
    };

    public ref struct InvalidSetOperationException : public Exception
    {
        static String^ message = gcnew String("An invalid set operation was specified.");

        InvalidSetOperationException() : Exception(message)
        {
            HelpLink = gcnew String("Benedict@NNcNannara.net");
            Source = gcnew String("Calculus Subsystem");
        }
    };

Node^ PreviousItem(Node^ node)
{
 if (node->IsHeader) {return node->Right;}

 else if (node->Left != nullptr)
  {
   Node^ y = node->Left;
   while (y->Right != nullptr) y = y->Right;
   node = y;
  }
 else
  {
   Node^ y = node->Parent;
   if (y->IsHeader) return y;
   while (node == y->Left) {node = y; y = y->Parent;}
   node = y;
  }
 return node;
}

Node^ NextItem(Node^ node)
{
 if (node->IsHeader) return node->Left;

 if (node->Right != nullptr)
  {
   node = node->Right;
   while (node->Left != nullptr) node = node->Left;
  }
 else
  {
   Node^ y = node->Parent;
   if (y->IsHeader) return y;
   while (node == y->Right) {node = y; y = y->Parent;}
   node = y;
  }
 return node;
}

void SwapNodeReference(Node^% first, Node^% second)
{Node^ temporary = first; first = second; second = temporary;}

void LeftNodeSwap(Node^ Root, Node^ Replace)
{
 if (Replace->Left) Replace->Left->Parent = Root;
 if (Replace->Right) Replace->Right->Parent = Root;

 if (Root->Right) Root->Right->Parent = Replace;

 if (Replace == Root->Left)
  {
   Replace->Parent = Root->Parent;
   Root->Parent = Replace;

   Root->Left = Replace->Left;
   Replace->Left = Root;
  }
 else
  {
   Root->Left->Parent = Replace;

   if (Replace->Parent->Left == Replace)
    Replace->Parent->Left = Root;
   else
    Replace->Parent->Right = Root;

   SwapNodeReference(Root->Left,Replace->Left);
   SwapNodeReference(Root->Parent,Replace->Parent);
  }

 SwapNodeReference(Root->Right,Replace->Right);

 State Balance = Root->Balance;
 Root->Balance = Replace->Balance;
 Replace->Balance=Balance;
}

void SwapNodes(Node^ A, Node^ B)
{
 if (B == A->Left)
  {
   if (B->Left) B->Left->Parent = A;
   if (B->Right) B->Right->Parent = A;

   if (A->Right) A->Right->Parent = B;

   if (!A->Parent->IsHeader)
    {
     if (A->Parent->Left == A)
      A->Parent->Left = B;
     else
      A->Parent->Right = B;
    }
   else A->Parent->Parent = B;

   B->Parent = A->Parent;
   A->Parent = B;

   A->Left = B->Left;
   B->Left = A;

   SwapNodeReference(A->Right,B->Right);
  }
 else if (B == A->Right)
  {
   if (B->Right) B->Right->Parent = A;
   if (B->Left) B->Left->Parent = A;

   if (A->Left) A->Left->Parent = B;

   if (!A->Parent->IsHeader)
    {
     if (A->Parent->Left == A)
      A->Parent->Left = B;
     else
      A->Parent->Right = B;
    }
   else A->Parent->Parent = B;

   B->Parent = A->Parent;
   A->Parent = B;

   A->Right = B->Right;
   B->Right = A;

   SwapNodeReference(A->Left,B->Left);
  }
 else if (A == B->Left)
  {
   if (A->Left) A->Left->Parent = B;
   if (A->Right) A->Right->Parent = B;

   if (B->Right) B->Right->Parent = A;

   if (!B->Parent->IsHeader)
    {
     if (B->Parent->Left == B)
      B->Parent->Left = A;
     else
      B->Parent->Right = A;
    }
   else B->Parent->Parent = A;

   A->Parent = B->Parent;
   B->Parent = A;

   B->Left = A->Left;
   A->Left = B;

   SwapNodeReference(A->Right,B->Right);
  }
 else if (A == B->Right)
  {
   if (A->Right) A->Right->Parent = B;
   if (A->Left) A->Left->Parent = B;

   if (B->Left) B->Left->Parent = A;

   if (!B->Parent->IsHeader)
    {
     if (B->Parent->Left == B)
      B->Parent->Left = A;
     else
      B->Parent->Right = A;
    }
   else B->Parent->Parent = A;

   A->Parent = B->Parent;
   B->Parent = A;

   B->Right = A->Right;
   A->Right = B;

   SwapNodeReference(A->Left,B->Left);
  }
 else
  {
   if (A->Parent == B->Parent)
    SwapNodeReference(A->Parent->Left,A->Parent->Right);
   else
    { 
     if (!A->Parent->IsHeader)
      {
       if (A->Parent->Left == A)
        A->Parent->Left = B;
       else
        A->Parent->Right = B;
      }
     else A->Parent->Parent = B;

     if (!B->Parent->IsHeader)
      {
       if (B->Parent->Left == B)
        B->Parent->Left = A;
       else
        B->Parent->Right = A;
      }
     else B->Parent->Parent = A;
    }

   if (B->Left)  B->Left->Parent = A;
   if (B->Right) B->Right->Parent = A;

   if (A->Left)  A->Left->Parent = B;
   if (A->Right) A->Right->Parent = B;

   SwapNodeReference(A->Left,B->Left);
   SwapNodeReference(A->Right,B->Right);
   SwapNodeReference(A->Parent,B->Parent);
  }

 State Balance = A->Balance;
 A->Balance = B->Balance;
 B->Balance=Balance;
}

void RotateLeft(Node^% Root)
{
 Node^ Parent = Root->Parent;
 Node^ x = Root->Right;

 Root->Parent = x;
 x->Parent = Parent;
 if (x->Left) x->Left->Parent = Root; 

 Root->Right = x->Left;
 x->Left = Root;
 Root = x;
}    

void RotateRight(Node^% Root)
{
 Node^ Parent = Root->Parent;
 Node^ x = Root->Left;

 Root->Parent = x;
 x->Parent = Parent;
 if (x->Right) x->Right->Parent = Root; 

 Root->Left = x->Right;
 x->Right = Root;
 Root = x;
} 

void BalanceLeft(Node^% Root)
{
 Node^ Left = Root->Left; // Left Subtree of Root Node

 switch (Left->Balance)
  {
   case State::LeftHigh:
    Root->Balance = State::Balanced;
    Left->Balance = State::Balanced;
    RotateRight(Root);
    break;           
    
   case State::RightHigh:
    {
     Node^ subRight = Left->Right;  // Right subtree of Left
     switch (subRight->Balance)
      {
       case State::Balanced:
        Root->Balance = State::Balanced;
        Left->Balance = State::Balanced;
        break;

       case State::RightHigh:
        Root->Balance = State::Balanced;
        Left->Balance = State::LeftHigh;
        break;

       case State::LeftHigh:
        Root->Balance = State::RightHigh;
        Left->Balance = State::Balanced;
        break;
      }
     subRight->Balance = State::Balanced;
     RotateLeft(Left);
     Root->Left = Left;
     RotateRight(Root);
    }
    break;

   case State::Balanced:
    Root->Balance = State::LeftHigh;
    Left->Balance = State::RightHigh;
    RotateRight(Root);
    break;           
  }
} 

void BalanceRight(Node^% Root)
{
 Node^ Right = Root->Right; // Right Subtree of Root Node

 switch (Right->Balance)
  {
   case State::RightHigh:
    Root ->Balance = State::Balanced;
    Right->Balance = State::Balanced;
    RotateLeft(Root);
    break;

   case State::LeftHigh:
    {
     Node^ subLeft = Right->Left; // Left Subtree of Right
     switch (subLeft->Balance)
      {
       case State::Balanced:
        Root ->Balance = State::Balanced;
        Right->Balance = State::Balanced;
        break;

       case State::LeftHigh:
        Root ->Balance = State::Balanced;
        Right->Balance = State::RightHigh;
        break;

       case State::RightHigh:
        Root ->Balance = State::LeftHigh;
        Right->Balance = State::Balanced;
        break;
      }
     subLeft->Balance = State::Balanced;
     RotateRight(Right);
     Root->Right = Right;
     RotateLeft(Root);
    }
    break;         

   case State::Balanced:
    Root ->Balance = State::RightHigh;
    Right->Balance = State::LeftHigh;
    RotateLeft(Root);
    break;           
  }
} 

void BalanceTree(Node^ Root, Direction From)
{
  bool Taller = true;

  while (Taller)
   {
    Node^ Parent = Root->Parent;
    Direction NextFrom = (Parent->Left == Root) ? Direction::FromLeft : Direction::FromRight;

    if (From == Direction::FromLeft)
    {
     switch (Root->Balance)
      {
       case State::LeftHigh:
        if (Parent->IsHeader)
          BalanceLeft(Parent->Parent);
        else if (Parent->Left == Root)
          BalanceLeft(Parent->Left);
        else
          BalanceLeft(Parent->Right);
        Taller = false;
        break;

        case State::Balanced:
         Root->Balance = State::LeftHigh;
         Taller = true;
         break;

        case State::RightHigh:
         Root->Balance = State::Balanced;
         Taller = false;
         break;
       }
     }
    else
     {
      switch (Root->Balance)
       {
        case State::LeftHigh:
         Root->Balance = State::Balanced;
         Taller = false;
         break;

        case State::Balanced:
         Root->Balance = State::RightHigh;
         Taller = true;
         break;

        case State::RightHigh:
         if (Parent->IsHeader)
           BalanceRight(Parent->Parent);
         else if (Parent->Left == Root)
           BalanceRight(Parent->Left);
         else
           BalanceRight(Parent->Right);
         Taller = false;
         break;
        }
      }

      if (Taller) // skip up a level
      {
       if (Parent->IsHeader)
        Taller = false;
       else
       {
        Root = Parent;
        From = NextFrom;
       }
     }
   }
 }

void BalanceTreeRemove(Node^ Root, Direction From)
{
  if (Root->IsHeader) return;
  bool Shorter = true;

  while (Shorter)
   {
    Node^ Parent = Root->Parent;
    Direction NextFrom = (Parent->Left == Root) ? Direction::FromLeft : Direction::FromRight;

    if (From == Direction::FromLeft)
     {
      switch (Root->Balance)
       {
        case State::LeftHigh:
         Root->Balance = State::Balanced;
         Shorter = true;
         break;

        case State::Balanced:
         Root->Balance = State::RightHigh;
         Shorter = false;
         break;

        case State::RightHigh:
         if (Root->Right->Balance == State::Balanced)
          Shorter = false;
         else
          Shorter = true;
        if (Parent->IsHeader)
         BalanceRight(Parent->Parent);
        else if (Parent->Left == Root)
         BalanceRight(Parent->Left);
        else
         BalanceRight(Parent->Right);
        break;
       }
    }
   else
    {
     switch (Root->Balance)
      {
       case State::RightHigh:
        Root->Balance = State::Balanced;
        Shorter = true;
        break;

       case State::Balanced:
        Root->Balance = State::LeftHigh;
        Shorter = false;
        break;

       case State::LeftHigh:
        if (Root->Left->Balance == State::Balanced)
         Shorter = false;
        else
         Shorter = true;
        if (Parent->IsHeader)
          BalanceLeft(Parent->Parent);
        else if (Parent->Left == Root)
          BalanceLeft(Parent->Left);
        else
          BalanceLeft(Parent->Right);
        break;
       }
     }

     if (Shorter)
      {
       if (Parent->IsHeader)
        Shorter = false;
       else
        {
         From = NextFrom;
         Root = Parent;
        }
      }
   }
}

Node^ Minimum(Node^ node)
{
 while (node->Left) node=node->Left;
 return node;
}

Node^ Maximum(Node^ node)
{
 while (node->Right) node=node->Right;
 return node;
}

void AdjustAdd(Node^ Root)
{
 Node^ Header = Root->Parent;
 while (!Header->IsHeader) Header=Header->Parent;

 if (Root->Parent->Left == Root)
 {
  BalanceTree(Root->Parent,Direction::FromLeft);
  if (Header->Left == Root->Parent) Header->Left = Root;
 }
 else
 {
  BalanceTree(Root->Parent,Direction::FromRight);
  if (Header->Right == Root->Parent) Header->Right = Root;
 }
}

void AdjustRemove(Node^ Parent, Direction Direction)
{
 BalanceTreeRemove(Parent,Direction);
 
 Node^ Header = Parent;
 while (!Header->IsHeader) Header=Header->Parent;

 if (Header->Parent == nullptr)
 {
  Header->Left = Header;
  Header->Right = Header;
 }
 else
 {
  Header->Left = Minimum(Header->Parent);
  Header->Right = Maximum(Header->Parent);
 }
}

unsigned long long Depth(Node^ Root)
{
 if (Root)
  {
   unsigned long long Left  = Root->Left  ? Depth(Root->Left)  : 0;
   unsigned long long Right = Root->Right ? Depth(Root->Right) : 0;
   return Left < Right ? Right+1 : Left+1;
  }
 else
  return 0;
}

unsigned long long Count(Node^ Root)
{
 if (Root)
  {
   unsigned long long left  = Root->Left  ? Count(Root->Left)  : 0;
   unsigned long long right = Root->Right ? Count(Root->Right) : 0;
   return left + right + 1;
  }
 else
  return 0;
}

 public enum class SetOperation
 {
            Union,
            Intersection,
            SymmetricDifference,
            Difference,
            Equality,
            Inequality,
            Subset,
            Superset
 };

generic<typename T>
public ref class SetNode : Node
{
 public:

  T Data;

  SetNode(T dataType, Node^ Parent) : Node(Parent) {Data = dataType; }
};

generic<typename T>
public value struct SetEntry : System::Collections::Generic::IEnumerator<T>
{
 public:

  SetEntry(Node^ n) { _Node = n; }

  property T Value
  {
   T get()
    {
     if (_Node->Balance == State::Header) throw gcnew IsEndItemException();
     return ((SetNode<T>^)_Node)->Data;
    }
   void set(T Value)
    {
     if (_Node->Balance == State::Header) throw gcnew IsEndItemException();
     ((SetNode<T>^)_Node)->Data = Value;
    }
  }

 property Boolean IsHeader { Boolean get() { return _Node->IsHeader; } }

 virtual Boolean MoveNext()
 {
  _Node = NextItem(_Node);
  return _Node->IsHeader ? false : true;
 }

 Boolean MovePrevious()
 {
  _Node = PreviousItem(_Node);
  return _Node->IsHeader ? false : true;
 }

 static SetEntry<T> operator ++(SetEntry<T> entry)
 {
  entry._Node = NextItem(entry._Node);
  return entry;
 }

 static SetEntry<T> operator --(SetEntry<T> entry)
 {
  entry._Node = PreviousItem(entry._Node);
  return entry;
 }

 static SetEntry<T> operator +(SetEntry<T> C, unsigned long long Increment)
 {
  SetEntry<T> Result =  SetEntry<T>(C._Node);
  for (unsigned long long i = 0; i < Increment; i++) ++Result;
  return Result;
 }

 static SetEntry<T> operator +(unsigned long long Increment, SetEntry<T> C)
 {
  SetEntry<T> Result = SetEntry<T>(C._Node);
  for (unsigned long long i = 0; i < Increment; i++) ++Result;
  return Result;
 }

 static SetEntry<T> operator -(SetEntry<T> C, unsigned long long Decrement)
 {
  SetEntry<T> Result = SetEntry<T>(C._Node);
  for (unsigned long long i = 0; i < Decrement; i++) --Result;
  return Result;
 }

 virtual void Reset()
 { while (!_Node->IsHeader) _Node = NextItem(_Node); }

 virtual property Object^ InterfaceCurrentA
  {
   Object^ get()  = System::Collections::IEnumerator::Current::get
      {
          if (_Node->Balance == State::Header) throw gcnew IsEndItemException();
          return ((SetNode<T>^)_Node)->Data;
      }
  }

 virtual property T InterfaceCurrentB
  {
   T get()  = System::Collections::Generic::IEnumerator<T>::Current::get
      {
          if (_Node->Balance == State::Header) throw gcnew IsEndItemException();
          return ((SetNode<T>^)_Node)->Data;
      }
  }

 static Boolean operator ==(SetEntry<T> x, SetEntry<T> y) { return x._Node == y._Node; }
 static Boolean operator !=(SetEntry<T> x, SetEntry<T> y) { return x._Node != y._Node; }

 static long long operator -(SetEntry<T> This, SetEntry<T> iter)
 {
  long long Result = 0;
  while (This._Node != iter._Node) { iter.MoveNext(); Result++; }
  return Result;
 }

 virtual String^ ToString() override
 {
  if (_Node->Balance == State::Header) throw gcnew IsEndItemException();
  return Value->ToString();
 }

 Node^ _Node;
};


generic<typename T>
[Serializable]
public ref class Set : public System::Collections::Generic::ICollection<T>,
                       public System::ICloneable,
                       public ISerializable,
                       public IComparable<Set<T>^>,
                       public IEquatable<Set<T>^>
{
 public:
  event TypeAdded<T>^ Added;
  event TypeRemoved<T>^ Removed;
  event TypeUpdated<T>^ Updated;

 protected:
  Node^ Header;
  System::Collections::Generic::IComparer<T>^ TComparer;
  ICloner<T>^ TCloner;
  IHasher<T>^ THasher;
  unsigned long long Nodes;

  property Node^ Root
  {
   Node^ get() { return Header->Parent; }
   void set(Node^ Value) { Header->Parent = Value; }
  }

        //*** Constructors ***

 public:

  Set()
   {
    Nodes=0;
    Header = gcnew Node();
    TComparer = System::Collections::Generic::Comparer<T>::Default;
    TCloner = Calculus::Cloner<T>::Default;
    THasher = Calculus::Hasher<T>::Default;
   }

  Set(System::Collections::Generic::IComparer<T>^ TCompare)
  {
   Nodes=0;
   Header = gcnew Node();
   TComparer = TCompare;
   TCloner = Calculus::Cloner<T>::Default;
   THasher = Calculus::Hasher<T>::Default;
  }

  Set(Set<T>^ SetToCopy)
  {
   Nodes=0;
   Header = gcnew Node();
   TComparer = SetToCopy->TComparer;
   TCloner = SetToCopy->TCloner;
   THasher = SetToCopy->THasher;
   Copy((SetNode<T>^)SetToCopy->Root);
  }

  Set(System::Collections::Generic::IEnumerable<T>^ Collection)
  {
   Nodes=0;
   Header = gcnew Node();
   TComparer = System::Collections::Generic::Comparer<T>::Default;
   TCloner = Calculus::Cloner<T>::Default;
   THasher = Calculus::Hasher<T>::Default;

   for each (T t in Collection) Add(TCloner->Clone(t));
  }

  Set(... array<T>^ Collection)
  {
   Nodes=0;
   Header = gcnew Node();
   TComparer = System::Collections::Generic::Comparer<T>::Default;
   TCloner = Calculus::Cloner<T>::Default;
   THasher = Calculus::Hasher<T>::Default;

   for each (T t in Collection) Add(TCloner->Clone(t));
  }

  Set(System::Collections::Generic::IEnumerable<T>^ Collection,
      System::Collections::Generic::IComparer<T>^ TCompare)
  {
   Nodes=0;
   Header = gcnew Node();
   TComparer = TCompare;
   TCloner = Calculus::Cloner<T>::Default;
   THasher = Calculus::Hasher<T>::Default;
 
   for each (T t in Collection) Add(TCloner->Clone(t));
  }

  Set(Set<T>^ A,
      Set<T>^ B,
      SetOperation operation)
  {
   Nodes=0;
   Header = gcnew Node();
   TComparer = A->TComparer;
   TCloner = A->TCloner;
   THasher = A->THasher;
   CombineSets(A, B, this, operation);
  }

  Set(SerializationInfo^ si, StreamingContext sc)
  {
   Nodes=0;
   System::Collections::Generic::IComparer<T>^ TCompare = (System::Collections::Generic::IComparer<T>^)si->GetValue("TComparer", System::Collections::Generic::IComparer<T>::typeid);
   Calculus::ICloner<T>^ TClone = (Calculus::ICloner<T>^)si->GetValue("TCloner", ICloner<T>::typeid);
   Calculus::IHasher<T>^ THasher = (Calculus::IHasher<T>^)si->GetValue("THasher", IHasher<T>::typeid);

   Header = gcnew Node();
   TComparer = TCompare;
   TCloner = TClone;

   Type^ type = T::typeid;

   unsigned long long LoadCount = si->GetUInt64("Count");

   for (unsigned long long i = 0; i < LoadCount; i++)
   {
    Object^ obj = si->GetValue(i.ToString(), type);
    Add((T)obj, false);
   }
  }

        //*** Operators ***

  static Set<T>^ operator |(Set<T>^ A, Set<T>^ B)
  {
   Set<T>^ U = gcnew Set<T>(A->TComparer);
   U->TCloner = A->TCloner;
   U->THasher = A->THasher;
   CombineSets(A, B, U, SetOperation::Union);
   return U;
  }

  static Set<T>^ operator &(Set<T>^ A, Set<T>^ B)
  {
   Set<T>^ I = gcnew Set<T>(A->TComparer);
   I->TCloner = A->TCloner;
   I->THasher = A->THasher;
   CombineSets(A, B, I, SetOperation::Intersection);
   return I;
  }

  static Set<T>^ operator ^(Set<T>^ A, Set<T>^ B)
  {
   Set<T>^ S = gcnew Set<T>(A->TComparer);
   S->TCloner = A->TCloner;
   S->THasher = A->THasher;
   CombineSets(A, B, S, SetOperation::SymmetricDifference);
   return S;
  }

  static Set<T>^ operator -(Set<T>^ A, Set<T>^ B)
  {
   Set<T>^ S = gcnew Set<T>(A->TComparer);
   S->TCloner = A->TCloner;
   S->THasher = A->THasher;
   CombineSets(A, B, S, SetOperation::Difference);
   return S;
  }

  static Boolean operator ==(Set<T>^ A, Set<T>^ B)
  {
   return CheckSets(A, B, SetOperation::Equality);
  }

  static Boolean operator !=(Set<T>^ A, Set<T>^ B)
  {
   return CheckSets(A, B, SetOperation::Inequality);
  }

  static Boolean operator <(Set<T>^ A, Set<T>^ B)
  {
   return CheckSets(A, B, SetOperation::Subset);
  }

  static Boolean operator >(Set<T>^ A, Set<T>^ B)
  {
   return CheckSets(A, B, SetOperation::Superset);
  }

  property Boolean default [T]
  {
   Boolean get(T key)
   {
    if (Root == nullptr)
     return false;
    else
     {
      Node^ search = Root;

      do
       {
        int Result = TComparer->Compare(key, static_cast<SetNode<T>^>(search)->Data);

        if (Result < 0) search = search->Left;

        else if (Result > 0) search = search->Right;

        else break;

       } while (search != nullptr);

       return search != nullptr;
      }
    }
  }

 static Set<T>^ operator +(Set<T>^ set, T t)
 {
  set->Add(t, false);
  return set;
 }

 static Set<T>^ operator -(Set<T>^ set, T t)
 {
  set->Remove(t);
  return set;
 }

 //*** Properties ***

 property SetEntry<T> Begin
 { SetEntry<T> get() { return SetEntry<T>(Header->Left); } }

 property ICloner<T>^ TypeCloner
 {
  ICloner<T>^ get() { return TCloner; }
  void set(ICloner<T>^ Value) { TCloner = Value; }
 }
 property System::Collections::Generic::IComparer<T>^ Comparer
 {System::Collections::Generic::IComparer<T>^ get() { return TComparer; } }

 virtual property int Count { int get() { return (int)Length; } }

 property SetEntry<T> End
 { SetEntry<T> get() { return SetEntry<T>(Header); } }

 property T First
 { T get() { return ((SetNode<T>^)LeftMost)->Data; } }

 property int Hash { int get() { return GetHashCode(); } }

 property IHasher<T>^ Hasher
 {
  IHasher<T>^ get() { return THasher; }
  void set(IHasher<T>^ Value) { THasher = Value; }
 }

 virtual property Boolean IsReadOnly { Boolean get() { return false; } }

 virtual property Boolean IsSynchronized { Boolean get() { return true; } }

 property T Last
 { T get() { return ((SetNode<T>^)RightMost)->Data; } }

 property Node^ LeftMost
 {
  Node^ get() { return Header->Left; }
  void set(Node^ Value) { Header->Left = Value; }
 }

 property unsigned long long Length {  unsigned long long get() { return Count;} }

 property Node^ RightMost
 {
  Node^ get() { return Header->Right; }
  void set(Node^ Value) { Header->Right = Value; }
 }
 
 property Object^ SyncRoot { Object^ get() { return this; } }

        //*** Public Methods ***

 SetEntry<T> After(T Value, Boolean equals)
 {
  return SetEntry<T>(equals ? AfterEquals(Value) : After(Value));
 }

 virtual void Add(T t)
 {
  Add(t, false);
 }

 void Add(SetEntry<T> cse)
 {
  Add(TCloner->Clone(cse.Value), false);
 }

 unsigned long long Add(System::Collections::Generic::IEnumerable<T>^ copy)
 {
  unsigned long long count = 0;

  for each(T t in copy)
  {
   Add(TCloner->Clone(t), false);
   count++;
  }

  return count;
 }

 SetEntry<T> Before(T value, bool equals)
 {
  return SetEntry<T>(equals ? BeforeEquals(value) : Before(value));
 }

 virtual void Clear() { Remove(); }

 void CallRemoved(T data) { Removed(this, data); }

 virtual Object^ Clone()
 {
  Set<T>^ setOut = gcnew Set<T>(TComparer);
  setOut->TCloner = TCloner;
  setOut->THasher = THasher;
  setOut->Copy((SetNode<T>^)Root);
  return setOut;
 }

 virtual int CompareTo(Set<T>^ B)
 {
  return CompareSets(this, B);
 }

 virtual bool Contains(T t)
 {
  Node^ found = Search(t);
  return found != nullptr ? true : false;
 }

 virtual Boolean Contains(Set<T>^ ss)
 {
  for each (T t in ss)
   if (Search(t) == nullptr) return false;

  return true;
 }

 virtual void CopyTo(array<T>^ arr, int i)
 {
  SetEntry<T> begin = SetEntry<T>((SetNode<T>^)Header->Left);
  SetEntry<T> end = SetEntry<T>(Header);

  while (begin != end)
  {
   arr->SetValue(TCloner->Clone(((SetNode<T>^)begin._Node)->Data), i);
   i++; begin.MoveNext();
  }
 }

  virtual void CopyTo(System::Array^ arr, int i)
  {
   SetEntry<T> begin = SetEntry<T>((SetNode<T>^)Header->Left);
   SetEntry<T> end = SetEntry<T>(Header);

   while (begin != end)
   {
     arr->SetValue(TCloner->Clone(((SetNode<T>^)begin._Node)->Data), i);
     i++; begin.MoveNext();
   }
  }

  virtual Boolean Equals(Set<T>^ compare)
  {
   SetEntry<T> first1 = Begin;
   SetEntry<T> last1 = End;
   SetEntry<T> first2 = compare->Begin;
   SetEntry<T> last2 = compare->End;

   Boolean equals = true;

   while (first1 != last1 && first2 != last2)
    {
     if (TComparer->Compare(first1.Value, first2.Value) == 0)
      { first1.MoveNext(); first2.MoveNext(); }
     else
      { equals = false; break; }
    }

   if (equals)
    {
     if (first1 != last1) equals = false;
     if (first2 != last2) equals = false;
    }

   return equals;
  }

  T Find(T value)
  {
   Node^ _Node = Search(value);
   if (_Node == nullptr)
     throw gcnew EntryNotFoundException();
   return ((SetNode<T>^)_Node)->Data;
  }

 virtual System::Collections::IEnumerator^ InterfaceGetEnumeratorSimple() sealed = System::Collections::IEnumerable::GetEnumerator
 { return gcnew SetEntry<T>(Header); }

 virtual System::Collections::Generic::IEnumerator<T>^ InterfaceGetEnumerator() sealed = System::Collections::Generic::IEnumerable<T>::GetEnumerator
 { return gcnew SetEntry<T>(Header); }

  virtual Int32 GetHashCode() override
  {
   Int32 HashCode = 0;
   for each (T t in this) HashCode += THasher->GetHashCode(t);
   return HashCode;
  }

  virtual void GetObjectData(SerializationInfo^ si, StreamingContext sc)
  {
   si->SetType(Calculus::Set<T>::typeid);

   Type^ type = T::typeid;

   unsigned long long index = 0;
   for each (T e in *this)
   {
     si->AddValue(index.ToString(), e, type);
     index++;
   }

   si->AddValue("Count", index);
   si->AddValue("TComparer", TComparer, TComparer->GetType());
   si->AddValue("TCloner", TCloner, TCloner->GetType());
   si->AddValue("THasher", THasher, THasher->GetType());
  }

  SetEntry<T> Insert(T t) { return SetEntry<T>(Add(t, false)); }

  SetEntry<T> Locate(T value)
  {
   Node^ _Node = Search(value);
   if (_Node == nullptr)
     throw gcnew EntryNotFoundException();
   return SetEntry<T>(_Node);
  }

  void Notify()
  {
   Notify((SetNode<T>^)Root);
  }

  unsigned long long Remove()
  {
   for each (T t in this) Removed(this, t);
   unsigned long long count = Nodes;
   Root = nullptr;
   LeftMost = Header;
   RightMost = Header;
   Nodes = 0;
   return count;
  }

  virtual bool Remove(T data)
  {
   Node^ root = Root;

   for (; ; )
   {
    if (root == nullptr) throw gcnew EntryNotFoundException();

    int compare = TComparer->Compare(data, ((SetNode<T>^)root)->Data);

    if (compare < 0)
     root = root->Left;

    else if (compare > 0)
     root = root->Right;

    else // Item is found
    {
     if (root->Left != nullptr && root->Right != nullptr)
     {
      Node^ replace = root->Left;
      while (replace->Right != nullptr) replace = replace->Right;
      SwapNodes(root, replace);
     }

     Node^ Parent = root->Parent;

     Direction From = (Parent->Left == root) ? Direction::FromLeft : Direction::FromRight;

     if (LeftMost == root)
      {
       Node^ n = NextItem(root);

       if (n->IsHeader)
        { LeftMost = Header; RightMost = Header; }
       else
         LeftMost = n;
      }
      else if (RightMost == root)
       {
        Node^ p = PreviousItem(root);

        if (p->IsHeader)
         { LeftMost = Header; RightMost = Header; }
        else
          RightMost = p;
       }

     if (root->Left == nullptr)
     {
      if (Parent == Header)
        Header->Parent = root->Right;
      else if (Parent->Left == root)
        Parent->Left = root->Right;
      else
        Parent->Right = root->Right;

      if (root->Right != nullptr) root->Right->Parent = Parent;
     }
     else
      {
       if (Parent == Header)
        Header->Parent = root->Left;
       else if (Parent->Left == root)
        Parent->Left = root->Left;
       else
        Parent->Right = root->Left;

       if (root->Left != nullptr) root->Left->Parent = Parent;
      }

      AdjustRemove(Parent, From);
      Nodes--;
      Removed(this, ((SetNode<T>^)root)->Data);
      break;
     }
   }
   return true;
  }

  void Remove(SetEntry<T> i) { Remove(i._Node); }

  Node^ Search(T data)
  {
   if (Root == nullptr)
     return nullptr;
   else
    {
     Node^ search = Root;

     do
      {
       int Result = TComparer->Compare(data, ((SetNode<T>^)search)->Data);

       if (Result < 0) search = search->Left;

       else if (Result > 0) search = search->Right;

       else break;

      } while (search != nullptr);

      return search;
    }
  }

  virtual String^ ToString() override
  {
   String^ StringOut = gcnew String("{");

   SetEntry<T> start = Begin;
   SetEntry<T> end = End;
   SetEntry<T> last = End - 1;

   while (start != end)
   {
    String^ NewStringOut = start.Value->ToString();
    if (start != last) NewStringOut = NewStringOut + gcnew String(",");
    StringOut = StringOut + NewStringOut;
    ++start;
   }

   StringOut = StringOut + gcnew String("}");
   return StringOut;
  }

 void Update(T value)
 {
  if (Root == nullptr)
   throw gcnew EntryNotFoundException();
  else
   {
    Node^ search = Root;

    do
    {
     int Result = TComparer->Compare(value, ((SetNode<T>^)search)->Data);

     if (Result < 0) search = search->Left;

     else if (Result > 0) search = search->Right;

     else break;

    } while (search != nullptr);

    if (search == nullptr) throw gcnew EntryNotFoundException();

    T saved = ((SetNode<T>^)search)->Data;
    ((SetNode<T>^)search)->Data = value;
    Updated(this, saved, value);
  }
 }

 void Update(SetEntry<T>^ entry, T after) {  Update((SetNode<T>^)entry->_Node, after); }

 void Validate()
 {
  if (Nodes == 0 || Root == nullptr)
  {
   if (Nodes != 0) { throw gcnew InvalidEmptyTreeException(); }
   if (Root != nullptr) { throw gcnew InvalidEmptyTreeException(); }
   if (LeftMost != Header) { throw gcnew InvalidEndItemException(); }
   if (RightMost != Header) { throw gcnew InvalidEndItemException(); }
  }

  Validate((SetNode<T>^)Root);

  if (Root != nullptr)
  {
   Node^ x = Root;
   while (x->Left != nullptr) x = x->Left;

   if (LeftMost != x) throw gcnew InvalidEndItemException();

   Node^ y = Root;
   while (y->Right != nullptr) y = y->Right;

   if (RightMost != y) throw gcnew InvalidEndItemException();
  }
 }

        //*** Private Methods ***

 protected:

 Node^ After(T data)
 {
  Node^ y = Header;
  Node^ x = Root;

  while (x != nullptr)
   if (TComparer->Compare(data, ((SetNode<T>^)x)->Data) < 0)
    { y = x; x = x->Left; }
   else
     x = x->Right;

  return y;
 }

 Node^ AfterEquals(T data)
 {
  Node^ y = Header;
  Node^ x = Root;

  while (x != nullptr)
  {
   int c = TComparer->Compare(data, ((SetNode<T>^)x)->Data);
   if (c == 0)
    { y = x; break; }
   else if (c < 0)
    { y = x; x = x->Left; }
   else
    x = x->Right;
  }

  return y;
 }

 SetNode<T>^ Add(T data, bool exist)
 {
  Node^ root = Root;

  if (root == nullptr)
   {
    Root = gcnew SetNode<T>(data, Header);
    Nodes++;
    LeftMost = Root;
    RightMost = Root;
    Added(this, ((SetNode<T>^)Root)->Data);
    return (SetNode<T>^)Root;
   }
  else
   {
    for (; ; )
     {
      int compare = TComparer->Compare(data, static_cast<SetNode<T>^>(root)->Data);

      if (compare == 0) // Item Exists
       {
        if (exist)
         {
          T saved = ((SetNode<T>^)root)->Data;
          ((SetNode<T>^)root)->Data = data;
          Updated(this, saved, data);
          return (SetNode<T>^)root;
         }
        else
         throw gcnew EntryAlreadyExistsException();
       }

      else if (compare < 0)
       {
        if (root->Left != nullptr)
         root = root->Left;
        else
         {
          SetNode<T>^ NewNode = gcnew SetNode<T>(data, root);
          Nodes++;
          root->Left = NewNode;
          AdjustAdd(NewNode);
          Added(this, NewNode->Data);
          return NewNode;
         }
      }

    else
     {
      if (root->Right != nullptr)
       root = root->Right;
      else
       {
        SetNode<T>^ NewNode = gcnew SetNode<T>(data, root);
        Nodes++;
        root->Right = NewNode;
        AdjustAdd(NewNode);
        Added(this, NewNode->Data);
        return NewNode;
       }
     }
    }
   }
 }

 unsigned long long Add(Node^ begin, Node^ end)
 {
  bool success = true;
  unsigned long long count = 0;

  SetEntry<T> i(begin);

  while (success && i._Node != end)
  {
   if (!i._Node->IsHeader)
    {
     try
      {
       Add(TCloner->Clone(i.Value), false);
       count++;
       i.MoveNext();
      }
     catch (Exception^) { success = false; }
    }
   else i.MoveNext();
  }
  if (!success)
   {
    if (count != 0)
     {
      i.MovePrevious();
      SetEntry<T> start(begin); start.MovePrevious();

      while (i != start)
       {
        SetEntry<T> j(i._Node); j.MovePrevious();
        if (!i._Node->IsHeader) Remove(i.Value);
        i = j;
       }
     }
    throw gcnew AddSubTreeFailedException();
   }
  return Count;
 }

 Node^ Before(T data)
 {
  Node^ y = Header;
  Node^ x = Root;

  while (x != nullptr)
   if (TComparer->Compare(data, ((SetNode<T>^)x)->Data) <= 0)
    x = x->Left;
   else
    { y = x; x = x->Right; }

  return y;
 }

 Node^ BeforeEquals(T data)
 {
  Node^ y = Header;
  Node^ x = Root;

  while (x != nullptr)
  {
   int c = TComparer->Compare(data, ((SetNode<T>^)x)->Data);
   if (c == 0)
    { y = x; break; }
   else if (c < 0)
    x = x->Left;
   else
    { y = x; x = x->Right; }
  }

  return y;
 }

 void Bounds()
 {
  LeftMost = GetFirst();
  RightMost = GetLast();
 }

 void Copy(SetNode<T>^ CopyRoot)
 {
  if (Root != nullptr) Remove();
  if (CopyRoot != nullptr)
   {
     Copy(Header->Parent, CopyRoot, Header);
     LeftMost = GetFirst();
     RightMost = GetLast();
    }
 }

 void Copy(Node^% root, SetNode<T>^ CopyRoot, Node^ Parent)
 {
  root = gcnew SetNode<T>(TCloner->Clone(CopyRoot->Data), Parent);
  Nodes++;

  root->Balance = CopyRoot->Balance;

  if (CopyRoot->Left != nullptr)
   Copy(root->Left, (SetNode<T>^)CopyRoot->Left, (SetNode<T>^)root);

  if (CopyRoot->Right != nullptr)
   Copy(root->Right, (SetNode<T>^)CopyRoot->Right, (SetNode<T>^)root);

  Added(this, ((SetNode<T>^)root)->Data);
 }

 Node^ GetFirst()
 {
  if (Root == nullptr)
   return Header;

  else
   {
    Node^ search = Root;
    while (search->Left != nullptr) search = search->Left;
    return search;
   }
 }

 Node^ GetLast()
 {
  if (Root == nullptr)
   return Header;

  else
   {
    Node^ search = Root;
    while (search->Right != nullptr) search = search->Right;
    return search;
   }
 }

 void Import(SetNode<T>^ n)
 {
  if (n != nullptr) ImportTree(n);
 }

 void ImportTree(SetNode<T>^ n)
 {
  if (n->Left != nullptr) ImportTree((SetNode<T>^)n->Left);
  Add(n->Data, false);
  if (n->Right != nullptr) ImportTree((SetNode<T>^)n->Right);
 }

 void Notify(SetNode<T>^ root)
 {
  if (root != nullptr)
  {
   if (root->Left != nullptr)
    Notify((SetNode<T>^)root->Left);

   Added(this, root->Data);

   if (root->Right != nullptr)
    Notify((SetNode<T>^)root->Right);
  }
 }

 void Remove(Node^ root)
 {
  if (root->Left != nullptr && root->Right != nullptr)
  {
   Node^ replace = root->Left;
   while (replace->Right != nullptr) replace = replace->Right;
   SwapNodes(root, replace);
  }

  Node^ Parent = root->Parent;

  Direction From = (Parent->Left == root) ? Direction::FromLeft : Direction::FromRight;

  if (LeftMost == root)
  {
   Node^ n = NextItem(root);

   if (n->IsHeader)
    { LeftMost = Header; RightMost = Header; }
   else
    LeftMost = n;
  }
  else if (RightMost == root)
  {
    Node^ p = PreviousItem(root);

    if (p->IsHeader)
     { LeftMost = Header; RightMost = Header; }
    else
     RightMost = p;
  }

  if (root->Left == nullptr)
  {
   if (Parent == Header)
    Header->Parent = root->Right;
   else if (Parent->Left == root)
    Parent->Left = root->Right;
   else
    Parent->Right = root->Right;

   if (root->Right != nullptr) root->Right->Parent = Parent;
  }
  else
  {
   if (Parent == Header)
    Header->Parent = root->Left;
   else if (Parent->Left == root)
    Parent->Left = root->Left;
   else
    Parent->Right = root->Left;

   if (root->Left != nullptr) root->Left->Parent = Parent;
  }

  AdjustRemove(Parent, From);
  Nodes--;
  Removed(this, ((SetNode<T>^)root)->Data);
 }

 unsigned long long Remove(Node^ i, Node^ j)
 {
  if (i == LeftMost && j == Header)
   return Remove();
  else
   {
    unsigned long long count = 0;
    while (i != j)
    {
     SetEntry<T> iter(i); iter.MoveNext();
     if (i != Header) { Remove(i); count++; }
     i = iter._Node;
    }

    return count;
   }
 }

 void Update(SetNode<T>^ Node, T value)
 {
  if (TComparer->Compare(Node->Data, value) != 0) throw gcnew DifferentKeysException();
  T saved = Node->Data;
  Node->Data = value;
  Updated(this, saved, value);
 }

 void Validate(SetNode<T>^ root)
 {
  if (root == nullptr) return;

  if (root->Left != nullptr)
   {
    SetNode<T>^ Left = (SetNode<T>^)root->Left;

    if (TComparer->Compare(Left->Data, root->Data) >= 0)
     throw gcnew OutOfKeyOrderException();

    if (Left->Parent != root)
     throw gcnew TreeInvalidParentException();

    Validate((SetNode<T>^)root->Left);
   }

  if (root->Right != nullptr)
   {
    SetNode<T>^ Right = (SetNode<T>^)root->Right;

    if (TComparer->Compare(Right->Data, root->Data) <= 0)
     throw gcnew OutOfKeyOrderException();

    if (Right->Parent != root)
     throw gcnew TreeInvalidParentException();

    Validate((SetNode<T>^)root->Right);
   }

  unsigned long long DepthLeft = root->Left != nullptr ? Depth(root->Left) : 0;
  unsigned long long DepthRight = root->Right != nullptr ? Depth(root->Right) : 0;

  if (DepthLeft > DepthRight && DepthLeft - DepthRight > 2)
   throw gcnew TreeOutOfBalanceException();

  if (DepthLeft < DepthRight && DepthRight - DepthLeft > 2)
   throw gcnew TreeOutOfBalanceException();
 }

        //*** Static Methods

 static void CombineSets(Set<T>^ A,
                         Set<T>^ B,
                         Set<T>^ R,
                         SetOperation operation)
{
 System::Collections::Generic::IComparer<T>^ TComparer = R->TComparer;
 Calculus::ICloner<T>^ TCloner = R->TCloner;

 SetEntry<T> first1 = A->Begin;
 SetEntry<T> last1 = A->End;
 SetEntry<T> first2 = B->Begin;
 SetEntry<T> last2 = B->End;

            switch (operation)
            {
                case SetOperation::Union:
                    while (first1 != last1 && first2 != last2)
                    {
                        int order = TComparer->Compare(first1.Value, first2.Value);

                        if (order < 0)
                        {
                            R->Add(TCloner->Clone(first1.Value));
                            first1.MoveNext();
                        }

                        else if (order > 0)
                        {
                            R->Add(TCloner->Clone(first2.Value));
                            first2.MoveNext();
                        }

                        else
                        {
                            R->Add(TCloner->Clone(first1.Value));
                            first1.MoveNext();
                            first2.MoveNext();
                        }
                    }
                    while (first1 != last1)
                    {
                        R->Add(TCloner->Clone(first1.Value));
                        first1.MoveNext();
                    }
                    while (first2 != last2)
                    {
                        R->Add(TCloner->Clone(first2.Value));
                        first2.MoveNext();
                    }
                    return;

                case SetOperation::Intersection:
                    while (first1 != last1 && first2 != last2)
                    {
                        int order = TComparer->Compare(first1.Value, first2.Value);

                        if (order < 0)
                            first1.MoveNext();

                        else if (order > 0)
                            first2.MoveNext();

                        else
                        {
                            R->Add(TCloner->Clone(first1.Value));
                            first1.MoveNext();
                            first2.MoveNext();
                        }
                    }
                    return;

                case SetOperation::SymmetricDifference:
                    while (first1 != last1 && first2 != last2)
                    {
                        int order = TComparer->Compare(first1.Value, first2.Value);

                        if (order < 0)
                        {
                            R->Add(TCloner->Clone(first1.Value));
                            first1.MoveNext();
                        }

                        else if (order > 0)
                        {
                            R->Add(TCloner->Clone(first2.Value));
                            first2.MoveNext();
                        }

                        else
                        { first1.MoveNext(); first2.MoveNext(); }
                    }

                    while (first1 != last1)
                    {
                        R->Add(TCloner->Clone(first1.Value));
                        first1.MoveNext();
                    }

                    while (first2 != last2)
                    {
                        R->Add(TCloner->Clone(first2.Value));
                        first2.MoveNext();
                    }
                    return;

                case SetOperation::Difference:
                    while (first1 != last1 && first2 != last2)
                    {
                        int order = TComparer->Compare(first1.Value, first2.Value);

                        if (order < 0)
                        {
                            R->Add(TCloner->Clone(first1.Value));
                            first1.MoveNext();
                        }

                        else if (order > 0)
                        {
                            R->Add(TCloner->Clone(first1.Value));
                            first1.MoveNext();
                            first2.MoveNext();
                        }

                        else
                        { first1.MoveNext(); first2.MoveNext(); }
                    }

                    while (first1 != last1)
                    {
                        R->Add(TCloner->Clone(first1.Value));
                        first1.MoveNext();
                    }
                    return;
            }

            throw gcnew InvalidSetOperationException();
        }

        static Boolean CheckSets(Set<T>^ A,
                                 Set<T>^ B,
                                 SetOperation operation)
        {
            System::Collections::Generic::IComparer<T>^ TComparer = A->TComparer;

            SetEntry<T> first1 = A->Begin;
            SetEntry<T> last1 = A->End;
            SetEntry<T> first2 = B->Begin;
            SetEntry<T> last2 = B->End;

            switch (operation)
            {
                case SetOperation::Equality:
                case SetOperation::Inequality:
                    {
                        bool equals = true;

                        while (first1 != last1 && first2 != last2)
                        {
                            if (TComparer->Compare(first1.Value, first2.Value) == 0)
                            { first1.MoveNext(); first2.MoveNext(); }
                            else
                            { equals = false; break; }
                        }

                        if (equals)
                        {
                            if (first1 != last1) equals = false;
                            if (first2 != last2) equals = false;
                        }

                        if (operation == SetOperation::Equality)
                            return equals;
                        else
                            return !equals;
                    }

                case SetOperation::Subset:
                case SetOperation::Superset:
                    {
                        bool subset = true;

                        while (first1 != last1 && first2 != last2)
                        {
                            int order = TComparer->Compare(first1.Value, first2.Value);

                            if (order < 0)
                            { subset = false; break; }

                            else if (order > 0)
                                first2.MoveNext();

                            else
                            { first1.MoveNext(); first2.MoveNext(); }
                        }

                        if (subset)
                            if (first1 != last1) subset = false;

                        if (operation == SetOperation::Subset)
                            return subset;
                        else
                            return !subset;
                    }
            }

            throw gcnew InvalidSetOperationException();
        }

        static int CompareSets(Set<T>^ A,
                               Set<T>^ B)
        {
            System::Collections::Generic::IComparer<T>^ TComparer = A->TComparer;

            SetEntry<T> first1 = A->Begin;
            SetEntry<T> last1 = A->End;
            SetEntry<T> first2 = B->Begin;
            SetEntry<T> last2 = B->End;

            int Result = 0;

            while (first1 != last1 && first2 != last2)
            {
                Result = TComparer->Compare(first1.Value, first2.Value);
                if (Result == 0)
                { first1.MoveNext(); first2.MoveNext(); }
                else
                    return Result;
            }

            if (first1 != last1) return 1;
            if (first2 != last2) return -1;

            return 0;
        }
    };

}

using namespace Calculus;

int main(array<System::String ^> ^args)
{
    Set<int>^ S = gcnew Set<int>(1, 3, 5 , 6, 7, 9);
    Set<int>^ T = gcnew Set<int>(2, 4, 6 , 7, 8, 9);
    Set<int>^ U = S | T;
    Console::WriteLine(S + " | " + T + " == " + U);
    return 0;
}