All files BitSet.ts

100% Statements 69/69
100% Branches 24/24
100% Functions 9/9
100% Lines 69/69
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118                  3x               9x 7x 7x 7x     3x 7510x 42x 42x 42x 42x 42x 42x 42x 42x 42x   7510x 2007x       3x 206x 192x 4x 4x 6x       3x 5504x     3x 7503x   7503x 7503x   7503x 7503x 2000x     5503x 5503x 224x   5503x     3x 4000x 4000x 4000x 4000x 4000x 4000x 4000x   4000x 2000x     2000x 2000x 1937x     63x 63x 61x     2x 2x 1x     1x 1x     3x 4000x 4000x 4000x     3x 224x 224x 224x 224x 224x   3x  
import { BitSetIterator } from "./Iteration";
import { calculateOffset, calculateMask, copyArrays, nextPowerOfTwo,
  SHIFT0, SHIFT1, SHIFT2, SHIFT3 } from "./Utils"
 
export interface HierarchicalBitset {
  byte(index: number, layer: number): number;
  size(): number;
}
 
export class BitSet implements HierarchicalBitset {
  layer0: Uint32Array;
  layer1: Uint32Array;
  layer2: Uint32Array;
  layer3: Uint32Array;
  capacity: number;
  internalSize: number;
 
  constructor(size: number = 0) {
    this.capacity = 0;
    this.internalSize = 0;
    this.grow(size);
  }
 
  grow(size: number) {
    if(this.capacity <= size) {
      const capacity = nextPowerOfTwo(size);
      const p0 = calculateOffset(capacity, SHIFT1);
      const p1 = calculateOffset(capacity, SHIFT2);
      const p2 = calculateOffset(capacity, SHIFT3);
      this.layer0 = copyArrays(this.layer0, new Uint32Array(p0+1));
      this.layer1 = copyArrays(this.layer1, new Uint32Array(p1+1));
      this.layer2 = copyArrays(this.layer2, new Uint32Array(p2+1));
      this.layer3 = copyArrays(this.layer3, new Uint32Array(1));
      this.capacity = capacity;
    }
    if (this.internalSize < size) {
      this.internalSize = size;
    }
  }
 
  byte(index: number, layer: number): number {
    switch(layer) {
      case 0: return this.layer0[index];
      case 1: return this.layer1[index];
      case 2: return this.layer2[index];
      case 3: return this.layer3[index];
    }
  }
 
  size(): number {
    return this.internalSize;
  }
 
  add(index: number): boolean {
    this.grow(index+1);
 
    const p0 = calculateOffset(index, SHIFT1);
    const mask = calculateMask(index, SHIFT0);
 
    const value = this.layer0[p0];
    if ((value & mask) != 0) {
      return true;
    }
 
    this.layer0[p0] |= mask;
    if(value == 0) {
      this.add_slow(index);
    }
    return false;
  }
 
  remove(index: number): boolean {
    const p0 = calculateOffset(index, SHIFT1);
    const p1 = calculateOffset(index, SHIFT2);;
    const p2 = calculateOffset(index, SHIFT3);
    const mask = calculateMask(index, SHIFT0);
    const mask1 = calculateMask(index, SHIFT1)
    const mask2 = calculateMask(index, SHIFT2);
    const mask3 = calculateMask(index, SHIFT3);
 
    if ((this.layer0[p0] & mask) == 0) {
      return false;
    }
 
    this.layer0[p0] &= ~mask;
    if (this.layer0[p0] != 0) {
      return true;
    }
 
    this.layer1[p1] &= ~mask1;
    if (this.layer1[p1] != 0) {
      return true;
    }
 
    this.layer2[p2] &= ~mask2;
    if (this.layer2[p2] != 0) {
      return true;
    }
 
    this.layer3[0] &= ~mask3;
    return true;
  }
 
  contains(index: number): boolean {
    const p0 = calculateOffset(index, SHIFT1);
    const mask = calculateMask(index, SHIFT0);
    return p0 < this.layer0.length && ((this.layer0[p0] & mask) != 0)
  }
 
  private add_slow(index: number) {
      const p1 = calculateOffset(index, SHIFT2);
      const p2 = calculateOffset(index, SHIFT3);
      this.layer1[p1] |= calculateMask(index, SHIFT1);
      this.layer2[p2] |= calculateMask(index, SHIFT2);
      this.layer3[0] |= calculateMask(index, SHIFT3);
  }
}