Created
May 22, 2018 18:39
-
-
Save KelsonBall/8234cc08825799e95c3224e7a74d7f5c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
// include prerelease nuget package 'System.Memory' | |
public static class CharSpanExtensions | |
{ | |
public static DateTime ConsumeDateTime(this ReadOnlySpan<char> source, out ReadOnlySpan<char> remaining) | |
{ | |
// date time parsing is a nightmare, so take the heap allocation hit and have DateTime.Parse do it | |
int i = 0; | |
while (i < source.Length) | |
{ | |
char character = source[i]; | |
if (character == ',') | |
break; | |
i++; | |
} | |
remaining = source.ConsumeAt(i); | |
unsafe | |
{ | |
fixed (char* data = &source[0]) | |
{ | |
return DateTime.Parse(new string(data, 0, i)); | |
} | |
} | |
} | |
public static int ConsumeInt(this ReadOnlySpan<char> source, out ReadOnlySpan<char> remaining) | |
{ | |
int result = 0; | |
int place = 1; | |
int i = 0; | |
while (i < source.Length) | |
{ | |
char character = source[i]; | |
if (character == ',') | |
break; | |
result += (source[i] - 48) * place; | |
place *= 10; | |
i++; | |
} | |
remaining = source.ConsumeAt(i); | |
return result; | |
} | |
public static float ConsumeFloat(this ReadOnlySpan<char> source, out ReadOnlySpan<char> remaining) | |
{ | |
double result = 0; // keeping double percision while doing a bunch of math to reduce rounding errors | |
bool integer_component = true; | |
double divisor = 10.0; | |
int i = 0; | |
while (i < source.Length) | |
{ | |
char character = source[i]; | |
if (character == ',') | |
break; | |
int digit = source[i] - 48; | |
if (integer_component) | |
{ | |
result *= 10; | |
result += digit; | |
} | |
else | |
{ | |
result += digit / divisor; | |
divisor *= 10; | |
} | |
i++; | |
} | |
remaining = source.ConsumeAt(i); | |
return (float)result; // cast down to float | |
} | |
public static char ConsumeChar(this ReadOnlySpan<char> source, out ReadOnlySpan<char> remaining) | |
{ | |
remaining = source.ConsumeAt(1); | |
return source[0]; | |
} | |
public static string ConsumeString(this ReadOnlySpan<char> source, out ReadOnlySpan<char> remaining) | |
{ | |
int i = 0; | |
while (i < source.Length) | |
{ | |
char character = source[i]; | |
if (character == ',') | |
break; | |
i++; | |
} | |
remaining = source.ConsumeAt(i); | |
unsafe | |
{ | |
fixed (char* data = &source[0]) | |
{ | |
return new string(data, 0, i); | |
} | |
} | |
} | |
private static ReadOnlySpan<char> ConsumeAt(this ReadOnlySpan<char> source, int index) | |
{ | |
if (index >= source.Length) | |
return new ReadOnlySpan<char>(); // empty | |
if (source[index] == ',') | |
{ | |
if (source.Length >= index + 2) | |
{ | |
if (source[index + 1] == '\\' && source[index + 2] == 'r') | |
return source.Slice(index + 5); | |
else if (source[index + 1] == '\r') | |
return source.Slice(index + 3); | |
} | |
return source.Slice(index + 1); | |
} | |
return source.Slice(index); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment