Ejemplo n.º 1
0
        /// <summary>
        /// Parses provided string representation of <see cref="IntX" /> object.
        /// </summary>
        /// <param name="value">Number as string.</param>
        /// <param name="startIndex">Index inside string from which to start.</param>
        /// <param name="endIndex">Index inside string on which to end.</param>
        /// <param name="numberBase">Number base.</param>
        /// <param name="charToDigits">Char->digit dictionary.</param>
        /// <param name="digitsRes">Resulting digits.</param>
        /// <returns>Parsed integer length.</returns>
        public uint Parse(string value, int startIndex, int endIndex, uint numberBase, IDictionary <char, uint> charToDigits, uint[] digitsRes)
        {
            // Calculate length of input string
            int   bitsInChar     = Bits.Msb(numberBase);
            uint  valueLength    = (uint)(endIndex - startIndex + 1);
            ulong valueBitLength = (ulong)valueLength * (ulong)bitsInChar;

            // Calculate needed digits length and first shift
            uint digitsLength = (uint)(valueBitLength / Constants.DigitBitCount) + 1;
            uint digitIndex   = digitsLength - 1;
            int  initialShift = (int)(valueBitLength % Constants.DigitBitCount);

            // Probably correct digits length
            if (initialShift == 0)
            {
                --digitsLength;
            }

            // Do parsing in big cycle
            uint digit;

            for (int i = startIndex; i <= endIndex; ++i)
            {
                digit = StrRepHelper.GetDigit(charToDigits, value[i], numberBase);

                // Correct initial digit shift
                if (initialShift == 0)
                {
                    // If shift is equals to zero then char is not on digit elemtns bounds,
                    // so just go to the previous digit
                    initialShift = Constants.DigitBitCount - bitsInChar;
                    --digitIndex;
                }
                else
                {
                    // Here shift might be negative, but it's okay
                    initialShift -= bitsInChar;
                }

                // Insert new digit in correct place
                digitsRes[digitIndex] |= initialShift < 0 ? digit >> -initialShift : digit << initialShift;

                // In case if shift was negative we also must modify previous digit
                if (initialShift < 0)
                {
                    initialShift            += Constants.DigitBitCount;
                    digitsRes[--digitIndex] |= digit << initialShift;
                }
            }

            if (digitsRes[digitsLength - 1] == 0)
            {
                --digitsLength;
            }
            return(digitsLength);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Parses provided string representation of <see cref="IntX" /> object.
        /// </summary>
        /// <param name="value">Number as string.</param>
        /// <param name="startIndex">Index inside string from which to start.</param>
        /// <param name="endIndex">Index inside string on which to end.</param>
        /// <param name="numberBase">Number base.</param>
        /// <param name="charToDigits">Char->digit dictionary.</param>
        /// <param name="digitsRes">Resulting digits.</param>
        /// <returns>Parsed integer length.</returns>
        override public uint Parse(string value, int startIndex, int endIndex, uint numberBase, IDictionary <char, uint> charToDigits, uint[] digitsRes)
        {
            uint newLength = base.Parse(value, startIndex, endIndex, numberBase, charToDigits, digitsRes);

            // Maybe base method already parsed this number
            if (newLength != 0)
            {
                return(newLength);
            }

            // Do parsing in big cycle
            ulong numberBaseLong = numberBase;
            ulong digit;

            for (int i = startIndex; i <= endIndex; ++i)
            {
                digit = StrRepHelper.GetDigit(charToDigits, value[i], numberBase);

                // Next multiply existing values by base and add this value to them
                if (newLength == 0)
                {
                    if (digit != 0)
                    {
                        digitsRes[0] = (uint)digit;
                        newLength    = 1;
                    }
                }
                else
                {
                    for (uint j = 0; j < newLength; ++j)
                    {
                        digit       += digitsRes[j] * numberBaseLong;
                        digitsRes[j] = (uint)digit;
                        digit      >>= 32;
                    }
                    if (digit != 0)
                    {
                        digitsRes[newLength++] = (uint)digit;
                    }
                }
            }

            return(newLength);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Parses provided string representation of <see cref="IntX" /> object.
        /// </summary>
        /// <param name="value">Number as string.</param>
        /// <param name="startIndex">Index inside string from which to start.</param>
        /// <param name="endIndex">Index inside string on which to end.</param>
        /// <param name="numberBase">Number base.</param>
        /// <param name="charToDigits">Char->digit dictionary.</param>
        /// <param name="digitsRes">Resulting digits.</param>
        /// <returns>Parsed integer length.</returns>
        override unsafe public uint Parse(string value, int startIndex, int endIndex, uint numberBase, IDictionary <char, uint> charToDigits, uint[] digitsRes)
        {
            uint newLength = base.Parse(value, startIndex, endIndex, numberBase, charToDigits, digitsRes);

            // Maybe base method already parsed this number
            if (newLength != 0)
            {
                return(newLength);
            }

            // Check length - maybe use classic parser instead
            uint initialLength = (uint)digitsRes.LongLength;

            if (initialLength < Constants.FastParseLengthLowerBound || initialLength > Constants.FastParseLengthUpperBound)
            {
                return(_classicParser.Parse(value, startIndex, endIndex, numberBase, charToDigits, digitsRes));
            }

            uint valueLength  = (uint)(endIndex - startIndex + 1);
            uint digitsLength = 1U << Bits.CeilLog2(valueLength);

            // Prepare array for digits in other base
            uint[] valueDigits = ArrayPool <uint> .Instance.GetArray(digitsLength);

            // This second array will store integer lengths initially
            uint[] valueDigits2 = ArrayPool <uint> .Instance.GetArray(digitsLength);

            fixed(uint *valueDigitsStartPtr = valueDigits, valueDigitsStartPtr2 = valueDigits2)
            {
                // In the string first digit means last in digits array
                uint *valueDigitsPtr  = valueDigitsStartPtr + valueLength - 1;
                uint *valueDigitsPtr2 = valueDigitsStartPtr2 + valueLength - 1;

                // Reverse copy characters into digits
                fixed(char *valueStartPtr = value)
                {
                    char *valuePtr    = valueStartPtr + startIndex;
                    char *valueEndPtr = valuePtr + valueLength;

                    for (; valuePtr < valueEndPtr; ++valuePtr, --valueDigitsPtr, --valueDigitsPtr2)
                    {
                        // Get digit itself - this call will throw an exception if char is invalid
                        *valueDigitsPtr = StrRepHelper.GetDigit(charToDigits, *valuePtr, numberBase);

                        // Set length of this digit (zero for zero)
                        *valueDigitsPtr2 = *valueDigitsPtr == 0U ? 0U : 1U;
                    }
                }

                // We have retrieved lengths array from pool - it needs to be cleared before using
                DigitHelper.SetBlockDigits(valueDigitsStartPtr2 + valueLength, digitsLength - valueLength, 0);

                // Now start from the digit arrays beginning
                valueDigitsPtr  = valueDigitsStartPtr;
                valueDigitsPtr2 = valueDigitsStartPtr2;

                // Current multiplier (classic or fast) will be used
                IMultiplier multiplier = MultiplyManager.GetCurrentMultiplier();

                // Here base in needed power will be stored
                IntX baseInt = null;

                // Temporary variables used on swapping
                uint[] tempDigits;
                uint * tempPtr;

                // Variables used in cycle
                uint *ptr1, ptr2, valueDigitsPtrEnd;
                uint  loLength, hiLength;

                // Outer cycle instead of recursion
                for (uint innerStep = 1, outerStep = 2; innerStep < digitsLength; innerStep <<= 1, outerStep <<= 1)
                {
                    // Maybe baseInt must be multiplied by itself
                    baseInt = baseInt == null ? numberBase : baseInt * baseInt;

                    // Using unsafe here
                    fixed(uint *baseDigitsPtr = baseInt._digits)
                    {
                        // Start from arrays beginning
                        ptr1 = valueDigitsPtr;
                        ptr2 = valueDigitsPtr2;

                        // vauleDigits array end
                        valueDigitsPtrEnd = valueDigitsPtr + digitsLength;

                        // Cycle thru all digits and their lengths
                        for (; ptr1 < valueDigitsPtrEnd; ptr1 += outerStep, ptr2 += outerStep)
                        {
                            // Get lengths of "lower" and "higher" value parts
                            loLength = *ptr2;
                            hiLength = *(ptr2 + innerStep);

                            if (hiLength != 0)
                            {
                                // We always must clear an array before multiply
                                DigitHelper.SetBlockDigits(ptr2, outerStep, 0U);

                                // Multiply per baseInt
                                hiLength = multiplier.Multiply(
                                    baseDigitsPtr,
                                    baseInt._length,
                                    ptr1 + innerStep,
                                    hiLength,
                                    ptr2);
                            }

                            // Sum results
                            if (hiLength != 0 || loLength != 0)
                            {
                                *ptr1 = DigitOpHelper.Add(
                                    ptr2,
                                    hiLength,
                                    ptr1,
                                    loLength,
                                    ptr2);
                            }
                            else
                            {
                                *ptr1 = 0U;
                            }
                        }
                    }

                    // After inner cycle valueDigits will contain lengths and valueDigits2 will contain actual values
                    // so we need to swap them here
                    tempDigits   = valueDigits;
                    valueDigits  = valueDigits2;
                    valueDigits2 = tempDigits;

                    tempPtr         = valueDigitsPtr;
                    valueDigitsPtr  = valueDigitsPtr2;
                    valueDigitsPtr2 = tempPtr;
                }
            }

            // Determine real length of converted number
            uint realLength = valueDigits2[0];

            // Copy to result
            Array.Copy(valueDigits, digitsRes, realLength);

            // Return arrays to pool
            ArrayPool <uint> .Instance.AddArray(valueDigits);

            ArrayPool <uint> .Instance.AddArray(valueDigits2);

            return(realLength);
        }