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; } }
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); } }
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; } }
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); }
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); }
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); }