Пример #1
0
        internal void Append(ReadOnlySpan <T> fromBuffer, int index, int length)
        {
            // we figured out that we can't be in place on
            //   the other buffer... but that doesn't actually
            //   matter until we next try to append.
            //
            // which is now, so copy everything out of the span
            //   into our local buffer and switch the mode
            //   to plain old Copy mode
            if (CurrentMode == Mode.CopyOnNextAppend)
            {
                SwitchToCopy(fromBuffer);
            }

            switch (CurrentMode)
            {
            case Mode.Uninitialized:
                CurrentMode = Mode.InPlace;
                StartIndex  = index;
                Length      = length;
                break;

            case Mode.Copy:
                var desiredSize = Length + length;
                if (desiredSize >= Copy.Length)
                {
                    ResizeCopy(desiredSize * 2);
                }

                fromBuffer.Slice(index, length).CopyTo(Copy.Slice(Length));
                Length += length;
                break;

            case Mode.InPlace:
                Length++;
                break;

            default:
                Throw.Exception($"Unexpected {nameof(Mode)}: {CurrentMode}");
                break;
            }
        }
Пример #2
0
        internal ReadOnlyMemory <T> AsMemory(ReadOnlyMemory <T> fromBufferMem)
        {
            switch (CurrentMode)
            {
            case Mode.CopyOnNextAppend:
            case Mode.InPlace:
                // we're able to just read out of the buffer, no intermediate copy required
                return(fromBufferMem.Slice(StartIndex, Length));

            case Mode.Copy:
                // whelp, we had to make a copy... better return it
                return(CopyOwner.Memory.Slice(StartIndex, Length));

            case Mode.Uninitialized:
                return(ReadOnlyMemory <T> .Empty);

            default:
                Throw.Exception($"Unexpected {nameof(Mode)}: {CurrentMode}");
                return(default);
            }
        }
Пример #3
0
        internal void Skipped()
        {
            // this means we can't jut blindly copy of out the backing buffer if
            //   another append comes through, so change state accordingly
            switch (CurrentMode)
            {
            case Mode.Uninitialized:
            case Mode.CopyOnNextAppend:
            case Mode.Copy:
                // nothing to do
                break;

            case Mode.InPlace:
                CurrentMode = Mode.CopyOnNextAppend;
                break;

            default:
                Throw.Exception($"Unexpected {nameof(Mode)}: {CurrentMode}");
                break;
            }
        }
Пример #4
0
        public override DynamicMetaObject BindConvert(ConvertBinder binder)
        {
            var converterInterface = Cell.Converter;
            var index     = Cell.ColumnNumber;
            var colName   = Cell.Row.Names?[index];
            var converter = converterInterface.GetCellConverter(index, colName, binder.ReturnType.GetTypeInfo());

            var restrictions = BindingRestrictions.GetTypeRestriction(Expression, LimitType);

            if (converter == null)
            {
                var throwMsg = Expression.Call(Methods.Throw.InvalidOperationException, Expression.Constant($"No cell converter discovered for {binder.ReturnType}"));

                return(new DynamicMetaObject(throwMsg, restrictions));
            }

            if (!binder.ReturnType.IsAssignableFrom(converter.TargetType))
            {
                var throwMsg = Expression.Call(Methods.Throw.InvalidOperationException, Expression.Constant($"Cell converter {converter} does not create a type assignable to {binder.ReturnType}, returns {converter.TargetType}"));

                return(new DynamicMetaObject(throwMsg, restrictions));
            }

            var selfAsCell = Expression.Convert(Expression, Types.DynamicCell);

            var callGetSpan = Expression.Call(selfAsCell, Methods.DynamicCell.GetDataSpan);

            var cons = converter.Constructor;

            if (cons != null)
            {
                var createType = Expression.New(converter.Constructor, callGetSpan);
                var cast       = Expression.Convert(createType, binder.ReturnType);

                return(new DynamicMetaObject(cast, restrictions));
            }

            var mtd = converter.Method;

            if (mtd != null)
            {
                var statements = new List <Expression>();

                var makeCtx = Expression.Call(selfAsCell, Methods.DynamicCell.GetReadContext);
                var outVar  = Expression.Parameter(converter.TargetType);
                var resVar  = Expression.Variable(Types.BoolType);

                var callConvert = Expression.Call(mtd, callGetSpan, makeCtx, outVar);
                var assignRes   = Expression.Assign(resVar, callConvert);

                statements.Add(assignRes);

                var callThrow = Expression.Call(Methods.Throw.InvalidOperationException, Expression.Constant($"{nameof(DynamicCellConverter)} returned false"));

                var ifNot = Expression.IfThen(Expression.Not(resVar), callThrow);
                statements.Add(ifNot);

                var convertOut = Expression.Convert(outVar, binder.ReturnType);
                statements.Add(convertOut);

                var block = Expression.Block(new ParameterExpression[] { outVar, resVar }, statements);

                return(new DynamicMetaObject(block, restrictions));
            }

            Throw.Exception("Converter could not be turned into an expression, this shouldn't be possible");
            return(null);
        }
