1 using System;
  2 using System.Collections;
  3 using System.Concepts;
  4 using System.Numerics.Multiprecision;
  5 
  6 namespace BigNumCalc
  7 {
  8     public concept BigValueType<T>
  9     {
 10         where Derived<TBigValue>;
 11     }
 12 
 13     public class EvaluationStack
 14     {
 15         public void Push(BigValue* value)
 16         {
 17             stack.Push(UniquePtr<BigValue>(value));
 18         }
 19         public BigValue* Pop()
 20         {
 21             UniquePtr<BigValue> value = stack.Pop();
 22             return value.Release();
 23         }
 24         private Stack<UniquePtr<BigValue>> stack;
 25     }
 26 
 27     public BigValue* UnaryEvaluate<BigValueTOp>(BigValue* operandOp op) where BigValueT is BigValueType and Op is UnaryFunction
 28     {
 29         BigValueT* value = cast<BigValueT*>(operand);
 30         BigValueT.OperandType result = op(value->Get());
 31         return new BigValueT(result);
 32     }
 33 
 34     public inline BigValue* UnaryPlus<BigValueT>(BigValue* operand) where BigValueT is BigValueType
 35     {
 36         return UnaryEvaluate<BigValueT>(operandIdentity<BigValueT.OperandType>());
 37     }
 38 
 39     public inline BigValue* UnaryMinus<BigValueT>(BigValue* operand) where BigValueT is BigValueType
 40     {
 41         return UnaryEvaluate<BigValueT>(operandNegate<BigValueT.OperandType>());
 42     }
 43 
 44     public delegate BigValue* UnaryOperatorDelegate(BigValue* operand);
 45 
 46     public nothrow UnaryOperatorDelegate GetUnaryOperatorDelegate(uchar opBigNumKind kind)
 47     {
 48         UnaryOperatorDelegate dlg;
 49         switch (op)
 50         {
 51             case '+':
 52             {
 53                 switch (kind)
 54                 {
 55                     case BigNumKind.bigInt: dlg = UnaryPlus<BigIntValue>; break;
 56                     case BigNumKind.bigRational: dlg = UnaryPlus<BigRationalValue>; break;
 57                     case BigNumKind.bigFloat: dlg = UnaryPlus<BigFloatValue>; break;
 58                 }
 59                 break;
 60             }
 61             case '-':
 62             {
 63                 switch (kind)
 64                 {
 65                     case BigNumKind.bigInt: dlg = UnaryMinus<BigIntValue>; break;
 66                     case BigNumKind.bigRational: dlg = UnaryMinus<BigRationalValue>; break;
 67                     case BigNumKind.bigFloat: dlg = UnaryMinus<BigFloatValue>; break;
 68                 }
 69                 break;
 70             }
 71         }
 72         return dlg;
 73     }
 74 
 75     public BigValue* Evaluate(BigValue* operanduchar op)
 76     {
 77         UnaryOperatorDelegate dlg = GetUnaryOperatorDelegate(opoperand->Kind());
 78         if (dlg != UnaryOperatorDelegate())
 79         {
 80             BigValue* result = dlg(operand);
 81             if (result != null)
 82             {
 83                 return result;
 84             }
 85             else
 86             {
 87                 throw Exception("operator '" + ToUtf8(CharStr(op)) + "' not implemented for this operand type");
 88             }
 89         }
 90         else
 91         {
 92             throw Exception("operator '" + ToUtf8(CharStr(op)) + "' not implemented");
 93         }
 94     }
 95 
 96     public BigValue* BinaryEvaluate<BigValueTOp>(BigValue* leftBigValue* rightOp op) where BigValueT is BigValueType and Op is BinaryFunction
 97     {
 98         BigValueT* left_ = cast<BigValueT*>(left);
 99         BigValueT* right_ = cast<BigValueT*>(right);
100         BigValueT.OperandType result = op(left_->Get()right_->Get());
101         return new BigValueT(result);
102     }
103 
104     public inline BigValue* Add<BigValueT>(BigValue* leftBigValue* right) where BigValueT is BigValueType
105     {
106         return BinaryEvaluate<BigValueT>(leftrightPlus<BigValueT.OperandType>());
107     }
108 
109     public inline BigValue* Sub<BigValueT>(BigValue* leftBigValue* right) where BigValueT is BigValueType
110     {
111         return BinaryEvaluate<BigValueT>(leftrightMinus<BigValueT.OperandType>());
112     }
113 
114     public inline BigValue* Mul<BigValueT>(BigValue* leftBigValue* right) where BigValueT is BigValueType
115     {
116         return BinaryEvaluate<BigValueT>(leftrightMultiplies<BigValueT.OperandType>());
117     }
118 
119     public inline BigValue* Div<BigValueT>(BigValue* leftBigValue* right) where BigValueT is BigValueType
120     {
121         return BinaryEvaluate<BigValueT>(leftrightDivides<BigValueT.OperandType>());
122     }
123 
124     public delegate BigValue* BinaryOperatorDelegate(BigValue* leftBigValue* right);
125 
126     public nothrow BinaryOperatorDelegate GetBinaryOperatorDelegate(uchar opBigNumKind kind)
127     {
128         BinaryOperatorDelegate dlg;
129         switch (op)
130         {
131             case '+':
132             {
133                 switch (kind)
134                 {
135                     case BigNumKind.bigInt: dlg = Add<BigIntValue>; break;
136                     case BigNumKind.bigRational: dlg = Add<BigRationalValue>; break;
137                     case BigNumKind.bigFloat: dlg = Add<BigFloatValue>; break;
138                 }
139                 break;
140             }
141             case '-':
142             {
143                 switch (kind)
144                 {
145                     case BigNumKind.bigInt: dlg = Sub<BigIntValue>; break;
146                     case BigNumKind.bigRational: dlg = Sub<BigRationalValue>; break;
147                     case BigNumKind.bigFloat: dlg = Sub<BigFloatValue>; break;
148                 }
149                 break;
150             }
151             case '*':
152             {
153                 switch (kind)
154                 {
155                     case BigNumKind.bigInt: dlg = Mul<BigIntValue>; break;
156                     case BigNumKind.bigRational: dlg = Mul<BigRationalValue>; break;
157                     case BigNumKind.bigFloat: dlg = Mul<BigFloatValue>; break;
158                 }
159                 break;
160             }
161             case '/':
162             {
163                 switch (kind)
164                 {
165                     case BigNumKind.bigInt: dlg = Div<BigIntValue>; break;
166                     case BigNumKind.bigRational: dlg = Div<BigRationalValue>; break;
167                     case BigNumKind.bigFloat: dlg = Div<BigFloatValue>; break;
168                 }
169                 break;
170             }
171         }
172         return dlg;
173     }
174 
175     public BigValue* Evaluate(BigValue* leftBigValue* rightuchar op)
176     {
177         BigNumKind commonType = CommonType(left->Kind()right->Kind());
178         UniquePtr<BigValue> left_(left->As(commonType));
179         UniquePtr<BigValue> right_(right->As(commonType));
180         BinaryOperatorDelegate dlg = GetBinaryOperatorDelegate(opcommonType);
181         if (dlg != BinaryOperatorDelegate())
182         {
183             BigValue* result = dlg(left_.Get()right_.Get());
184             if (result != null)
185             {
186                 return result;
187             }
188             else
189             {
190                 throw Exception("operator '" + ToUtf8(CharStr(op)) + "' not implemented for these operand types");
191             }
192         }
193         else
194         {
195             throw Exception("operator '" + ToUtf8(CharStr(op)) + "' not implemented");
196         }
197     }
198 }