static Constants() { BaseCharToDigits = StrRepHelper.CharDictionaryFromAlphabet(new string(BaseUpperChars), 16U); for (int i = 10; i < BaseLowerChars.Length; i++) { BaseCharToDigits.Add(BaseLowerChars[i], (uint)i); } }
/// <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); }
/// <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); }
/// <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); }