public static void LengthIncreasesOnPrepend(string textA, string textB) { var builder = new ReverseStringBuilder(100); Assert.AreEqual(builder.Length, 0); builder.Prepend(textA); Assert.AreEqual(builder.Length, textA.Length); builder.Prepend(textB); Assert.AreEqual(builder.Length, textA.Length + textB.Length); }
public static void ToStringWithNegativeBackIndexThrowsEvenWithCapacity() { var builder = new ReverseStringBuilder(20); builder.Prepend("0123456789"); Assert.Throws <ArgumentOutOfRangeException, string>(() => builder.ToString(-1, 1)); }
public static void ToStringWithBackIndexBeyondLengthReturnsNullChars() { var builder = new ReverseStringBuilder(20); builder.Prepend("0123456789"); Assert.AreEqual("\0", builder.ToString(builder.Length + 1, 1)); }
public static void ToStringWithBackIndexBeyondCapacityThrows() { var builder = new ReverseStringBuilder(10); builder.Prepend("0123456789"); Assert.Throws <ArgumentOutOfRangeException, string>(() => builder.ToString(builder.Length + 1, 1)); }
public static void ToStringTakesRange() { var builder = new ReverseStringBuilder(100); builder.Prepend("0123456789"); Assert.AreEqual("0", builder.ToString(builder.Length, 1)); Assert.AreEqual("12345", builder.ToString(builder.Length - 1, 5)); }
public static void PrependBeyondCapacityThrows(string text) { var builder = new ReverseStringBuilder(0); Assert.Throws <ArgumentOutOfRangeException>(() => builder.Prepend(text)); }
private static ReverseStringBuilder StringWithGroups(int capacity, IEnumerable<char> builder, int[] groupingSizes, string groupingSeparator) { var newBuffer = new ReverseStringBuilder(capacity); using (var enumerator = builder.GetEnumerator()) { if (!enumerator.MoveNext()) { return newBuffer; } foreach (var size in groupingSizes) { for (var count = size - 1; count >= 0; count--) { newBuffer.Prepend(enumerator.Current); if (!enumerator.MoveNext()) { return newBuffer; } } newBuffer.Prepend(groupingSeparator); } { var size = groupingSizes[groupingSizes.Length - 1]; if (size != 0) { while (true) { for (var count = size - 1; count >= 0; count--) { newBuffer.Prepend(enumerator.Current); if (!enumerator.MoveNext()) { return newBuffer; } } newBuffer.Prepend(groupingSeparator); } } while (true) { newBuffer.Prepend(enumerator.Current); if (!enumerator.MoveNext()) { return newBuffer; } } } } }
private static ReverseStringBuilder CreateBuilder(BigInteger value, NumberFormatInfo info, bool decimalFmt, int digits) { // First convert to base 10^9. const uint NumericBase = 1000000000; // 10^9 const int NumericBaseLog10 = 9; var sourceLength = Length(value.InternalBits); int maxConvertedLength; try { maxConvertedLength = checked(sourceLength * 10 / 9 + 2); } catch (OverflowException e) { throw new FormatException("The value is too large to be represented by this format specifier.", e); } var converted = new uint[maxConvertedLength]; var convertedLength = 0; for (var sourceIndex = sourceLength; --sourceIndex >= 0;) { // Take a cipher from the source var carry = value.InternalBits[sourceIndex]; // Add it to converted for (var convertedIndex = 0; convertedIndex < convertedLength; convertedIndex++) { var cipherBlock = NumericsHelpers.MakeUlong(converted[convertedIndex], carry); converted[convertedIndex] = (uint)(cipherBlock % NumericBase); carry = (uint)(cipherBlock / NumericBase); } if (carry != 0) { converted[convertedLength++] = carry % NumericBase; carry /= NumericBase; if (carry != 0) { converted[convertedLength++] = carry; } } } int stringCapacity; try { // Each uint contributes at most 9 digits to the decimal representation. stringCapacity = checked(convertedLength * NumericBaseLog10); } catch (OverflowException e) { throw new FormatException("The value is too large to be represented by this format specifier.", e); } if (decimalFmt) { if (digits > 0 && stringCapacity < digits) { stringCapacity = digits; } if (value.InternalSign < 0) { try { // Leave an extra slot for a minus sign. stringCapacity = checked(stringCapacity + info.NegativeSign.Length); } catch (OverflowException e) { throw new FormatException("The value is too large to be represented by this format specifier.", e); } } } var result = new ReverseStringBuilder(stringCapacity); for (var stringIndex = 0; stringIndex < convertedLength - 1; stringIndex++) { var cipherBlock = converted[stringIndex]; for (var cch = NumericBaseLog10; --cch >= 0;) { result.Prepend((char)('0' + cipherBlock % 10)); cipherBlock /= 10; } } for (var cipherBlock = converted[convertedLength - 1]; cipherBlock != 0;) { result.Prepend((char)('0' + cipherBlock % 10)); cipherBlock /= 10; } return result; }
internal static string FormatBigInteger(BigInteger value, string format, NumberFormatInfo info) { int digits; var fmt = ParseFormatSpecifier(format, out digits); if (fmt == 'x' || fmt == 'X') { return FormatBigIntegerToHexString(value, fmt, digits, info); } if (fmt == 'e' || fmt == 'E') { var precision = digits != -1 ? digits : 6; if (value.InternalBits == null) { return value.InternalSign.ToString(format, info); } var scale = (int)Math.Floor(Log10(value)); // --- if (scale > precision + 10) { do { value /= 1000000000; } while (Log10(value) > precision + 10); } while (Log10(value) > precision + 2) { value /= 10; } if ((Log10(value) > precision + 1)) { var round = value % 10 >= 5; value = (value / 10) + (round ? One : Zero); } ReverseStringBuilder builder; if (value.InternalBits == null) { builder = new ReverseStringBuilder(10); builder.Prepend(value.InternalSign.ToString("D")); } else { builder = CreateBuilder(value, info, false, 0); } // --- var decimalSeparator = info.NumberDecimalSeparator; var result = new StringBuilder(builder.Length + 6); var extra = 0; if (precision >= builder.Length) { extra = precision - (builder.Length - 1); precision = builder.Length - 1; } result.Append(builder.ToString(builder.Length, 1)); result.Append(decimalSeparator); result.Append(builder.ToString(builder.Length - 1, precision)); result.Append(new string('0', extra)); result.Append(fmt); result.Append(info.PositiveSign); if (scale < 10) { result.Append("00"); } else if (scale < 100) { result.Append('0'); } result.Append(scale); return result.ToString(); } else { var decimalFmt = (fmt == 'g' || fmt == 'G' || fmt == 'd' || fmt == 'D' || fmt == 'r' || fmt == 'R'); if (value.InternalBits == null) { if (fmt == 'g' || fmt == 'G' || fmt == 'r' || fmt == 'R') { if (digits > 0) { format = "D" + digits.ToString(CultureInfo.InvariantCulture); } else { format = "D"; } } return value.InternalSign.ToString(format, info); } var builder = CreateBuilder(value, info, decimalFmt, digits); if (decimalFmt) { // Format Round-trip decimal // This format is supported for integral types only. The number is converted to a string of // decimal digits (0-9), prefixed by a minus sign if the number is negative. The precision // specifier indicates the minimum number of digits desired in the resulting string. If required, // the number is padded with zeros to its left to produce the number of digits given by the // precision specifier. while (digits > 0 && digits >= builder.Length) { builder.Prepend('0'); digits--; } if (value.InternalSign < 0) { builder.Prepend(info.NegativeSign); } return builder.ToString(); } // 'c', 'C', 'e', 'E', 'f', 'F', 'n', 'N', 'p', 'P', custom var precision = -1; var groupingSizes = new[] {3}; var groupingSeparator = info.NumberGroupSeparator; var decimalSeparator = info.NumberDecimalSeparator; var groups = false; var type = 0; if (fmt == '\0') { // parse custom } else { if (fmt == 'c' || fmt == 'C') { decimalSeparator = info.CurrencyDecimalSeparator; precision = digits != -1 ? digits : info.CurrencyDecimalDigits; groupingSeparator = info.CurrencyGroupSeparator; groupingSizes = info.CurrencyGroupSizes; groups = true; type = 1; } else if (fmt == 'f' || fmt == 'F') { precision = digits != -1 ? digits : info.NumberDecimalDigits; } else if (fmt == 'n' || fmt == 'N') { precision = digits != -1 ? digits : info.NumberDecimalDigits; groups = true; } else if (fmt == 'p' || fmt == 'P') { decimalSeparator = info.PercentDecimalSeparator; precision = digits != -1 ? digits : info.PercentDecimalDigits; groups = true; type = 2; } else { throw new NotImplementedException(); } } var result = new StringBuilder(builder.Length + 20); var close = SetWrap(value, info, type, result); var append = builder; if (groups) { var extra = groupingSizes.Length - 1; if (groupingSizes[groupingSizes.Length - 1] != 0) { var totalDigits = builder.Length; extra += (int) Math.Ceiling(totalDigits*1.0/groupingSizes[groupingSizes.Length - 1]); } var length = extra + builder.Length; if (type == 2) { length += 2; append = StringWithGroups(length, new ExtendedEnumerable<char>(new[] { '0', '0' }, builder), groupingSizes, groupingSeparator); } else { append = StringWithGroups(extra + builder.Length, builder, groupingSizes, groupingSeparator); } } result.Append(append); if (precision > 0) { result.Append(decimalSeparator); result.Append(new string('0', precision)); } result.Append(close); return result.ToString(); } }