mask.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /**
  2. * Copyright (c) 2017 Mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. // TODO check if the removal of FastSet and the removal of the context object for forEach
  7. // have any performance implications
  8. function _ascSort(a: number, b: number) {
  9. return a - b;
  10. }
  11. export function sortAsc<T extends ArrayLike<number>>(array: T): T {
  12. Array.prototype.sort.call(array, _ascSort);
  13. return array;
  14. }
  15. interface Mask {
  16. '@type': 'mask'
  17. size: number;
  18. has(i: number): boolean;
  19. /** in-order iteration of all "masked elements". */
  20. forEach<Ctx>(f: (i: number, ctx?: Ctx) => void, ctx?: Ctx): Ctx | undefined;
  21. }
  22. namespace Mask {
  23. class EmptyMask implements Mask {
  24. '@type': 'mask'
  25. size = 0;
  26. has(i: number) { return false; }
  27. forEach<Ctx>(f: (i: number, ctx?: Ctx) => void, ctx: Ctx) { return ctx; }
  28. constructor() { }
  29. }
  30. class SingletonMask implements Mask {
  31. '@type': 'mask'
  32. size = 1;
  33. has(i: number) { return i === this.idx; }
  34. forEach<Ctx>(f: (i: number, ctx?: Ctx) => void, ctx?: Ctx) { f(this.idx, ctx); return ctx; }
  35. constructor(private idx: number) { }
  36. }
  37. class BitMask implements Mask {
  38. '@type': 'mask'
  39. private length: number;
  40. has(i: number) { return i < this.length && !!this.mask[i] as any; }
  41. private _forEach<Ctx>(f: (i: number, ctx?: Ctx) => void, ctx: Ctx | undefined) {
  42. for (let i = 0; i < this.length; i++) {
  43. if (this.mask[i]) f(i, ctx);
  44. }
  45. }
  46. forEach<Ctx>(f: (i: number, ctx?: Ctx) => void, ctx?: Ctx) {
  47. this._forEach(f, ctx);
  48. return ctx;
  49. }
  50. constructor(private mask: boolean[], public size: number) { this.length = mask.length; }
  51. }
  52. class AllMask implements Mask {
  53. '@type': 'mask'
  54. has(i: number) { return true; }
  55. private _forEach<Ctx>(f: (i: number, ctx?: Ctx) => void, ctx: Ctx | undefined) {
  56. for (let i = 0; i < this.size; i++) {
  57. f(i, ctx);
  58. }
  59. }
  60. forEach<Ctx>(f: (i: number, ctx?: Ctx) => void, ctx?: Ctx) {
  61. this._forEach(f, ctx);
  62. return ctx;
  63. }
  64. constructor(public size: number) { }
  65. }
  66. class SetMask implements Mask {
  67. '@type': 'mask'
  68. private _flat: number[] | undefined = void 0;
  69. size: number;
  70. has(i: number) { return this.set.has(i); }
  71. private _forEach<Ctx>(f: (i: number, ctx: Ctx) => void, ctx: Ctx) {
  72. for (const idx of this.flatten()) {
  73. f(idx, ctx);
  74. }
  75. }
  76. private flatten() {
  77. if (this._flat) return this._flat;
  78. const indices = new Int32Array(this.size);
  79. let offset = 0
  80. this.set.forEach(i => indices[offset++] = i);
  81. sortAsc(indices);
  82. this._flat = indices as any as number[];
  83. return this._flat;
  84. }
  85. forEach<Ctx>(f: (i: number, ctx: Ctx) => void, ctx: Ctx) {
  86. this._forEach(f, ctx);
  87. return ctx;
  88. }
  89. constructor(private set: Set<number>) {
  90. this.size = set.size;
  91. }
  92. }
  93. export function always(size: number) { return new AllMask(size); }
  94. export const never = new EmptyMask();
  95. export function ofSet(set: Set<number>): Mask {
  96. return new SetMask(set);
  97. }
  98. export function singleton(i: number) {
  99. return new SingletonMask(i);
  100. }
  101. export function ofUniqueIndices(indices: ArrayLike<number>): Mask {
  102. const len = indices.length;
  103. if (len === 0) return new EmptyMask();
  104. if (len === 1) return new SingletonMask(indices[0]);
  105. let max = 0;
  106. for (const i of (indices as number[])) {
  107. if (i > max) max = i;
  108. }
  109. if (len === max) return new AllMask(len);
  110. const f = len / max;
  111. if (f < 1 / 12) {
  112. const set = new Set<number>();
  113. for (const i of (indices as number[])) set.add(i);
  114. return new SetMask(set);
  115. }
  116. const mask = new Int8Array(max + 1);
  117. for (const i of (indices as number[])) {
  118. mask[i] = 1;
  119. }
  120. return new BitMask(mask as any as boolean[], indices.length);
  121. }
  122. export function ofMask(mask: boolean[], size: number): Mask {
  123. return new BitMask(mask, size);
  124. }
  125. export function hasAny(mask: Mask, xs: number[]) {
  126. for (const x of xs) {
  127. if (mask.has(x)) return true;
  128. }
  129. return false;
  130. }
  131. export function complement(mask: Mask, against: Mask) {
  132. let count = 0
  133. let max = 0
  134. against.forEach(i => {
  135. if (!mask.has(i)) {
  136. count++;
  137. if (i > max) max = i;
  138. }
  139. });
  140. if (count / max < 1 / 12) {
  141. // set based
  142. const set = new Set<number>()
  143. against.forEach(i => {
  144. if (!mask.has(i)) {
  145. set.add(i);
  146. }
  147. });
  148. return ofSet(set);
  149. } else {
  150. // mask based
  151. const target = new Uint8Array(max + 1);
  152. against.forEach(i => {
  153. if (!mask.has(i)) {
  154. target[i] = 1;
  155. }
  156. });
  157. return ofMask(target as any as boolean[], count);
  158. }
  159. }
  160. }
  161. export default Mask;