Пример #5
0
        private bool ProcessBuffer(int bufferLen, out int unprocessedCharacters)
        {
            var buffSpan = Buffer.Buffer.Span;

            ReaderStateMachine.AdvanceResult?inBatchableResult = null;
            var consistentResultSince = -1;

            for (var i = 0; i < bufferLen; i++)
            {
                var c   = buffSpan[i];
                var res = StateMachine.Advance(c);

                // try and batch skips and appends
                //   to save time on copying AND on
                //   basically pointless method calls
                if (inBatchableResult != null)
                {
                    if (res == inBatchableResult)
                    {
                        continue;
                    }
                    else
                    {
                        switch (inBatchableResult.Value)
                        {
                        case ReaderStateMachine.AdvanceResult.Skip_Character:

                            // there's no distinction between skipping several characters and skipping one
                            //    so this doesn't need the length
                            Partial.SkipCharacter();
                            break;

                        case ReaderStateMachine.AdvanceResult.Append_Character:
                            var length = i - consistentResultSince;

                            Partial.AppendCharacters(buffSpan, consistentResultSince, length);
                            break;

                        default:
                            Throw.Exception($"Unexpected {nameof(ReaderStateMachine.AdvanceResult)}: {inBatchableResult.Value}");
                            break;
                        }

                        inBatchableResult     = null;
                        consistentResultSince = -1;

                        // fall through into the switch to handle the current character
                    }
                }

                switch (res)
                {
                case ReaderStateMachine.AdvanceResult.Skip_Character:
                    if (inBatchableResult == null)
                    {
                        inBatchableResult     = ReaderStateMachine.AdvanceResult.Skip_Character;
                        consistentResultSince = i;
                        continue;
                    }

                    Partial.SkipCharacter();
                    break;

                case ReaderStateMachine.AdvanceResult.Append_Character:
                    if (inBatchableResult == null)
                    {
                        inBatchableResult     = ReaderStateMachine.AdvanceResult.Append_Character;
                        consistentResultSince = i;
                        continue;
                    }

                    Partial.AppendCharacters(buffSpan, i, 1);
                    break;

                case ReaderStateMachine.AdvanceResult.Finished_Value:
                    PushPendingCharactersToValue();
                    break;

                case ReaderStateMachine.AdvanceResult.Finished_Record:
                    if (Partial.PendingCharsCount > 0)
                    {
                        PushPendingCharactersToValue();
                    }

                    unprocessedCharacters = bufferLen - i - 1;
                    return(true);

                case ReaderStateMachine.AdvanceResult.Exception_ExpectedEndOfRecord:
                    Throw.InvalidOperationException($"Encountered '{c}' when expecting end of record");
                    break;

                case ReaderStateMachine.AdvanceResult.Exception_InvalidState:
                    Throw.InvalidOperationException($"Internal state machine is in an invalid state due to a previous error");
                    break;

                case ReaderStateMachine.AdvanceResult.Exception_StartEscapeInValue:
                    Throw.InvalidOperationException($"Encountered '{c}', starting an escaped value, when already in a value");
                    break;

                case ReaderStateMachine.AdvanceResult.Exception_UnexpectedCharacterInEscapeSequence:
                    Throw.InvalidOperationException($"Encountered '{c}' in an escape sequence, which is invalid");
                    break;

                case ReaderStateMachine.AdvanceResult.Exception_UnexpectedLineEnding:
                    Throw.Exception($"Unexpected {nameof(Cesil.RowEndings)} value encountered");
                    break;

                case ReaderStateMachine.AdvanceResult.Exception_UnexpectedState:
                    Throw.Exception($"Unexpected state value entered");
                    break;

                case ReaderStateMachine.AdvanceResult.Exception_ExpectedEndOfRecordOrValue:
                    Throw.InvalidOperationException($"Encountered '{c}' when expecting the end of a record or value");
                    break;

                default:
                    Throw.Exception($"Unexpected {nameof(ReaderStateMachine.AdvanceResult)}: {res}");
                    break;
                }
            }

            // handle any batch that was still pending
            if (inBatchableResult != null)
            {
                switch (inBatchableResult.Value)
                {
                case ReaderStateMachine.AdvanceResult.Skip_Character:

                    // there's no distinction between skipping several characters and skipping one
                    //    so this doesn't need the length
                    Partial.SkipCharacter();
                    break;

                case ReaderStateMachine.AdvanceResult.Append_Character:
                    // we read all the up to the end, so length needs to include the last character
                    var length = bufferLen - consistentResultSince;

                    Partial.AppendCharacters(buffSpan, consistentResultSince, length);
                    break;

                default:
                    Throw.Exception($"Unexpected {nameof(ReaderStateMachine.AdvanceResult)}: {inBatchableResult.Value}");
                    break;
                }
            }

            unprocessedCharacters = 0;
            return(false);
        }
