| File: Utilities\LineParser.cs | Web Access |
| Project: src\src\Microsoft.ML.Core\Microsoft.ML.Core.csproj (Microsoft.ML.Core) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Runtime.CompilerServices; namespace Microsoft.ML.Internal.Utilities { [BestFriend] internal static class LineParser { public static (bool isSuccess, string key, float[] values) ParseKeyThenNumbers(string line, bool invariantCulture) { if (string.IsNullOrWhiteSpace(line)) return (false, null, null); ReadOnlySpan<char> trimmedLine = line.AsSpan().TrimEnd(); // TrimEnd creates a Span, no allocations int firstSeparatorIndex = trimmedLine.IndexOfAny(' ', '\t'); // the first word is the key, we just skip it ReadOnlySpan<char> valuesToParse = trimmedLine.Slice(start: firstSeparatorIndex + 1); float[] values = AllocateFixedSizeArrayToStoreParsedValues(valuesToParse); int toParseStartIndex = 0; int valueIndex = 0; for (int i = 0; i <= valuesToParse.Length; i++) { if (i == valuesToParse.Length || valuesToParse[i] == ' ' || valuesToParse[i] == '\t') { if (invariantCulture) { if (DoubleParser.TryParse(valuesToParse.Slice(toParseStartIndex, i - toParseStartIndex), out float parsed)) values[valueIndex++] = parsed; else return (false, null, null); } else { if (float.TryParse(valuesToParse.Slice(toParseStartIndex, i - toParseStartIndex).ToString(), out float parsed)) values[valueIndex++] = parsed; else return (false, null, null); } toParseStartIndex = i + 1; } } return (true, trimmedLine.Slice(0, firstSeparatorIndex).ToString(), values); } /// <summary> /// we count the number of values first to allocate a single array with of proper size /// </summary> [MethodImpl(MethodImplOptions.AggressiveInlining)] private static float[] AllocateFixedSizeArrayToStoreParsedValues(ReadOnlySpan<char> valuesToParse) { int valuesCount = 0; for (int i = 0; i < valuesToParse.Length; i++) if (valuesToParse[i] == ' ' || valuesToParse[i] == '\t') valuesCount++; return new float[valuesCount + 1]; // + 1 because the line is trimmed and there is no whitespace at the end } } }