GroupByHelper.cs 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. using Jint.Native.Array;
  2. using Jint.Native.Iterator;
  3. using Jint.Runtime;
  4. namespace Jint.Native;
  5. internal static class GroupByHelper
  6. {
  7. internal static Dictionary<JsValue, JsArray> GroupBy(
  8. Engine engine,
  9. Realm realm,
  10. JsValue items,
  11. JsValue callbackfn,
  12. bool mapMode)
  13. {
  14. var callable = callbackfn.GetCallable(realm);
  15. var groups = new Dictionary<JsValue, JsArray>();
  16. var iteratorRecord = items.GetIterator(realm);
  17. new GroupByProtocol(engine, groups, iteratorRecord, callable, mapMode).Execute();
  18. return groups;
  19. }
  20. private sealed class GroupByProtocol : IteratorProtocol
  21. {
  22. private readonly Engine _engine;
  23. private readonly Dictionary<JsValue, JsArray> _result;
  24. private readonly ICallable _callable;
  25. private readonly bool _mapMode;
  26. private ulong _k;
  27. private readonly JsValue[] _callArgs = new JsValue[2];
  28. public GroupByProtocol(
  29. Engine engine,
  30. Dictionary<JsValue, JsArray> result,
  31. IteratorInstance iterator,
  32. ICallable callable,
  33. bool mapMode) : base(engine, iterator, 0)
  34. {
  35. _engine = engine;
  36. _result = result;
  37. _callable = callable;
  38. _mapMode = mapMode;
  39. }
  40. protected override void ProcessItem(JsValue[] arguments, JsValue currentValue)
  41. {
  42. if (_k >= ArrayOperations.MaxArrayLength)
  43. {
  44. Throw.TypeError(_engine.Realm);
  45. }
  46. _callArgs[0] = currentValue;
  47. _callArgs[1] = _k;
  48. var value = _callable.Call(JsValue.Undefined, _callArgs);
  49. JsValue key;
  50. if (_mapMode)
  51. {
  52. key = (value as JsNumber)?.IsNegativeZero() == true ? JsNumber.PositiveZero : value;
  53. }
  54. else
  55. {
  56. key = TypeConverter.ToPropertyKey(value);
  57. }
  58. if (!_result.TryGetValue(key, out var list))
  59. {
  60. _result[key] = list = new JsArray(_engine);
  61. }
  62. list.Push(currentValue);
  63. _k++;
  64. }
  65. }
  66. }