From 5c9be81de6663f0e1abb8a9e359ff74d1b133c3f Mon Sep 17 00:00:00 2001 From: Pent Ploompuu Date: Wed, 18 Jul 2018 00:59:00 +0300 Subject: [PATCH] Clean-up number.cpp (dotnet/coreclr#18964) Commit migrated from https://github.com/dotnet/coreclr/commit/4b618d9dfe1690c9df9e3c5ce351ae18d1a7c239 --- src/coreclr/src/classlibnative/bcltype/number.cpp | 1229 --------------------- src/coreclr/src/classlibnative/bcltype/number.h | 2 - 2 files changed, 1231 deletions(-) diff --git a/src/coreclr/src/classlibnative/bcltype/number.cpp b/src/coreclr/src/classlibnative/bcltype/number.cpp index b4bf7a5..b20044e 100644 --- a/src/coreclr/src/classlibnative/bcltype/number.cpp +++ b/src/coreclr/src/classlibnative/bcltype/number.cpp @@ -8,88 +8,21 @@ // #include "common.h" -#include "excep.h" #include "number.h" -#include "string.h" #include "bignum.h" #include "grisu3.h" #include "fp.h" -#include typedef wchar_t wchar; -#define INT32_PRECISION 10 -#define UINT32_PRECISION INT32_PRECISION -#define INT64_PRECISION 19 -#define UINT64_PRECISION 20 -#define FLOAT_PRECISION 7 -#define DOUBLE_PRECISION 15 -#define LARGE_BUFFER_SIZE 600 -#define MIN_BUFFER_SIZE 105 - #define SCALE_NAN 0x80000000 #define SCALE_INF 0x7FFFFFFF - -static const char* const posCurrencyFormats[] = { - "$#", "#$", "$ #", "# $"}; - -static const char* const negCurrencyFormats[] = { - "($#)", "-$#", "$-#", "$#-", - "(#$)", "-#$", "#-$", "#$-", - "-# $", "-$ #", "# $-", "$ #-", - "$ -#", "#- $", "($ #)", "(# $)"}; - -static const char* const posPercentFormats[] = { - "# %", "#%", "%#", "% #" // Last one is new in Whidbey -}; - -static const char* const negPercentFormats[] = { - "-# %", "-#%", "-%#", - "%-#", "%#-", // Last 9 are new in WHidbey - "#-%", "#%-", - "-% #", "# %-", "% #-", - "% -#", "#- %" -}; - -static const char* const negNumberFormats[] = { - "(#)", "-#", "- #", "#-", "# -", -}; - -static const char posNumberFormat[] = "#"; - #if defined(_TARGET_X86_) && !defined(FEATURE_PAL) extern "C" void _cdecl /*__stdcall*/ DoubleToNumber(double value, int precision, NUMBER* number); extern "C" void _cdecl /*__stdcall*/ NumberToDouble(NUMBER* number, double* value); -#pragma warning(disable:4035) - -wchar_t* COMNumber::Int32ToDecChars(__in wchar_t* p, unsigned int value, int digits) -{ - LIMITED_METHOD_CONTRACT - - _asm { - mov eax,value - mov ebx,10 - mov ecx,digits - mov edi,p - jmp L2 -L1: xor edx,edx - div ebx - add edx,'0' //promote dl to edx to avoid partial register stall and LCP stall - sub edi,2 - mov [edi],dx -L2: dec ecx - jge L1 - or eax,eax - jne L1 - mov eax,edi - } -} - -#pragma warning(default:4035) - #else // _TARGET_X86_ && !FEATURE_PAL void Dragon4( double value, int count, int* dec, int* sign, wchar_t* digits ) @@ -807,1170 +740,8 @@ done: if (number->sign) *(UINT64*)value |= I64(0x8000000000000000); } -wchar_t* COMNumber::Int32ToDecChars(__in wchar_t* p, unsigned int value, int digits) -{ - LIMITED_METHOD_CONTRACT - _ASSERTE(p != NULL); - - while (--digits >= 0 || value != 0) { - *--p = value % 10 + '0'; - value /= 10; - } - return p; -} #endif // _TARGET_X86_ && !FEATURE_PAL -#if defined(_MSC_VER) && defined(_TARGET_X86_) -#pragma optimize("y", on) // Small critical routines, don't put in EBP frame -#endif - -inline void AddStringRef(__in wchar** ppBuffer, STRINGREF strRef) -{ - WRAPPER_NO_CONTRACT - _ASSERTE(ppBuffer != NULL && strRef != NULL); - - wchar* buffer = strRef->GetBuffer(); - _ASSERTE(buffer != NULL); - DWORD length = strRef->GetStringLength(); - for (wchar* str = buffer; str < buffer + length; (*ppBuffer)++, str++) - { - **ppBuffer = *str; - } -} - -inline wchar* GetDigitsBuffer(NUMBER* number) -{ - return (number->allDigits != NULL) ? number->allDigits : number->digits; -} - -#if defined(_MSC_VER) && defined(_TARGET_X86_) -#pragma optimize("", on) // Go back to command line default optimizations -#endif - - -void RoundNumber(NUMBER* number, int pos) -{ - LIMITED_METHOD_CONTRACT - _ASSERTE(number != NULL); - - wchar_t* digits = GetDigitsBuffer(number); - int i = 0; - while (i < pos && digits[i] != 0) i++; - if (i == pos && digits[i] >= '5') { - while (i > 0 && digits[i - 1] == '9') i--; - if (i > 0) { - digits[i - 1]++; - } - else { - number->scale++; - digits[0] = '1'; - i = 1; - } - } - else { - while (i > 0 && digits[i - 1] == '0') i--; - } - if (i == 0) { - number->scale = 0; - number->sign = 0; - } - digits[i] = 0; - -} - -#if defined(_MSC_VER) && defined(_TARGET_X86_) -#pragma optimize("y", on) // Small critical routines, don't put in EBP frame -#endif - -wchar ParseFormatSpecifier(STRINGREF str, int* digits) -{ - WRAPPER_NO_CONTRACT - _ASSERTE(digits != NULL); - - if (str != 0) { - wchar* p = str->GetBuffer(); - _ASSERTE(p != NULL); - wchar ch = *p; - if (ch != 0) { - if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) { - p++; - int n = -1; - if (*p >= '0' && *p <= '9') { - n = *p++ - '0'; - while (*p >= '0' && *p <= '9') { - n = n * 10 + *p++ - '0'; - if (n >= 10) break; - } - } - if (*p == 0) { - *digits = n; - return ch; - } - } - return 0; - } - } - *digits = -1; - return 'G'; -} - -wchar* FormatExponent(__in wchar* buffer, int value, wchar expChar, - STRINGREF posSignStr, STRINGREF negSignStr, int minDigits) -{ - WRAPPER_NO_CONTRACT - _ASSERTE(buffer != NULL); - - wchar digits[11]; - *buffer++ = expChar; - if (value < 0) { - _ASSERTE(negSignStr != NULL); - AddStringRef(&buffer, negSignStr); - value = -value; - } - else { - if (posSignStr!= NULL) { - AddStringRef(&buffer, posSignStr); - } - } - wchar* p = COMNumber::Int32ToDecChars(digits + 10, value, minDigits); - _ASSERTE(p != NULL); - int i = (int) (digits + 10 - p); - while (--i >= 0) *buffer++ = *p++; - return buffer; -} - -#if defined(_MSC_VER) && defined(_TARGET_X86_) -#pragma optimize("", on) // Go back to command line default optimizations -#endif - -wchar* FormatGeneral(__in_ecount(cchBuffer) wchar* buffer, SIZE_T cchBuffer, NUMBER* number, int nMinDigits, int nMaxDigits, wchar expChar, - STRINGREF sNumberDecimal, STRINGREF sPositive, STRINGREF sNegative, STRINGREF sZero, BOOL bSuppressScientific = FALSE) -{ - WRAPPER_NO_CONTRACT - _ASSERTE(number != NULL); - _ASSERTE(buffer != NULL); - - int digPos = number->scale; - int scientific = 0; - if (!bSuppressScientific) { // Don't switch to scientific notation - if (digPos > nMaxDigits || digPos < -3) { - digPos = 1; - scientific = 1; - } - } - - wchar* dig = GetDigitsBuffer(number); - _ASSERT(dig != NULL); - if (digPos > 0) { - do { - *buffer++ = *dig != 0? *dig++: '0'; - } while (--digPos > 0); - } - else { - *buffer++ = '0'; - } - if (*dig != 0 || digPos < 0) { - AddStringRef(&buffer, sNumberDecimal); - while (digPos < 0) { - *buffer++ = '0'; - digPos++; - } - while (*dig != 0) { - *buffer++ = *dig++; - } - } - if (scientific) buffer = FormatExponent(buffer, number->scale - 1, expChar, sPositive, sNegative, 2); - return buffer; -} - -wchar* FormatScientific(__in_ecount(cchBuffer) wchar* buffer, SIZE_T cchBuffer, NUMBER* number, int nMinDigits, int nMaxDigits, wchar expChar, - STRINGREF sNumberDecimal, STRINGREF sPositive, STRINGREF sNegative, STRINGREF sZero) -{ - WRAPPER_NO_CONTRACT - _ASSERTE(number != NULL); - _ASSERTE(buffer != NULL); - - wchar* dig = GetDigitsBuffer(number); - _ASSERTE(dig != NULL); - *buffer++ = *dig != 0? *dig++: '0'; - if (nMaxDigits != 1) // For E0 we would like to suppress the decimal point - AddStringRef(&buffer, sNumberDecimal); - while (--nMaxDigits > 0) *buffer++ = *dig != 0? *dig++: '0'; - int e = (GetDigitsBuffer(number))[0] == 0 ? 0 : number->scale - 1; - buffer = FormatExponent(buffer, e, expChar, sPositive, sNegative, 3); - _ASSERTE(buffer != NULL); - return buffer; -} - -wchar* FormatFixed(__in_ecount(cchBuffer) wchar* buffer, SIZE_T cchBuffer, NUMBER* number, int nMinDigits, int nMaxDigits, - I4ARRAYREF groupDigitsRef, STRINGREF sDecimal, STRINGREF sGroup, STRINGREF sNegative,STRINGREF sZero) -{ - CONTRACTL { - THROWS; - INJECT_FAULT(COMPlusThrowOM()); - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(buffer)); - PRECONDITION(CheckPointer(number)); - } CONTRACTL_END; - - int digPos = number->scale; - wchar* dig = GetDigitsBuffer(number); - const I4* groupDigits = NULL; - if (groupDigitsRef != NULL) { - groupDigits = groupDigitsRef->GetDirectConstPointerToNonObjectElements(); - } - - if (digPos > 0) { - if (groupDigits != NULL) { - - int groupSizeIndex = 0; // index into the groupDigits array. - int groupSizeCount = groupDigits[groupSizeIndex]; // the current total of group size. - int groupSizeLen = groupDigitsRef->GetNumComponents(); // the length of groupDigits array. - int bufferSize = digPos; // the length of the result buffer string. - int groupSeparatorLen = sGroup->GetStringLength(); // the length of the group separator string. - int groupSize = 0; // the current group size. - - // - // Find out the size of the string buffer for the result. - // - if (groupSizeLen != 0) // You can pass in 0 length arrays - { - while (digPos > groupSizeCount) { - groupSize = groupDigits[groupSizeIndex]; - if (groupSize == 0) { - break; - } - - bufferSize += groupSeparatorLen; - if (groupSizeIndex < groupSizeLen - 1) { - groupSizeIndex++; - } - groupSizeCount += groupDigits[groupSizeIndex]; - if (groupSizeCount < 0 || bufferSize < 0) { - COMPlusThrow(kArgumentOutOfRangeException); // if we overflow - } - } - if (groupSizeCount == 0) // If you passed in an array with one entry as 0, groupSizeCount == 0 - groupSize = 0; - else - groupSize = groupDigits[0]; - } - - groupSizeIndex = 0; - int digitCount = 0; - int digStart; - int digLength = (int)wcslen(dig); - digStart = (digPos=0; i--) { - *(p--) = (i 0) { - digitCount++; - if (digitCount == groupSize && i != 0) { - for (int j = groupSeparatorLen - 1; j >=0; j--) { - *(p--) = sGroup->GetBuffer()[j]; - } - - if (groupSizeIndex < groupSizeLen - 1) { - groupSizeIndex++; - groupSize = groupDigits[groupSizeIndex]; - } - digitCount = 0; - } - } - } - if (p < buffer - 1) { - // This indicates a buffer underflow since we write in backwards. - DoJITFailFast(); - } - buffer += bufferSize; - dig += digStart; - } else { - do { - *buffer++ = *dig != 0? *dig++: '0'; - } while (--digPos > 0); - } - } - else { - *buffer++ = '0'; - } - if (nMaxDigits > 0) { - AddStringRef(&buffer, sDecimal); - while (digPos < 0 && nMaxDigits > 0) { - *buffer++ = '0'; - digPos++; - nMaxDigits--; - } - while (nMaxDigits > 0) { - *buffer++ = *dig != 0? *dig++: '0'; - nMaxDigits--; - } - } - return buffer; -} - -wchar* FormatNumber(__in_ecount(cchBuffer) wchar* buffer, SIZE_T cchBuffer, NUMBER* number, int nMinDigits, int nMaxDigits, int cNegativeNumberFormat, I4ARRAYREF cNumberGroup, STRINGREF sNumberDecimal, STRINGREF sNumberGroup, STRINGREF sNegative, STRINGREF sZero) -{ - CONTRACTL { - MODE_COOPERATIVE; - THROWS; - GC_TRIGGERS; - PRECONDITION(CheckPointer(buffer)); - PRECONDITION(CheckPointer(number)); - } CONTRACTL_END; - - char ch; - const char* fmt; - fmt = number->sign? - negNumberFormats[cNegativeNumberFormat]: - posNumberFormat; - - while ((ch = *fmt++) != 0) { - switch (ch) { - case '#': - buffer = FormatFixed(buffer, cchBuffer, number, nMinDigits,nMaxDigits, - cNumberGroup, - sNumberDecimal, sNumberGroup,sNegative,sZero); - break; - case '-': - AddStringRef(&buffer, sNegative); - break; - default: - *buffer++ = ch; - } - } - return buffer; - -} - -wchar* FormatCurrency(__in_ecount(cchBuffer) wchar* buffer, SIZE_T cchBuffer, NUMBER* number, int nMinDigits,int nMaxDigits, int cNegCurrencyFormat, int cPosCurrencyFormat, I4ARRAYREF cCurrencyGroup, - STRINGREF sCurrencyDecimal, STRINGREF sCurrencyGroup, STRINGREF sNegative, STRINGREF sCurrency,STRINGREF sZero) -{ - CONTRACTL { - MODE_COOPERATIVE; - THROWS; - GC_TRIGGERS; - PRECONDITION(CheckPointer(buffer)); - PRECONDITION(CheckPointer(number)); - } CONTRACTL_END; - - char ch; - const char* fmt; - fmt = number->sign? - negCurrencyFormats[cNegCurrencyFormat]: - posCurrencyFormats[cPosCurrencyFormat]; - - while ((ch = *fmt++) != 0) { - switch (ch) { - case '#': - buffer = FormatFixed(buffer, cchBuffer, number, nMinDigits,nMaxDigits, - cCurrencyGroup, - sCurrencyDecimal, sCurrencyGroup,sNegative,sZero); - break; - case '-': - AddStringRef(&buffer, sNegative); - break; - case '$': - AddStringRef(&buffer, sCurrency); - break; - default: - *buffer++ = ch; - } - } - return buffer; -} - -wchar* FormatPercent(__in_ecount(cchBuffer) wchar* buffer, SIZE_T cchBuffer, NUMBER* number, int nMinDigits, int nMaxDigits, int cNegativePercentFormat, int cPositivePercentFormat, I4ARRAYREF cPercentGroup, - STRINGREF sPercentDecimal, STRINGREF sPercentGroup, STRINGREF sNegative, STRINGREF sPercent, STRINGREF sZero) -{ - CONTRACTL { - MODE_COOPERATIVE; - THROWS; - GC_TRIGGERS; - PRECONDITION(CheckPointer(buffer)); - PRECONDITION(CheckPointer(number)); - } CONTRACTL_END; - - char ch; - const char* fmt; - fmt = number->sign? - negPercentFormats[cNegativePercentFormat]: - posPercentFormats[cPositivePercentFormat]; - - while ((ch = *fmt++) != 0) { - switch (ch) { - case '#': - buffer = FormatFixed(buffer, cchBuffer, number, nMinDigits,nMaxDigits, - cPercentGroup, - sPercentDecimal, sPercentGroup,sNegative,sZero); - break; - case '-': - AddStringRef(&buffer, sNegative); - break; - case '%': - AddStringRef(&buffer, sPercent); - break; - default: - *buffer++ = ch; - } - } - return buffer; -} - -STRINGREF NumberToString(NUMBER* number, wchar format, int nMaxDigits, NUMFMTREF numfmt, BOOL bDecimal = FALSE ) -{ - CONTRACTL { - THROWS; - INJECT_FAULT(COMPlusThrowOM()); - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(number)); - } CONTRACTL_END; - - int nMinDigits=-1; - STRINGREF sZero=NULL; - - // @TODO what if not sequential? - - // Do the worst case calculation - /* US English - for Double.MinValue.ToString("C99"); we require 514 characters - ---------- - 2 paranthesis - 1 currency character - 308 characters - 103 group seperators - 1 decimal separator - 99 0's - - digPos + 99 + 6(slack) => digPos + 105 - C - sNegative - sCurrencyGroup - sCurrencyDecimal - sCurrency - F - sNegative - sNumberDecimal - N - sNegative - sNumberDecimal - sNumberGroup - E - sNegative - sPositive - sNegative (for exponent) - sPositive - sNumberDecimal - G - sNegative - sPositive - sNegative (for exponent) - sPositive - sNumberDecimal - P (+2 for some spaces) - sNegative - sPercentGroup - sPercentDecimal - sPercent - */ - - _ASSERTE(numfmt != NULL); - _ASSERTE(!bDecimal); - UINT64 newBufferLen = MIN_BUFFER_SIZE; - - CQuickBytesSpecifySize buf; - - wchar *buffer = NULL; - wchar* dst = NULL; - wchar ftype = format & 0xFFDF; - int digCount = 0; - - switch (ftype) { - case 'C': - { - nMinDigits = nMaxDigits >= 0 ? nMaxDigits : numfmt->cCurrencyDecimals; - - if (nMaxDigits< 0) - nMaxDigits = numfmt->cCurrencyDecimals; - if (number->scale < 0) - digCount = 0; - else if (!ClrSafeInt::addition(number->scale, nMaxDigits, digCount)) - COMPlusThrowOM(); - - // It is critical to format with the same values that we use to calculate buffer size. - int cNegCurrencyFormat = numfmt->cNegCurrencyFormat; - int cPosCurrencyFormat = numfmt->cPosCurrencyFormat; - I4ARRAYREF cCurrencyGroup = numfmt->cCurrencyGroup; - STRINGREF sCurrencyDecimal = numfmt->sCurrencyDecimal; - STRINGREF sCurrencyGroup = numfmt->sCurrencyGroup; - STRINGREF sNegative = numfmt->sNegative; - STRINGREF sCurrency = numfmt->sCurrency; - // Prefix: bogus warning 22011: newBufferLen+=digCount may be smaller than MIN_BUFFER_SIZE - PREFIX_ASSUME(digCount >=0 && digCount <= INT32_MAX); - newBufferLen += digCount; - newBufferLen += sNegative->GetStringLength(); // For number and exponent - if (!ClrSafeInt::addition((UINT64)sCurrencyGroup->GetStringLength() * digCount, newBufferLen, newBufferLen)) - COMPlusThrowOM(); - newBufferLen += sCurrencyDecimal->GetStringLength(); - newBufferLen += sCurrency->GetStringLength(); - - _ASSERTE(newBufferLen >= MIN_BUFFER_SIZE); - if (newBufferLen > INT32_MAX) { - COMPlusThrowOM(); - } - newBufferLen = newBufferLen * sizeof(WCHAR); - dst = buffer = (WCHAR*)buf.AllocThrows(static_cast(newBufferLen)); - - RoundNumber(number, number->scale + nMaxDigits); // Don't change this line to use digPos since digCount could have its sign changed. - dst = FormatCurrency(dst, static_cast(newBufferLen/sizeof(WCHAR)), number, nMinDigits,nMaxDigits, cNegCurrencyFormat, cPosCurrencyFormat, cCurrencyGroup, sCurrencyDecimal, sCurrencyGroup, sNegative, sCurrency,sZero); - - break; - } - case 'F': - { - if (nMaxDigits< 0) - // This ensures that the PAL code pads out to the correct place even when we use the default precision - nMaxDigits = nMinDigits = numfmt->cNumberDecimals; - else - nMinDigits=nMaxDigits; - - if (number->scale < 0) - digCount = 0; - else - digCount = number->scale + nMaxDigits; - - - // It is critical to format with the same values that we use to calculate buffer size. - STRINGREF sNumberDecimal = numfmt->sNumberDecimal; - STRINGREF sNegative = numfmt->sNegative; - - newBufferLen += digCount; - newBufferLen += sNegative->GetStringLength(); // For number and exponent - newBufferLen += sNumberDecimal->GetStringLength(); - - _ASSERTE(newBufferLen >= MIN_BUFFER_SIZE); - if (newBufferLen > INT32_MAX) { - COMPlusThrowOM(); - } - newBufferLen = newBufferLen * sizeof(WCHAR); - dst = buffer = (WCHAR*)buf.AllocThrows(static_cast(newBufferLen)); - - RoundNumber(number, number->scale + nMaxDigits); - if (number->sign) { - AddStringRef(&dst, sNegative); - } - dst = FormatFixed(dst, static_cast(newBufferLen/sizeof(WCHAR)-(dst-buffer)), number, nMinDigits,nMaxDigits, - NULL, - sNumberDecimal, NULL, sNegative, sZero); - - break; - } - case 'N': - { - if (nMaxDigits < 0) - // This ensures that the PAL code pads out to the correct place even when we use the default precision - nMaxDigits = nMinDigits = numfmt->cNumberDecimals; // Since we are using digits in our calculation - else - nMinDigits=nMaxDigits; - - if (number->scale < 0) - digCount = 0; - else - digCount = number->scale + nMaxDigits; - - // It is critical to format with the same values that we use to calculate buffer size. - I4ARRAYREF cNumberGroup = numfmt->cNumberGroup; - STRINGREF sNegative = numfmt->sNegative; - STRINGREF sNumberDecimal = numfmt->sNumberDecimal; - STRINGREF sNumberGroup = numfmt->sNumberGroup; - int cNegativeNumberFormat = numfmt->cNegativeNumberFormat; - newBufferLen += digCount; - newBufferLen += sNegative->GetStringLength(); // For number and exponent - if (!ClrSafeInt::addition((UINT64)sNumberGroup->GetStringLength() * digCount, newBufferLen, newBufferLen)) - COMPlusThrowOM(); - newBufferLen += sNumberDecimal->GetStringLength(); - - _ASSERTE(newBufferLen >= MIN_BUFFER_SIZE); - if (newBufferLen > INT32_MAX) { - COMPlusThrowOM(); - } - newBufferLen = newBufferLen * sizeof(WCHAR); - dst = buffer = (WCHAR*)buf.AllocThrows(static_cast(newBufferLen)); - - RoundNumber(number, number->scale + nMaxDigits); - dst = FormatNumber(dst, static_cast(newBufferLen/sizeof(WCHAR)),number, nMinDigits, nMaxDigits, cNegativeNumberFormat, cNumberGroup, sNumberDecimal, sNumberGroup, sNegative, sZero); - - break; - } - case 'E': - { - // It is critical to format with the same values that we use to calculate buffer size. - STRINGREF sNumberDecimal = numfmt->sNumberDecimal; - STRINGREF sNegative = numfmt->sNegative; - STRINGREF sPositive = numfmt->sPositive; - - if (nMaxDigits < 0) - // This ensures that the PAL code pads out to the correct place even when we use the default precision - nMaxDigits = nMinDigits = 6; - else - nMinDigits=nMaxDigits; - nMaxDigits++; - - newBufferLen += nMaxDigits; - newBufferLen += (((INT64)sNegative->GetStringLength() + sPositive->GetStringLength()) *2); // For number and exponent - newBufferLen += sNumberDecimal->GetStringLength(); - - _ASSERTE(newBufferLen >= MIN_BUFFER_SIZE); - if (newBufferLen > INT32_MAX) { - COMPlusThrowOM(); - } - newBufferLen = newBufferLen * sizeof(WCHAR); - dst = buffer = (WCHAR*)buf.AllocThrows(static_cast(newBufferLen)); - - RoundNumber(number, nMaxDigits); - if (number->sign) { - AddStringRef(&dst, sNegative); - } - dst = FormatScientific(dst, static_cast(newBufferLen * sizeof(WCHAR)-(dst-buffer)),number, nMinDigits,nMaxDigits, format, sNumberDecimal, sPositive, sNegative,sZero); - - break; - } - case 'G': - { - bool enableRounding = true; - if (nMaxDigits < 1) { - // This ensures that the PAL code pads out to the correct place even when we use the default precision - nMaxDigits = nMinDigits = number->precision; - } - else - nMinDigits=nMaxDigits; - - // It is critical to format with the same values that we use to calculate buffer size. - STRINGREF sNumberDecimal = numfmt->sNumberDecimal; - STRINGREF sNegative = numfmt->sNegative; - STRINGREF sPositive = numfmt->sPositive; - newBufferLen += nMaxDigits; - newBufferLen += (((INT64)sNegative->GetStringLength() + sPositive->GetStringLength()) *2); // For number and exponent - newBufferLen += sNumberDecimal->GetStringLength(); - - _ASSERTE(newBufferLen >= MIN_BUFFER_SIZE); - if (newBufferLen > INT32_MAX) { - COMPlusThrowOM(); - } - newBufferLen = newBufferLen * sizeof(WCHAR); - dst = buffer = (WCHAR*)buf.AllocThrows(static_cast(newBufferLen)); - - if (enableRounding) // Don't round for G formatting without precision - RoundNumber(number, nMaxDigits); // This also fixes up the minus zero case - if (number->sign) { - AddStringRef(&dst, sNegative); - } - - - dst = FormatGeneral(dst, static_cast(newBufferLen/sizeof(WCHAR)), number, nMinDigits,nMaxDigits, format - ('G' - 'E'), sNumberDecimal, sPositive, sNegative, sZero, !enableRounding); - - } - break; - case 'P': - { - if (nMaxDigits< 0) - // This ensures that the PAL code pads out to the correct place even when we use the default precision - nMaxDigits = nMinDigits = numfmt->cPercentDecimals; - else - nMinDigits=nMaxDigits; - number->scale += 2; - - if (number->scale < 0) - digCount = 0; - else - digCount = number->scale + nMaxDigits; - - - - // It is critical to format with the same values that we use to calculate buffer size. - int cNegativePercentFormat = numfmt->cNegativePercentFormat; - int cPositivePercentFormat = numfmt->cPositivePercentFormat; - I4ARRAYREF cPercentGroup = numfmt->cPercentGroup; - STRINGREF sPercentDecimal = numfmt->sPercentDecimal; - STRINGREF sPercentGroup = numfmt->sPercentGroup; - STRINGREF sNegative = numfmt->sNegative; - STRINGREF sPercent = numfmt->sPercent; - - newBufferLen += digCount; - newBufferLen += sNegative->GetStringLength(); // For number and exponent - if (!ClrSafeInt::addition((UINT64)sPercentGroup->GetStringLength() * digCount, newBufferLen, newBufferLen)) - COMPlusThrowOM(); - newBufferLen += sPercentDecimal->GetStringLength(); - newBufferLen += sPercent->GetStringLength(); - - _ASSERTE(newBufferLen >= MIN_BUFFER_SIZE); - if (newBufferLen > INT32_MAX) { - COMPlusThrowOM(); - } - newBufferLen = newBufferLen * sizeof(WCHAR); - dst = buffer = (WCHAR*)buf.AllocThrows(static_cast(newBufferLen)); - - RoundNumber(number, number->scale + nMaxDigits); - dst = FormatPercent(dst, static_cast(newBufferLen/sizeof(WCHAR)),number, nMinDigits,nMaxDigits, cNegativePercentFormat, cPositivePercentFormat, cPercentGroup, sPercentDecimal, sPercentGroup, sNegative, sPercent, sZero); - - break; - } - default: - COMPlusThrow(kFormatException, W("Argument_BadFormatSpecifier")); - } - // check for overflow of the preallocated buffer -// Review signed/unsigned mismatch in '<=' comparison. -#pragma warning(push) -#pragma warning(disable:4018) - if (!((dst - buffer >= 0) && (dst - buffer) <= (newBufferLen / sizeof(WCHAR) ))) { -#pragma warning(pop) - DoJITFailFast(); - } - - return StringObject::NewString(buffer, (int) (dst - buffer)); -} - -LPCWSTR FindSection(LPCWSTR format, int section) -{ - LIMITED_METHOD_CONTRACT - _ASSERTE(format != NULL); - - LPCWSTR src; - wchar ch; - if (section == 0) return format; - src = format; - for (;;) { - switch (ch = *src++) { - case '\'': - case '"': - while (*src != 0 && *src++ != ch); - break; - case '\\': - if (*src != 0) src++; - break; - case ';': - if (--section != 0) break; - if (*src != 0 && *src != ';') return src; - case 0: - return format; - } - } -} - -#ifdef _PREFAST_ -#pragma warning(push) -#pragma warning(disable:21000) // Suppress PREFast warning about overly large function -#endif -STRINGREF NumberToStringFormat(NUMBER* number, STRINGREF str, NUMFMTREF numfmt) -{ - CONTRACTL { - THROWS; - INJECT_FAULT(COMPlusThrowOM()); - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - int digitCount; - int decimalPos; - int firstDigit; - int lastDigit; - int digPos; - int scientific; - int percent; - int permille; - int thousandPos; - int thousandCount = 0; - int thousandSeps; - int scaleAdjust; - int adjust; - wchar* format=NULL; - LPCWSTR section=NULL; - LPCWSTR src=NULL; - wchar* dst=NULL; - wchar* dig=NULL; - wchar ch; - wchar* buffer=NULL; - CQuickBytes buf; - - _ASSERTE(str != NULL); - _ASSERTE(numfmt != NULL); - - STRINGREF sNegative = numfmt->sNegative; - STRINGREF sPositive = numfmt->sPositive; - STRINGREF sNumberDecimal = numfmt->sNumberDecimal; - STRINGREF sPercent = numfmt->sPercent; - STRINGREF sPerMille = numfmt->sPerMille; - STRINGREF sNumberGroup = numfmt->sNumberGroup; - I4ARRAYREF cNumberGroup = numfmt->cNumberGroup; - - format = str->GetBuffer(); - - section = FindSection(format, (GetDigitsBuffer(number))[0] == 0 ? 2 : number->sign ? 1 : 0); - -ParseSection: - digitCount = 0; - decimalPos = -1; - firstDigit = 0x7FFFFFFF; - lastDigit = 0; - scientific = 0; - percent = 0; - permille = 0; - thousandPos = -1; - thousandSeps = 0; - scaleAdjust = 0; - src = section; - _ASSERTE(src != NULL); - while ((ch = *src++) != 0 && ch != ';') { - switch (ch) { - case '#': - digitCount++; - break; - case '0': - if (firstDigit == 0x7FFFFFFF) firstDigit = digitCount; - digitCount++; - lastDigit = digitCount; - break; - case '.': - if (decimalPos < 0) { - decimalPos = digitCount; - } - break; - case ',': - if (digitCount > 0 && decimalPos < 0) { - if (thousandPos >= 0) { - if (thousandPos == digitCount) { - thousandCount++; - break; - } - thousandSeps = 1; - } - thousandPos = digitCount; - thousandCount = 1; - } - break; - case '%': - percent++; - scaleAdjust += 2; - break; - case 0x2030: - permille++; - scaleAdjust += 3; - break; - case '\'': - case '"': - while (*src != 0 && *src++ != ch); - break; - case '\\': - if (*src != 0) src++; - break; - case 'E': - case 'e': - if (*src=='0' || ((*src == '+' || *src == '-') && src[1] == '0')) { - while (*++src == '0'); - scientific = 1; - } - break; - } - } - - if (decimalPos < 0) decimalPos = digitCount; - if (thousandPos >= 0) { - if (thousandPos == decimalPos) { - scaleAdjust -= thousandCount * 3; - } - else { - thousandSeps = 1; - } - } - if ((GetDigitsBuffer(number))[0] != 0) { - number->scale += scaleAdjust; - int pos = scientific? digitCount: number->scale + digitCount - decimalPos; - RoundNumber(number, pos); - if ((GetDigitsBuffer(number))[0] == 0) { - src = FindSection(format, 2); - if (src != section) { - section = src; - goto ParseSection; - } - } - } else { - number->sign = 0; // We need to format -0 without the sign set. - number->scale = 0; // Decimals with scale ('0.00') should be rounded. - } - - firstDigit = firstDigit < decimalPos? decimalPos - firstDigit: 0; - lastDigit = lastDigit > decimalPos? decimalPos - lastDigit: 0; - if (scientific) { - digPos = decimalPos; - adjust = 0; - } - else { - digPos = number->scale > decimalPos? number->scale: decimalPos; - adjust = number->scale - decimalPos; - } - src = section; - dig = GetDigitsBuffer(number); - - // Find maximum number of characters that the destination string can grow by - // in the following while loop. Use this to avoid buffer overflows. - // Longest strings are potentially +/- signs with 10 digit exponents, - // or decimal numbers, or the while loops copying from a quote or a \ onwards. - // Check for positive and negative - UINT64 maxStrIncLen = 0; // We need this to be UINT64 since the percent computation could go beyond a UINT. - if (number->sign) { - maxStrIncLen = sNegative->GetStringLength(); - } - else { - maxStrIncLen = sPositive->GetStringLength(); - } - - // Add for any big decimal seperator - maxStrIncLen += sNumberDecimal->GetStringLength(); - - // Add for scientific - if (scientific) { - int inc1 = sPositive->GetStringLength(); - int inc2 = sNegative->GetStringLength(); - maxStrIncLen +=(inc1>inc2)?inc1:inc2; - } - - // Add for percent separator - if (percent) { - maxStrIncLen += ((INT64)sPercent->GetStringLength()) * percent; - } - - // Add for permilli separator - if (permille) { - maxStrIncLen += ((INT64)sPerMille->GetStringLength()) * permille; - } - - //adjust can be negative, so we make this an int instead of an unsigned int. - // adjust represents the number of characters over the formatting eg. format string is "0000" and you are trying to - // format 100000 (6 digits). Means adjust will be 2. On the other hand if you are trying to format 10 adjust will be - // -2 and we'll need to fixup these digits with 0 padding if we have 0 formatting as in this example. - INT64 adjustLen=(adjust>0)?adjust:0; // We need to add space for these extra characters anyway. - CQuickBytes thousands; - INT32 bufferLen2 = 125; - INT32 *thousandsSepPos = NULL; - INT32 thousandsSepCtr = -1; - - if (thousandSeps) { // Fixup possible buffer overrun problems - // We need to precompute this outside the number formatting loop - if(cNumberGroup->GetNumComponents() == 0) { - thousandSeps = 0; // Nothing to add - } - else { - thousandsSepPos = (INT32 *)thousands.AllocThrows(bufferLen2 * sizeof(INT32)); - // We need this array to figure out where to insert the thousands separator. We would have to traverse the string - // backwards. PIC formatting always traverses forwards. These indices are precomputed to tell us where to insert - // the thousands separator so we can get away with traversing forwards. Note we only have to compute up to digPos. - // The max is not bound since you can have formatting strings of the form "000,000..", and this - // should handle that case too. - - const I4* groupDigits = cNumberGroup->GetDirectConstPointerToNonObjectElements(); - _ASSERTE(groupDigits != NULL); - - int groupSizeIndex = 0; // index into the groupDigits array. - INT64 groupTotalSizeCount = 0; - int groupSizeLen = cNumberGroup->GetNumComponents(); // the length of groupDigits array. - if (groupSizeLen != 0) - groupTotalSizeCount = groupDigits[groupSizeIndex]; // the current running total of group size. - int groupSize = static_cast(groupTotalSizeCount); // safe cast as long as groupDigits remains I4 - - int totalDigits = digPos + ((adjust < 0)?adjust:0); // actual number of digits in o/p - int numDigits = (firstDigit > totalDigits) ? firstDigit : totalDigits; - while (numDigits > groupTotalSizeCount) { - if (groupSize == 0) - break; - thousandsSepPos[++thousandsSepCtr] = static_cast(groupTotalSizeCount); - if (groupSizeIndex < groupSizeLen - 1) { - groupSizeIndex++; - groupSize = groupDigits[groupSizeIndex]; - } - groupTotalSizeCount += groupSize; - if (bufferLen2 - thousandsSepCtr < 10) { // Slack of 10 - bufferLen2 *= 2; - thousands.ReSizeThrows(bufferLen2*sizeof(INT32)); // memcopied by CQuickBytes automatically - thousandsSepPos = (INT32 *)thousands.Ptr(); - } - } - - // We already have computed the number of separators above. Simply add space for them. - adjustLen += ( (thousandsSepCtr + 1) * ((INT64)sNumberGroup->GetStringLength())); - } - } - - maxStrIncLen += adjustLen; - - // Allocate temp buffer - gotta deal with Schertz' 500 MB strings. - // Some computations like when you specify Int32.MaxValue-2 %'s and each percent is setup to be Int32.MaxValue in length - // will generate a result that will be largest than an unsigned int can hold. This is to protect against overflow. - UINT64 tempLen = str->GetStringLength() + maxStrIncLen + 10; // Include a healthy amount of temp space. - if (tempLen > 0x7FFFFFFF) - COMPlusThrowOM(); // if we overflow - - unsigned int bufferLen = (UINT)tempLen; - if (bufferLen < 250) // Stay under 512 bytes - bufferLen = 250; // This is to prevent unnecessary calls to resize - buffer = (wchar *) buf.AllocThrows(bufferLen* sizeof(WCHAR)); - dst = buffer; - - - if (number->sign && section == format) { - AddStringRef(&dst, sNegative); - } - - BOOL decimalWritten = FALSE; - - while ((ch = *src++) != 0 && ch != ';') { - // Make sure temp buffer is big enough, else resize it. - if (bufferLen - (unsigned int)(dst-buffer) < 10) { - int offset = static_cast(dst - buffer); - bufferLen *= 2; - buf.ReSizeThrows(bufferLen*sizeof(WCHAR)); - buffer = (wchar*)buf.Ptr(); // memcopied by QuickBytes automatically - dst = buffer + offset; - } - - if (adjust > 0) { - switch (ch) { - case '#': - case '0': - case '.': - while (adjust > 0) { // digPos will be one greater than thousandsSepPos[thousandsSepCtr] since we are at - // the character after which the groupSeparator needs to be appended. - *dst++ = *dig != 0? *dig++: '0'; - if (thousandSeps && digPos > 1 && thousandsSepCtr>=0) { - if (digPos == thousandsSepPos[thousandsSepCtr] + 1) { - AddStringRef(&dst, sNumberGroup); - thousandsSepCtr--; - } - } - digPos--; - adjust--; - } - } - } - - switch (ch) { - case '#': - case '0': - { - if (adjust < 0) { - adjust++; - ch = digPos <= firstDigit? '0': 0; - } - else { - ch = *dig != 0? *dig++: digPos > lastDigit? '0': 0; - } - if (ch != 0) { - *dst++ = ch; - if (thousandSeps && digPos > 1 && thousandsSepCtr>=0) { - if (digPos == thousandsSepPos[thousandsSepCtr] + 1) { - AddStringRef(&dst, sNumberGroup); - thousandsSepCtr--; - } - } - } - - digPos--; - break; - } - case '.': - { - if (digPos != 0 || decimalWritten) { - // For compatibility, don't echo repeated decimals - break; - } - // If the format has trailing zeros or the format has a decimal and digits remain - if (lastDigit < 0 - || (decimalPos < digitCount && *dig != 0)) { - AddStringRef(&dst, sNumberDecimal); - decimalWritten = TRUE; - } - break; - } - case 0x2030: - AddStringRef(&dst, sPerMille); - break; - case '%': - AddStringRef(&dst, sPercent); - break; - case ',': - break; - case '\'': - case '"': - // Buffer overflow possibility - while (*src != 0 && *src != ch) { - *dst++ = *src++; - if ((unsigned int)(dst-buffer) == bufferLen-1) { - if (bufferLen - (unsigned int)(dst-buffer) < maxStrIncLen) { - int offset = static_cast(dst - buffer); - bufferLen *= 2; - buf.ReSizeThrows(bufferLen*sizeof(WCHAR)); // memcopied by CQuickBytes automatically - buffer = (wchar *)buf.Ptr(); - dst = buffer + offset; - } - } - } - if (*src != 0) src++; - break; - case '\\': - if (*src != 0) *dst++ = *src++; - break; - case 'E': - case 'e': - { - STRINGREF sign = NULL; - int i = 0; - if (scientific) { - if (*src=='0') { - //Handles E0, which should format the same as E-0 - i++; - } else if (*src == '+' && src[1] == '0') { - //Handles E+0 - sign = sPositive; - } else if (*src == '-' && src[1] == '0') { - //Handles E-0 - //Do nothing, this is just a place holder s.t. we don't break out of the loop. - } else { - *dst++ = ch; - break; - } - while (*++src == '0') i++; - if (i > 10) i = 10; - int exp = (GetDigitsBuffer(number))[0] == 0 ? 0 : number->scale - decimalPos; - dst = FormatExponent(dst, exp, ch, sign, sNegative, i); - scientific = 0; - } - else - { - *dst++ = ch; // Copy E or e to output - if (*src== '+' || *src == '-') { - *dst++ = *src++; - } - while (*src == '0') { - *dst++ = *src++; - } - } - break; - } - default: - *dst++ = ch; - } - } - if (!((dst - buffer >= 0) && (dst - buffer <= (int)bufferLen))) { - DoJITFailFast(); - } - STRINGREF newStr = StringObject::NewString(buffer, (int)(dst - buffer)); - return newStr; -} -#ifdef _PREFAST_ -#pragma warning(pop) -#endif - FCIMPL3_VII(void, COMNumber::DoubleToNumberFC, double value, int precision, NUMBER* number) { FCALL_CONTRACT; diff --git a/src/coreclr/src/classlibnative/bcltype/number.h b/src/coreclr/src/classlibnative/bcltype/number.h index 0fd12b1..22c74ca 100644 --- a/src/coreclr/src/classlibnative/bcltype/number.h +++ b/src/coreclr/src/classlibnative/bcltype/number.h @@ -33,8 +33,6 @@ class COMNumber public: static FCDECL3_VII(void, DoubleToNumberFC, double value, int precision, NUMBER* number); static FCDECL1(double, NumberToDoubleFC, NUMBER* number); - - static wchar_t* Int32ToDecChars(__in wchar_t* p, unsigned int value, int digits); }; #include -- 2.7.4