typescript-algorithms-and-datastructures
Version:
Useful algorithms and Data structures written in typescript.
184 lines • 7.34 kB
JavaScript
(function (factory) {
if (typeof module === "object" && typeof module.exports === "object") {
var v = factory(require, exports);
if (v !== undefined) module.exports = v;
}
else if (typeof define === "function" && define.amd) {
define(["require", "exports"], factory);
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class BitMatrix {
constructor(rowSize, colSize) {
this.rowCount = 0;
this.colCount = 0;
this.rowCount = rowSize;
this.colCount = colSize;
this.buffer = new Uint32Array(this.calculateBufferSize(this.colCount * this.rowCount));
}
clone() {
const clone = new BitMatrix(this.rowCount, this.colCount);
clone.setBuffer(this.buffer.slice(0));
return clone;
}
count() {
return this.buffer.reduce((total, chunk) => this.bitsCountInNumber(chunk) + total, 0);
}
get(rowIndex, colIndex) {
this.validateIndex(rowIndex, colIndex);
const index = this.getBitPosition(rowIndex, colIndex);
const chunkOffset = Math.floor(index / 32);
const bitOffset = index - chunkOffset * 32;
return !!(this.buffer[chunkOffset] & (1 << bitOffset));
}
getColIndexes(column) {
const output = [];
for (let i = 0; i < this.rowCount; i++) {
if (this.get(i, column)) {
output.push(i);
}
}
return output;
}
getRowIndexes(row) {
const output = [];
for (let i = 0; i < this.colCount; i++) {
if (this.get(row, i)) {
output.push(i);
}
}
return output;
}
getIndexes(resultPerColumn = false) {
let result = [];
let index = 0;
if (resultPerColumn) {
while (index < this.colCount) {
result.push(this.getColIndexes(index));
index++;
}
}
else {
while (index < this.rowCount) {
result.push(this.getRowIndexes(index));
index++;
}
}
return result;
}
reset() {
this.buffer.fill(0);
return this;
}
resize(rowCount, colCount) {
if (rowCount < 0 || colCount < 0) {
throw new RangeError(`Invalid new BitMatrix size ${rowCount}x${colCount}`);
}
const setIndexes = this.getIndexes();
this.buffer = new Uint32Array(this.calculateBufferSize(rowCount * colCount));
this.rowCount = rowCount;
this.colCount = colCount;
setIndexes.filter((setIndexes, row) => row < rowCount)
.forEach((setIndexes, row) => {
setIndexes.forEach(column => {
if (column < this.colCount) {
this.set(row, column, true);
}
});
});
return this;
}
setBuffer(newBuffer) {
if (!newBuffer || newBuffer.length !== this.buffer.length) {
throw new Error(`Invalid buffer ${newBuffer}`);
}
this.buffer = newBuffer;
return this;
}
size() {
return [this.rowCount, this.colCount];
}
spliceColumn(startIndex, deleteCount) {
if (isNaN(deleteCount) || deleteCount < 1) {
return;
}
if (startIndex < 0) {
startIndex = this.colCount + startIndex;
if (startIndex < 0) {
throw new RangeError(`${startIndex} is less than 0`);
}
}
else if (startIndex >= this.colCount) {
throw new RangeError(`${startIndex} exceeds the matrix size ${this.colCount}`);
}
const tempBuffer = this.getIndexes();
this.reset();
this.resize(this.rowCount, this.colCount - deleteCount);
tempBuffer.forEach((indexes, row) => {
indexes.forEach(id => {
if (id < startIndex || id >= startIndex + deleteCount) {
let normalizedId = id >= startIndex + deleteCount ? id - deleteCount : id;
this.set(row, normalizedId, true);
}
});
});
}
spliceRow(startIndex, deleteCount) {
if (isNaN(deleteCount) || deleteCount < 1) {
return;
}
if (startIndex < 0) {
startIndex = this.colCount + startIndex;
if (startIndex < 0) {
throw new RangeError(`${startIndex} is less than 0`);
}
}
else if (startIndex >= this.colCount) {
throw new RangeError(`${startIndex} exceeds the matrix size ${this.colCount}`);
}
const tempBuffer = this.getIndexes().filter((setIds, row) => row < startIndex || row >= startIndex + deleteCount);
this.reset();
this.resize(this.rowCount - deleteCount, this.colCount);
tempBuffer.forEach((indexes, row) => {
indexes.forEach(id => {
this.set(row, id, true);
});
});
}
set(rowIndex, colIndex, value) {
this.validateIndex(rowIndex, colIndex);
const index = this.getBitPosition(rowIndex, colIndex);
const chunkOffset = Math.floor(index / 32);
const offset = index - chunkOffset * 32;
if (value) {
this.buffer[chunkOffset] |= (1 << offset);
}
else {
this.buffer[chunkOffset] &= ~(1 << offset);
}
return this;
}
calculateBufferSize(bitsCount) {
return Math.ceil(bitsCount / 32) * 4;
}
getBitPosition(rowIndex, colIndex) {
return this.colCount * rowIndex + colIndex;
}
bitsCountInNumber(value) {
value -= ((value >>> 1) & 0x55555555);
value = (value & 0x33333333) + ((value >>> 2) & 0x33333333);
return (((value + (value >>> 4) & 0xF0F0F0F) * 0x1010101) >>> 24);
}
validateIndex(rowIndex, colIndex) {
if (rowIndex >= this.rowCount || rowIndex < 0) {
throw new RangeError(`Row index is incorrect. Maximum allowed index: ${this.rowCount - 1}. Actual index ${rowIndex}`);
}
if (colIndex >= this.colCount || colIndex < 0) {
throw new RangeError(`Column index is incorrect. Maximum allowed index: ${this.colCount - 1}. Actual index ${colIndex}`);
}
}
}
exports.BitMatrix = BitMatrix;
});
//# sourceMappingURL=BitMatrix.js.map