JsNumber.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. using System;
  2. using System.Globalization;
  3. using Jint.Runtime;
  4. namespace Jint.Native
  5. {
  6. public sealed class JsNumber : JsValue, IEquatable<JsNumber>
  7. {
  8. internal readonly double _value;
  9. // how many decimals to check when determining if double is actually an int
  10. private const double DoubleIsIntegerTolerance = double.Epsilon * 100;
  11. private static readonly long NegativeZeroBits = BitConverter.DoubleToInt64Bits(-0.0);
  12. // we can cache most common values, doubles are used in indexing too at times so we also cache
  13. // integer values converted to doubles
  14. private const int NumbersMax = 1024 * 10;
  15. private static readonly JsNumber[] _doubleToJsValue = new JsNumber[NumbersMax];
  16. private static readonly JsNumber[] _intToJsValue = new JsNumber[NumbersMax];
  17. private static readonly JsNumber DoubleNaN = new JsNumber(double.NaN);
  18. private static readonly JsNumber DoubleNegativeOne = new JsNumber((double) -1);
  19. private static readonly JsNumber DoublePositiveInfinity = new JsNumber(double.PositiveInfinity);
  20. private static readonly JsNumber DoubleNegativeInfinity = new JsNumber(double.NegativeInfinity);
  21. private static readonly JsNumber IntegerNegativeOne = new JsNumber(-1);
  22. static JsNumber()
  23. {
  24. for (int i = 0; i < NumbersMax; i++)
  25. {
  26. _intToJsValue[i] = new JsNumber(i);
  27. _doubleToJsValue[i] = new JsNumber((double) i);
  28. }
  29. }
  30. public JsNumber(double value) : base(Types.Number)
  31. {
  32. _value = value;
  33. }
  34. public JsNumber(int value) : base(Types.Number)
  35. {
  36. _value = value;
  37. }
  38. public JsNumber(uint value) : base(Types.Number)
  39. {
  40. _value = value;
  41. }
  42. public override object ToObject()
  43. {
  44. return _value;
  45. }
  46. internal static JsNumber Create(double value)
  47. {
  48. // we can cache positive double zero, but not negative, -0 == 0 in C# but in JS it's a different story
  49. if ((value == 0 && BitConverter.DoubleToInt64Bits(value) != NegativeZeroBits || value >= 1)
  50. && value < _doubleToJsValue.Length
  51. && System.Math.Abs(value % 1) <= DoubleIsIntegerTolerance)
  52. {
  53. return _doubleToJsValue[(int) value];
  54. }
  55. if (value == -1)
  56. {
  57. return DoubleNegativeOne;
  58. }
  59. if (value == double.NegativeInfinity)
  60. {
  61. return DoubleNegativeInfinity;
  62. }
  63. if (value == double.PositiveInfinity)
  64. {
  65. return DoublePositiveInfinity;
  66. }
  67. if (double.IsNaN(value))
  68. {
  69. return DoubleNaN;
  70. }
  71. return new JsNumber(value);
  72. }
  73. internal static JsNumber Create(int value)
  74. {
  75. if ((uint) value < (uint) _intToJsValue.Length)
  76. {
  77. return _intToJsValue[value];
  78. }
  79. if (value == -1)
  80. {
  81. return IntegerNegativeOne;
  82. }
  83. return new JsNumber(value);
  84. }
  85. internal static JsNumber Create(uint value)
  86. {
  87. if (value < (uint) _intToJsValue.Length)
  88. {
  89. return _intToJsValue[value];
  90. }
  91. return new JsNumber(value);
  92. }
  93. internal static JsNumber Create(ulong value)
  94. {
  95. if (value < (ulong) _intToJsValue.Length)
  96. {
  97. return _intToJsValue[value];
  98. }
  99. return new JsNumber(value);
  100. }
  101. public override string ToString()
  102. {
  103. return _value.ToString(CultureInfo.InvariantCulture);
  104. }
  105. public override bool Equals(JsValue obj)
  106. {
  107. if (ReferenceEquals(null, obj))
  108. {
  109. return false;
  110. }
  111. if (!(obj is JsNumber number))
  112. {
  113. return false;
  114. }
  115. return Equals(number);
  116. }
  117. public bool Equals(JsNumber other)
  118. {
  119. if (ReferenceEquals(null, other))
  120. {
  121. return false;
  122. }
  123. if (ReferenceEquals(this, other))
  124. {
  125. return true;
  126. }
  127. return _value == other._value;
  128. }
  129. public override int GetHashCode()
  130. {
  131. return _value.GetHashCode();
  132. }
  133. }
  134. }