_Set.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import _includes from "./_includes.js";
  2. var _Set =
  3. /*#__PURE__*/
  4. function () {
  5. function _Set() {
  6. /* globals Set */
  7. this._nativeSet = typeof Set === 'function' ? new Set() : null;
  8. this._items = {};
  9. }
  10. // until we figure out why jsdoc chokes on this
  11. // @param item The item to add to the Set
  12. // @returns {boolean} true if the item did not exist prior, otherwise false
  13. //
  14. _Set.prototype.add = function (item) {
  15. return !hasOrAdd(item, true, this);
  16. }; //
  17. // @param item The item to check for existence in the Set
  18. // @returns {boolean} true if the item exists in the Set, otherwise false
  19. //
  20. _Set.prototype.has = function (item) {
  21. return hasOrAdd(item, false, this);
  22. }; //
  23. // Combines the logic for checking whether an item is a member of the set and
  24. // for adding a new item to the set.
  25. //
  26. // @param item The item to check or add to the Set instance.
  27. // @param shouldAdd If true, the item will be added to the set if it doesn't
  28. // already exist.
  29. // @param set The set instance to check or add to.
  30. // @return {boolean} true if the item already existed, otherwise false.
  31. //
  32. return _Set;
  33. }();
  34. function hasOrAdd(item, shouldAdd, set) {
  35. var type = typeof item;
  36. var prevSize, newSize;
  37. switch (type) {
  38. case 'string':
  39. case 'number':
  40. // distinguish between +0 and -0
  41. if (item === 0 && 1 / item === -Infinity) {
  42. if (set._items['-0']) {
  43. return true;
  44. } else {
  45. if (shouldAdd) {
  46. set._items['-0'] = true;
  47. }
  48. return false;
  49. }
  50. } // these types can all utilise the native Set
  51. if (set._nativeSet !== null) {
  52. if (shouldAdd) {
  53. prevSize = set._nativeSet.size;
  54. set._nativeSet.add(item);
  55. newSize = set._nativeSet.size;
  56. return newSize === prevSize;
  57. } else {
  58. return set._nativeSet.has(item);
  59. }
  60. } else {
  61. if (!(type in set._items)) {
  62. if (shouldAdd) {
  63. set._items[type] = {};
  64. set._items[type][item] = true;
  65. }
  66. return false;
  67. } else if (item in set._items[type]) {
  68. return true;
  69. } else {
  70. if (shouldAdd) {
  71. set._items[type][item] = true;
  72. }
  73. return false;
  74. }
  75. }
  76. case 'boolean':
  77. // set._items['boolean'] holds a two element array
  78. // representing [ falseExists, trueExists ]
  79. if (type in set._items) {
  80. var bIdx = item ? 1 : 0;
  81. if (set._items[type][bIdx]) {
  82. return true;
  83. } else {
  84. if (shouldAdd) {
  85. set._items[type][bIdx] = true;
  86. }
  87. return false;
  88. }
  89. } else {
  90. if (shouldAdd) {
  91. set._items[type] = item ? [false, true] : [true, false];
  92. }
  93. return false;
  94. }
  95. case 'function':
  96. // compare functions for reference equality
  97. if (set._nativeSet !== null) {
  98. if (shouldAdd) {
  99. prevSize = set._nativeSet.size;
  100. set._nativeSet.add(item);
  101. newSize = set._nativeSet.size;
  102. return newSize === prevSize;
  103. } else {
  104. return set._nativeSet.has(item);
  105. }
  106. } else {
  107. if (!(type in set._items)) {
  108. if (shouldAdd) {
  109. set._items[type] = [item];
  110. }
  111. return false;
  112. }
  113. if (!_includes(item, set._items[type])) {
  114. if (shouldAdd) {
  115. set._items[type].push(item);
  116. }
  117. return false;
  118. }
  119. return true;
  120. }
  121. case 'undefined':
  122. if (set._items[type]) {
  123. return true;
  124. } else {
  125. if (shouldAdd) {
  126. set._items[type] = true;
  127. }
  128. return false;
  129. }
  130. case 'object':
  131. if (item === null) {
  132. if (!set._items['null']) {
  133. if (shouldAdd) {
  134. set._items['null'] = true;
  135. }
  136. return false;
  137. }
  138. return true;
  139. }
  140. /* falls through */
  141. default:
  142. // reduce the search size of heterogeneous sets by creating buckets
  143. // for each type.
  144. type = Object.prototype.toString.call(item);
  145. if (!(type in set._items)) {
  146. if (shouldAdd) {
  147. set._items[type] = [item];
  148. }
  149. return false;
  150. } // scan through all previously applied items
  151. if (!_includes(item, set._items[type])) {
  152. if (shouldAdd) {
  153. set._items[type].push(item);
  154. }
  155. return false;
  156. }
  157. return true;
  158. }
  159. } // A simple Set type that honours R.equals semantics
  160. export default _Set;