static void _CustomWriteUInt_ThunkWriter(ref ThunkWriter writer, uint number, char[] buffer) { var ptr = InlineSerializer<object>.CharBufferSize - 1; var copy = number; do { byte ix = (byte)(copy % 100); copy /= 100; var chars = DigitPairs[ix]; buffer[ptr--] = chars.Second; buffer[ptr--] = chars.First; } while (copy != 0); if (buffer[ptr + 1] == '0') { ptr++; } writer.Write(buffer, ptr + 1, InlineSerializer<object>.CharBufferSize - 1 - ptr); }
static void _CustomWriteUIntUnrolled_ThunkWriter(ref ThunkWriter writer, uint number, char[] buffer) { int numLen; if (number < 1000) { if (number >= 100) { writer.Write(DigitTriplets, (int)(number * 3), 3); } else { if (number >= 10) { writer.Write(DigitTriplets, (int)(number * 3 + 1), 2); } else { writer.Write(DigitTriplets, (int)(number * 3 + 2), 1); } } return; } var d012 = number % 1000 * 3; uint d543; if (number < 1000000) { d543 = (number / 1000) * 3; if (number >= 100000) { numLen = 6; goto digit5; } else { if (number >= 10000) { numLen = 5; goto digit4; } else { numLen = 4; goto digit3; } } } d543 = (number / 1000) % 1000 * 3; uint d876; if (number < 1000000000) { d876 = (number / 1000000) * 3; if (number >= 100000000) { numLen = 9; goto digit8; } else { if (number >= 10000000) { numLen = 8; goto digit7; } else { numLen = 7; goto digit6; } } } d876 = (number / 1000000) % 1000 * 3; numLen = 10; // uint is between 0 & 4,294,967,295 (in practice we only get to int.MaxValue, but that's the same # of digits) // so 1 to 10 digits // [01,]000,000-[99,]000,000 var d9 = number / 1000000000; buffer[0] = (char)('0' + d9); digit8: buffer[1] = DigitTriplets[d876]; digit7: buffer[2] = DigitTriplets[d876 + 1]; digit6: buffer[3] = DigitTriplets[d876 + 2]; digit5: buffer[4] = DigitTriplets[d543]; digit4: buffer[5] = DigitTriplets[d543 + 1]; digit3: buffer[6] = DigitTriplets[d543 + 2]; buffer[7] = DigitTriplets[d012]; buffer[8] = DigitTriplets[d012 + 1]; buffer[9] = DigitTriplets[d012 + 2]; writer.Write(buffer, 10 - numLen, numLen); }
static void _CustomWriteInt_ThunkWriter(ref ThunkWriter writer, int number, char[] buffer) { // Gotta special case this, we can't negate it if (number == int.MinValue) { writer.WriteMinConstant(ConstantString_Min.Int_MinValue); return; } var ptr = InlineSerializer<object>.CharBufferSize - 1; uint copy; if (number < 0) { writer.Write('-'); copy = (uint)(-number); } else { copy = (uint)number; } do { byte ix = (byte)(copy % 100); copy /= 100; var chars = DigitPairs[ix]; buffer[ptr--] = chars.Second; buffer[ptr--] = chars.First; } while (copy != 0); if (buffer[ptr + 1] == '0') { ptr++; } writer.Write(buffer, ptr + 1, InlineSerializer<object>.CharBufferSize - 1 - ptr); }
static void _CustomWriteIntUnrolledSigned_ThunkWriter(ref ThunkWriter writer, int num, char[] buffer) { // Why signed integers? // Earlier versions of this code used unsigned integers, // but it turns out that's not ideal and here's why. // // The signed version of the relevant code gets JIT'd down to: // instr operands latency/throughput (approx. worst case; Haswell) // ======================================================================================== // mov ecx,### 2 / 0.5 // cdq 1 / - // idiv eax,ecx 29 / 11 // mov ecx,### 2 / 0.5 // cdq 1 / - // idiv eax,ecx 29 / 11 // movsx edx,dl - / 0.5 // // The unsigned version gets JIT'd down to: // instr operands latency/throughput (approx. worst case; Haswell) // ======================================================================================== // mov ecx,### 2 / 0.5 // xor edx,edx 1 / 0.25 // div eax,ecx 29 / 11 // mov ecx,### 2 / 0.5 // xor edx,edx 1 / 0.25 // div eax,ecx 29 / 11 // and edx,### 1 / 0.25 // // In theory div (usigned division) is faster than idiv, and it probably is *but* cdq + cdq + movsx is // faster than xor + xor + and; in practice it's fast *enough* to make up the difference. // have to special case this, we can't negate it if (num == int.MinValue) { writer.WriteMinConstant(ConstantString_Min.Int_MinValue); return; } int numLen; int number; if (num < 0) { writer.Write('-'); number = -num; } else { number = num; } if (number < 1000) { if (number >= 100) { writer.Write(DigitTriplets, number * 3, 3); } else { if (number >= 10) { writer.Write(DigitTriplets, number * 3 + 1, 2); } else { writer.Write(DigitTriplets, number * 3 + 2, 1); } } return; } var d012 = number % 1000 * 3; int d543; if (number < 1000000) { d543 = (number / 1000) * 3; if (number >= 100000) { numLen = 6; goto digit5; } else { if (number >= 10000) { numLen = 5; goto digit4; } else { numLen = 4; goto digit3; } } } d543 = (number / 1000) % 1000 * 3; int d876; if (number < 1000000000) { d876 = (number / 1000000) * 3; if (number >= 100000000) { numLen = 9; goto digit8; } else { if (number >= 10000000) { numLen = 8; goto digit7; } else { numLen = 7; goto digit6; } } } d876 = (number / 1000000) % 1000 * 3; numLen = 10; // uint is between 0 & 4,294,967,295 (in practice we only get to int.MaxValue, but that's the same # of digits) // so 1 to 10 digits // [01,]000,000-[99,]000,000 var d9 = number / 1000000000; buffer[0] = (char)('0' + d9); digit8: buffer[1] = DigitTriplets[d876]; digit7: buffer[2] = DigitTriplets[d876 + 1]; digit6: buffer[3] = DigitTriplets[d876 + 2]; digit5: buffer[4] = DigitTriplets[d543]; digit4: buffer[5] = DigitTriplets[d543 + 1]; digit3: buffer[6] = DigitTriplets[d543 + 2]; buffer[7] = DigitTriplets[d012]; buffer[8] = DigitTriplets[d012 + 1]; buffer[9] = DigitTriplets[d012 + 2]; writer.Write(buffer, 10 - numLen, numLen); }
static void _CustomISO8601WithOffsetToString_ThunkWriter(ref ThunkWriter writer, DateTime dt, int hours, int minutes, char[] buffer) { if (hours == 0 && minutes == 0) { // It's actually in UTC time, bail! _CustomISO8601ToString_ThunkWriter(ref writer, dt, buffer); return; } // "yyyy-mm-ddThh:mm:ss.fffffff+oo:oo" // 0123456789ABCDEFGHIJKLMNOPQRSTUVWXY // // Yes, DateTime.Max is in fact guaranteed to have a 4 digit year (and no more) // f of 7 digits allows for 1 Tick level resolution var offsetIsNegative = false; if (hours < 0 || minutes < 0) { offsetIsNegative = true; hours = -hours; minutes = -minutes; } buffer[0] = '"'; uint val; // Year val = (uint)dt.Year; var digits = DigitPairs[(byte)(val % 100)]; buffer[4] = digits.Second; buffer[3] = digits.First; digits = DigitPairs[(byte)(val / 100)]; buffer[2] = digits.Second; buffer[1] = digits.First; // delimiter buffer[5] = '-'; // Month digits = DigitPairs[dt.Month]; buffer[7] = digits.Second; buffer[6] = digits.First; // Delimiter buffer[8] = '-'; // Day digits = DigitPairs[dt.Day]; buffer[10] = digits.Second; buffer[9] = digits.First; // Delimiter buffer[11] = 'T'; digits = DigitPairs[dt.Hour]; buffer[13] = digits.Second; buffer[12] = digits.First; // Delimiter buffer[14] = ':'; digits = DigitPairs[dt.Minute]; buffer[16] = digits.Second; buffer[15] = digits.First; // Delimiter buffer[17] = ':'; digits = DigitPairs[dt.Second]; buffer[19] = digits.Second; buffer[18] = digits.First; int fracEnd; var remainingTicks = (dt - new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second)).Ticks; if (remainingTicks > 0) { buffer[20] = '.'; var fracPart = remainingTicks % 100; remainingTicks /= 100; if (fracPart > 0) { digits = DigitPairs[fracPart]; buffer[27] = digits.Second; buffer[26] = digits.First; fracEnd = 28; } else { fracEnd = 26; } fracPart = remainingTicks % 100; remainingTicks /= 100; if (fracPart > 0) { digits = DigitPairs[fracPart]; buffer[25] = digits.Second; buffer[24] = digits.First; } else { if (fracEnd == 26) { fracEnd = 24; } else { buffer[25] = '0'; buffer[24] = '0'; } } fracPart = remainingTicks % 100; remainingTicks /= 100; if (fracPart > 0) { digits = DigitPairs[fracPart]; buffer[23] = digits.Second; buffer[22] = digits.First; } else { if (fracEnd == 24) { fracEnd = 22; } else { buffer[23] = '0'; buffer[22] = '0'; } } fracPart = remainingTicks; buffer[21] = (char)('0' + fracPart); } else { fracEnd = 20; } if (offsetIsNegative) { buffer[fracEnd] = '-'; } else { buffer[fracEnd] = '+'; } digits = DigitPairs[hours]; buffer[fracEnd + 1] = digits.First; buffer[fracEnd + 2] = digits.Second; buffer[fracEnd + 3] = ':'; digits = DigitPairs[minutes]; buffer[fracEnd + 4] = digits.First; buffer[fracEnd + 5] = digits.Second; buffer[fracEnd + 6] = '"'; writer.Write(buffer, 0, fracEnd + 7); }
static unsafe void _WriteEncodedStringWithNullsInlineUnsafe_ThunkWriter(ref ThunkWriter writer, string strRef) { if (strRef == null) { writer.WriteValueConstant(ConstantString_Value.Null); return; } fixed (char* strFixed = strRef) { char* str = strFixed; char c; var len = strRef.Length; while (len > 0) { c = *str; str++; len--; if (c == '\\') { writer.WriteCommonConstant(ConstantString_Common.DoubleBackSlash); continue; } if (c == '"') { writer.WriteFormattingConstant(ConstantString_Formatting.BackSlashQuote); continue; } // This is converted into an IL switch, so don't fret about lookup times switch (c) { case '\u0000': writer.Write000EscapeConstant(ConstantString_000Escape.EscapeSequence_0000); continue; case '\u0001': writer.Write000EscapeConstant(ConstantString_000Escape.EscapeSequence_0001); continue; case '\u0002': writer.Write000EscapeConstant(ConstantString_000Escape.EscapeSequence_0002); continue; case '\u0003': writer.Write000EscapeConstant(ConstantString_000Escape.EscapeSequence_0003); continue; case '\u0004': writer.Write000EscapeConstant(ConstantString_000Escape.EscapeSequence_0004); continue; case '\u0005': writer.Write000EscapeConstant(ConstantString_000Escape.EscapeSequence_0005); continue; case '\u0006': writer.Write000EscapeConstant(ConstantString_000Escape.EscapeSequence_0006); continue; case '\u0007': writer.Write000EscapeConstant(ConstantString_000Escape.EscapeSequence_0007); continue; case '\u0008': writer.WriteCommonConstant(ConstantString_Common.EscapeSequence_b); continue; case '\u0009': writer.WriteCommonConstant(ConstantString_Common.EscapeSequence_t); continue; case '\u000A': writer.WriteCommonConstant(ConstantString_Common.EscapeSequence_n); continue; case '\u000B': writer.Write000EscapeConstant(ConstantString_000Escape.EscapeSequence_000B); continue; case '\u000C': writer.WriteCommonConstant(ConstantString_Common.EscapeSequence_f); continue; case '\u000D': writer.WriteCommonConstant(ConstantString_Common.EscapeSequence_r); continue; case '\u000E': writer.Write000EscapeConstant(ConstantString_000Escape.EscapeSequence_000E); continue; case '\u000F': writer.Write000EscapeConstant(ConstantString_000Escape.EscapeSequence_000F); continue; case '\u0010': writer.Write001EscapeConstant(ConstantString_001Escape.EscapeSequence_0010); continue; case '\u0011': writer.Write001EscapeConstant(ConstantString_001Escape.EscapeSequence_0011); continue; case '\u0012': writer.Write001EscapeConstant(ConstantString_001Escape.EscapeSequence_0012); continue; case '\u0013': writer.Write001EscapeConstant(ConstantString_001Escape.EscapeSequence_0013); continue; case '\u0014': writer.Write001EscapeConstant(ConstantString_001Escape.EscapeSequence_0014); continue; case '\u0015': writer.Write001EscapeConstant(ConstantString_001Escape.EscapeSequence_0015); continue; case '\u0016': writer.Write001EscapeConstant(ConstantString_001Escape.EscapeSequence_0016); continue; case '\u0017': writer.Write001EscapeConstant(ConstantString_001Escape.EscapeSequence_0017); continue; case '\u0018': writer.Write001EscapeConstant(ConstantString_001Escape.EscapeSequence_0018); continue; case '\u0019': writer.Write001EscapeConstant(ConstantString_001Escape.EscapeSequence_0019); continue; case '\u001A': writer.Write001EscapeConstant(ConstantString_001Escape.EscapeSequence_001A); continue; case '\u001B': writer.Write001EscapeConstant(ConstantString_001Escape.EscapeSequence_001B); continue; case '\u001C': writer.Write001EscapeConstant(ConstantString_001Escape.EscapeSequence_001C); continue; case '\u001D': writer.Write001EscapeConstant(ConstantString_001Escape.EscapeSequence_001D); continue; case '\u001E': writer.Write001EscapeConstant(ConstantString_001Escape.EscapeSequence_001E); continue; case '\u001F': writer.Write001EscapeConstant(ConstantString_001Escape.EscapeSequence_001F); continue; default: writer.Write(c); continue; } } } }
static void _WriteGuid_ThunkWriter(ref ThunkWriter writer, Guid guid, char[] buffer) { // 1314FAD4-7505-439D-ABD2-DBD89242928C // 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ // // Guid is guaranteed to be a 36 character string // get all the dashes in place buffer[8] = '-'; buffer[13] = '-'; buffer[18] = '-'; buffer[23] = '-'; // Bytes are in a different order than you might expect // For: 35 91 8b c9 - 19 6d - 40 ea - 97 79 - 88 9d 79 b7 53 f0 // Get: C9 8B 91 35 6D 19 EA 40 97 79 88 9D 79 B7 53 F0 // Ix: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // // And we have to account for dashes // // So the map is like so: // bytes[0] -> chars[3] -> buffer[ 6, 7] // bytes[1] -> chars[2] -> buffer[ 4, 5] // bytes[2] -> chars[1] -> buffer[ 2, 3] // bytes[3] -> chars[0] -> buffer[ 0, 1] // bytes[4] -> chars[5] -> buffer[11,12] // bytes[5] -> chars[4] -> buffer[ 9,10] // bytes[6] -> chars[7] -> buffer[16,17] // bytes[7] -> chars[6] -> buffer[14,15] // bytes[8] -> chars[8] -> buffer[19,20] // bytes[9] -> chars[9] -> buffer[21,22] // bytes[10] -> chars[10] -> buffer[24,25] // bytes[11] -> chars[11] -> buffer[26,27] // bytes[12] -> chars[12] -> buffer[28,29] // bytes[13] -> chars[13] -> buffer[30,31] // bytes[14] -> chars[14] -> buffer[32,33] // bytes[15] -> chars[15] -> buffer[34,35] var visibleMembers = new GuidStruct(guid); // bytes[0] var b = visibleMembers.B00 * 2; buffer[6] = WriteGuidLookup[b]; buffer[7] = WriteGuidLookup[b + 1]; // bytes[1] b = visibleMembers.B01 * 2; buffer[4] = WriteGuidLookup[b]; buffer[5] = WriteGuidLookup[b + 1]; // bytes[2] b = visibleMembers.B02 * 2; buffer[2] = WriteGuidLookup[b]; buffer[3] = WriteGuidLookup[b + 1]; // bytes[3] b = visibleMembers.B03 * 2; buffer[0] = WriteGuidLookup[b]; buffer[1] = WriteGuidLookup[b + 1]; // bytes[4] b = visibleMembers.B04 * 2; buffer[11] = WriteGuidLookup[b]; buffer[12] = WriteGuidLookup[b + 1]; // bytes[5] b = visibleMembers.B05 * 2; buffer[9] = WriteGuidLookup[b]; buffer[10] = WriteGuidLookup[b + 1]; // bytes[6] b = visibleMembers.B06 * 2; buffer[16] = WriteGuidLookup[b]; buffer[17] = WriteGuidLookup[b + 1]; // bytes[7] b = visibleMembers.B07 * 2; buffer[14] = WriteGuidLookup[b]; buffer[15] = WriteGuidLookup[b + 1]; // bytes[8] b = visibleMembers.B08 * 2; buffer[19] = WriteGuidLookup[b]; buffer[20] = WriteGuidLookup[b + 1]; // bytes[9] b = visibleMembers.B09 * 2; buffer[21] = WriteGuidLookup[b]; buffer[22] = WriteGuidLookup[b + 1]; // bytes[10] b = visibleMembers.B10 * 2; buffer[24] = WriteGuidLookup[b]; buffer[25] = WriteGuidLookup[b + 1]; // bytes[11] b = visibleMembers.B11 * 2; buffer[26] = WriteGuidLookup[b]; buffer[27] = WriteGuidLookup[b + 1]; // bytes[12] b = visibleMembers.B12 * 2; buffer[28] = WriteGuidLookup[b]; buffer[29] = WriteGuidLookup[b + 1]; // bytes[13] b = visibleMembers.B13 * 2; buffer[30] = WriteGuidLookup[b]; buffer[31] = WriteGuidLookup[b + 1]; // bytes[14] b = visibleMembers.B14 * 2; buffer[32] = WriteGuidLookup[b]; buffer[33] = WriteGuidLookup[b + 1]; // bytes[15] b = visibleMembers.B15 * 2; buffer[34] = WriteGuidLookup[b]; buffer[35] = WriteGuidLookup[b + 1]; writer.Write(buffer, 0, 36); }
static void _CustomWriteMicrosoftStyleWithOffset_ThunkWriter(ref ThunkWriter writer, long utcTicks, int hours, int minutes, char[] buffer) { const long EpochTicks = 621355968000000000L; const long TicksToMilliseconds = 10000L; writer.WriteValueConstant(ConstantString_Value.Date); var delta = (utcTicks - EpochTicks) / TicksToMilliseconds; _CustomWriteLong_ThunkWriter(ref writer, delta, buffer); if (hours < 0 || minutes < 0) { writer.Write('-'); hours = -hours; minutes = -minutes; } else { writer.Write('+'); } var digits = DigitPairs[hours]; writer.Write(digits.First); writer.Write(digits.Second); digits = DigitPairs[minutes]; writer.Write(digits.First); writer.Write(digits.Second); writer.WriteValueConstant(ConstantString_Value.CloseDate); }
static void _CustomISO8601ToString_ThunkWriter(ref ThunkWriter writer, DateTime dt, char[] buffer) { // "yyyy-mm-ddThh:mm:ss.fffffffZ" // 0123456789ABCDEFGHIJKL // // Yes, DateTime.Max is in fact guaranteed to have a 4 digit year (and no more) // f of 7 digits allows for 1 Tick level resolution buffer[0] = '"'; uint val; // Year val = (uint)dt.Year; var digits = DigitPairs[(byte)(val % 100)]; buffer[4] = digits.Second; buffer[3] = digits.First; digits = DigitPairs[(byte)(val / 100)]; buffer[2] = digits.Second; buffer[1] = digits.First; // delimiter buffer[5] = '-'; // Month digits = DigitPairs[dt.Month]; buffer[7] = digits.Second; buffer[6] = digits.First; // Delimiter buffer[8] = '-'; // Day digits = DigitPairs[dt.Day]; buffer[10] = digits.Second; buffer[9] = digits.First; // Delimiter buffer[11] = 'T'; digits = DigitPairs[dt.Hour]; buffer[13] = digits.Second; buffer[12] = digits.First; // Delimiter buffer[14] = ':'; digits = DigitPairs[dt.Minute]; buffer[16] = digits.Second; buffer[15] = digits.First; // Delimiter buffer[17] = ':'; digits = DigitPairs[dt.Second]; buffer[19] = digits.Second; buffer[18] = digits.First; int fracEnd; var remainingTicks = (dt - new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second)).Ticks; if (remainingTicks > 0) { buffer[20] = '.'; var fracPart = remainingTicks % 100; remainingTicks /= 100; if (fracPart > 0) { digits = DigitPairs[fracPart]; buffer[27] = digits.Second; buffer[26] = digits.First; fracEnd = 28; } else { fracEnd = 26; } fracPart = remainingTicks % 100; remainingTicks /= 100; if (fracPart > 0) { digits = DigitPairs[fracPart]; buffer[25] = digits.Second; buffer[24] = digits.First; } else { if (fracEnd == 26) { fracEnd = 24; } else { buffer[25] = '0'; buffer[24] = '0'; } } fracPart = remainingTicks % 100; remainingTicks /= 100; if (fracPart > 0) { digits = DigitPairs[fracPart]; buffer[23] = digits.Second; buffer[22] = digits.First; } else { if (fracEnd == 24) { fracEnd = 22; } else { buffer[23] = '0'; buffer[22] = '0'; } } fracPart = remainingTicks; buffer[21] = (char)('0' + fracPart); } else { fracEnd = 20; } buffer[fracEnd] = 'Z'; buffer[fracEnd + 1] = '"'; writer.Write(buffer, 0, fracEnd + 2); }
static void _CustomRFC1123_ThunkWriter(ref ThunkWriter writer, DateTime dt) { writer.WriteFormattingConstant(ConstantString_Formatting.Quote); var dayOfWeek = (ConstantString_DaysOfWeek)(((byte)dt.DayOfWeek) * 3); writer.WriteDayOfWeek(dayOfWeek); writer.WriteFormattingConstant(ConstantString_Formatting.CommaSpace); { var day = DigitPairs[dt.Day]; writer.Write(day.First); writer.Write(day.Second); writer.WriteFormattingConstant(ConstantString_Formatting.Space); } // compiles as a switch // not converted to a ConstantString_* enum because you can't pack these such that // they fit in a cache line switch (dt.Month) { case 1: writer.Write("Jan "); break; case 2: writer.Write("Feb "); break; case 3: writer.Write("Mar "); break; case 4: writer.Write("Apr "); break; case 5: writer.Write("May "); break; case 6: writer.Write("Jun "); break; case 7: writer.Write("Jul "); break; case 8: writer.Write("Aug "); break; case 9: writer.Write("Sep "); break; case 10: writer.Write("Oct "); break; case 11: writer.Write("Nov "); break; case 12: writer.Write("Dec "); break; } { var year = dt.Year; var firstHalfYear = DigitPairs[year / 100]; writer.Write(firstHalfYear.First); writer.Write(firstHalfYear.Second); var secondHalfYear = DigitPairs[year % 100]; writer.Write(secondHalfYear.First); writer.Write(secondHalfYear.Second); writer.WriteFormattingConstant(ConstantString_Formatting.Space); } { var hour = DigitPairs[dt.Hour]; writer.Write(hour.First); writer.Write(hour.Second); writer.WriteFormattingConstant(ConstantString_Formatting.Colon); } { var minute = DigitPairs[dt.Minute]; writer.Write(minute.First); writer.Write(minute.Second); writer.WriteFormattingConstant(ConstantString_Formatting.Colon); } { var second = DigitPairs[dt.Second]; writer.Write(second.First); writer.Write(second.Second); } writer.WriteValueConstant(ConstantString_Value.SpaceGMTQuote); }
static void _WriteTimeSpanMicrosoft_ThunkWriter(ref ThunkWriter writer, TimeSpan ts, char[] buffer) { // can't negate this, have to handle it manually if (ts.Ticks == long.MinValue) { writer.Write("\"-10675199.02:48:05.4775808\""); return; } writer.WriteFormattingConstant(ConstantString_Formatting.Quote); if (ts.Ticks < 0) { writer.Write('-'); ts = ts.Negate(); } var days = ts.Days; var hours = ts.Hours; var minutes = ts.Minutes; var secs = ts.Seconds; int endCount; TwoDigits digits; // days { if (days != 0) { _CustomWriteInt_ThunkWriter(ref writer, days, buffer); writer.Write('.'); } } // hours { digits = DigitPairs[hours]; buffer[0] = digits.First; buffer[1] = digits.Second; } buffer[2] = ':'; // minutes { digits = DigitPairs[minutes]; buffer[3] = digits.First; buffer[4] = digits.Second; } buffer[5] = ':'; // seconds { digits = DigitPairs[secs]; buffer[6] = digits.First; buffer[7] = digits.Second; } endCount = 8; // factional part { int fracEnd; var remainingTicks = (ts - new TimeSpan(ts.Days, ts.Hours, ts.Minutes, ts.Seconds, 0)).Ticks; if (remainingTicks > 0) { buffer[8] = '.'; var fracPart = remainingTicks % 100; remainingTicks /= 100; if (fracPart > 0) { digits = DigitPairs[fracPart]; buffer[15] = digits.Second; buffer[14] = digits.First; fracEnd = 16; } else { fracEnd = 14; } fracPart = remainingTicks % 100; remainingTicks /= 100; if (fracPart > 0) { digits = DigitPairs[fracPart]; buffer[13] = digits.Second; buffer[12] = digits.First; } else { if (fracEnd == 14) { fracEnd = 12; } else { buffer[13] = '0'; buffer[12] = '0'; } } fracPart = remainingTicks % 100; remainingTicks /= 100; if (fracPart > 0) { digits = DigitPairs[fracPart]; buffer[11] = digits.Second; buffer[10] = digits.First; } else { if (fracEnd == 12) { fracEnd = 10; } else { buffer[11] = '0'; buffer[10] = '0'; } } fracPart = remainingTicks; buffer[9] = (char)('0' + fracPart); endCount = fracEnd; } } writer.Write(buffer, 0, endCount); writer.WriteFormattingConstant(ConstantString_Formatting.Quote); }
static void _WriteTimeSpanISO8601_ThunkWriter(ref ThunkWriter writer, TimeSpan ts, char[] buffer) { // can't negate this, have to handle it manually if (ts.Ticks == long.MinValue) { writer.Write("\"-P10675199DT2H48M5.4775808S\""); return; } writer.Write('"'); if (ts.Ticks < 0) { writer.Write('-'); ts = ts.Negate(); } writer.Write('P'); var days = ts.Days; var hours = ts.Hours; var minutes = ts.Minutes; var seconds = ts.Seconds; // days if (days > 0) { _CustomWriteIntUnrolledSigned_ThunkWriter(ref writer, days, buffer); writer.Write('D'); } // time separator writer.Write('T'); // hours if (hours > 0) { _CustomWriteIntUnrolledSigned_ThunkWriter(ref writer, hours, buffer); writer.Write('H'); } // minutes if (minutes > 0) { _CustomWriteIntUnrolledSigned_ThunkWriter(ref writer, minutes, buffer); writer.Write('M'); } // seconds _CustomWriteIntUnrolledSigned_ThunkWriter(ref writer, seconds, buffer); // fractional part { TwoDigits digits; int fracEnd; var endCount = 0; var remainingTicks = (ts - new TimeSpan(days, hours, minutes, seconds, 0)).Ticks; if (remainingTicks > 0) { buffer[0] = '.'; var fracPart = remainingTicks % 100; remainingTicks /= 100; if (fracPart > 0) { digits = DigitPairs[fracPart]; buffer[7] = digits.Second; buffer[6] = digits.First; fracEnd = 8; } else { fracEnd = 6; } fracPart = remainingTicks % 100; remainingTicks /= 100; if (fracPart > 0) { digits = DigitPairs[fracPart]; buffer[5] = digits.Second; buffer[4] = digits.First; } else { if (fracEnd == 6) { fracEnd = 4; } else { buffer[5] = '0'; buffer[4] = '0'; } } fracPart = remainingTicks % 100; remainingTicks /= 100; if (fracPart > 0) { digits = DigitPairs[fracPart]; buffer[3] = digits.Second; buffer[2] = digits.First; } else { if (fracEnd == 4) { fracEnd = 2; } else { buffer[3] = '0'; buffer[2] = '0'; } } fracPart = remainingTicks; buffer[1] = (char)('0' + fracPart); endCount = fracEnd; } writer.Write(buffer, 0, endCount); } writer.Write("S\""); }
static void _ProxyDecimal_ThunkWriter(ref ThunkWriter writer, decimal d) { writer.Write(d); }
static void _ProxyDouble_ThunkWriter(ref ThunkWriter writer, double d) { writer.Write(d); }
static void _ProxyFloat_ThunkWriter(ref ThunkWriter writer, float f) { writer.Write(f); }