Beispiel #1
0
        public void Add(Type commonType, BinaryCallTarget implementation, TypeConverter resultConverter)
        {
            TypePair       key = new TypePair(commonType, commonType);
            DispatchRecord rec = new DispatchRecord(key, commonType, null, null, resultConverter, implementation);

            Add(rec);
        }
Beispiel #2
0
        public void Evaluate(EvaluationContext context)
        {
            DispatchRecord record = null;

            try {
                Type     arg1Type = (context.Arg1 == null ? null : context.Arg1.GetType());
                Type     arg2Type = (context.Arg2 == null ? null : context.Arg2.GetType());
                TypePair key      = new TypePair(arg1Type, arg2Type);
                //FIND RECORD for types - remember threads!!! We don't use any locks here - see below Add(record) method.
                if (!DispatchRecords.TryGetValue(key, out record))
                {
                    record = this.Runtime.CreateDispatchRecord(this, key);
                }
                context.CurrentResult = record.Evaluate(context.Arg1, context.Arg2);
            } catch (OverflowException ex) {
                if (this.Runtime.HandleOverflow(ex, this, record, context))
                {
                    Evaluate(context); //recursively call self again, with new arg types
                }
            } catch (Exception ex) {
                if (!this.Runtime.HandleException(ex, this, record, context))
                {
                    throw;
                }
            }
        }
Beispiel #3
0
        //This is just a sketch
        //TODO: implement customizable behavior, using dictionary type->type, to specify to which  type to switch in case of overflow
        public virtual bool HandleOverflow(Exception ex, CallDispatcher dispatcher, DispatchRecord failedRecord, EvaluationContext context)
        {
            //get the common type and decide what to do...
            Type newType = null;

            switch (failedRecord.CommonType.Name)
            {
            case "Byte":
            case "SByte":
            case "Int16":
            case "UInt16":
            case "Int32":
            case "UInt32":
                newType = typeof(Int64);
                break;

            case "Int64":
            case "UInt64":
                newType = typeof(BigInteger);
                break;

            case "Single":
                newType = typeof(double);
                break;
            }
            if (newType == null)
            {
                throw ex;
            }
            context.CallArgs[0] = Convert.ChangeType(context.CallArgs[0], newType);
            context.CallArgs[1] = Convert.ChangeType(context.CallArgs[1], newType);
            return(true);
        }
Beispiel #4
0
 // Thread safety. We don't want to slow down operator evaluation, so in Evaluate method
 // we call DispatchRecords.TryGetValue without any locks.
 // However, we need to update the DispatchRecords table from time to time
 // adding records for new combinations of arg types.
 // Here's how we do it. We maintain two identical copies of DispatchRecords table: primary and clone.
 // When we need to add a record, we first add it to the clone;
 // next, in atomic operation (using Interlocked) we swap primary and clone tables.
 // Finally, we add the new record to the clone table, which is the former primary.
 #endregion
 internal void Add(DispatchRecord record)
 {
     lock (this) {                                  //lock the whole operation
         DispatchRecordsClone[record.Key] = record; //add the record to clone
         //swap primary and clone tables in atomic operation
         //disable message "a reference to a volatile field will not be treated as volatile"; interlocked operations are exceptions
 #pragma warning disable 0420
         DispatchRecordsClone             = System.Threading.Interlocked.Exchange(ref DispatchRecords, DispatchRecordsClone);
         DispatchRecordsClone[record.Key] = record; //update new clone/former primary
     }
 }
Beispiel #5
0
        public virtual DispatchRecord CreateDispatchRecord(CallDispatcher dispatcher, TypePair forKey)
        {
            Type commonType = GetCommonType(dispatcher.MethodName, forKey.Arg1Type, forKey.Arg2Type);

            if (commonType == null)
            {
                return(null);
            }
            TypeConverter arg1Converter = GetConverter(forKey.Arg1Type, commonType);
            TypeConverter arg2Converter = GetConverter(forKey.Arg2Type, commonType);
            //Get base method for the operator and common type
            TypePair       baseKey = new TypePair(commonType, commonType);
            DispatchRecord rec     = dispatcher.GetRecord(baseKey);

            if (rec == null)
            {
                throw new RuntimeException("Operator or method " + dispatcher.MethodName + " is not defined for type " + commonType);
            }
            rec = new DispatchRecord(forKey, commonType, arg1Converter, arg2Converter, rec.ResultConverter, rec.Implementation);
            dispatcher.Add(rec);
            return(rec);
        }
Beispiel #6
0
 public virtual bool HandleException(Exception ex, CallDispatcher dispatcher, DispatchRecord failedTarget, EvaluationContext context)
 {
     return(false);
 }