예제 #1
0
        public static bool TryParseSByte(ReadOnlySpan <byte> text, out sbyte value, out int bytesConsumed, ParsedFormat format = default, SymbolTable symbolTable = null)
        {
            symbolTable = symbolTable ?? SymbolTable.InvariantUtf8;

            if (!format.IsDefault && format.HasPrecision)
            {
                throw new NotImplementedException("Format with precision not supported.");
            }

            if (symbolTable == SymbolTable.InvariantUtf8)
            {
                if (IsHexFormat(format))
                {
                    return(InvariantUtf8.Hex.TryParseSByte(text, out value, out bytesConsumed));
                }
                else
                {
                    return(InvariantUtf8.TryParseSByte(text, out value, out bytesConsumed));
                }
            }
            else if (symbolTable == SymbolTable.InvariantUtf16)
            {
                ReadOnlySpan <char> utf16Text = text.NonPortableCast <byte, char>();
                int  charsConsumed;
                bool result;
                if (IsHexFormat(format))
                {
                    result = InvariantUtf16.Hex.TryParseSByte(utf16Text, out value, out charsConsumed);
                }
                else
                {
                    result = InvariantUtf16.TryParseSByte(utf16Text, out value, out charsConsumed);
                }
                bytesConsumed = charsConsumed * sizeof(char);
                return(result);
            }

            if (IsHexFormat(format))
            {
                throw new NotImplementedException("The only supported encodings for hexadecimal parsing are InvariantUtf8 and InvariantUtf16.");
            }

            if (!(format.IsDefault || format.Symbol == 'G' || format.Symbol == 'g'))
            {
                throw new NotImplementedException(String.Format("Format '{0}' not supported.", format.Symbol));
            }

            SymbolTable.Symbol nextSymbol;
            int thisSymbolConsumed;

            if (!symbolTable.TryParse(text, out nextSymbol, out thisSymbolConsumed))
            {
                value         = default;
                bytesConsumed = 0;
                return(false);
            }

            int sign = 1;

            if (nextSymbol == SymbolTable.Symbol.MinusSign)
            {
                sign = -1;
            }

            int signConsumed = 0;

            if (nextSymbol == SymbolTable.Symbol.PlusSign || nextSymbol == SymbolTable.Symbol.MinusSign)
            {
                signConsumed = thisSymbolConsumed;
                if (!symbolTable.TryParse(text.Slice(signConsumed), out nextSymbol, out thisSymbolConsumed))
                {
                    value         = default;
                    bytesConsumed = 0;
                    return(false);
                }
            }

            if (nextSymbol > SymbolTable.Symbol.D9)
            {
                value         = default;
                bytesConsumed = 0;
                return(false);
            }

            int parsedValue = (int)nextSymbol;
            int index       = signConsumed + thisSymbolConsumed;

            while (index < text.Length)
            {
                bool success = symbolTable.TryParse(text.Slice(index), out nextSymbol, out thisSymbolConsumed);
                if (!success || nextSymbol > SymbolTable.Symbol.D9)
                {
                    bytesConsumed = index;
                    value         = (sbyte)(parsedValue * sign);
                    return(true);
                }

                // If parsedValue > (sbyte.MaxValue / 10), any more appended digits will cause overflow.
                // if parsedValue == (sbyte.MaxValue / 10), any nextDigit greater than 7 or 8 (depending on sign) implies overflow.
                bool positive          = sign > 0;
                bool nextDigitTooLarge = nextSymbol > SymbolTable.Symbol.D8 || (positive && nextSymbol > SymbolTable.Symbol.D7);
                if (parsedValue > sbyte.MaxValue / 10 || (parsedValue == sbyte.MaxValue / 10 && nextDigitTooLarge))
                {
                    bytesConsumed = 0;
                    value         = default;
                    return(false);
                }

                index      += thisSymbolConsumed;
                parsedValue = parsedValue * 10 + (int)nextSymbol;
            }

            bytesConsumed = text.Length;
            value         = (sbyte)(parsedValue * sign);
            return(true);
        }
