public void TryCopyTo_FailsWhenDestinationIsTooSmall_SucceedsWhenItsLargeEnough() { var vsb = new ValueStringBuilder(); const string Text = "expected text"; vsb.Append(Text); Assert.Equal(Text.Length, vsb.Length); Span <char> dst = new char[Text.Length - 1]; Assert.False(vsb.TryCopyTo(dst, out int charsWritten)); Assert.Equal(0, charsWritten); dst = new char[Text.Length]; Assert.True(vsb.TryCopyTo(dst, out charsWritten)); Assert.Equal(Text.Length, charsWritten); Assert.Equal(0, vsb.Length); }
public void TryCopyTo_ClearsBuilder_ThenReusable() { const string Text1 = "test"; var vsb = new ValueStringBuilder(); vsb.Append(Text1); Assert.Equal(Text1.Length, vsb.Length); Span <char> dst = new char[Text1.Length]; Assert.True(vsb.TryCopyTo(dst, out int charsWritten)); Assert.Equal(Text1.Length, charsWritten); Assert.Equal(Text1, new string(dst)); Assert.Equal(0, vsb.Length); Assert.Equal(string.Empty, vsb.ToString()); Assert.True(vsb.TryCopyTo(Span <char> .Empty, out _)); const string Text2 = "another test"; vsb.Append(Text2); Assert.Equal(Text2.Length, vsb.Length); Assert.Equal(Text2, vsb.ToString()); }
public void Dispose_ClearsBuilder_ThenReusable() { const string Text1 = "test"; var vsb = new ValueStringBuilder(); vsb.Append(Text1); Assert.Equal(Text1.Length, vsb.Length); vsb.Dispose(); Assert.Equal(0, vsb.Length); Assert.Equal(string.Empty, vsb.ToString()); Assert.True(vsb.TryCopyTo(Span <char> .Empty, out _)); const string Text2 = "another test"; vsb.Append(Text2); Assert.Equal(Text2.Length, vsb.Length); Assert.Equal(Text2, vsb.ToString()); }
private static string FormatBigIntegerToHex(bool targetSpan, BigInteger value, char format, int digits, NumberFormatInfo info, Span <char> destination, out int charsWritten, out bool spanSuccess) { Debug.Assert(format == 'x' || format == 'X'); // Get the bytes that make up the BigInteger. byte[] arrayToReturnToPool = null; Span <byte> bits = stackalloc byte[64]; // arbitrary threshold if (!value.TryWriteOrCountBytes(bits, out int bytesWrittenOrNeeded)) { bits = arrayToReturnToPool = ArrayPool <byte> .Shared.Rent(bytesWrittenOrNeeded); bool success = value.TryWriteBytes(bits, out bytesWrittenOrNeeded); Debug.Assert(success); } bits = bits.Slice(0, bytesWrittenOrNeeded); Span <char> stackSpace = stackalloc char[128]; // each byte is typically two chars var sb = new ValueStringBuilder(stackSpace); int cur = bits.Length - 1; if (cur > -1) { // [FF..F8] drop the high F as the two's complement negative number remains clear // [F7..08] retain the high bits as the two's complement number is wrong without it // [07..00] drop the high 0 as the two's complement positive number remains clear bool clearHighF = false; byte head = bits[cur]; if (head > 0xF7) { head -= 0xF0; clearHighF = true; } if (head < 0x08 || clearHighF) { // {0xF8-0xFF} print as {8-F} // {0x00-0x07} print as {0-7} sb.Append(head < 10 ? (char)(head + '0') : format == 'X' ? (char)((head & 0xF) - 10 + 'A') : (char)((head & 0xF) - 10 + 'a')); cur--; } } if (cur > -1) { Span <char> chars = sb.AppendSpan((cur + 1) * 2); int charsPos = 0; string hexValues = format == 'x' ? "0123456789abcdef" : "0123456789ABCDEF"; while (cur > -1) { byte b = bits[cur--]; chars[charsPos++] = hexValues[b >> 4]; chars[charsPos++] = hexValues[b & 0xF]; } } if (digits > sb.Length) { // Insert leading zeros, e.g. user specified "X5" so we create "0ABCD" instead of "ABCD" sb.Insert( 0, value._sign >= 0 ? '0' : (format == 'x') ? 'f' : 'F', digits - sb.Length); } if (arrayToReturnToPool != null) { ArrayPool <byte> .Shared.Return(arrayToReturnToPool); } if (targetSpan) { spanSuccess = sb.TryCopyTo(destination, out charsWritten); return(null); } else { charsWritten = 0; spanSuccess = false; return(sb.ToString()); } }