Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
TimeSpanFormat.cs
Go to the documentation of this file.
4using System.Text;
5
7
8internal static class TimeSpanFormat
9{
10 private enum StandardFormat
11 {
12 C,
13 G,
14 g
15 }
16
17 internal struct FormatLiterals
18 {
19 internal string AppCompatLiteral;
20
21 internal int dd;
22
23 internal int hh;
24
25 internal int mm;
26
27 internal int ss;
28
29 internal int ff;
30
31 private string[] _literals;
32
33 internal string Start => _literals[0];
34
35 internal string DayHourSep => _literals[1];
36
37 internal string HourMinuteSep => _literals[2];
38
39 internal string MinuteSecondSep => _literals[3];
40
41 internal string SecondFractionSep => _literals[4];
42
43 internal string End => _literals[5];
44
45 internal static FormatLiterals InitInvariant(bool isNegative)
46 {
47 FormatLiterals result = default(FormatLiterals);
48 result._literals = new string[6];
49 result._literals[0] = (isNegative ? "-" : string.Empty);
50 result._literals[1] = ".";
51 result._literals[2] = ":";
52 result._literals[3] = ":";
53 result._literals[4] = ".";
54 result._literals[5] = string.Empty;
55 result.AppCompatLiteral = ":.";
56 result.dd = 2;
57 result.hh = 2;
58 result.mm = 2;
59 result.ss = 2;
60 result.ff = 7;
61 return result;
62 }
63
64 internal void Init(ReadOnlySpan<char> format, bool useInvariantFieldLengths)
65 {
66 dd = (hh = (mm = (ss = (ff = 0))));
67 _literals = new string[6];
68 for (int i = 0; i < _literals.Length; i++)
69 {
70 _literals[i] = string.Empty;
71 }
73 bool flag = false;
74 char c = '\'';
75 int num = 0;
76 for (int j = 0; j < format.Length; j++)
77 {
78 switch (format[j])
79 {
80 case '"':
81 case '\'':
82 if (flag && c == format[j])
83 {
84 if (num < 0 || num > 5)
85 {
86 return;
87 }
88 _literals[num] = stringBuilder.ToString();
89 stringBuilder.Length = 0;
90 flag = false;
91 }
92 else if (!flag)
93 {
94 c = format[j];
95 flag = true;
96 }
97 continue;
98 case '\\':
99 if (!flag)
100 {
101 j++;
102 continue;
103 }
104 break;
105 case 'd':
106 if (!flag)
107 {
108 num = 1;
109 dd++;
110 }
111 continue;
112 case 'h':
113 if (!flag)
114 {
115 num = 2;
116 hh++;
117 }
118 continue;
119 case 'm':
120 if (!flag)
121 {
122 num = 3;
123 mm++;
124 }
125 continue;
126 case 's':
127 if (!flag)
128 {
129 num = 4;
130 ss++;
131 }
132 continue;
133 case 'F':
134 case 'f':
135 if (!flag)
136 {
137 num = 5;
138 ff++;
139 }
140 continue;
141 }
142 stringBuilder.Append(format[j]);
143 }
145 if (useInvariantFieldLengths)
146 {
147 dd = 2;
148 hh = 2;
149 mm = 2;
150 ss = 2;
151 ff = 7;
152 }
153 else
154 {
155 if (dd < 1 || dd > 2)
156 {
157 dd = 2;
158 }
159 if (hh < 1 || hh > 2)
160 {
161 hh = 2;
162 }
163 if (mm < 1 || mm > 2)
164 {
165 mm = 2;
166 }
167 if (ss < 1 || ss > 2)
168 {
169 ss = 2;
170 }
171 if (ff < 1 || ff > 7)
172 {
173 ff = 7;
174 }
175 }
176 StringBuilderCache.Release(stringBuilder);
177 }
178 }
179
180 internal static readonly FormatLiterals PositiveInvariantFormatLiterals = FormatLiterals.InitInvariant(isNegative: false);
181
183
184 internal static string Format(TimeSpan value, string format, IFormatProvider formatProvider)
185 {
186 if (string.IsNullOrEmpty(format))
187 {
188 return FormatC(value);
189 }
190 if (format.Length == 1)
191 {
192 char c = format[0];
193 if (c == 'c' || (c | 0x20) == 116)
194 {
195 return FormatC(value);
196 }
197 if ((c | 0x20) == 103)
198 {
199 return FormatG(value, DateTimeFormatInfo.GetInstance(formatProvider), (c == 'G') ? StandardFormat.G : StandardFormat.g);
200 }
202 }
204 }
205
206 internal static bool TryFormat(TimeSpan value, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider formatProvider)
207 {
208 if (format.Length == 0)
209 {
210 return TryFormatStandard(value, StandardFormat.C, null, destination, out charsWritten);
211 }
212 if (format.Length == 1)
213 {
214 char c = format[0];
215 if (c == 'c' || (c | 0x20) == 116)
216 {
217 return TryFormatStandard(value, StandardFormat.C, null, destination, out charsWritten);
218 }
219 return TryFormatStandard(value, c switch
220 {
221 'G' => StandardFormat.G,
222 'g' => StandardFormat.g,
223 _ => throw new FormatException(SR.Format_InvalidString),
224 }, DateTimeFormatInfo.GetInstance(formatProvider).DecimalSeparator, destination, out charsWritten);
225 }
226 StringBuilder stringBuilder = FormatCustomized(value, format, DateTimeFormatInfo.GetInstance(formatProvider));
227 if (stringBuilder.Length <= destination.Length)
228 {
229 stringBuilder.CopyTo(0, destination, stringBuilder.Length);
230 charsWritten = stringBuilder.Length;
231 StringBuilderCache.Release(stringBuilder);
232 return true;
233 }
234 charsWritten = 0;
235 StringBuilderCache.Release(stringBuilder);
236 return false;
237 }
238
239 internal static string FormatC(TimeSpan value)
240 {
241 Span<char> destination = stackalloc char[26];
242 TryFormatStandard(value, StandardFormat.C, null, destination, out var charsWritten);
243 return new string(destination.Slice(0, charsWritten));
244 }
245
247 {
248 string decimalSeparator = dtfi.DecimalSeparator;
249 int num = 25 + decimalSeparator.Length;
250 Span<char> span = ((num >= 128) ? ((Span<char>)new char[num]) : stackalloc char[num]);
251 Span<char> destination = span;
252 TryFormatStandard(value, format, decimalSeparator, destination, out var charsWritten);
253 return new string(destination.Slice(0, charsWritten));
254 }
255
256 private static bool TryFormatStandard(TimeSpan value, StandardFormat format, string decimalSeparator, Span<char> destination, out int charsWritten)
257 {
258 int num = 8;
259 long num2 = value.Ticks;
260 uint valueWithoutTrailingZeros;
261 ulong num3;
262 if (num2 < 0)
263 {
264 num = 9;
265 num2 = -num2;
266 if (num2 < 0)
267 {
268 valueWithoutTrailingZeros = 4775808u;
269 num3 = 922337203685uL;
270 goto IL_0050;
271 }
272 }
273 (ulong Quotient, ulong Remainder) tuple = Math.DivRem((ulong)num2, 10000000uL);
274 num3 = tuple.Quotient;
275 ulong item = tuple.Remainder;
276 valueWithoutTrailingZeros = (uint)item;
277 goto IL_0050;
278 IL_0050:
279 int num4 = 0;
280 switch (format)
281 {
282 case StandardFormat.C:
283 if (valueWithoutTrailingZeros != 0)
284 {
285 num4 = 7;
286 num += num4 + 1;
287 }
288 break;
289 case StandardFormat.G:
290 num4 = 7;
291 num += num4 + 1;
292 break;
293 default:
294 if (valueWithoutTrailingZeros != 0)
295 {
296 num4 = 7 - FormattingHelpers.CountDecimalTrailingZeros(valueWithoutTrailingZeros, out valueWithoutTrailingZeros);
297 num += num4 + 1;
298 }
299 break;
300 }
301 ulong num5 = 0uL;
302 ulong num6 = 0uL;
303 if (num3 != 0)
304 {
305 (num5, num6) = Math.DivRem(num3, 60uL);
306 }
307 ulong num7 = 0uL;
308 ulong num8 = 0uL;
309 if (num5 != 0)
310 {
311 (num7, num8) = Math.DivRem(num5, 60uL);
312 }
313 uint num9 = 0u;
314 uint num10 = 0u;
315 if (num7 != 0)
316 {
317 (num9, num10) = Math.DivRem((uint)num7, 24u);
318 }
319 int num11 = 2;
320 if (format == StandardFormat.g && num10 < 10)
321 {
322 num11 = 1;
323 num--;
324 }
325 int num12 = 0;
326 if (num9 != 0)
327 {
328 num12 = FormattingHelpers.CountDigits(num9);
329 num += num12 + 1;
330 }
331 else if (format == StandardFormat.G)
332 {
333 num += 2;
334 num12 = 1;
335 }
336 if (destination.Length < num)
337 {
338 charsWritten = 0;
339 return false;
340 }
341 int num13 = 0;
342 if (value.Ticks < 0)
343 {
344 destination[num13++] = '-';
345 }
346 if (num12 != 0)
347 {
348 WriteDigits(num9, destination.Slice(num13, num12));
349 num13 += num12;
350 destination[num13++] = ((format == StandardFormat.C) ? '.' : ':');
351 }
352 if (num11 == 2)
353 {
354 WriteTwoDigits(num10, destination.Slice(num13));
355 num13 += 2;
356 }
357 else
358 {
359 destination[num13++] = (char)(48 + num10);
360 }
361 destination[num13++] = ':';
362 WriteTwoDigits((uint)num8, destination.Slice(num13));
363 num13 += 2;
364 destination[num13++] = ':';
365 WriteTwoDigits((uint)num6, destination.Slice(num13));
366 num13 += 2;
367 if (num4 != 0)
368 {
369 if (format == StandardFormat.C)
370 {
371 destination[num13++] = '.';
372 }
373 else if (decimalSeparator.Length == 1)
374 {
375 destination[num13++] = decimalSeparator[0];
376 }
377 else
378 {
379 decimalSeparator.CopyTo(destination);
380 num13 += decimalSeparator.Length;
381 }
382 WriteDigits(valueWithoutTrailingZeros, destination.Slice(num13, num4));
383 num13 += num4;
384 }
385 charsWritten = num;
386 return true;
387 }
388
389 [MethodImpl(MethodImplOptions.AggressiveInlining)]
390 private static void WriteTwoDigits(uint value, Span<char> buffer)
391 {
392 uint num = 48 + value;
393 value /= 10;
394 buffer[1] = (char)(num - value * 10);
395 buffer[0] = (char)(48 + value);
396 }
397
398 [MethodImpl(MethodImplOptions.AggressiveInlining)]
399 private static void WriteDigits(uint value, Span<char> buffer)
400 {
401 for (int num = buffer.Length - 1; num >= 1; num--)
402 {
403 uint num2 = 48 + value;
404 value /= 10;
405 buffer[num] = (char)(num2 - value * 10);
406 }
407 buffer[0] = (char)(48 + value);
408 }
409
411 {
412 bool flag = false;
413 if (result == null)
414 {
415 result = StringBuilderCache.Acquire();
416 flag = true;
417 }
418 int num = (int)(value.Ticks / 864000000000L);
419 long num2 = value.Ticks % 864000000000L;
420 if (value.Ticks < 0)
421 {
422 num = -num;
423 num2 = -num2;
424 }
425 int value2 = (int)(num2 / 36000000000L % 24);
426 int value3 = (int)(num2 / 600000000 % 60);
427 int value4 = (int)(num2 / 10000000 % 60);
428 int num3 = (int)(num2 % 10000000);
429 long num4 = 0L;
430 int num6;
431 for (int i = 0; i < format.Length; i += num6)
432 {
433 char c = format[i];
434 switch (c)
435 {
436 case 'h':
438 if (num6 <= 2)
439 {
440 DateTimeFormat.FormatDigits(result, value2, num6);
441 continue;
442 }
443 break;
444 case 'm':
446 if (num6 <= 2)
447 {
448 DateTimeFormat.FormatDigits(result, value3, num6);
449 continue;
450 }
451 break;
452 case 's':
454 if (num6 <= 2)
455 {
456 DateTimeFormat.FormatDigits(result, value4, num6);
457 continue;
458 }
459 break;
460 case 'f':
462 if (num6 <= 7)
463 {
464 num4 = num3;
465 num4 /= TimeSpanParse.Pow10(7 - num6);
466 result.AppendSpanFormattable(num4, DateTimeFormat.fixedNumberFormats[num6 - 1], CultureInfo.InvariantCulture);
467 continue;
468 }
469 break;
470 case 'F':
472 if (num6 <= 7)
473 {
474 num4 = num3;
475 num4 /= TimeSpanParse.Pow10(7 - num6);
476 int num7 = num6;
477 while (num7 > 0 && num4 % 10 == 0L)
478 {
479 num4 /= 10;
480 num7--;
481 }
482 if (num7 > 0)
483 {
484 result.AppendSpanFormattable(num4, DateTimeFormat.fixedNumberFormats[num7 - 1], CultureInfo.InvariantCulture);
485 }
486 continue;
487 }
488 break;
489 case 'd':
491 if (num6 <= 8)
492 {
493 DateTimeFormat.FormatDigits(result, num, num6, overrideLengthLimit: true);
494 continue;
495 }
496 break;
497 case '"':
498 case '\'':
499 num6 = DateTimeFormat.ParseQuoteString(format, i, result);
500 continue;
501 case '%':
502 {
503 int num5 = DateTimeFormat.ParseNextChar(format, i);
504 if (num5 >= 0 && num5 != 37)
505 {
506 char reference = (char)num5;
507 StringBuilder stringBuilder = FormatCustomized(value, MemoryMarshal.CreateReadOnlySpan(ref reference, 1), dtfi, result);
508 num6 = 2;
509 continue;
510 }
511 break;
512 }
513 case '\\':
514 {
515 int num5 = DateTimeFormat.ParseNextChar(format, i);
516 if (num5 >= 0)
517 {
518 result.Append((char)num5);
519 num6 = 2;
520 continue;
521 }
522 break;
523 }
524 }
525 if (flag)
526 {
528 }
530 }
531 return result;
532 }
533}
static int CountDecimalTrailingZeros(uint value, out uint valueWithoutTrailingZeros)
static int ParseNextChar(ReadOnlySpan< char > format, int pos)
static int ParseRepeatPattern(ReadOnlySpan< char > format, int pos, char patternChar)
static int ParseQuoteString(ReadOnlySpan< char > format, int pos, StringBuilder result)
static void FormatDigits(StringBuilder outputBuffer, int value, int len)
static string[] fixedNumberFormats
static CultureInfo InvariantCulture
static string FormatG(TimeSpan value, DateTimeFormatInfo dtfi, StandardFormat format)
static readonly FormatLiterals NegativeInvariantFormatLiterals
static StringBuilder FormatCustomized(TimeSpan value, ReadOnlySpan< char > format, DateTimeFormatInfo dtfi, StringBuilder result=null)
static bool TryFormatStandard(TimeSpan value, StandardFormat format, string decimalSeparator, Span< char > destination, out int charsWritten)
static void WriteTwoDigits(uint value, Span< char > buffer)
static readonly FormatLiterals PositiveInvariantFormatLiterals
static bool TryFormat(TimeSpan value, Span< char > destination, out int charsWritten, ReadOnlySpan< char > format, IFormatProvider formatProvider)
static string FormatC(TimeSpan value)
static string Format(TimeSpan value, string format, IFormatProvider formatProvider)
static void WriteDigits(uint value, Span< char > buffer)
static int DivRem(int a, int b, out int result)
Definition Math.cs:329
static string Format_InvalidString
Definition SR.cs:1354
Definition SR.cs:7
static string GetStringAndRelease(StringBuilder sb)
static void Release(StringBuilder sb)
static StringBuilder Acquire(int capacity=16)
override string ToString()
void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)
StringBuilder Append(char value, int repeatCount)
static FormatLiterals InitInvariant(bool isNegative)
void Init(ReadOnlySpan< char > format, bool useInvariantFieldLengths)