예제 #2
0
        public static bool TryFormatNumber(double value, bool isSingle, Span <byte> buffer, out int bytesWritten, ParsedFormat format = default, SymbolTable symbolTable = null)
        {
            Precondition.Require(format.Symbol == 'G' || format.Symbol == 'E' || format.Symbol == 'F');

            symbolTable = symbolTable ?? SymbolTable.InvariantUtf8;

            bytesWritten = 0;
            int written;

            if (Double.IsNaN(value))
            {
                return(symbolTable.TryEncode(SymbolTable.Symbol.NaN, buffer, out bytesWritten));
            }

            if (Double.IsInfinity(value))
            {
                if (Double.IsNegativeInfinity(value))
                {
                    if (!symbolTable.TryEncode(SymbolTable.Symbol.MinusSign, buffer, out written))
                    {
                        bytesWritten = 0;
                        return(false);
                    }
                    bytesWritten += written;
                }
                if (!symbolTable.TryEncode(SymbolTable.Symbol.InfinitySign, buffer.Slice(bytesWritten), out written))
                {
                    bytesWritten = 0;
                    return(false);
                }
                bytesWritten += written;
                return(true);
            }

            // TODO: the lines below need to be replaced with properly implemented algorithm
            // the problem is the algorithm is complex, so I am commiting a stub for now
            var hack       = value.ToString(format.Symbol.ToString());
            var utf16Bytes = hack.AsReadOnlySpan().AsBytes();

            if (symbolTable == SymbolTable.InvariantUtf8)
            {
                var status = Encoders.Utf16.ToUtf8(utf16Bytes, buffer, out int consumed, out bytesWritten);
                return(status == Buffers.TransformationStatus.Done);
            }
            else if (symbolTable == SymbolTable.InvariantUtf16)
            {
                bytesWritten = utf16Bytes.Length;
                if (utf16Bytes.TryCopyTo(buffer))
                {
                    return(true);
                }

                bytesWritten = 0;
                return(false);
            }
            else
            {
                // TODO: This is currently pretty expensive. Can this be done more efficiently?
                //       Note: removing the hack might solve this problem a very different way.
                var status = Encoders.Utf16.ToUtf8Length(utf16Bytes, out int needed);
                if (status != Buffers.TransformationStatus.Done)
                {
                    bytesWritten = 0;
                    return(false);
                }

                Span <byte> temp;
                unsafe
                {
                    var buf = stackalloc byte[needed];
                    temp = new Span <byte>(buf, needed);
                }

                status = Encoders.Utf16.ToUtf8(utf16Bytes, temp, out int consumed, out written);
                if (status != Buffers.TransformationStatus.Done)
                {
                    bytesWritten = 0;
                    return(false);
                }

                return(symbolTable.TryEncode(temp, buffer, out consumed, out bytesWritten));
            }
        }
예제 #3
0
        public static bool TryParseInt32(ReadOnlySpan <byte> text, out int value, out int bytesConsumed, ParsedFormat format = default, SymbolTable symbolTable = null)
        {
            bool isDefault = format.IsDefault;

            symbolTable = symbolTable ?? SymbolTable.InvariantUtf8;

            if (!isDefault && format.HasPrecision)
            {
                throw new NotImplementedException("Format with precision not supported.");
            }

            bool isHex = IsHexFormat(format);

            if (symbolTable == SymbolTable.InvariantUtf8)
            {
                return(isHex ? InvariantUtf8.Hex.TryParseInt32(text, out value, out bytesConsumed) :
                       InvariantUtf8.TryParseInt32(text, out value, out bytesConsumed));
            }
            else if (symbolTable == SymbolTable.InvariantUtf16)
            {
                /*return isHex ? InvariantUtf16.Hex.TryParseInt32(text, out value, out bytesConsumed) :
                 *  InvariantUtf16.TryParseInt32(text, out value, out bytesConsumed);*/
                ReadOnlySpan <char> utf16Text = text.NonPortableCast <byte, char>();
                bool result = isHex ? InvariantUtf16.Hex.TryParseInt32(utf16Text, out value, out int charsConsumed) :
                              InvariantUtf16.TryParseInt32(utf16Text, out value, out charsConsumed);
                bytesConsumed = charsConsumed * sizeof(char);
                return(result);
            }

            if (isHex)
            {
                throw new NotImplementedException("The only supported encodings for hexadecimal parsing are InvariantUtf8 and InvariantUtf16.");
            }

            if (!(isDefault || format.Symbol == 'G' || format.Symbol == 'g'))
            {
                throw new NotImplementedException(String.Format("Format '{0}' not supported.", format.Symbol));
            }

            int textLength = text.Length;

            if (textLength < 1)
            {
                goto FalseExit;
            }

            if (!symbolTable.TryParse(text, out SymbolTable.Symbol symbol, out int consumed))
            {
                goto FalseExit;
            }

            sbyte sign  = 1;
            int   index = 0;

            if (symbol == SymbolTable.Symbol.MinusSign)
            {
                sign   = -1;
                index += consumed;
                if (index >= textLength)
                {
                    goto FalseExit;
                }
                if (!symbolTable.TryParse(text.Slice(index), out symbol, out consumed))
                {
                    goto FalseExit;
                }
            }
            else if (symbol == SymbolTable.Symbol.PlusSign)
            {
                index += consumed;
                if (index >= textLength)
                {
                    goto FalseExit;
                }
                if (!symbolTable.TryParse(text.Slice(index), out symbol, out consumed))
                {
                    goto FalseExit;
                }
            }

            int answer = 0;

            if (IsValid(symbol))
            {
                int numBytes = consumed;
                if (symbol == SymbolTable.Symbol.D0)
                {
                    do
                    {
                        index += consumed;
                        if (index >= textLength)
                        {
                            goto Done;
                        }
                        if (!symbolTable.TryParse(text.Slice(index), out symbol, out consumed))
                        {
                            goto Done;
                        }
                    } while (symbol == SymbolTable.Symbol.D0);
                    if (!IsValid(symbol))
                    {
                        goto Done;
                    }
                }

                int firstNonZeroDigitIndex = index;
                if (textLength - firstNonZeroDigitIndex < Int32OverflowLength * numBytes)
                {
                    do
                    {
                        answer = answer * 10 + (int)symbol;
                        index += consumed;
                        if (index >= textLength)
                        {
                            goto Done;
                        }
                        if (!symbolTable.TryParse(text.Slice(index), out symbol, out consumed))
                        {
                            goto Done;
                        }
                    } while (IsValid(symbol));
                }
                else
                {
                    do
                    {
                        answer = answer * 10 + (int)symbol;
                        index += consumed;
                        if (index - firstNonZeroDigitIndex == (Int32OverflowLength - 1) * numBytes)
                        {
                            if (!symbolTable.TryParse(text.Slice(index), out symbol, out consumed))
                            {
                                goto Done;
                            }
                            if (IsValid(symbol))
                            {
                                if (WillOverFlow(answer, (int)symbol, sign))
                                {
                                    goto FalseExit;
                                }
                                answer = answer * 10 + (int)symbol;
                                index += consumed;
                            }
                            goto Done;
                        }
                        if (!symbolTable.TryParse(text.Slice(index), out symbol, out consumed))
                        {
                            goto Done;
                        }
                    } while (IsValid(symbol));
                }
                goto Done;
            }

FalseExit:
            bytesConsumed = 0;
            value         = 0;
            return(false);

Done:
            bytesConsumed = index;
            value         = answer * sign;
            return(true);
        }
