Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
BigNumber.cs
Go to the documentation of this file.
5using System.Text;
6
7namespace System.Numerics;
8
9internal static class BigNumber
10{
11 private struct BigNumberBuffer
12 {
14
15 public int precision;
16
17 public int scale;
18
19 public bool sign;
20
21 public static BigNumberBuffer Create()
22 {
23 BigNumberBuffer result = default(BigNumberBuffer);
24 result.digits = new StringBuilder();
25 return result;
26 }
27 }
28
29 private static readonly uint[] s_uint32PowersOfTen = new uint[10] { 1u, 10u, 100u, 1000u, 10000u, 100000u, 1000000u, 10000000u, 100000000u, 1000000000u };
30
31 internal static bool TryValidateParseStyleInteger(NumberStyles style, [NotNullWhen(false)] out ArgumentException e)
32 {
33 if (((uint)style & 0xFFFFFC00u) != 0)
34 {
36 return false;
37 }
38 if ((style & NumberStyles.AllowHexSpecifier) != 0 && ((uint)style & 0xFFFFFDFCu) != 0)
39 {
41 return false;
42 }
43 e = null;
44 return true;
45 }
46
47 internal static bool TryParseBigInteger(string value, NumberStyles style, NumberFormatInfo info, out BigInteger result)
48 {
49 if (value == null)
50 {
51 result = default(BigInteger);
52 return false;
53 }
54 return TryParseBigInteger(value.AsSpan(), style, info, out result);
55 }
56
58 {
59 if (!TryValidateParseStyleInteger(style, out var e))
60 {
61 throw e;
62 }
64 if (!FormatProvider.TryStringToBigInteger(value, style, info, number.digits, out number.precision, out number.scale, out number.sign))
65 {
66 result = default(BigInteger);
67 return false;
68 }
69 if ((style & NumberStyles.AllowHexSpecifier) != 0)
70 {
71 return HexNumberToBigInteger(ref number, out result);
72 }
73 return NumberToBigInteger(ref number, out result);
74 }
75
77 {
78 if (value == null)
79 {
80 throw new ArgumentNullException("value");
81 }
82 return ParseBigInteger(value.AsSpan(), style, info);
83 }
84
86 {
87 if (!TryValidateParseStyleInteger(style, out var e))
88 {
89 throw e;
90 }
91 if (!TryParseBigInteger(value, style, info, out var result))
92 {
94 }
95 return result;
96 }
97
98 private static bool HexNumberToBigInteger(ref BigNumberBuffer number, out BigInteger result)
99 {
100 if (number.digits == null || number.digits.Length == 0)
101 {
102 result = default(BigInteger);
103 return false;
104 }
105 int a = number.digits.Length - 1;
106 int result2;
107 int num = Math.DivRem(a, 8, out result2);
108 int num2;
109 if (result2 == 0)
110 {
111 num2 = 0;
112 }
113 else
114 {
115 num++;
116 num2 = 8 - result2;
117 }
118 bool flag = System.HexConverter.FromChar(number.digits[0]) >= 8;
119 uint num3 = ((flag && num2 > 0) ? uint.MaxValue : 0u);
120 int[] array = null;
121 Span<uint> span = ((num > 64) ? MemoryMarshal.Cast<int, uint>((array = ArrayPool<int>.Shared.Rent(num)).AsSpan(0, num)) : stackalloc uint[num]);
122 Span<uint> span2 = span;
123 int num4 = num - 1;
124 try
125 {
126 StringBuilder.ChunkEnumerator enumerator = number.digits.GetChunks().GetEnumerator();
127 while (enumerator.MoveNext())
128 {
129 ReadOnlySpan<char> span3 = enumerator.Current.Span;
130 for (int i = 0; i < span3.Length; i++)
131 {
132 char c = span3[i];
133 if (c == '\0')
134 {
135 break;
136 }
137 int num5 = System.HexConverter.FromChar(c);
138 num3 = (num3 << 4) | (uint)num5;
139 num2++;
140 if (num2 == 8)
141 {
142 span2[num4] = num3;
143 num4--;
144 num3 = 0u;
145 num2 = 0;
146 }
147 }
148 }
149 span2 = span2.TrimEnd(0u);
150 int num6;
151 uint[] array2;
152 if (span2.IsEmpty)
153 {
154 num6 = 0;
155 array2 = null;
156 }
157 else if (span2.Length == 1)
158 {
159 num6 = (int)span2[0];
160 array2 = null;
161 if ((!flag && num6 < 0) || num6 == int.MinValue)
162 {
163 array2 = new uint[1] { (uint)num6 };
164 num6 = ((!flag) ? 1 : (-1));
165 }
166 }
167 else
168 {
169 num6 = ((!flag) ? 1 : (-1));
170 array2 = span2.ToArray();
171 if (flag)
172 {
174 }
175 }
176 result = new BigInteger(num6, array2);
177 return true;
178 }
179 finally
180 {
181 if (array != null)
182 {
184 }
185 }
186 }
187
188 private static bool NumberToBigInteger(ref BigNumberBuffer number, out BigInteger result)
189 {
190 Span<uint> span = stackalloc uint[64];
191 Span<uint> currentBuffer2 = span;
192 int currentBufferSize = 0;
193 int[] arrayFromPool = null;
194 uint partialValue = 0u;
195 int partialDigitCount = 0;
196 int totalDigitCount = 0;
197 int numberScale = number.scale;
198 try
199 {
200 StringBuilder.ChunkEnumerator enumerator = number.digits.GetChunks().GetEnumerator();
201 while (enumerator.MoveNext())
202 {
203 if (!ProcessChunk(enumerator.Current.Span, ref currentBuffer2))
204 {
205 result = default(BigInteger);
206 return false;
207 }
208 }
209 if (partialDigitCount > 0)
210 {
211 MultiplyAdd(ref currentBuffer2, s_uint32PowersOfTen[partialDigitCount], partialValue);
212 }
213 int num;
214 for (num = numberScale - totalDigitCount; num >= 9; num -= 9)
215 {
216 MultiplyAdd(ref currentBuffer2, 1000000000u, 0u);
217 }
218 if (num > 0)
219 {
220 MultiplyAdd(ref currentBuffer2, s_uint32PowersOfTen[num], 0u);
221 }
222 int n;
223 uint[] rgu;
224 if (currentBufferSize == 0)
225 {
226 n = 0;
227 rgu = null;
228 }
229 else if (currentBufferSize == 1 && currentBuffer2[0] <= int.MaxValue)
230 {
231 n = (int)(number.sign ? (0L - (long)currentBuffer2[0]) : currentBuffer2[0]);
232 rgu = null;
233 }
234 else
235 {
236 n = ((!number.sign) ? 1 : (-1));
237 rgu = currentBuffer2.Slice(0, currentBufferSize).ToArray();
238 }
239 result = new BigInteger(n, rgu);
240 return true;
241 }
242 finally
243 {
244 if (arrayFromPool != null)
245 {
246 ArrayPool<int>.Shared.Return(arrayFromPool);
247 }
248 }
249 void MultiplyAdd(ref Span<uint> currentBuffer, uint multiplier, uint addValue)
250 {
251 Span<uint> span2 = currentBuffer.Slice(0, currentBufferSize);
252 uint num2 = addValue;
253 for (int i = 0; i < span2.Length; i++)
254 {
255 ulong num3 = (ulong)((long)multiplier * (long)span2[i] + num2);
256 span2[i] = (uint)num3;
257 num2 = (uint)(num3 >> 32);
258 }
259 if (num2 != 0)
260 {
261 if (currentBufferSize == currentBuffer.Length)
262 {
263 int[] array = arrayFromPool;
264 arrayFromPool = ArrayPool<int>.Shared.Rent(checked(currentBufferSize * 2));
265 Span<uint> span3 = MemoryMarshal.Cast<int, uint>(arrayFromPool);
266 currentBuffer.CopyTo(span3);
267 currentBuffer = span3;
268 if (array != null)
269 {
271 }
272 }
273 currentBuffer[currentBufferSize] = num2;
274 currentBufferSize++;
275 }
276 }
277 bool ProcessChunk(ReadOnlySpan<char> chunkDigits, ref Span<uint> currentBuffer)
278 {
279 int val = Math.Max(numberScale - totalDigitCount, 0);
280 ReadOnlySpan<char> readOnlySpan = chunkDigits.Slice(0, Math.Min(val, chunkDigits.Length));
281 bool flag = false;
282 uint num4 = partialValue;
283 int num5 = partialDigitCount;
284 int num6 = totalDigitCount;
285 for (int j = 0; j < readOnlySpan.Length; j++)
286 {
287 char c = chunkDigits[j];
288 if (c == '\0')
289 {
290 flag = true;
291 break;
292 }
293 num4 = num4 * 10 + (uint)(c - 48);
294 num5++;
295 num6++;
296 if (num5 == 9)
297 {
298 MultiplyAdd(ref currentBuffer, 1000000000u, num4);
299 num4 = 0u;
300 num5 = 0;
301 }
302 }
303 if (!flag)
304 {
305 ReadOnlySpan<char> readOnlySpan2 = chunkDigits.Slice(readOnlySpan.Length);
306 for (int k = 0; k < readOnlySpan2.Length; k++)
307 {
308 switch (readOnlySpan2[k])
309 {
310 default:
311 return false;
312 case '0':
313 continue;
314 case '\0':
315 break;
316 }
317 break;
318 }
319 }
320 partialValue = num4;
321 partialDigitCount = num5;
322 totalDigitCount = num6;
323 return true;
324 }
325 }
326
327 internal static char ParseFormatSpecifier(ReadOnlySpan<char> format, out int digits)
328 {
329 digits = -1;
330 if (format.Length == 0)
331 {
332 return 'R';
333 }
334 int num = 0;
335 char c = format[num];
336 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
337 {
338 num++;
339 int num2 = -1;
340 if (num < format.Length && format[num] >= '0' && format[num] <= '9')
341 {
342 num2 = format[num++] - 48;
343 while (num < format.Length && format[num] >= '0' && format[num] <= '9')
344 {
345 int num3 = num2 * 10 + (format[num++] - 48);
346 if (num3 < num2)
347 {
349 }
350 num2 = num3;
351 }
352 }
353 if (num >= format.Length || format[num] == '\0')
354 {
355 digits = num2;
356 return c;
357 }
358 }
359 return '\0';
360 }
361
362 private static string FormatBigIntegerToHex(bool targetSpan, BigInteger value, char format, int digits, NumberFormatInfo info, Span<char> destination, out int charsWritten, out bool spanSuccess)
363 {
364 byte[] array = null;
365 Span<byte> destination2 = stackalloc byte[64];
366 if (!value.TryWriteOrCountBytes(destination2, out var bytesWritten))
367 {
368 destination2 = (array = ArrayPool<byte>.Shared.Rent(bytesWritten));
369 bool flag = value.TryWriteBytes(destination2, out bytesWritten);
370 }
371 destination2 = destination2.Slice(0, bytesWritten);
372 Span<char> initialBuffer = stackalloc char[128];
373 System.Text.ValueStringBuilder valueStringBuilder = new System.Text.ValueStringBuilder(initialBuffer);
374 int num = destination2.Length - 1;
375 if (num > -1)
376 {
377 bool flag2 = false;
378 byte b = destination2[num];
379 if (b > 247)
380 {
381 b -= 240;
382 flag2 = true;
383 }
384 if (b < 8 || flag2)
385 {
386 valueStringBuilder.Append((b < 10) ? ((char)(b + 48)) : ((format == 'X') ? ((char)((b & 0xF) - 10 + 65)) : ((char)((b & 0xF) - 10 + 97))));
387 num--;
388 }
389 }
390 if (num > -1)
391 {
392 Span<char> span = valueStringBuilder.AppendSpan((num + 1) * 2);
393 int num2 = 0;
394 string text = ((format == 'x') ? "0123456789abcdef" : "0123456789ABCDEF");
395 while (num > -1)
396 {
397 byte b2 = destination2[num--];
398 span[num2++] = text[b2 >> 4];
399 span[num2++] = text[b2 & 0xF];
400 }
401 }
402 if (digits > valueStringBuilder.Length)
403 {
404 valueStringBuilder.Insert(0, (value._sign >= 0) ? '0' : ((format == 'x') ? 'f' : 'F'), digits - valueStringBuilder.Length);
405 }
406 if (array != null)
407 {
409 }
410 if (targetSpan)
411 {
412 spanSuccess = valueStringBuilder.TryCopyTo(destination, out charsWritten);
413 return null;
414 }
415 charsWritten = 0;
416 spanSuccess = false;
417 return valueStringBuilder.ToString();
418 }
419
421 {
422 int charsWritten;
423 bool spanSuccess;
424 return FormatBigInteger(targetSpan: false, value, format, format, info, default(Span<char>), out charsWritten, out spanSuccess);
425 }
426
428 {
429 FormatBigInteger(targetSpan: true, value, null, format, info, destination, out charsWritten, out var spanSuccess);
430 return spanSuccess;
431 }
432
433 private static string FormatBigInteger(bool targetSpan, BigInteger value, string formatString, ReadOnlySpan<char> formatSpan, NumberFormatInfo info, Span<char> destination, out int charsWritten, out bool spanSuccess)
434 {
435 int digits = 0;
436 char c = ParseFormatSpecifier(formatSpan, out digits);
437 if (c == 'x' || c == 'X')
438 {
439 return FormatBigIntegerToHex(targetSpan, value, c, digits, info, destination, out charsWritten, out spanSuccess);
440 }
441 if (value._bits == null)
442 {
443 if (c == 'g' || c == 'G' || c == 'r' || c == 'R')
444 {
445 formatSpan = (formatString = ((digits > 0) ? $"D{digits}" : "D"));
446 }
447 if (targetSpan)
448 {
449 spanSuccess = value._sign.TryFormat(destination, out charsWritten, formatSpan, info);
450 return null;
451 }
452 charsWritten = 0;
453 spanSuccess = false;
454 return value._sign.ToString(formatString, info);
455 }
456 int num = value._bits.Length;
457 uint[] array;
458 int num3;
459 int num4;
460 checked
461 {
462 int num2;
463 try
464 {
465 num2 = unchecked(checked(num * 10) / 9) + 2;
466 }
467 catch (OverflowException innerException)
468 {
469 throw new FormatException(System.SR.Format_TooLarge, innerException);
470 }
471 array = new uint[num2];
472 num3 = 0;
473 num4 = num;
474 }
475 while (--num4 >= 0)
476 {
477 uint num5 = value._bits[num4];
478 for (int i = 0; i < num3; i++)
479 {
480 ulong num6 = NumericsHelpers.MakeUlong(array[i], num5);
481 array[i] = (uint)(num6 % 1000000000);
482 num5 = (uint)(num6 / 1000000000);
483 }
484 if (num5 != 0)
485 {
486 array[num3++] = num5 % 1000000000;
487 num5 /= 1000000000;
488 if (num5 != 0)
489 {
490 array[num3++] = num5;
491 }
492 }
493 }
494 int num7;
495 bool flag;
496 char[] array2;
497 int num9;
498 checked
499 {
500 try
501 {
502 num7 = num3 * 9;
503 }
504 catch (OverflowException innerException2)
505 {
506 throw new FormatException(System.SR.Format_TooLarge, innerException2);
507 }
508 flag = c == 'g' || c == 'G' || c == 'd' || c == 'D' || c == 'r' || c == 'R';
509 if (flag)
510 {
511 if (digits > 0 && digits > num7)
512 {
513 num7 = digits;
514 }
515 if (value._sign < 0)
516 {
517 try
518 {
519 num7 += info.NegativeSign.Length;
520 }
521 catch (OverflowException innerException3)
522 {
523 throw new FormatException(System.SR.Format_TooLarge, innerException3);
524 }
525 }
526 }
527 int num8;
528 try
529 {
530 num8 = num7 + 1;
531 }
532 catch (OverflowException innerException4)
533 {
534 throw new FormatException(System.SR.Format_TooLarge, innerException4);
535 }
536 array2 = new char[num8];
537 num9 = num7;
538 }
539 for (int j = 0; j < num3 - 1; j++)
540 {
541 uint num10 = array[j];
542 int num11 = 9;
543 while (--num11 >= 0)
544 {
545 array2[--num9] = (char)(48 + num10 % 10);
546 num10 /= 10;
547 }
548 }
549 for (uint num12 = array[num3 - 1]; num12 != 0; num12 /= 10)
550 {
551 array2[--num9] = (char)(48 + num12 % 10);
552 }
553 if (!flag)
554 {
555 bool sign = value._sign < 0;
556 int precision = 29;
557 int scale = num7 - num9;
558 Span<char> initialBuffer = stackalloc char[128];
560 FormatProvider.FormatBigInteger(ref sb, precision, scale, sign, formatSpan, info, array2, num9);
561 if (targetSpan)
562 {
563 spanSuccess = sb.TryCopyTo(destination, out charsWritten);
564 return null;
565 }
566 charsWritten = 0;
567 spanSuccess = false;
568 return sb.ToString();
569 }
570 int num13 = num7 - num9;
571 while (digits > 0 && digits > num13)
572 {
573 array2[--num9] = '0';
574 digits--;
575 }
576 if (value._sign < 0)
577 {
578 string negativeSign = info.NegativeSign;
579 for (int num14 = negativeSign.Length - 1; num14 > -1; num14--)
580 {
581 array2[--num9] = negativeSign[num14];
582 }
583 }
584 int num15 = num7 - num9;
585 if (!targetSpan)
586 {
587 charsWritten = 0;
588 spanSuccess = false;
589 return new string(array2, num9, num7 - num9);
590 }
591 if (new ReadOnlySpan<char>(array2, num9, num7 - num9).TryCopyTo(destination))
592 {
593 charsWritten = num15;
594 spanSuccess = true;
595 return null;
596 }
597 charsWritten = 0;
598 spanSuccess = false;
599 return null;
600 }
601}
static ArrayPool< T > Shared
Definition ArrayPool.cs:7
static unsafe bool TryStringToBigInteger(ReadOnlySpan< char > s, NumberStyles styles, NumberFormatInfo numberFormatInfo, StringBuilder receiver, out int precision, out int scale, out bool sign)
static unsafe void FormatBigInteger(ref System.Text.ValueStringBuilder sb, int precision, int scale, bool sign, ReadOnlySpan< char > format, NumberFormatInfo numberFormatInfo, char[] digits, int startIndex)
static int FromChar(int c)
static byte Min(byte val1, byte val2)
Definition Math.cs:912
static int DivRem(int a, int b, out int result)
Definition Math.cs:329
static byte Max(byte val1, byte val2)
Definition Math.cs:738
static char ParseFormatSpecifier(ReadOnlySpan< char > format, out int digits)
Definition BigNumber.cs:327
static bool TryParseBigInteger(ReadOnlySpan< char > value, NumberStyles style, NumberFormatInfo info, out BigInteger result)
Definition BigNumber.cs:57
static bool TryValidateParseStyleInteger(NumberStyles style, [NotNullWhen(false)] out ArgumentException e)
Definition BigNumber.cs:31
static bool TryParseBigInteger(string value, NumberStyles style, NumberFormatInfo info, out BigInteger result)
Definition BigNumber.cs:47
static BigInteger ParseBigInteger(ReadOnlySpan< char > value, NumberStyles style, NumberFormatInfo info)
Definition BigNumber.cs:85
static BigInteger ParseBigInteger(string value, NumberStyles style, NumberFormatInfo info)
Definition BigNumber.cs:76
static string FormatBigInteger(BigInteger value, string format, NumberFormatInfo info)
Definition BigNumber.cs:420
static string FormatBigInteger(bool targetSpan, BigInteger value, string formatString, ReadOnlySpan< char > formatSpan, NumberFormatInfo info, Span< char > destination, out int charsWritten, out bool spanSuccess)
Definition BigNumber.cs:433
static string FormatBigIntegerToHex(bool targetSpan, BigInteger value, char format, int digits, NumberFormatInfo info, Span< char > destination, out int charsWritten, out bool spanSuccess)
Definition BigNumber.cs:362
static readonly uint[] s_uint32PowersOfTen
Definition BigNumber.cs:29
static bool HexNumberToBigInteger(ref BigNumberBuffer number, out BigInteger result)
Definition BigNumber.cs:98
static bool TryFormatBigInteger(BigInteger value, ReadOnlySpan< char > format, NumberFormatInfo info, Span< char > destination, out int charsWritten)
Definition BigNumber.cs:427
static bool NumberToBigInteger(ref BigNumberBuffer number, out BigInteger result)
Definition BigNumber.cs:188
static ulong MakeUlong(uint uHi, uint uLo)
static void DangerousMakeTwosComplement(Span< uint > d)
static string Argument_InvalidNumberStyles
Definition SR.cs:720
static string Overflow_ParseBigInteger
Definition SR.cs:30
static string Format(string resourceFormat, object p1)
Definition SR.cs:118
static string Argument_BadFormatSpecifier
Definition SR.cs:488
static string Format_TooLarge
Definition SR.cs:22
static string Argument_InvalidHexStyle
Definition SR.cs:18
Definition SR.cs:7
static BigNumberBuffer Create()
Definition BigNumber.cs:21
unsafe ReadOnlySpan< T > Span
ReadOnlySpan< T > Slice(int start)
override string ToString()
bool IsEmpty
Definition Span.cs:79
Span< T > Slice(int start)
Definition Span.cs:271
T[] ToArray()
Definition Span.cs:291
int Length
Definition Span.cs:70
void Insert(int index, string s)
bool TryCopyTo(Span< char > destination, out int charsWritten)
Span< char > AppendSpan(int length)