|
4 | 4 | using System.Diagnostics.CodeAnalysis; |
5 | 5 | using System.Globalization; |
6 | 6 | using System.Net; |
| 7 | +using System.Runtime.CompilerServices; |
7 | 8 | using System.Text; |
8 | 9 |
|
9 | 10 | #if UNIX_SOCKET |
@@ -168,24 +169,41 @@ internal static bool TryParseDouble(string? s, out double value) |
168 | 169 | value = s[0] - '0'; |
169 | 170 | return true; |
170 | 171 | // RESP3 spec demands inf/nan handling |
171 | | - case 3 when CaseInsensitiveASCIIEqual("inf", s): |
172 | | - value = double.PositiveInfinity; |
173 | | - return true; |
174 | | - case 3 when CaseInsensitiveASCIIEqual("nan", s): |
175 | | - value = double.NaN; |
176 | | - return true; |
177 | | - case 4 when CaseInsensitiveASCIIEqual("+inf", s): |
178 | | - value = double.PositiveInfinity; |
179 | | - return true; |
180 | | - case 4 when CaseInsensitiveASCIIEqual("-inf", s): |
181 | | - value = double.NegativeInfinity; |
182 | | - return true; |
183 | | - case 4 when CaseInsensitiveASCIIEqual("+nan", s): |
184 | | - case 4 when CaseInsensitiveASCIIEqual("-nan", s): |
185 | | - value = double.NaN; |
| 172 | + case 3 when TryParseInfNaN(s.AsSpan(), true, out value): |
| 173 | + case 4 when s[0] == '+' && TryParseInfNaN(s.AsSpan(1), true, out value): |
| 174 | + case 4 when s[0] == '-' && TryParseInfNaN(s.AsSpan(1), false, out value): |
186 | 175 | return true; |
187 | 176 | } |
188 | 177 | return double.TryParse(s, NumberStyles.Any, NumberFormatInfo.InvariantInfo, out value); |
| 178 | + |
| 179 | + static bool TryParseInfNaN(ReadOnlySpan<char> s, bool positive, out double value) |
| 180 | + { |
| 181 | + switch (s[0]) |
| 182 | + { |
| 183 | + case 'i': |
| 184 | + case 'I': |
| 185 | + if (s[1] is 'n' or 'N' && s[2] is 'f' or 'F') |
| 186 | + { |
| 187 | + value = positive ? double.PositiveInfinity : double.NegativeInfinity; |
| 188 | + return true; |
| 189 | + } |
| 190 | + break; |
| 191 | + case 'n': |
| 192 | + case 'N': |
| 193 | + if (s[1] is 'a' or 'A' && s[2] is 'n' or 'N') |
| 194 | + { |
| 195 | + value = double.NaN; |
| 196 | + return true; |
| 197 | + } |
| 198 | + break; |
| 199 | + } |
| 200 | +#if NET6_0_OR_GREATER |
| 201 | + Unsafe.SkipInit(out value); |
| 202 | +#else |
| 203 | + value = 0; |
| 204 | +#endif |
| 205 | + return false; |
| 206 | + } |
189 | 207 | } |
190 | 208 |
|
191 | 209 | internal static bool TryParseUInt64(string s, out ulong value) => |
@@ -235,37 +253,41 @@ internal static bool TryParseDouble(ReadOnlySpan<byte> s, out double value) |
235 | 253 | value = s[0] - '0'; |
236 | 254 | return true; |
237 | 255 | // RESP3 spec demands inf/nan handling |
238 | | - case 3 when CaseInsensitiveASCIIEqual("inf", s): |
239 | | - value = double.PositiveInfinity; |
240 | | - return true; |
241 | | - case 3 when CaseInsensitiveASCIIEqual("nan", s): |
242 | | - value = double.NaN; |
243 | | - return true; |
244 | | - case 4 when CaseInsensitiveASCIIEqual("+inf", s): |
245 | | - value = double.PositiveInfinity; |
246 | | - return true; |
247 | | - case 4 when CaseInsensitiveASCIIEqual("-inf", s): |
248 | | - value = double.NegativeInfinity; |
249 | | - return true; |
250 | | - case 4 when CaseInsensitiveASCIIEqual("+nan", s): |
251 | | - case 4 when CaseInsensitiveASCIIEqual("-nan", s): |
252 | | - value = double.NaN; |
| 256 | + case 3 when TryParseInfNaN(s, true, out value): |
| 257 | + case 4 when s[0] == '+' && TryParseInfNaN(s.Slice(1), true, out value): |
| 258 | + case 4 when s[0] == '-' && TryParseInfNaN(s.Slice(1), false, out value): |
253 | 259 | return true; |
254 | 260 | } |
255 | 261 | return Utf8Parser.TryParse(s, out value, out int bytes) & bytes == s.Length; |
256 | | - } |
257 | 262 |
|
258 | | - private static bool CaseInsensitiveASCIIEqual(string xLowerCase, string y) |
259 | | - => string.Equals(xLowerCase, y, StringComparison.OrdinalIgnoreCase); |
260 | | - |
261 | | - private static bool CaseInsensitiveASCIIEqual(string xLowerCase, ReadOnlySpan<byte> y) |
262 | | - { |
263 | | - if (y.Length != xLowerCase.Length) return false; |
264 | | - for (int i = 0; i < y.Length; i++) |
| 263 | + static bool TryParseInfNaN(ReadOnlySpan<byte> s, bool positive, out double value) |
265 | 264 | { |
266 | | - if (char.ToLower((char)y[i]) != xLowerCase[i]) return false; |
| 265 | + switch (s[0]) |
| 266 | + { |
| 267 | + case (byte)'i': |
| 268 | + case (byte)'I': |
| 269 | + if (s[1] is (byte)'n' or (byte)'N' && s[2] is (byte)'f' or (byte)'F') |
| 270 | + { |
| 271 | + value = positive ? double.PositiveInfinity : double.NegativeInfinity; |
| 272 | + return true; |
| 273 | + } |
| 274 | + break; |
| 275 | + case (byte)'n': |
| 276 | + case (byte)'N': |
| 277 | + if (s[1] is (byte)'a' or (byte)'A' && s[2] is (byte)'n' or (byte)'N') |
| 278 | + { |
| 279 | + value = double.NaN; |
| 280 | + return true; |
| 281 | + } |
| 282 | + break; |
| 283 | + } |
| 284 | +#if NET6_0_OR_GREATER |
| 285 | + Unsafe.SkipInit(out value); |
| 286 | +#else |
| 287 | + value = 0; |
| 288 | +#endif |
| 289 | + return false; |
267 | 290 | } |
268 | | - return true; |
269 | 291 | } |
270 | 292 |
|
271 | 293 | /// <summary> |
|
0 commit comments