Exemple #1
0
        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);
        }
Exemple #2
0
        public static void ToStringWithNegativeBackIndexThrowsEvenWithCapacity()
        {
            var builder = new ReverseStringBuilder(20);

            builder.Prepend("0123456789");
            Assert.Throws <ArgumentOutOfRangeException, string>(() => builder.ToString(-1, 1));
        }
Exemple #3
0
        public static void ToStringWithBackIndexBeyondLengthReturnsNullChars()
        {
            var builder = new ReverseStringBuilder(20);

            builder.Prepend("0123456789");
            Assert.AreEqual("\0", builder.ToString(builder.Length + 1, 1));
        }
Exemple #4
0
        public static void ToStringWithBackIndexBeyondCapacityThrows()
        {
            var builder = new ReverseStringBuilder(10);

            builder.Prepend("0123456789");
            Assert.Throws <ArgumentOutOfRangeException, string>(() => builder.ToString(builder.Length + 1, 1));
        }
Exemple #5
0
        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));
        }
Exemple #6
0
        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();
            }
        }