NumberUtilities.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. enum class LikelyNumberType
  7. {
  8. Double,
  9. Int,
  10. BigInt,
  11. };
  12. namespace Js
  13. {
  14. class NumberConstants : public NumberConstantsBase
  15. {
  16. public:
  17. // Our float tagging scheme relies on NaNs to be of this value - changing the NaN value
  18. // will break float tagging for x64.
  19. static const uint64 k_PosInf = 0x7FF0000000000000ull;
  20. static const uint64 k_NegInf = 0xFFF0000000000000ull;
  21. static const uint64 k_PosMin = 0x0000000000000001ull;
  22. static const uint64 k_PosMax = 0x7FEFFFFFFFFFFFFFull;
  23. static const uint64 k_NegZero = 0x8000000000000000ull;
  24. static const uint64 k_Zero = 0x0000000000000000ull;
  25. static const uint64 k_PointFive = 0x3FE0000000000000ull;
  26. static const uint64 k_NegPointFive = 0xBFE0000000000000ull;
  27. static const uint64 k_NegOne = 0xBFF0000000000000ull;
  28. static const uint64 k_OnePointZero = 0x3FF0000000000000ull;
  29. // 2^52
  30. static const uint64 k_TwoToFraction = 0x4330000000000000ull;
  31. // -2^52
  32. static const uint64 k_NegTwoToFraction = 0xC330000000000000ull;
  33. static const uint64 k_TwoTo63 = 0x43e0000000000000ull;
  34. static const uint64 k_NegTwoTo63 = 0xc3e0000000000000ull;
  35. static const uint64 k_TwoTo64 = 0x43f0000000000000ull;
  36. static const uint64 k_TwoTo31 = 0x41dfffffffc00000ull;
  37. static const uint64 k_NegTwoTo31 = 0xc1e0000000000000ull;
  38. static const uint64 k_TwoTo32 = 0x41efffffffe00000ull;
  39. static const uint64 k_MinIntMinusOne = 0xc1e0000000200000ull;
  40. static const uint64 k_UintMaxPlusOne = 0x41f0000000000000ull;
  41. static const uint64 k_IntMaxPlusOne = 0x41e0000000000000ull;
  42. static const uint32 k_Float32Zero = 0x00000000ul;
  43. static const uint32 k_Float32PointFive = 0x3F000000ul;
  44. static const uint32 k_Float32NegPointFive = 0xBF000000ul;
  45. static const uint32 k_Float32NegZero = 0x80000000ul;
  46. // 2^23
  47. static const uint32 k_Float32TwoToFraction = 0x4B000000ul;
  48. // -2^23
  49. static const uint32 k_Float32NegTwoToFraction = 0xCB000000ul;
  50. static const uint32 k_Float32TwoTo63 = 0x5f000000u;
  51. static const uint32 k_Float32NegTwoTo63 = 0xdf000000u;
  52. static const uint32 k_Float32TwoTo64 = 0x5f800000u;
  53. static const uint32 k_Float32NegOne = 0xbf800000u;
  54. static const uint32 k_Float32TwoTo31 = 0x4f000000u;
  55. static const uint32 k_Float32NegTwoTo31 = 0xcf000000u;
  56. static const uint32 k_Float32TwoTo32 = 0x4f800000u;
  57. static const double MAX_VALUE;
  58. static const double MIN_VALUE;
  59. static const double NaN;
  60. static const double NegativeNaN;
  61. static const double NEGATIVE_INFINITY;
  62. static const double POSITIVE_INFINITY;
  63. static const double NEG_ZERO;
  64. static const double ONE_POINT_ZERO;
  65. static const double DOUBLE_INT_MIN;
  66. static const double DOUBLE_TWO_TO_31;
  67. static const BYTE AbsDoubleCst[];
  68. static const BYTE AbsFloatCst[];
  69. static const BYTE SgnFloatBitCst[];
  70. static const BYTE SgnDoubleBitCst[];
  71. static double const UIntConvertConst[];
  72. static double const MaskNegDouble[];
  73. static float const MaskNegFloat[];
  74. };
  75. class NumberUtilities : public NumberUtilitiesBase
  76. {
  77. public:
  78. static bool IsDigit(int ch);
  79. static BOOL FHexDigit(char16 ch, int *pw);
  80. static uint32 MulLu(uint32 lu1, uint32 lu2, uint32 *pluHi);
  81. static int AddLu(uint32 *plu1, uint32 lu2);
  82. static uint32 &LuHiDbl(double &dbl);
  83. static uint32 &LuLoDbl(double &dbl);
  84. static INT64 TryToInt64(double d);
  85. static bool IsValidTryToInt64(__int64 value); // Whether TryToInt64 resulted in a valid value.
  86. static int CbitZeroLeft(uint32 lu);
  87. static bool IsFinite(double value);
  88. static bool IsNan(double value);
  89. static bool IsNegative(double value);
  90. static bool IsFloat32NegZero(float value);
  91. static bool IsSpecial(double value, uint64 nSpecial);
  92. static uint64 ToSpecial(double value);
  93. static uint32 ToSpecial(float value);
  94. static float VECTORCALL ReinterpretBits(int value);
  95. static double VECTORCALL ReinterpretBits(int64 value);
  96. // Convert a given UINT16 into its corresponding string.
  97. // outBufferSize is in WCHAR elements (and used only for ASSERTs)
  98. // Returns the number of characters written to outBuffer (not including the \0)
  99. static charcount_t UInt16ToString(uint16 integer, __out __ecount(outBufferSize) WCHAR* outBuffer, charcount_t outBufferSize, char widthForPaddingZerosInsteadSpaces);
  100. // Try to parse an integer string to find out if the string contains an index property name.
  101. static BOOL TryConvertToUInt32(const char16* str, int length, uint32* intVal);
  102. static double Modulus(double dblLeft, double dblRight);
  103. enum FormatType
  104. {
  105. FormatFixed,
  106. FormatExponential,
  107. FormatPrecision
  108. };
  109. // Ref: Warren's Hacker's Delight, Chapter 10.
  110. // Calculates magic number (multiplier) and shift amounts (shiftAmt) to replace division by constants with multiplication and shifts
  111. struct DivMagicNumber
  112. {
  113. DivMagicNumber(int multiplier, uint shiftAmt) : multiplier(multiplier), shiftAmt(shiftAmt), addIndicator(0){}
  114. DivMagicNumber(int multiplier, uint shiftAmt, int addIndicator) : multiplier(multiplier), shiftAmt(shiftAmt), addIndicator(addIndicator) {}
  115. int multiplier;
  116. uint shiftAmt;
  117. int addIndicator; // Only used for unsigned
  118. };
  119. // Calculation for signed divisors
  120. DivMagicNumber static GenerateDivMagicNumber(const int divisor)
  121. {
  122. Assert((1 < divisor && divisor < INT32_MAX) || (-1 > divisor && divisor > INT32_MIN));
  123. int p;
  124. unsigned ad, anc, delta, q1, r1, q2, r2, t;
  125. const unsigned two31 = static_cast<unsigned>(1) << (sizeof(int) * 8 - 1); // 2^31
  126. ad = (divisor < 0) ? (0 - divisor) : divisor;
  127. t = two31 + ((unsigned)divisor >> 31);
  128. anc = t - 1 - t % ad; // abs(nc)
  129. p = 31; // init p
  130. q1 = two31 / anc; // init q1 = 2^p/|nc|
  131. r1 = two31 - q1 * anc;// init r1 = rem(2^p, |nc|)
  132. q2 = two31 / ad; // init q2 = 2^p / |d|
  133. r2 = two31 - q2 * ad; // init r2 = rem(2^p, |d|)
  134. do
  135. {
  136. p = p + 1;
  137. q1 = 2 * q1; // update q1 = 2 ^p / |nc|
  138. r1 = 2 * r1; // update r1 = rem(2^p, |nc|)
  139. if (r1 >= anc) // Must be an unsigned comparison here.
  140. {
  141. q1 = q1 + 1;
  142. r1 = r1 - anc;
  143. }
  144. q2 = 2 * q2; // update q2 = 2^p / |d|
  145. r2 = 2 * r2; // update r2 = rem(2^p, |d|)
  146. if (r2 >= ad) // Must be an unsigned comparison here.
  147. {
  148. q2 = q2 + 1;
  149. r2 = r2 - ad;
  150. }
  151. delta = ad - r2;
  152. } while (q1 < delta || (q1 == delta && r1 == 0));
  153. int magic_num = q2 + 1;
  154. if (divisor < 0)
  155. {
  156. magic_num = -magic_num;
  157. }
  158. return DivMagicNumber(magic_num, p - 32); // (Magic number, shift amount)
  159. }
  160. // Ref: Warren's Hacker's Delight, Chapter 10.
  161. // Calculation for unsigned divisors
  162. DivMagicNumber static GenerateDivMagicNumber(const uint divisor)
  163. {
  164. Assert(1 <= divisor && divisor <= UINT32_MAX - 1);
  165. auto p = 31;
  166. unsigned p32 = 0, q, r, delta;
  167. auto addIndicator = 0;
  168. const unsigned two31 = static_cast<unsigned>(1) << (sizeof(int) * 8 - 1); // 2^31
  169. q = (two31 - 1) / divisor; // (2^p -1)/d
  170. r = (two31 - 1) - q * divisor; // rem(2^p - 1, d);
  171. do
  172. {
  173. ++p;
  174. p32 = (p == 32) ? 1 : 2 * p32;// p32 = 2^(p-32)
  175. if (r + 1 >= divisor - r)
  176. {
  177. if (q >= (two31 - 1))
  178. {
  179. addIndicator = 1;
  180. }
  181. q = 2 * q + 1;
  182. r = 2 * r + 1 - divisor;
  183. }
  184. else
  185. {
  186. if (q > two31)
  187. {
  188. addIndicator = 1;
  189. }
  190. q = 2 * q;
  191. r = 2 * r + 1;
  192. }
  193. delta = divisor - 1 - r;
  194. } while (p < 64 && p32 < delta);
  195. return DivMagicNumber(q + 1, p - 32, addIndicator);
  196. }
  197. // Implemented in lib\parser\common. Should move to lib\common
  198. template<typename EncodedChar>
  199. static double StrToDbl(const EncodedChar *psz, const EncodedChar **ppchLim, LikelyNumberType& likelyType, bool isESBigIntEnabled = false, bool isNumericSeparatorEnabled = false);
  200. static BOOL FDblToStr(double dbl, __out_ecount(nDstBufSize) char16 *psz, int nDstBufSize);
  201. static int FDblToStr(double dbl, NumberUtilities::FormatType ft, int nDigits, __out_ecount(cchDst) char16 *pchDst, int cchDst);
  202. static BOOL FNonZeroFiniteDblToStr(double dbl, _Out_writes_(nDstBufSize) WCHAR* psz, int nDstBufSize);
  203. _Success_(return) static BOOL FNonZeroFiniteDblToStr(double dbl, _In_range_(2, 36) int radix, _Out_writes_(nDstBufSize) WCHAR* psz, int nDstBufSize);
  204. static double DblFromDecimal(DECIMAL * pdecIn);
  205. static void CodePointAsSurrogatePair(codepoint_t codePointValue, __out char16* first, __out char16* second);
  206. static codepoint_t SurrogatePairAsCodePoint(codepoint_t first, codepoint_t second);
  207. static bool IsSurrogateUpperPart(codepoint_t codePointValue);
  208. static bool IsSurrogateLowerPart(codepoint_t codePointValue);
  209. static bool IsInSupplementaryPlane(codepoint_t codePointValue);
  210. static int32 LwFromDblNearest(double dbl);
  211. static uint32 LuFromDblNearest(double dbl);
  212. static BOOL FDblIsInt32(double dbl, int32 *plw);
  213. template<typename EncodedChar>
  214. static double DblFromHex(const EncodedChar *psz, const EncodedChar **ppchLim, bool isNumericSeparatorEnabled = false);
  215. template <typename EncodedChar>
  216. static double DblFromBinary(const EncodedChar *psz, const EncodedChar **ppchLim, bool isNumericSeparatorEnabled = false);
  217. template<typename EncodedChar>
  218. static double DblFromOctal(const EncodedChar *psz, const EncodedChar **ppchLim, bool isNumericSeparatorEnabled = false);
  219. template<typename EncodedChar>
  220. static double StrToDbl(const EncodedChar *psz, const EncodedChar **ppchLim, Js::ScriptContext *const scriptContext);
  221. const NumberUtilitiesBase* GetNumberUtilitiesBase() const { return static_cast<const NumberUtilitiesBase*>(this); }
  222. };
  223. }