JsString.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. using System;
  2. using System.Text;
  3. using Jint.Native.Array;
  4. using Jint.Runtime;
  5. namespace Jint.Native
  6. {
  7. public class JsString : JsValue, IEquatable<JsString>
  8. {
  9. private const int AsciiMax = 126;
  10. private static readonly JsString[] _charToJsValue;
  11. private static readonly JsString[] _charToStringJsValue;
  12. public static readonly JsString Empty = new JsString("");
  13. private static readonly JsString NullString = new JsString("null");
  14. internal static readonly JsString UndefinedString = new JsString("undefined");
  15. internal static readonly JsString ObjectString = new JsString("object");
  16. internal static readonly JsString FunctionString = new JsString("function");
  17. internal static readonly JsString BooleanString = new JsString("boolean");
  18. internal static readonly JsString StringString = new JsString("string");
  19. internal static readonly JsString NumberString = new JsString("number");
  20. internal static readonly JsString LengthString = new JsString("length");
  21. internal static readonly JsString DefaultString = new JsString("default");
  22. internal string _value;
  23. static JsString()
  24. {
  25. _charToJsValue = new JsString[AsciiMax + 1];
  26. _charToStringJsValue = new JsString[AsciiMax + 1];
  27. for (int i = 0; i <= AsciiMax; i++)
  28. {
  29. _charToJsValue[i] = new JsString((char) i);
  30. _charToStringJsValue[i] = new JsString(((char) i).ToString());
  31. }
  32. }
  33. public JsString(string value) : base(Types.String)
  34. {
  35. _value = value;
  36. }
  37. public override object ToObject()
  38. {
  39. return _value;
  40. }
  41. public JsString(char value) : base(Types.String)
  42. {
  43. _value = value.ToString();
  44. }
  45. public virtual JsString Append(JsValue jsValue)
  46. {
  47. return new ConcatenatedString(string.Concat(_value, TypeConverter.ToString(jsValue)));
  48. }
  49. internal virtual JsString EnsureCapacity(int capacity)
  50. {
  51. return new ConcatenatedString(_value, capacity);
  52. }
  53. internal virtual bool IsNullOrEmpty()
  54. {
  55. return string.IsNullOrEmpty(_value);
  56. }
  57. public virtual int Length => _value.Length;
  58. internal static JsString Create(string value)
  59. {
  60. if (value.Length == 0)
  61. {
  62. return Empty;
  63. }
  64. if (value.Length == 1)
  65. {
  66. var i = (uint) value[0];
  67. if (i < (uint) _charToStringJsValue.Length)
  68. {
  69. return _charToStringJsValue[i];
  70. }
  71. }
  72. else if (value.Length == 4 && value == Native.Null.Text)
  73. {
  74. return NullString;
  75. }
  76. return new JsString(value);
  77. }
  78. internal static JsString Create(char value)
  79. {
  80. if (value < (uint) _charToJsValue.Length)
  81. {
  82. return _charToJsValue[value];
  83. }
  84. return new JsString(value);
  85. }
  86. internal override Key ToPropertyKey()
  87. {
  88. return new Key(_value);
  89. }
  90. public override string ToString()
  91. {
  92. return _value;
  93. }
  94. public ArrayInstance ToArray(Engine engine)
  95. {
  96. var array = engine.Array.ConstructFast((uint) _value.Length);
  97. for (int i = 0; i < _value.Length; ++i)
  98. {
  99. array.SetIndexValue((uint) i, _value[i], updateLength: false);
  100. }
  101. return array;
  102. }
  103. public override bool Equals(JsValue obj)
  104. {
  105. if (ReferenceEquals(null, obj))
  106. {
  107. return false;
  108. }
  109. if (!(obj is JsString s))
  110. {
  111. return false;
  112. }
  113. return Equals(s);
  114. }
  115. public bool Equals(JsString other)
  116. {
  117. if (ReferenceEquals(null, other))
  118. {
  119. return false;
  120. }
  121. if (ReferenceEquals(this, other))
  122. {
  123. return true;
  124. }
  125. return _value == other.ToString();
  126. }
  127. internal sealed class ConcatenatedString : JsString
  128. {
  129. private StringBuilder _stringBuilder;
  130. private bool _dirty;
  131. internal ConcatenatedString(string value, int capacity = 0) : base(value)
  132. {
  133. if (capacity > 0)
  134. {
  135. _stringBuilder = new StringBuilder(value, capacity);
  136. }
  137. else
  138. {
  139. _value = value;
  140. }
  141. }
  142. public override string ToString()
  143. {
  144. if (_dirty)
  145. {
  146. _value = _stringBuilder.ToString();
  147. _dirty = false;
  148. }
  149. return _value;
  150. }
  151. public override JsString Append(JsValue jsValue)
  152. {
  153. var value = TypeConverter.ToString(jsValue);
  154. if (_stringBuilder == null)
  155. {
  156. _stringBuilder = new StringBuilder(_value, _value.Length + value.Length);
  157. }
  158. _stringBuilder.Append(value);
  159. _dirty = true;
  160. return this;
  161. }
  162. internal override JsString EnsureCapacity(int capacity)
  163. {
  164. _stringBuilder.EnsureCapacity(capacity);
  165. return this;
  166. }
  167. internal override bool IsNullOrEmpty()
  168. {
  169. return _stringBuilder == null && string.IsNullOrEmpty(_value)
  170. || _stringBuilder != null && _stringBuilder.Length == 0;
  171. }
  172. public override int Length => _stringBuilder?.Length ?? _value?.Length ?? 0;
  173. public override object ToObject() => ToString();
  174. public override bool Equals(JsValue other)
  175. {
  176. if (other is ConcatenatedString cs)
  177. {
  178. if (_stringBuilder != null && cs._stringBuilder != null)
  179. {
  180. return _stringBuilder.Equals(cs._stringBuilder);
  181. }
  182. return ToString() == cs.ToString();
  183. }
  184. if (other is JsString jsString)
  185. {
  186. if (jsString._value.Length != Length)
  187. {
  188. return false;
  189. }
  190. return ToString() == jsString._value;
  191. }
  192. return base.Equals(other);
  193. }
  194. internal override JsValue Clone()
  195. {
  196. return ToString();
  197. }
  198. }
  199. }
  200. }