summaryrefslogtreecommitdiff
path: root/src/classlibnative
diff options
context:
space:
mode:
authorPent Ploompuu <kaalikas@gmail.com>2018-07-18 00:59:00 +0300
committerJan Kotas <jkotas@microsoft.com>2018-07-17 14:59:00 -0700
commit4b618d9dfe1690c9df9e3c5ce351ae18d1a7c239 (patch)
treef82d7657661a4bb002957305749b5b537172353e /src/classlibnative
parenteaf111b08dce413738f9133748e302248359c5e9 (diff)
downloadcoreclr-4b618d9dfe1690c9df9e3c5ce351ae18d1a7c239.tar.gz
coreclr-4b618d9dfe1690c9df9e3c5ce351ae18d1a7c239.tar.bz2
coreclr-4b618d9dfe1690c9df9e3c5ce351ae18d1a7c239.zip
Clean-up number.cpp (#18964)
Diffstat (limited to 'src/classlibnative')
-rw-r--r--src/classlibnative/bcltype/number.cpp1229
-rw-r--r--src/classlibnative/bcltype/number.h2
2 files changed, 0 insertions, 1231 deletions
diff --git a/src/classlibnative/bcltype/number.cpp b/src/classlibnative/bcltype/number.cpp
index b4bf7a5bfc..b20044ec41 100644
--- a/src/classlibnative/bcltype/number.cpp
+++ b/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 <stdlib.h>
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<digLength)?digPos:digLength;
- wchar* p = buffer + bufferSize - 1;
- for (int i = digPos - 1; i >=0; i--) {
- *(p--) = (i<digStart)?dig[i]:'0';
-
- if (groupSize > 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<LARGE_BUFFER_SIZE * sizeof(WCHAR)> 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<INT32>::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<UINT64>::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<SIZE_T>(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<SIZE_T>(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<SIZE_T>(newBufferLen));
-
- RoundNumber(number, number->scale + nMaxDigits);
- if (number->sign) {
- AddStringRef(&dst, sNegative);
- }
- dst = FormatFixed(dst, static_cast<SIZE_T>(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<UINT64>::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<SIZE_T>(newBufferLen));
-
- RoundNumber(number, number->scale + nMaxDigits);
- dst = FormatNumber(dst, static_cast<SIZE_T>(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<SIZE_T>(newBufferLen));
-
- RoundNumber(number, nMaxDigits);
- if (number->sign) {
- AddStringRef(&dst, sNegative);
- }
- dst = FormatScientific(dst, static_cast<SIZE_T>(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<SIZE_T>(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<SIZE_T>(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<UINT64>::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<SIZE_T>(newBufferLen));
-
- RoundNumber(number, number->scale + nMaxDigits);
- dst = FormatPercent(dst, static_cast<SIZE_T>(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<INT32>(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<INT32>(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<INT32>(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<INT32>(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/classlibnative/bcltype/number.h b/src/classlibnative/bcltype/number.h
index 0fd12b11bd..22c74cacdb 100644
--- a/src/classlibnative/bcltype/number.h
+++ b/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 <poppack.h>