예제 #4
0
 public static bool TryFormat(this double value, Span <byte> buffer, out int bytesWritten, ParsedFormat format = default, SymbolTable symbolTable = null)
 {
     if (format.IsDefault)
     {
         format = 'G';
     }
     Precondition.Require(format.Symbol == 'G');
     symbolTable = symbolTable ?? SymbolTable.InvariantUtf8;
     return(FloatFormatter.TryFormatNumber(value, false, buffer, out bytesWritten, format, symbolTable));
 }
예제 #5
0
 static bool TryFormatDateTimeFormatG(DateTime value, TimeSpan offset, Span <byte> buffer, out int bytesWritten, SymbolTable symbolTable)
 {
     // for now it only works for invariant culture
     if (symbolTable == SymbolTable.InvariantUtf8)
     {
         return(InvariantUtf8TimeFormatter.TryFormatG(value, offset, buffer, out bytesWritten));
     }
     else if (symbolTable == SymbolTable.InvariantUtf16)
     {
         return(InvariantUtf16TimeFormatter.TryFormatG(value, offset, buffer, out bytesWritten));
     }
     else
     {
         throw new NotImplementedException();
     }
 }
예제 #6
0
        public static bool TryFormat(this TimeSpan value, Span <byte> buffer, out int bytesWritten, TextFormat format = default, SymbolTable symbolTable = null)
        {
            if (format.IsDefault)
            {
                format.Symbol = 'c';
            }

            Precondition.Require(format.Symbol == 'G' || format.Symbol == 'g' || format.Symbol == 'c' || format.Symbol == 't' || format.Symbol == 'T');

            symbolTable = symbolTable ?? SymbolTable.InvariantUtf8;

            return(TryFormatTimeSpan(value, format.Symbol, buffer, out bytesWritten, symbolTable));
        }
예제 #7
0
        public static bool TryFormat(this DateTime value, Span <byte> buffer, out int bytesWritten, TextFormat format = default, SymbolTable symbolTable = null)
        {
            if (format.IsDefault)
            {
                format.Symbol = 'G';
            }

            Precondition.Require(format.Symbol == 'R' || format.Symbol == 'O' || format.Symbol == 'G');

            symbolTable = symbolTable ?? SymbolTable.InvariantUtf8;

            switch (format.Symbol)
            {
            case 'R':
                return(TryFormatDateTimeRfc1123(value, buffer, out bytesWritten, symbolTable));

            case 'O':
                return(TryFormatDateTimeFormatO(value, NullOffset, buffer, out bytesWritten, symbolTable));

            case 'G':
                return(TryFormatDateTimeFormatG(value, NullOffset, buffer, out bytesWritten, symbolTable));

            default:
                throw new NotImplementedException();
            }
        }