Пример #6
0
        public override DynamicMetaObject BindConvert(ConvertBinder binder)
        {
            var converterInterface = Row.Converter;
            var index       = Row.RowNumber;
            var columnNames = Row.Names;
            var converter   = converterInterface.GetRowConverter(index, Row.Width, columnNames, binder.ReturnType.GetTypeInfo());

            var restrictions = BindingRestrictions.GetTypeRestriction(Expression, LimitType);

            if (converter == null)
            {
                var throwMsg = Expression.Call(Methods.Throw.InvalidOperationException, Expression.Constant($"No row converter discovered for {binder.ReturnType}"));

                return(new DynamicMetaObject(throwMsg, restrictions));
            }

            if (!binder.ReturnType.IsAssignableFrom(converter.TargetType))
            {
                var throwMsg = Expression.Call(Methods.Throw.InvalidOperationException, Expression.Constant($"Row converter {converter} does not create a type assignable to {binder.ReturnType}, returns {converter.TargetType}"));

                return(new DynamicMetaObject(throwMsg, restrictions));
            }

            var selfAsRow = Expression.Convert(Expression, Types.DynamicRow);

            var cons = converter.ConstructorForObject;

            if (cons != null)
            {
                var createType = Expression.New(cons, selfAsRow);
                var cast       = Expression.Convert(createType, binder.ReturnType);

                return(new DynamicMetaObject(cast, restrictions));
            }

            var mtd = converter.Method;

            if (mtd != null)
            {
                var statements = new List <Expression>();

                var callGetContext = Expression.Call(selfAsRow, Methods.DynamicRow.GetReadContext);

                var outVar = Expression.Parameter(converter.TargetType);
                var resVar = Expression.Variable(Types.BoolType);

                var callConvert = Expression.Call(mtd, selfAsRow, callGetContext, outVar);
                var assignRes   = Expression.Assign(resVar, callConvert);

                statements.Add(assignRes);

                var callThrow = Expression.Call(Methods.Throw.InvalidOperationException, Expression.Constant($"{nameof(DynamicRowConverter)} returned false"));

                var ifNot = Expression.IfThen(Expression.Not(resVar), callThrow);
                statements.Add(ifNot);

                var convertOut = Expression.Convert(outVar, binder.ReturnType);
                statements.Add(convertOut);

                var block = Expression.Block(new ParameterExpression[] { outVar, resVar }, statements);

                return(new DynamicMetaObject(block, restrictions));
            }

            var typedCons = converter.ConstructorTakingParams;

            if (typedCons != null)
            {
                var colsForPs  = converter.ColumnsForParameters;
                var paramTypes = converter.ParameterTypes;

                var ps = new List <Expression>();
                for (var pIx = 0; pIx < colsForPs.Length; pIx++)
                {
                    var colIx  = colsForPs[pIx];
                    var pType  = paramTypes[pIx];
                    var getter = Methods.DynamicRow.GetIndexTyped.MakeGenericMethod(pType);

                    var call = Expression.Call(selfAsRow, getter, Expression.Constant(colIx));

                    ps.Add(call);
                }

                var createType = Expression.New(typedCons, ps);
                var cast       = Expression.Convert(createType, binder.ReturnType);

                return(new DynamicMetaObject(cast, restrictions));
            }

            var zeroCons = converter.EmptyConstructor;

            if (zeroCons != null)
            {
                var setters      = converter.Setters;
                var setterParams = converter.SetterParameters;
                var setterCols   = converter.ColumnsForSetters;

                var retVar = Expression.Variable(converter.TargetType);

                var createType  = Expression.New(zeroCons);
                var assignToVar = Expression.Assign(retVar, createType);

                var statements = new List <Expression>();
                statements.Add(assignToVar);

                for (var i = 0; i < setters.Length; i++)
                {
                    var setter       = setters[i];
                    var setterParam  = setterParams[i];
                    var setterColumn = setterCols[i];

                    var        getValueMtd  = Methods.DynamicRow.GetIndexTyped.MakeGenericMethod(setterParam);
                    var        getValueCall = Expression.Call(selfAsRow, getValueMtd, Expression.Constant(setterColumn));
                    Expression callSetter;
                    if (setter.IsStatic)
                    {
                        callSetter = Expression.Call(setter, getValueCall);
                    }
                    else
                    {
                        callSetter = Expression.Call(retVar, setter, getValueCall);
                    }

                    statements.Add(callSetter);
                }

                var cast = Expression.Convert(retVar, binder.ReturnType);
                statements.Add(cast);

                var block = Expression.Block(new[] { retVar }, statements);

                return(new DynamicMetaObject(block, restrictions));
            }

            Throw.Exception("Converter could not be turned into an expression, this shouldn't be possible");
            return(null);
        }