New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

structurae

Package Overview
Dependencies
Maintainers
1
Versions
75
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

structurae - npm Package Compare versions

Comparing version 3.3.0 to 4.0.0-pre.1

adjacency-list.d.ts

731

index.d.ts

@@ -1,702 +0,29 @@

// Type definitions for structurae
// Project: structurae
// Definitions by: Maga D. Zandaqo <denelxan@gmail.com> (http://maga.name)
type TypedArray =
| Int8Array
| Uint8Array
| Uint8ClampedArray
| Int16Array
| Uint16Array
| Int32Array
| Uint32Array
| Float32Array
| Float64Array;
type TypedArrayConstructor =
| Int8ArrayConstructor
| Uint8ArrayConstructor
| Uint8ClampedArrayConstructor
| Int16Array
| Uint16ArrayConstructor
| Int32ArrayConstructor
| Uint32ArrayConstructor
| Float32ArrayConstructor
| Float64ArrayConstructor;
type Collection = any[] | TypedArray;
type CollectionConstructor = ArrayConstructor | TypedArrayConstructor;
interface Constructor<T> {
new (...args): T;
}
interface GridOptions {
rows: number;
columns: number;
pad?: any;
}
interface Coordinates {
row: number;
column: number;
}
declare class Grid {
columns: number;
rows: number;
offset: number;
pad: any;
lastCoordinates: Coordinates;
constructor(options?: GridOptions, ...args: any);
get(row: number, column: number): any;
set(row: number | ArrayLike<number>, column?: number, value?: any): this;
setArray(array: Collection, offset: number): void;
getCoordinates(index: number): Coordinates;
toArrays(withPadding?: boolean): any[][];
static getOffset(columns: number): number;
static getLength(rows: number, columns: number): number;
static fromArrays(arrays: any[][], pad: any): Grid;
}
export declare function GridMixin<T extends Collection>(
Base?: Constructor<T>,
): Constructor<T & Grid>;
interface BitPosition {
bucket: number;
position: number;
}
type Bit = 0 | 1;
interface BinaryGridOptions {
rows: number;
columns: number;
}
export declare class BinaryGrid extends Uint16Array {
offset: number;
columns: number;
rows: number;
lastPosition: BitPosition;
constructor(options: BinaryGridOptions, ...args: any);
get(row: number, column: number): Bit;
set(row: number | ArrayLike<number>, column?: number, value?: Bit): this;
private getBitPosition(row: number, column: number): BitPosition;
static getLength(rows: number, columns: number): number;
static getOffset(columns: number): number;
}
declare class SymmetricGrid {
rows: number;
columns: number;
pad: any;
lastCoordinates: Coordinates;
constructor(options?: GridOptions, ...args: any);
get(row: number, column: number): any;
set(row: number | ArrayLike<number>, column?: number, value?: any): this;
setArray(array: Collection, offset: number): void;
getCoordinates(index: number): Coordinates;
toArrays(withPadding?: boolean): any[][];
static getLength(rows: number, columns: number): number;
static fromArrays(arrays: any[][], pad: any): SymmetricGrid;
}
export declare function SymmetricGridMixin<T extends Collection>(
Base?: Constructor<T>,
): Constructor<T & SymmetricGrid>;
type GridStructure = Grid | BinaryGrid | SymmetricGrid;
type Matcher = [number, number];
interface NumberMap {
[propName: string]: number;
}
export declare class BitField {
value: number;
static schema: NumberMap;
static size: number;
static isInitialized: boolean;
private static fields: string[];
private static masks: NumberMap;
private static offsets: NumberMap;
private static mask: number;
constructor(data?: number | BitField | number[] | NumberMap);
get(field: string): number;
set(field: string, value: number);
has(...fields: string[]): boolean;
match(matcher: Matcher | NumberMap): boolean;
toJSON(): number;
toObject(): NumberMap;
toString(): string;
valueOf(): number;
static initialize(): void;
static encode(data: number[] | NumberMap): number;
static decode(data: number): NumberMap;
static isValid(data: NumberMap): boolean;
static getMinSize(number: number): number;
static getMatcher(matcher: NumberMap): Matcher;
static match(value: number, matcher: Matcher): boolean;
}
type BigIntMatcher = [number, number];
interface BigIntMap {
[propName: string]: bigint;
}
export declare class BigBitField {
value: bigint;
static schema: BigIntMap;
static size: bigint;
static isInitialized: boolean;
private static fields: string[];
private static masks: BigIntMap;
private static offsets: BigIntMap;
private static mask: bigint;
constructor(data?: bigint | BigBitField | number[] | NumberMap);
get(field: string): number;
set(field: string, value: number);
has(...fields: string[]): boolean;
match(matcher: BigIntMatcher | NumberMap): boolean;
toJSON(): bigint;
toObject(): NumberMap;
toString(): string;
valueOf(): bigint;
static initialize(): void;
static encode(data: number[] | NumberMap): number;
static decode(data: number): NumberMap;
static isValid(data: NumberMap): boolean;
static getMinSize(number: number): number;
static getMatcher(matcher: NumberMap): BigIntMatcher;
static match(value: bigint, matcher: BigIntMatcher): boolean;
}
export declare function BitFieldMixin(
schema: string[] | NumberMap,
BitFieldClass?: typeof BitField | typeof BigBitField,
): typeof BitField | typeof BitFieldClass;
type CompareResult = 1 | -1 | 0;
interface Comparator {
(a: any, b: any): CompareResult;
}
declare class SortedCollection {
isSorted(): boolean;
isUnique(): boolean;
range(start: number, end: number, subarray?: boolean): SortedCollection;
rank(element: any): number;
static compare(a: any, b: any): CompareResult;
static getDifference<T extends Collection>(
a: Collection,
b: Collection,
symmetric?: boolean,
comparator?: Comparator,
container?: T,
): T;
static getDifferenceScore(
a: Collection,
b: Collection,
symmetric?: boolean,
comparator?: Comparator,
): number;
static getIndex(
arr: Collection,
target: any,
comparator?: Comparator,
rank?: boolean,
start?: number,
end?: number,
): number;
static getIntersection<T extends Collection>(
a: Collection,
b: Collection,
comparator?: Comparator,
container?: T,
): T;
static getIntersectionScore(a: Collection, b: Collection, comparator?: Comparator): number;
static getRange<T extends Collection>(
arr: T,
start?: number,
end?: number,
comparator?: Comparator,
subarray?: boolean,
): T;
static getUnion<T extends Collection>(
a: Collection,
b: Collection,
unique?: boolean,
comparator?: Comparator,
container?: T,
): T;
static getUnique<T extends Collection>(
arr: Collection,
comparator?: Comparator,
container?: T,
): T;
static isSorted(arr: Collection, comparator?: Comparator): boolean;
static isUnique(arr: Collection, comparator?: Comparator): boolean;
}
export declare function SortedMixin<T extends Collection>(
Base?: Constructor<T>,
): Constructor<T & SortedCollection>;
export class SortedArray extends SortedMixin(Array) {
unique: boolean;
set(arr: Collection): this;
uniquify(): this;
}
type PrimitiveFieldType =
| 'int8'
| 'uint8'
| 'int16'
| 'uint16'
| 'int32'
| 'uint32'
| 'float32'
| 'float64'
| 'bigint64'
| 'biguint64';
type ViewType = typeof ArrayView | typeof ObjectView | typeof StringView | typeof TypeView;
type View = ObjectView | ArrayView | StringView | TypeView;
export declare class TypeView extends DataView {
static offset: number;
static littleEndian: true;
static viewLength: number;
static Views: Map<string, typeof TypeView>;
static ArrayClass: typeof ArrayView;
get(): number;
set(value: number): this;
toJSON(): number;
static getLength(): number;
static from(value: any, view?: View, start?: number): View;
static toJSON(view: View, start?: number): any;
static of(): TypeView;
}
export declare class BooleanView extends TypeView {
static from(value: number | boolean, view?: View, start?: number): View;
static toJSON(view: View, start?: number): boolean;
}
export declare function TypeViewMixin(
type: PrimitiveFieldType,
littleEndian?: boolean,
TypeViewClass?: typeof TypeView,
): typeof TypeView;
export declare class ArrayView extends DataView {
size: number;
static itemLength: number;
static View: ViewType;
static ArrayClass: typeof ArrayView;
get(index: number): any;
getView(index: number): View;
set(index: number, value: any): this;
setView(index: number, value: View): this;
toJSON(): any[];
[Symbol.iterator](): IterableIterator<View | number>;
static from(value: ArrayLike<any>, array?: View, start?: number, length?: number): View;
static toJSON(view: View, start: number, length: number): any[];
static of(size?: number): ArrayView;
static getLength(size: number): number;
static getOffset(size: number): number;
static getSize(length: number): number;
}
export declare class TypedArrayView extends ArrayView {
static View: typeof TypeView;
get(index: number): number;
set(index: number, value: number): this;
toJSON(): Array<number>;
[Symbol.iterator](): IterableIterator<number>;
static from(value: ArrayLike<number>, array?: View, start?: number, length?: number): View;
static toJSON(view: View, start: number, length: number): number[];
static of(size?: number): TypedArrayView;
}
export declare function ArrayViewMixin(
ObjectViewClass: ViewType | PrimitiveFieldType,
itemLength?: number | boolean,
): typeof ArrayView;
interface ViewLayoutField {
View: ViewType;
start?: number;
length?: number;
default?: any;
}
interface ViewLayout {
[propName: string]: ViewLayoutField;
}
interface ViewTypes {
[propName: string]: ViewType;
}
interface ObjectViewTypeDefs {
[propName: string]: (field: ViewLayoutField) => void;
}
export declare class ObjectView extends DataView {
static schema: object;
static layout: ViewLayout;
static fields: string[];
static Views: ViewTypes;
static ArrayClass: typeof ArrayView;
static types: ObjectViewTypeDefs;
static viewLength: number;
private static defaultBuffer: ArrayBuffer;
get(field: string): any;
getView(field: string): View;
set(field: string, value: any): this;
setView(field: string, value: View): this;
toJSON(): object;
static from(object: object, view?: View, start?: number, length?: number): View;
static toJSON(view: View, start?: number): object;
static getLength(): number;
static initialize(): void;
private static setDefaultBuffer(): void;
static getSchemaOrdering(schema: object): object[];
static getLayoutFromSchema(schema: object): [ViewLayout, number, string[]];
static getViewFromSchema(schema: object): ViewType;
}
export declare function ObjectViewMixin(
schema: object,
ObjectViewClass?: typeof ObjectView,
): typeof ObjectView;
export declare class StringView extends Uint8Array {
size: number;
static masks: Int8Array;
static ArrayClass: typeof ArrayView;
characters(): Iterable<string>;
charAt(index?: number): string;
private getCharEnd(index: number): number;
private getCharStart(index: number, startCharIndex?: number, startIndex?: number): number;
replace(pattern: Collection, replacement: Collection): this;
reverse(): this;
search(searchValue: Collection, fromIndex?: number): number;
private searchNaive(searchValue: Collection, fromIndex?: number): number;
private searchShiftOr(searchValue: Collection, fromIndex?: number): number;
substring(indexStart: number, indexEnd?: number): string;
private toChar(index: number): string;
toString(): string;
toJSON(): string;
trim(): StringView;
static decode(bytes: Uint8Array): string;
static encode(
string: string,
view: number[] | Uint8Array | DataView,
start?: number,
length?: number,
): number;
static from(...args: any[]): View;
static toJSON(view: View, start?: number, length?: number): string;
static getLength(string: string): number;
}
export declare class VariableView extends DataView {
static maxLength: number;
static maxView: DataView;
static bufferView: DataView;
}
type AnyView = View | VariableView;
export declare class MapView extends VariableView {
static schema: object;
static layout: ViewLayout;
static optionalFields: string[];
static requiredFields: string[];
static optionalOffset: number;
static lengthOffset: number;
static defaultBuffer: Uint8Array;
static ObjectViewClass: typeof ObjectView;
static Views: ViewTypes;
get(field: string): any;
getView(field: string): AnyView;
private getLayout(field: string): [ViewType, number, number];
set(field: string, value: any): this;
setView(field: string, value: View): this;
toJSON(): object;
static encode(value: object, view: AnyView, start?: number): number;
static from(value: object, view?: AnyView, start?: number): View;
static toJSON(view: AnyView, start?: number): object;
static getLength(value: any): number;
static initialize(): void;
private static getFieldLayout(
field: ViewLayoutField,
start: number,
required: boolean,
): ViewLayoutField;
private static setDefaultBuffer(): void;
}
export declare function MapViewMixin(
schema: object,
MapViewClass?: typeof MapView,
ObjectViewClass?: typeof ObjectView,
): typeof MapView;
export declare class VectorView extends VariableView {
static View: ViewType | typeof VariableView;
static Views: WeakMap<ViewType | typeof VariableView, typeof VectorView>;
get(index: number): any;
getView(index: number): AnyView;
private getLayout(index: number): [number, number];
set(index: number, value: any): this;
setView(index: number, value: AnyView): this;
toJSON(): any[];
[Symbol.iterator](): IterableIterator<AnyView>;
static encode(value: ArrayLike<any>, view: AnyView, start?: number): number;
static from(value: ArrayLike<any>, view?: AnyView, start?: number): AnyView;
static toJSON(view: AnyView, start?: number, length?: number): any[];
static getLength(value: any[]): number;
static getSize(view: AnyView): number;
}
export declare function VectorViewMixin(
ViewClass: ViewType | typeof VariableView,
VectorViewClass?: typeof VectorView,
): typeof VectorView;
interface BinaryProtocolSchema {
[propName: number]: typeof ObjectView;
}
export declare class BinaryProtocol {
Views: BinaryProtocolSchema;
private tagName: string;
private tagType: PrimitiveFieldType;
constructor(views: object, tagName?: string, tagType?: string);
view(buffer: ArrayBuffer, offset?: number): ObjectView;
encode(object: object, arrayBuffer?: ArrayBuffer, offset?: number): ObjectView;
decode(buffer: ArrayBuffer, offset?: number): object;
}
export declare class BitArray extends Uint32Array {
size: number;
private lastPosition: BitPosition;
constructor(size: number | ArrayLike<number> | ArrayBuffer, ...args: any);
getBit(index: number): Bit;
setBit(index: number, value: Bit): this;
protected getBitPosition(index: number): void;
static getLength(size: number): number;
}
export declare class Pool extends BitArray {
get(): number;
free(index: number): void;
static getLength(size: number): number;
}
export declare class RankedBitArray extends BitArray {
setBit(index: number, value: Bit): this;
rank(index: number): number;
select(index: number): number;
static getLength(size: number): number;
}
export declare class BinaryHeap extends Array {
heapify(): this;
isHeap(): boolean;
left(index: number): any;
parent(index: number): any;
replace(item: any): any;
right(index: number): any;
update(index: number): void;
private has(index: number): boolean;
private siftDown(start: number): void;
private siftUp(start: number): void;
static compare(a: any, b: any): boolean;
private static getLeftIndex(index: number): number;
private static getParentIndex(index: number): number;
private static getRightIndex(index: number): number;
static isHeap(heap: Collection): boolean;
}
interface AdjacencyListOptions {
vertices: number;
edges: number;
}
export declare class UnweightedAdjacencyList extends Uint32Array {
vertices: number;
edges: number;
static undirected: boolean;
static weighted: false;
constructor(options?: AdjacencyListOptions, ...args: any);
addEdge(x: number, y: number): this;
removeEdge(x: number, y: number): this;
hasEdge(x: number, y: number): boolean;
getEdge(x: number, y: number): Bit;
private setEdge(x: number, y: number): this;
private unsetEdge(x: number, y: number): this;
outEdges(x: number): IterableIterator<number>;
inEdges(x: number): IterableIterator<number>;
private setOffsets(): void;
isFull(): boolean;
grow(vertices?: number, edges?: number): UnweightedAdjacencyList;
static getLength(vertices: number, edges: number): number;
static getVertexCount(array: Collection): number;
static fromGrid(grid: Grid): UnweightedAdjacencyList;
}
declare class WeightedAdjacencyList {
vertices: number;
edges: number;
static undirected: boolean;
static weighted: true;
constructor(options?: AdjacencyListOptions, ...args: any);
addEdge(x: number, y: number, weight: number): this;
removeEdge(x: number, y: number): this;
hasEdge(x: number, y: number): boolean;
getEdge(x: number, y: number): number;
private setEdge(x: number, y: number, weight: number): this;
private unsetEdge(x: number, y: number): this;
outEdges(x: number): IterableIterator<number>;
inEdges(x: number): IterableIterator<number>;
private setOffsets(): void;
isFull(): boolean;
grow(vertices?: number, edges?: number): UnweightedAdjacencyList;
static getLength(vertices: number, edges: number): number;
static getVertexCount(array: Collection): number;
static fromGrid(grid: Grid): WeightedAdjacencyList;
}
export declare function WeightedAdjacencyListMixin<T extends Collection>(
Base?: Constructor<T>,
): Constructor<T & WeightedAdjacencyList>;
interface UnweightedMatrixOptions {
vertices: number;
}
export declare class UnweightedAdjacencyMatrix extends BinaryGrid {
vertices: number;
static undirected: boolean;
static weighted: false;
constructor(options?: UnweightedMatrixOptions, ...args: any);
addEdge(x: number, y: number): this;
removeEdge(x: number, y: number): this;
hasEdge(x: number, y: number): boolean;
getEdge(x: number, y: number): number;
outEdges(x: number): IterableIterator<number>;
inEdges(x: number): IterableIterator<number>;
static getLength(size: number): number;
static fromList(list: UnweightedAdjacencyList): UnweightedAdjacencyMatrix;
}
interface WeightedMatrixOptions {
vertices: number;
pad?: any;
}
declare class WeightedAdjacencyMatrix {
vertices: number;
static undirected: boolean;
static weighted: true;
constructor(options?: WeightedMatrixOptions, ...args: any);
addEdge(x: number, y: number): this;
removeEdge(x: number, y: number): this;
hasEdge(x: number, y: number): boolean;
getEdge(x: number, y: number): number;
outEdges(x: number): IterableIterator<number>;
inEdges(x: number): IterableIterator<number>;
static getLength(size: number): number;
static fromList(list: WeightedAdjacencyList, pad: number): WeightedAdjacencyMatrix;
}
export declare function WeightedAdjacencyMatrixMixin<T extends GridStructure>(
Base: CollectionConstructor,
undirected?: boolean,
): Constructor<T & WeightedAdjacencyMatrix>;
type AdjacencyStructure =
| UnweightedAdjacencyList
| UnweightedAdjacencyMatrix
| WeightedAdjacencyList
| WeightedAdjacencyMatrix;
interface GraphOptions {
vertices: number;
edges?: number;
pad?: number;
}
declare class Graph {
colors: BinaryGrid;
constructor(options: GraphOptions, ...args: any);
isGray(x: number): boolean;
setGray(x: number): this;
isBlack(x: number): boolean;
setBlack(x: number): this;
traverse(
isDFS?: boolean,
start?: number,
gray?: boolean,
white?: boolean,
black?: boolean,
): IterableIterator<number>;
path(start: number, end: number, isAcyclic?: boolean, isPositive?: boolean): number[];
tree(start?: number): number[];
isAcyclic(): boolean;
topologicalSort(): number[];
private searchUnweighted(start: number, end: number, predecessors: number[]): boolean;
private searchTopological(
start: number,
end: number,
distances: number[],
predecessors: number[],
): boolean;
private searchDijkstra(
start: number,
end: number,
distances: number[],
predecessors: number[],
): boolean;
private searchBellmanFord(
start: number,
end: number,
distances: number[],
predecessors: number[],
): boolean;
}
export declare function GraphMixin<T extends AdjacencyStructure>(
Base: Constructor<T>,
undirected?: boolean,
): Constructor<T & Graph>;
export { AdjacencyListMixin } from "./adjacency-list.ts";
export { AdjacencyMatrixUnweightedDirected } from "./adjacency-matrix-unweighted-directed.ts";
export { AdjacencyMatrixUnweightedUndirected } from "./adjacency-matrix-unweighted-undirected.ts";
export { AdjacencyMatrixWeightedDirectedMixin } from "./adjacency-matrix-weighted-directed.ts";
export { AdjacencyMatrixWeightedUndirectedMixin } from "./adjacency-matrix-weighted-undirected.ts";
export { ArrayView } from "./array-view.ts";
export { BigBitFieldMixin } from "./big-bit-field.ts";
export { BinaryGrid } from "./binary-grid.ts";
export { BinaryHeap } from "./binary-heap.ts";
export { BitArray } from "./bit-array.ts";
export { BitFieldMixin } from "./bit-field.ts";
export { BooleanView } from "./boolean-view.ts";
export { GraphMixin } from "./graph.ts";
export type { Colors } from "./graph.ts";
export { GridMixin } from "./grid.ts";
export { MapView } from "./map-view.ts";
export { BigInt64View, BigUint64View, Float32View, Float64View, Int16View, Int32View, Int8View, Uint16View, Uint32View, Uint8View, } from "./numeric-view.ts";
export { ObjectView } from "./object-view.ts";
export { Pool } from "./pool.ts";
export { RankedBitArray } from "./ranked-bit-array.ts";
export { SortedArray } from "./sorted-array.ts";
export type { Comparator } from "./sorted-array.ts";
export { StringView } from "./string-view.ts";
export { SymmetricGridMixin } from "./symmetric-grid.ts";
export { TypedArrayView } from "./typed-array-view.ts";
export type { AdjacencyStructure, AdjacencyStructureConstructor, Bit, IndexedCollection, } from "./utility-types.ts";
export { getBitSize, getLog2, getLSBIndex, popCount32 } from "./utilities.ts";
export { VectorView } from "./vector-view.ts";
export { View } from "./view.ts";

@@ -1,74 +0,27 @@

const BitField = require('./lib/bit-field');
const BigBitField = require('./lib/big-bit-field');
const BitFieldMixin = require('./lib/bit-field-mixin');
const GraphMixin = require('./lib/graph');
const GridMixin = require('./lib/grid');
const BinaryHeap = require('./lib/binary-heap.js');
const Pool = require('./lib/pool');
const RankedBitArray = require('./lib/ranked-bit-array');
const SortedArray = require('./lib/sorted-array');
const SortedMixin = require('./lib/sorted-collection');
const SymmetricGridMixin = require('./lib/symmetric-grid');
const UnweightedAdjacencyList = require('./lib/unweighted-adjacency-list');
const UnweightedAdjacencyMatrix = require('./lib/unweighted-adjacency-matrix');
const WeightedAdjacencyListMixin = require('./lib/weighted-adjacency-list');
const WeightedAdjacencyMatrixMixin = require('./lib/weighted-adjacency-matrix');
const ArrayView = require('./lib/array-view');
const TypedArrayView = require('./lib/typed-array-view');
const ArrayViewMixin = require('./lib/array-view-mixin');
const { MapView, MapViewMixin } = require('./lib/map-view');
const { ObjectView, ObjectViewMixin } = require('./lib/object-view');
const StringView = require('./lib/string-view');
const BinaryProtocol = require('./lib/binary-protocol');
const { TypeView, TypeViewMixin } = require('./lib/type-view');
const BooleanView = require('./lib/boolean-view');
const VariableView = require('./lib/variable-view');
const { VectorView, VectorViewMixin } = require('./lib/vector-view');
/**
* @external ArrayBuffer
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer|ArrayBuffer}
*/
/**
* @external DataView
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView|DataView}
*/
/**
* @external TypedArray
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray|TypedArray}
*/
module.exports = {
BitField,
BigBitField,
BitFieldMixin,
GraphMixin,
GridMixin,
BinaryHeap,
Pool,
RankedBitArray,
SortedArray,
SortedMixin,
SymmetricGridMixin,
UnweightedAdjacencyList,
UnweightedAdjacencyMatrix,
WeightedAdjacencyListMixin,
WeightedAdjacencyMatrixMixin,
ArrayView,
TypedArrayView,
ArrayViewMixin,
MapView,
MapViewMixin,
ObjectView,
ObjectViewMixin,
StringView,
BinaryProtocol,
TypeView,
TypeViewMixin,
BooleanView,
VariableView,
VectorView,
VectorViewMixin,
};
export { AdjacencyListMixin } from "./adjacency-list.ts";
export { AdjacencyMatrixUnweightedDirected } from "./adjacency-matrix-unweighted-directed.ts";
export { AdjacencyMatrixUnweightedUndirected } from "./adjacency-matrix-unweighted-undirected.ts";
export { AdjacencyMatrixWeightedDirectedMixin } from "./adjacency-matrix-weighted-directed.ts";
export { AdjacencyMatrixWeightedUndirectedMixin } from "./adjacency-matrix-weighted-undirected.ts";
export { ArrayView } from "./array-view.ts";
export { BigBitFieldMixin } from "./big-bit-field.ts";
export { BinaryGrid } from "./binary-grid.ts";
export { BinaryHeap } from "./binary-heap.ts";
export { BitArray } from "./bit-array.ts";
export { BitFieldMixin } from "./bit-field.ts";
export { BooleanView } from "./boolean-view.ts";
export { GraphMixin } from "./graph.ts";
export { GridMixin } from "./grid.ts";
export { MapView } from "./map-view.ts";
export { BigInt64View, BigUint64View, Float32View, Float64View, Int16View, Int32View, Int8View, Uint16View, Uint32View, Uint8View, } from "./numeric-view.ts";
export { ObjectView } from "./object-view.ts";
export { Pool } from "./pool.ts";
export { RankedBitArray } from "./ranked-bit-array.ts";
export { SortedArray } from "./sorted-array.ts";
export { StringView } from "./string-view.ts";
export { SymmetricGridMixin } from "./symmetric-grid.ts";
export { TypedArrayView } from "./typed-array-view.ts";
export { getBitSize, getLog2, getLSBIndex, popCount32 } from "./utilities.ts";
export { VectorView } from "./vector-view.ts";
export { View } from "./view.ts";
//# sourceMappingURL=index.js.map
{
"name": "structurae",
"version": "3.3.0",
"version": "4.0.0-pre.1",
"description": "Data structures for performance-sensitive modern JavaScript applications.",
"main": "index.js",
"types": "index.d.ts",
"type": "module",
"keywords": [

@@ -23,15 +23,8 @@ "optimization",

"scripts": {
"test": "jest",
"lint": "eslint ./lib/*.js ./test/*.js",
"doc:api": "jsdoc2md > doc/API.md",
"benchmark": "node bench/index.js"
"build": "tsc-silent -p tsconfig.json --suppress @"
},
"directories": {
"lib": "lib",
"doc": "doc",
"test": "test"
},
"files": [
"/lib/",
"index.d.ts"
"*.js",
"*.d.ts",
"*.js.map"
],

@@ -48,80 +41,9 @@ "author": "Maga D. Zandaqo <denelxan@gmail.com> (http://maga.name)",

},
"devDependencies": {
"@types/jest": "^26.0.4",
"benchmark": "^2.1.4",
"eslint": "^7.4.0",
"eslint-config-airbnb-base": "^14.2.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-import": "^2.22.0",
"jest": "^26.1.0",
"jsdoc-to-markdown": "^6.0.1",
"json-schema-faker": "^0.5.0-rcv.24"
},
"jest": {
"testEnvironment": "node",
"collectCoverage": true,
"collectCoverageFrom": [
"**/lib/**",
"!**/node_modules/**",
"!**/test/**"
],
"coverageDirectory": "<rootDir>/coverage",
"coverageReporters": [
"lcov"
],
"coverageThreshold": {
"global": {
"branches": 95,
"functions": 100,
"lines": 100,
"statements": 100
}
}
},
"engines": {
"node": ">=11.0.0"
"node": ">=14.0.0"
},
"prettier": {
"printWidth": 100,
"singleQuote": true,
"trailingComma": "all"
},
"eslintConfig": {
"extends": [
"airbnb-base",
"prettier"
],
"env": {
"node": true,
"jest": true
},
"globals": {
"globalThis": false
},
"rules": {
"max-classes-per-file": 0,
"no-bitwise": 0,
"no-plusplus": 0,
"no-continue": 0,
"no-restricted-syntax": 0,
"no-nested-ternary": 1,
"no-labels": 1,
"no-param-reassign": [
2,
{
"props": false
}
],
"valid-jsdoc": [
2,
{
"prefer": {
"return": "returns"
},
"requireReturnDescription": false,
"requireParamDescription": false
}
]
}
"devDependencies": {
"tsc-silent": "^1.2.1",
"typescript": "^4.3.2"
}
}
# Structurae
[![Actions Status](https://github.com/zandaqo/structurae/workflows/ci/badge.svg)](https://github.com/zandaqo/structurae/actions)
[![npm](https://img.shields.io/npm/v/structurae.svg?style=flat-square)](https://www.npmjs.com/package/structurae)
[![Actions Status](https://github.com/zandaqo/structurae/workflows/Build/badge.svg)](https://github.com/zandaqo/structurae/actions)
A collection of data structures for high-performance JavaScript applications that includes:
A collection of data structures for high-performance JavaScript applications
that includes:
- [Binary Structures](https://github.com/zandaqo/structurae#binary-structures):
- [ObjectView](https://github.com/zandaqo/structurae#ObjectView) - extends DataView to implement C-like struct.
- [ArrayView](https://github.com/zandaqo/structurae#ArrayView) - DataView based array of ObjectViews, strings, numbers, etc.
- [MapView](https://github.com/zandaqo/structurae#MapView) - ObjectView with optional fields and fields of varying sizes.
- [VectorView](https://github.com/zandaqo/structurae#VectorView) - ArrayView that supports optional and variable length elements, including MapViews.
- [StringView](https://github.com/zandaqo/structurae#StringView) - extends Uint8Array to handle C-like representation of UTF-8 encoded strings.
- [BinaryProtocol](https://github.com/zandaqo/structurae#BinaryProtocol) - a helper class that simplifies defining and operating on multiple tagged ObjectViews.
- [Binary Protocol](https://github.com/zandaqo/structurae#binary-protocol) -
simple binary protocol based on DataView and defined with JSONSchema
- Bit Structures:
- [BitField & BigBitField](https://github.com/zandaqo/structurae#BitField) - stores and operates on data in Numbers and BigInts treating them as bitfields.
- [BitArray](https://github.com/zandaqo/structurae#BitArray) - an array of bits implemented with Uint32Array.
- [Pool](https://github.com/zandaqo/structurae#Pool) - manages availability of objects in object pools.
- [RankedBitArray](https://github.com/zandaqo/structurae#RankedBitArray) - extends BitArray with O(1) time rank and O(logN) select methods.
- [BitField & BigBitField](https://github.com/zandaqo/structurae#BitField) -
stores and operates on data in Numbers and BigInts treating them as
bitfields.
- [BitArray](https://github.com/zandaqo/structurae#BitArray) - an array of
bits implemented with Uint32Array.
- [Pool](https://github.com/zandaqo/structurae#Pool) - manages availability of
objects in object pools.
- [RankedBitArray](https://github.com/zandaqo/structurae#RankedBitArray) -
extends BitArray with O(1) time rank and O(logN) select methods.
- [Graphs](https://github.com/zandaqo/structurae#Graphs):
- [Graph](https://github.com/zandaqo/structurae#Graph) - extends an adjacency list/matrix structure and provides methods for traversal (BFS, DFS),
pathfinding (Dijkstra, Bellman-Ford), spanning tree construction (BFS, Prim), etc.
- [UnweightedAdjacencyList & WeightedAdjacencyList](https://github.com/zandaqo/structurae#Adjacency-Lists) - implements Adjacency List data structure.
- [UnweightedAdjacencyMatrix & WeightedAdjacencyMatrix](https://github.com/zandaqo/structurae#Adjacency-Matrices) - implements Adjacency Matrix data structure.
- [Adjacency Structures](https://github.com/zandaqo/structurae#Adjacency-Structures) -
implement adjacency list & matrix data structures.
- [Graph](https://github.com/zandaqo/structurae#Graph) - extends an adjacency
list/matrix structure and provides methods for traversal (BFS, DFS),
pathfinding (Dijkstra, Bellman-Ford), spanning tree construction (BFS,
Prim), etc.
- [Grids](https://github.com/zandaqo/structurae#Grids):
- [BinaryGrid](https://github.com/zandaqo/structurae#BinaryGrid) - creates a grid or 2D matrix of bits.
- [Grid](https://github.com/zandaqo/structurae#Grid) - extends built-in indexed collections to handle 2 dimensional data (e.g. nested arrays).
- [SymmetricGrid](https://github.com/zandaqo/structurae#SymmetricGrid) - a grid to handle symmetric or triangular matrices using half the space required for a normal grid.
- [BinaryGrid](https://github.com/zandaqo/structurae#BinaryGrid) - creates a
grid or 2D matrix of bits.
- [Grid](https://github.com/zandaqo/structurae#Grid) - extends built-in
indexed collections to handle 2 dimensional data (e.g. nested arrays).
- [SymmetricGrid](https://github.com/zandaqo/structurae#SymmetricGrid) - a
grid to handle symmetric or triangular matrices using half the space
required for a normal grid.
- [Sorted Structures](https://github.com/zandaqo/structurae#sorted-structures):
- [BinaryHeap](https://github.com/zandaqo/structurae#BinaryHeap) - extends Array to implement the Binary Heap data structure.
- [SortedCollection](https://github.com/zandaqo/structurae#SortedCollection) - extends TypedArrays to handle sorted data.
- [SortedArray](https://github.com/zandaqo/structurae#SortedArray) - extends Array to handle sorted data.
- [BinaryHeap](https://github.com/zandaqo/structurae#BinaryHeap) - extends
Array to implement the Binary Heap data structure.
- [SortedArray](https://github.com/zandaqo/structurae#SortedArray) - extends
Array to handle sorted data.
## Installation
## Usage
Node.js:
```
npm i structurae
npm i structurae
```
```
import {...} from "structurae";
```
Deno:
```
import * as structurae from "https://raw.githubusercontent.com/zandaqo/structurae/4.0.0-rc1/index.ts"
```
## Documentation
- [API documentation](https://github.com/zandaqo/structurae/blob/master/doc/API.md)
- Articles:
- [Structurae: Data Structures for Heigh-Performance JavaScript](https://blog.usejournal.com/structurae-data-structures-for-high-performance-javascript-9b7da4c73f8)
- [Structurae 1.0: Graphs, Strings, and WebAssembly](https://medium.com/@zandaqo/structurae-1-0-graphs-strings-and-webassembly-25dd964d5a70)
- [Structurae: Data Structures for Heigh-Performance
JavaScript](https://blog.usejournal.com/structurae-data-structures-for-high-performance-javascript-9b7da4c73f8)
- [Structurae 1.0: Graphs, Strings, and
WebAssembly](https://medium.com/@zandaqo/structurae-1-0-graphs-strings-and-webassembly-25dd964d5a70)
## Overview
### Binary Structures
Binary data in JavaScript is represented by ArrayBuffer and accessed through "view" objects--TypedArrays and DataView.
However, both of those interfaces are limited to working with numbers. Structurae offers a set of classes that extend these interfaces to
support using ArrayBuffers for strings, objects, and arrays of objects defined with schema akin to C-like structs.
Useful on their own, when combined, these classes form the basis for a simple binary protocol that is smaller and faster than
schema-less binary formats (e.g. BSON, MessagePack) and supports zero-copy operations. Unlike other schema-based formats
(e.g. Flatbuffers), these interfaces are native to JavaScript, hence, supported in all modern browsers and Node.js,
and do not require compilation.
### Binary Protocol
#### ObjectView
ObjectView extends DataView to store a JavaScript object in an ArrayBuffer akin to C-like struct.
Fields of an ObjectView are defined using a subset of JSON Schema. ObjectView supports all JavaScript values, that is, numbers, strings,
booleans, objects, and arrays. Internally, the data is laid out sequentially with fixed sizes, hence,
variable length arrays and optional fields are not supported (for those check out [MapView](https://github.com/zandaqo/structurae#MapView)).
Binary data in JavaScript is represented by ArrayBuffer and accessed through
"view" interfaces--TypedArrays and DataView. However, both of those interfaces
are limited to working with numbers. Structurae offers a set of classes that
extend the DataView interface to support using ArrayBuffers for strings,
objects, and arrays. These classes ("views") form the basis for a simple binary
protocol ("view protocol") with the following features:
```javascript
const { ObjectViewMixin } = require('structurae');
- smaller and faster than schema-less binary formats (e.g. BSON, MessagePack);
- supports zero-copy operations, e.g. reading and changing object fields
without; decoding the whole object;
- supports static typing through TypeScript;
- uses JSON Schema for schema definitions;
- does not require compilation unlike most other schema-based formats (e.g.
FlatBuffers).
const Person = ObjectViewMixin({
$id: 'Person', // each object requires a unique id
type: 'object',
The protocol is operated through the `View` class that handles creation and
caching of necessary structures for a given JSON Schema as well as simplifying
serialization of tagged objects.
```typescript
import { View } from "structurae";
// define interface for out animal objects
interface Animal {
name: string;
age: number;
}
// create and return a view class (extension of DataView) that handles our Animal objects
const AnimalView = View.create<Animal>({
$id: "Pet",
type: "object",
properties: {
name: { type: 'string', maxLength: 10 }, // the size of a string field is required and defined by maxLength
name: { type: "string", maxLength: 10 },
// by default, type `number` is treated as int32, but can be further specified usin `btype`
age: { type: "number", btype: "uint8" },
},
});
// encode our animal object
const animal = AnimalView.from({ name: "Gaspode", age: 10 });
animal instanceof DataView;
//=> true
animal.byteLength;
//=> 14
animal.get("name");
//=> Gaspode
animal.get("age");
//=> 10
animal.set("age", 20);
animal.toJSON();
//=> { name: "Gaspode", age: 20 }
```
#### Objects and Maps
Objects by default are treated as C-like structs, the data is laid out
sequentially with fixed sizes, all standard JavaScript values are supported,
inluding other objects and arrays of fixed size:
```typescript
interface Friend {
name: string;
}
interface Person {
name: string;
fullName: Array<string>;
bestFriend: Friend;
friends: Array<Friend>;
}
const PersonView = View.create<Person>({
// each object requires a unique id
$id: "Person",
type: "object",
properties: {
// the size of a string field is required and defined by maxLength
name: { type: "string", maxLength: 10 },
fullName: {
type: 'array',
maxItems: 2, // the size of an array is required and defined by maxItems
items: { type: 'string', maxLength: 10 }, // all items have to be the same type
type: "array",
// the size of an array is required and defined by maxItems
maxItems: 2,
// all items have to be the same type
items: { type: "string", maxLength: 20 },
},
bestFriend: { $ref: '#Friend' }, // objects can be referenced with $ref using their $id
// objects can be referenced with $ref using their $id
bestFriend: { $ref: "#Friend" },
friends: {
type: 'array',
type: "array",
maxItems: 3,
items: {
$id: 'Friend',
type: 'object',
$id: "Friend",
type: "object",
properties: {
name: { type: 'string', maxLength: 10 },
name: { type: "string", maxLength: 20 },
},
},
},
scores: {
type: 'array',
maxItems: 10,
items: { type: 'integer', btype: 'int16' },
},
house: {
$id: 'House',
type: 'object',
properties: {
size: { type: 'number', btype: 'float32', default: 100 }, // default values are applied upon creation of a view
},
},
pets: {
type: 'array',
maxItems: 3,
items: {
$id: 'Pet',
type: 'object',
properties: {
type: { type: 'string', maxLength: 10 },
}
},
},
},
});
const person = Person.from({
name: 'Zaphod',
fullName: ['Zaphod', 'Beeblebrox'],
scores: [1, 2, 3],
house: {
size: 1,
},
pets: [
{ type: 'dog' }, { type: 'cat' }
],
name: "Carrot",
fullName: ["Carrot", "Ironfoundersson"],
bestFriend: { name: "Sam Vimes" },
friends: [{ name: "Sam Vimes" }],
});
person.byteLength
//=> 64
person.get('scores');
//=> 1
person.get('name');
//=> Zaphod
person.getView('name')
person.byteLength;
//=> 130
person.get("name");
//=> Carrot
person.getView("name");
//=> StringView [10]
person.get('scores')
//=> [1, 2, 3, 0, 0, 0, 0, 0, 0, 0,]
person.set('house', { size: 5 });
person.get('house');
//=> { size: 5 }
person.toJSON()
//=> { name: 'Zaphod', fullName: ['Zaphod', 'Beeblebrox'], scores: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0,],
// house: { size: 5 }, pets: [{ type: 'dog' }, { type: 'cat' }, { type: '' }] }
person.get("fullName");
//=> ["Carrot", "Ironfoundersson"]
person.toJSON();
//=> {
// name: "Carrot",
// fullName: ["Carrot", "Ironfoundersson"],
// bestFriend: { name: "Sam Vimes" },
// friends: [{ name: "Sam Vimes" }]
// }
```
There are certain requirements for a JSON Schema used for ObjectViews:
- Each object should have a unique id defined with `$id` field. Upon initialization, the view class is stored in `ObjectView.Views`
and accessed with the id used as the key. References made with `$ref` are also resolved against the id.
- Sizes of strings and arrays should be defined using `maxLength` and `maxItems` properties respectfully.
- `$ref` can be used to reference objects and only objects by their `$id`. The referenced object should be defined either in the
same schema or in a schema of an ObjectView class initialized previously.
- Type `number` by default resolves to `float64` and type `integer` to `int32`, you can use any other type by specifying it in
`btype` property.
Objects that support optional fields and fields of variable size ("maps") should
additionally specify `btype` `map` and list non-optional (fixed sized) fields as
`required`:
ObjectView supports setting default values of fields. Default values are applied upon creation of a view:
```javascript
const House = ObjectViewMixin({
$id: 'House',
type: 'object',
properties: {
size: { type: 'integer', btype: 'uint32', default: 100 }
},
});
const house = House.from({});
house.get('size');
//=> 100
```typescript
interface Town {
name: string;
railstation: boolean;
clacks?: number;
}
const TownView = View.create<Town>({
$id: "Town",
type: "object",
btype: "map",
properties: {
// notice that maxLength is not required for optional fields in maps
// however, if set, map with truncate longer strings to fit the maxLength
name: { type: "string" },
railstation: { type: "boolean" },
// optional, nullable field
clacks: { type: "integer" },
}
required: ["railstation"],
});
const lancre = TownView.from({ name: "Lancre", railstation: false });
lancre.get("name") //=> Lancre
lancre.get("clacks") //=> undefined
lancre.byteLength //=> 19
const stoLat = TownView.from({ name: "Sto Lat", railstation: true, clacks: 1 });
stoLat.get("clacks") //=> 1
stoLat.byteLength //=> 24
```
Default values of an ObjectView can be overridden when the view is used as a field inside other views:
```javascript
const Neighborhood = ObjectViewMixin({
$id: 'Neighborhood',
type: 'object',
properties: {
house: { $ref: '#House' },
biggerHouse: { $ref: '#House', default: { size: 200 } },
},
});
The size and layout of each map instance is calculated upon creation and stored
within the instance (unlike fixed sized objects, where each instance have the
same size and layout). Maps are useful for densely packing objects and arrays
whose size my vary greatly. There is a limitation, though, since ArrayBuffers
cannot be resized, optional fields that were absent upon creation of a map view
cannot be set later, and those set cannot be resized, that is, assigned a value
that is greater than their current size.
const neighborhood = Neighborhood.from({});
neighborhood.get('house')
//=> { size: 100 }
neighborhood.get('biggerHouse')
//=> { size: 200 }
```
For performance sake, all variable size views are encoded using single global
ArrayBuffer that is 8192 bytes long, if you expect to handle bigger views, set
`View.maxLength` to desired max length before instantiating any view.
You can add your own field types to ObjectView, for example an ObjectView that supports Date:
```javascript
const { TypeViewMixin } = require('structurae');
class DateView extends TypeViewMixin('float64', true) {
static from(value, view, start) {
super.from(+value, view, start);
}
static toJSON(view, start) {
return new Date(super.toJSON(view, start));
}
}
There are certain requirements for a JSON Schema used for fixed sized objects:
class View extends ObjectView {}
View.types = {
...ObjectView.types,
date(field) {
return DateView;
},
};
- Each object should have a unique id defined with `$id` field. Upon
initialization, the view class is stored in `View.Views` and accessed with the
id used as the key. References made with `$ref` are also resolved against the
id.
- For fixed sized objects, sizes of strings and arrays should be defined using
`maxLength` and `maxItems` properties respectfully.
- `$ref` can be used to reference objects by their `$id`. The referenced object
should be defined either in the same schema or in a schema initialized
previously.
- Type `number` by default resolves to `float64` and type `integer` to `int32`,
you can use any other type by specifying it in `btype` property.
const ViewWithDate = ObjectViewMixin({
$id: 'ViewWithDate',
type: 'object',
Objects and maps support setting default values of required fields. Default
values are applied upon creation of a view:
```typescript
interface House {
size: number;
}
const House = View.create<House>({
$id: "House",
type: "object",
properties: {
a: { type: 'date' },
size: { type: "integer", btype: "uint32", default: 100 },
},
}, View);
const date = ViewWithDate.from({ a: new Date(0) });
date.get('a')
//=> Thu Jan 01 1970 00:00:00 GMT+0000
date.set('a', new Date(1e8));
date.toJSON();
//=> { a: Fri Jan 02 1970 03:46:40 GMT+0000 }
});
const house = House.from({} as House);
house.get("size");
//=> 100
```
#### ArrayView
DataView based array of "views": objects, number, strings, etc:
```javascript
const { ObjectViewMixin, ArrayViewMixin, StringView } = require('structurae');
Default values of an object can be overridden when it is nested inside another
object:
const Int32ArrayView = ArrayViewMixin('int32', true); // create an ArrayView class for int32 values with little endian encoding
const Int32ArrayViewBE = ArrayViewMixin('int32', false); // big endian int32 values
const StringsView = ArrayViewMixin(StringView, 20); // an ArrayView class for strings with maximum length of 20 bytes each
const Person = ObjectViewMixin({
$id: 'Person', // each object requires a unique id
type: 'object',
```typescript
interface Neighborhood {
house: House;
biggerHouse: House;
}
const Neighborhood = View.create<Neighborhood>({
$id: "Neighborhood",
type: "object",
properties: {
id: { type: 'integer', btype: 'uint32' },
name: { type: 'string', maxLength: 10 },
house: { $ref: "#House" },
biggerHouse: { $ref: "#House", default: { size: 200 } },
},
});
// an array class for Person objects
const PeopleArray = ArrayViewMixin(Person);
// create an empty array view of 10 Person objects
const people = PeopleArray.of(10);
// create an array view from a given array
const hitchhikers = PeopleArray.from([
{ id: 1, name: 'Arthur' },
{ id: 2, name: 'Ford' },
]);
// get a view of the first object
hitchhikers.getView(0);
//=> Person [14]
// get the value of the first object
hitchhikers.get(0);
//=> { id: 1, name: 'Arthur' }
// set the first object data
hitchhikers.set(0, { id: 3, name: 'Trillian' });
hitchhikers.get(0);
//=> { id: 3, name: 'Trillian' }
hitchhikers.toJSON();
//=> [{ id: 1, name: 'Arthur' }, { id: 2, name: 'Ford' }]
const neighborhood = Neighborhood.from({} as Neighborhood);
neighborhood.get("house");
//=> { size: 100 }
neighborhood.get("biggerHouse");
//=> { size: 200 }
```
TypedArrays in JavaScript have two limitations that make them cumbersome to use in conjunction with DataView.
First, there is no way to specify the endianness of numbers in TypedArrays unlike DataView.
Second, TypedArrays require their offset (byteOffset) to be a multiple of their element size (BYTES_PER_ELEMENT),
which means that they often cannot "view" into existing ArrayBuffer starting from certain positions.
ArrayViews for numbers are essentially TypedArrays that circumvent both issues by using the DataView interface.
You can specify endianness and instantiate them at any position in an existing ArrayBuffer.
#### Arrays and Vectors
```javascript
const { ArrayViewMixin } = require('structurae');
The protocol supports arrays of non-nullable fixed sized values (numbers,
strings of fixed maximum size, objects) and vectors--arrays with nullable or
variable sized values. The type of items held by both "container" views is
defined in `items` field of the schema.
// create a class for little endian doubles
const Float64View = ArrayViewMixin('float64', true);
const buffer = new ArrayBuffer(11);
const doubles = new Float64View(buffer, 3, 8);
doubles.byteLength
//=> 20
doubles.byteOffset
//=> 3
doubles.set(0, 5).set(1, 10);
[...doubles]
//=> [5, 10]
```typescript
const Street = View.create<Array<House>>({
type: "array",
items: {
type: "object",
// we can also reference previously created class with $ref
$ref: "#House",
},
});
const street = Street.from([{ size: 10 }, { size: 20 }]);
street.byteLength; //=> 8
street.get(0); //=> { size: 10 }
street.getView(0).get("size"); //=> 10
street.size; //=> 2
street.set(0, { size: 100 });
street.get(0); //=> { size: 100 }
```
For vectors set `btype` to `vector`:
#### MapView
MapView is an ObjectView that supports optional fields and fields of variable size. The size and layout of each MapView instance
is calculated upon creation and stored within the instance (unlike ObjectViews, where each instance have the same size and layout).
MapViews are useful for densely packing objects and arrays whose size my vary greatly.
There is a limitation, though, since ArrayBuffers cannot be resized, optional fields that were absent upon creation of a map view cannot be set later, and those set cannot be resized.
```javascript
const { MapViewMixin } = require('structurae');
const Person = MapViewMixin({
$id: 'Person',
type: 'object',
properties: {
id: { type: 'integer', btype: 'uint32', default: 10 },
// notice that maxLength is not required for optional fields in MapView
// however, if set, MapView with truncate longer strings to fit the maxLength
name: { type: 'string' },
pets: {
type: 'array',
// maxItems is also not required for MapView
// if set, MapView truncate arrays exceeding the specified maximum
items: {
$id: 'Pet',
type: 'object',
properties: {
// however both maxLengh and maxItems are required in nested objects and arrays
type: { type: 'string', maxLength: 10 }
},
},
},
names: {
type: 'array',
// uses VectorView for an array of variable length elements
// if btype is set to vector
btype: 'vector',
items: { type: 'string' },
},
```typescript
const Names = View.create<Array<string | undefined>>({
type: "array",
btype: "vector",
items: {
type: "string",
},
// required fields are always present and can have default values
required: ['id'],
});
const person0 = Person.from({});
person.get('id')
//=> 10
person.get('name')
//=> name
// create a person with one pet
const person1 = Person.from({ id: 1, name: 'Artur', pets: [{ type: 'dog'}] });
person1.byteLength;
//=> 31
// create a person with no pets
const person0 = Person.from({ id: 1, name: 'Artur'});
person0.byteLength;
//=> 18
person0.get('pets');
//=> undefined
person0.set('pets', [{ type: 'dog'}]);
person0.get('pets');
//=> undefined
const person2 = Person.from({ names: ['Arthur', 'Dent', '', 'Arthur Dent']})
person2.toJSON();
//=> { id: 10, names: ['Arthur', 'Dent', undefined, 'Arthur Dent']}
const witches = Names.from([
"Granny Weatherwax",
"Nanny Ogg",
undefined,
"Magrat Garlick",
]);
witches.byteLength; //=> 64
witches.get(0); //=> "Granny Weatherwax"
witches.get(2); //=> undefined
```
For performance reasons, MapView uses a single buffer for serialization, thus, limiting the maximum size of a view.
The buffer is inherited from `VariableView` class and the default is 8192 bytes, if you expect bigger views, please set the desired size in `VariableView.maxLength`.
As with maps, the layout of vectors is calculated upon creation and editing is
limited to the items present upon creation.
#### VectorView
VectorView is an ArrayView that supports optional elements (i.e. `undefined`) and elements of variable length, such as MapView or StringView.
VectorView stores offsets inside the view itself resulting in an overhead of 4 * (_n_ + 2) bytes where _n_ is the number of elements in the view.
Like MapView, VectorView has limited editablity: the layout of an instance is calculated once upon creation,
hence, setting absent elements or resizing existing elements is not possible.
```javascript
const { MapViewMixin, VectorViewMixin, TypeViewMixin } = require('structurae');
const SparseArrayView = VectorViewMixin(TypeViewMixin('uint8'));
SparseArrayView.from([1, , 2, null]).toJSON();
//=> [1, undefined, 2, undefined]
#### Strings
const MapVector = VectorViewMixin(MapViewMixin({
$id: 'SomeMap',
btype: 'map',
properties: {
id: { type: 'integer' },
name: { type: 'string' },
},
}));
const mapVector = MapVector.from([{ id: 1 }, null, { name: 'abc'}]);
mapVector.size;
//=> 3
mapVector.get(0);
//=> { id: 1 };
mapVector.toJSON();
//=> [{ id: 1 }, undefined, { name: 'abc'}]
```
The protocol handles strings through StringView, an extension of DataView that
handles string serialization. It also offers a handful of convenience methods to
operate on encoded strings so that some common operations can be performed
without decoding the string:
Like MapView, VectorView uses for serialization the default buffer inherited from `VariableView`, if you expect your
vectors to exceed the default 8192 bytes in length, please set the desired maximum length in `VariableView.maxLength`.
#### StringView
Encoding API (available both in modern browsers and Node.js) allows us to convert JavaScript strings to
(and from) UTF-8 encoded stream of bytes represented by a Uint8Array. StringView extends Uint8Array with string related methods
and relies on Encoding API internally for conversions.
You can use `StringView.fromString` to create an encoded string, and `StringView#toString` to convert it back to a string:
```javascript
const { StringView } = require('structurae');
import { StringView } from "structurae";
const stringView = StringView.from('abc😀a');
let stringView = StringView.from("abc😀a");
//=> StringView [ 97, 98, 99, 240, 159, 152, 128, 97 ]
stringView.toString();
//=> 'abc😀a'
stringView == 'abc😀a';
//=> "abc😀a"
stringView == "abc😀a";
//=> true
```
While the array itself holds code points, StringView provides methods to operate on characters of the underlying string:
```javascript
const stringView = StringView.from('abc😀');
stringView = StringView.from("abc😀");
stringView.length; // length of the view in bytes

@@ -416,139 +364,116 @@ //=> 8

stringView.charAt(0); // get the first character in the string
//=> 'a'
//=> "a"
stringView.charAt(3); // get the fourth character in the string
//=> '😀'
[...stringView.characters()] // iterate over characters
//=> ['a', 'b', 'c', '😀']
//=> "😀"
[...stringView.characters()]; // iterate over characters
//=> ["a", "b", "c", "😀"]
stringView.substring(0, 4);
//=> 'abc😀'
```
//=> "abc😀"
StringView also offers methods for searching and in-place changing the underlying string without decoding:
```javascript
const stringView = StringView.from('abc😀a');
const searchValue = StringView.from('😀');
stringView = StringView.from("abc😀a");
const searchValue = StringView.from("😀");
stringView.search(searchValue); // equivalent of String#indexOf
//=> 3
const replacement = StringView.from('d');
const replacement = StringView.from("d");
stringView.replace(searchValue, replacement).toString();
//=> 'abcda'
//=> "abcda"
stringView.reverse().toString();
//=> 'adcba'
//=> "adcba"
```
#### BinaryProtocol
When transferring our buffers encoded with views we can often rely on meta information to know what kind of ObjectView
to use in order to decode a received buffer, e.g. let's say we have a `HouseView` class to encode/decode all buffers
that go through `/houses` route. However, sometimes we need our ObjectViews to carry within themselves an information
as to what kind of ObjectView was used to encode them. To do that, we can prepend or tag each view with a value indicating its
class, i.e. add a field that defaults to a certain value for each view class. Now upon receiving a buffer we can read that field
using the DataView and convert it into an appropriate view. The `BinaryProtocol` does all that under the hood serving as a helper class
to remove boilerplate, plus it creates the necessary ObjectView classes from schemas for when we are not concerned too much about individual
classes:
#### Tagged Objects
```javascript
const { BinaryProtocol } = require('structurae');
When transferring our buffers encoded with views we can often rely on meta
information to know what kind of view to use in order to decode a received
buffer. However, sometimes we might want our views to carry that information
within themselves. To do that, we can prepend or tag each view with a value
indicating its class, i.e. add a field that defaults to a certain value for each
view class. Now upon receiving a buffer we can read that field using the
DataView and convert it into an appropriate view.
const protocol = new BinaryProtocol({
0: {
$id: 'Person',
type: 'object',
properties: {
age: { type: 'integer', btype: 'int8' },
name: { type: 'string', length: 10 },
}
The `View` class offers a few convenience methods to simplify this process:
```typescript
import { View } from "structurae";
interface Dog {
tag: 0;
name: string;
}
interface Cat {
tag: 1;
name: string;
}
const DogView = View.create<Dog>({
type: "object",
$id: "Dog",
properties: {
// the tag field with default value
tag: { type: "number", btype: "uint8", default: 0 }
name: { type: "string", maxLength: 10 }
},
1: {
$id: 'Items',
type: 'object',
properties: {
id: { type: 'integer', btype: 'uint32' },
items: {
type: 'array',
maxItems: 3,
items: { type: 'string', maxLength: 10 },
},
},
});
const CatView = View.create<Cat>({
type: "object",
$id: "Cat",
properties: {
// the tag field with default value
tag: { type: "number", btype: "uint8", default: 1 }
name: { type: "string", maxLength: 10 }
},
});
const person = protocol.encode({ tag: 0, age: 100, name: 'abc' });
//=> ObjectView (12)
protocol.decode(person.buffer)
//=> { tag: 0, age: 100, name: 'abc' }
const personView = protocol.view(person.buffer);
personView.get('age');
//=> 100
const item = protocol.encode({ tag: 1, id: 10, items: ['a', 'b', 'c'] });
//=> ObjectView (35)
protocol.decode(item.buffer)
//=> { tag: 1, id: 10, items: ['a', 'b', 'c'] }
// now we can encode tagged objects without specifying views first:
const animal = View.encode({ tag: 0, name: "Gaspode" });
// and decode them:
View.decode(animal) //=> { tag: 0, name: "Gaspode" }
```
We can use references to existing ObjectViews, however, those views should have a tag field and appropriate default value specified.
By default, the tag field is named `tag` and has the type of `uint8`. A
different tag name can be specified in `View.tagName`.
```javascript
const View = ObjectViewMixin({
$id: 'Items',
type: 'object',
properties: {
tag: { type: 'integer', btype: 'uint8', default: 1 },
id: { type: 'integer', btype: 'uint32' },
items: {
type: 'array',
maxItems: 3,
items: { type: 'string', maxLength: 10 },
},
$id: "Items",
type: "object",
properties: {
tagId: { type: "integer", btype: "uint32", default: 1 },
id: { type: "integer", btype: "uint32" },
items: {
type: "array",
maxItems: 3,
items: { type: "string", maxLength: 10 },
},
});
const protocol = new BinaryProtocol({
0: {
$id: 'Person',
type: 'object',
properties: {
age: { type: 'integer', btype: 'int8' },
name: { type: 'string', length: 10 },
}
},
1: { $ref: '#Items' },
});
```
By default, the tag field is named `tag` and has the type of `uint8`, both can be changed and provided as second and third parameters to protocol constructor.
```javascript
const View = ObjectViewMixin({
$id: 'Items',
type: 'object',
properties: {
tagId: { type: 'integer', btype: 'uint32', default: 1 },
id: { type: 'integer', btype: 'uint32' },
items: {
type: 'array',
maxItems: 3,
items: { type: 'string', maxLength: 10 },
const protocol = new BinaryProtocol(
{
0: {
$id: "Person",
type: "object",
properties: {
age: { type: "integer", btype: "int8" },
name: { type: "string", length: 10 },
},
},
});
const protocol = new BinaryProtocol({
0: {
$id: 'Person',
type: 'object',
properties: {
age: { type: 'integer', btype: 'int8' },
name: { type: 'string', length: 10 },
}
1: { $ref: "#Items" },
},
1: { $ref: '#Items' },
}, 'tagId', 'uint32');
"tagId",
"uint32",
);
```
### Bit Structures
#### BitField & BigBitField
BitField and BigBitField use JavaScript Numbers and BigInts respectively as bitfields to store and operate on data using bitwise operations.
By default, BitField operates on 31 bit long bitfield where bits are indexed from least significant to most:
BitField and BigBitField use JavaScript Numbers and BigInts respectively as
bitfields to store and operate on data using bitwise operations. By default,
BitField operates on 31 bit long bitfield where bits are indexed from least
significant to most:
```javascript
const { BitField } = require('structurae');
import { BitField } from "structurae";

@@ -564,12 +489,14 @@ const bitfield = new BitField(29); // 29 === 0b11101

You can extend BitField or BigBitField directly or use BitFieldMixin with your own schema by specifying field names and their respective sizes in bits:
You can use BitFieldMixin or BigBitFieldMixin with your own schema by specifying
field names and their respective sizes in bits:
```javascript
const Field = BitFieldMixin({ width: 8, height: 8 });
const field = new Field({ width: 100, height: 200 });
field.get('width');
field.get("width");
//=> 100;
field.get('height');
field.get("height");
//=> 200
field.set('width', 18);
field.get('width');
field.set("width", 18);
field.get("width");
//=> 18

@@ -580,27 +507,19 @@ field.toObject();

You can forgo specifying sizes if your field size is 1 bit:
```javascript
const Privileges = BitFieldMixin(['user', 'moderator', 'administrator']);
const privileges = new Privileges(0);
privileges.set('user').set('moderator');
privileges.has('user', 'moderator');
//=> true
privileges.set('moderator', 0).has('moderator');
//=> false
```
If the total size of your fields exceeds 31 bits, use BigBitFieldMixin that
internally uses a BigInt to represent the resulting number, however, you can
still use normal numbers to set each field and get their value as a number as
well:
If the total size of your fields exceeds 31 bits, BitFieldMixin will switch to BigBitField that internally uses
a BigInt to represent the resulting number, however, you can still use normal numbers to set each field
and get their value as a number as well:
```javascript
const LargeField = BitFieldMixin({ width: 20, height: 20 });
const largeField = new LargeField([1048576, 1048576]);
largeField.value
largeField.value;
//=> 1099512676352n
largeField.set('width', 1000).get('width')
largeField.set("width", 1000).get("width");
//=> 1000
```
If you have to add more fields to your schema later on, you do not have to re-encode your existing values, just add new fields
at the end of your new schema:
If you have to add more fields to your schema later on, you do not have to
re-encode your existing values, just add new fields at the end of your new
schema:

@@ -614,14 +533,16 @@ ```javascript

const newField = new NewField(oldField);
newField.get('width');
newField.get("width");
//=> 20
newField.get('height');
newField.get("height");
//=> 1
newField.set('weight', 100).get('weight');
newField.set("weight", 100).get("weight");
//=> 100
```
If you only want to encode or decode a set of field values without creating an instance, you can do so by using static methods
`BitField.encode` and `BitField.decode` respectively:
If you only want to encode or decode a set of field values without creating an
instance, you can do so by using static methods `BitField.encode` and
`BitField.decode` respectively:
```javascript
const Field = BitFieldMixin({ width: 7, height: 1 })
const Field = BitFieldMixin({ width: 7, height: 1 });

@@ -638,4 +559,5 @@ Field.encode([20, 1]);

If you don't know beforehand how many bits you need for your field, you can call `BitField.getMinSize` with the maximum
possible value of your field to find out:
If you don't know beforehand how many bits you need for your field, you can call
`BitField.getMinSize` with the maximum possible value of your field to find out:
```javascript

@@ -647,4 +569,7 @@ BitField.getMinSize(100);

For performance sake, BitField doesn't check the size of values being set and setting values that exceed the specified
field size will lead to undefined behavior. If you want to check whether values fit their respective fields, you can use `BitField.isValid`:
For performance sake, BitField doesn't check the size of values being set and
setting values that exceed the specified field size will lead to undefined
behavior. If you want to check whether values fit their respective fields, you
can use `BitField.isValid`:
```javascript

@@ -659,3 +584,5 @@ const Field = BitFieldMixin({ width: 7, height: 1 });

`BitField#match` (and its static variation `BitField.match`) can be used to check values of multiple fields at once:
`BitField#match` (and its static variation `BitField.match`) can be used to
check values of multiple fields at once:
```javascript

@@ -674,4 +601,6 @@ const Field = BitFieldMixin({ width: 7, height: 1 });

If you have to check multiple BitField instances for the same values, create a special matcher with `BitField.getMatcher`
and use it in the match method, that way each check will require only one bitwise operation and a comparison:
If you have to check multiple BitField instances for the same values, create a
special matcher with `BitField.getMatcher` and use it in the match method, that
way each check will require only one bitwise operation and a comparison:
```javascript

@@ -687,23 +616,32 @@ const Field = BitFieldMixin({ width: 7, height: 1 });

#### BitArray
BitArray uses Uint32Array as an array or vector of bits. It's a simpler version of BitField that only sets and checks individual bits:
BitArray uses Uint32Array as an array or vector of bits. It's a simpler version
of BitField that only sets and checks individual bits:
```javascript
const array = new BitArray(10);
array.getBit(0)
array.getBit(0);
//=> 0
array.setBit(0).getBit(0);
//=> 1
array.size
array.size;
//=> 10
array.length
array.length;
//=> 1
```
BitArray is the base class for [Pool](https://github.com/zandaqo/structurae#Pool) and [RankedBitArray](https://github.com/zandaqo/structurae#RankedBitArray) classes.
It's useful in cases where one needs more bits than can be stored in a number, but doesn't want to use BigInts as it is done by [BitField](https://github.com/zandaqo/structurae#BitField).
BitArray is the base class for
[Pool](https://github.com/zandaqo/structurae#Pool) and
[RankedBitArray](https://github.com/zandaqo/structurae#RankedBitArray) classes.
It's useful in cases where one needs more bits than can be stored in a number,
but doesn't want to use BigInts as it is done by
[BitField](https://github.com/zandaqo/structurae#BitField).
#### Pool
Implements a fast algorithm to manage availability of objects in an object pool using a BitArray.
Implements a fast algorithm to manage availability of objects in an object pool
using a BitArray.
```javascript
const { Pool } = require('structurae');
const { Pool } = require("structurae");

@@ -729,6 +667,8 @@ // create a pool of 1600 indexes

#### RankedBitArray
RankedBitArray is an extension of BitArray with methods to efficiently calculate rank and select.
The rank is calculated in constant time where as select has O(logN) time complexity.
This is often used as a basic element in implementing succinct data structures.
RankedBitArray is an extension of BitArray with methods to efficiently calculate
rank and select. The rank is calculated in constant time where as select has
O(logN) time complexity. This is often used as a basic element in implementing
succinct data structures.
```javascript

@@ -746,117 +686,127 @@ const array = new RankedBitArray(10);

### Graphs
Structurae offers classes that implement Adjacency List (`UnweightedAdjacencyList`, `WeightedAdjacencyList`) and Adjacency Matrix (`UnweightedAdjacencyMatrix`,
`WeightedAdjacencyMatrix`) as basic primitives to represent graphs using a TypedArray, and the `Graph` class that extends the adjacency structures to offer methods for traversing
graphs (BFS, DFS), pathfinding (Dijkstra, Bellman-Ford), and spanning tree construction (BFS, Prim).
#### Adjacency Lists
`UnweightedAdjacencyList` and `WeightedAdjacencyList` implement Adjacency List data structure extending a TypedArray class.
The adjacency list requires less storage space: number of vertices + number of edges (for an unweighted list) or number of edges * 2 (for a weighted list).
However, adding and removing edges is much slower since it involves shifting/unshifting values in the underlying typed array.
```javascript
const { UnweightedAdjacencyList, WeightedAdjacencyListMixin } = require('structurae');
Structurae offers classes that implement adjacency list (`AdjacencyList`) and
adjacency matrix (`AdjacencyMatrixUnweightedDirected`,
`AdjacencyMatrixUnweightedUndirected`, `AdjacencyMatrixWeightedDirected`,
`AdjacencyMatrixWeightedUnirected`) as basic primitives to represent graphs
using TypedArrays, and the `Graph` class that extends the adjacency structures
to offer methods for traversing graphs (BFS, DFS), pathfinding (Dijkstra,
Bellman-Ford), and spanning tree construction (BFS, Prim).
const WeightedAdjacencyList = WeightedAdjacencyListMixin(Int32Array);
#### Adjacency Structures
const unweightedGraph = new UnweightedAdjacencyList({ vertices: 6, edges: 6 });
const weightedGraph = new WeightedAdjacencyList({ vertices: 6, edges: 6 });
`AdjacencyList` implements adjacency list data structure extending a TypedArray
class. The adjacency list requires less storage space: number of vertices +
number of edges * 2 (for a weighted list). However, adding and removing edges is
much slower since it involves shifting/unshifting values in the underlying typed
array.
// the length of an unweighted graph is vertices + edges + 1
unweightedGraph.length;
//=> 13
```javascript
import { AdjacencyListMixin } from "structurae";
const List = AdjacencyListMixin(Int32Array);
const graph = List.create(6, 6);
// the length of a weighted graph is vertices + edges * 2 + 1
weightedGraph.length;
graph.length;
//=> 19
unweightedGraph.addEdge(0, 1).addEdge(0, 2).addEdge(2, 4).addEdge(2, 5);
unweightedGraph.hasEdge(0, 1);
graph.addEdge(0, 1, 5);
graph.addEdge(0, 2, 1);
graph.addEdge(2, 4, 1);
graph.addEdge(2, 5, 2);
graph.hasEdge(0, 1);
//=> true
unweightedGraph.hasEdge(0, 4);
graph.hasEdge(0, 4);
//=> false
unweightedGraph.outEdges(2);
graph.outEdges(2);
//=> [4, 5]
unweightedGraph.inEdges(2);
graph.inEdges(2);
//=> [0]
weightedGraph.addEdge(0, 1, 5);
weightedGraph.hasEdge(0, 1);
graph.hasEdge(0, 1);
//=> true
weightedGraph.getEdge(0, 1);
graph.getEdge(0, 1);
//=> 5
```
Since the maximum amount of egdes is limited to the number specified at creation, adding edges can overflow throwing a RangeError.
If that's a possibility, use `isFull` to check if the limit is reached before adding. If additional edges are required, one can use the
`grow` method specifying the amount of additional vertices and edges required. `grow` creates a copy of the graph with increased limits:
```javascript
graph.length
//=> 13
const biggerGraph = graph.grow(4, 10); // add 4 vertices and 10 edges
biggerGraph.length
//=> 27
```
Since the maximum amount of egdes in AdjacencyList is limited to the number
specified at creation, adding edges can overflow throwing a RangeError. If
that's a possibility, use `AdjacencyList#isFull` method to check if the limit is
reached before adding an edge.
Adjacency lists can be created from an existing adjacency matrices or grids using the `fromGrid` method.
`AdjacencyMatrixUnweightedDirected` and `AdjacencyMatrixUnweightedUndirected`
implement adjacency matrix data structure for unweighted graphs representing
each edge by a single bit in an underlying ArrayBuffer.
#### Adjacency Matrices
`UnweightedAdjacencyMatrix` and `WeightedAdjacencyMatrix` build on Grid classes extending them to implement Adjacency Matrix data structure
using TypedArrays. They offer the same methods to operate on edges as the adjacency list structures described above.
`AdjacencyMatrixWeightedDirected` and `AdjacencyMatrixWeightedUnirected`
implement adjacency matrix for weighted graphs extending a given TypedArray to
store the weights akin to [Grid](https://github.com/zandaqo/structurae#Grid).
`UnweightedAdjacencyMatrix` extends [BinaryGrid](https://github.com/zandaqo/structurae#BinaryGrid) to represent
an unweighted graph in the densest possible way: each edge is represented by a single bit in an underlying ArrayBuffer.
For example, to represent a graph with 80 vertices as an Adjacency Matrix we need 80 * 80 bits or 800 bytes. UnweightedAdjacencyMatrix will
will create an ArrayBuffer of that size, "view" it as Uint16Array (of length 400) and operate on edges using bitwise operations.
```javascript
import {
AdjacencyMatrixUnweightedDirected,
AdjacencyMatrixWeightedDirectedMixin,
} from "structurae";
`WeightedAdjacencyMatrix` extends [Grid](https://github.com/zandaqo/structurae#Grid) (for directed graphs)
or [SymmetricGrid](https://github.com/zandaqo/structurae#SymmetricGrid) (for undirected) to handle weighted graphs.
```javascript
const { UnweightedAdjacencyMatrix, WeightedAdjacencyMatrixMixin } = require('structurae');
// creates a class for directed graphs that uses Int32Array for edge weights
const WeightedAdjacencyMatrix = WeightedAdjacencyMatrixMixin(Int32Array, true);
const Matrix = AdjacencyMatrixWeightedDirectedMixin(Int32Array);
const unweightedGraph = new UnweightedAdjacencyMatrix({ vertices: 6 });
unweightedGraph.addEdge(0, 1).addEdge(0, 2).addEdge(0, 3).addEdge(2, 4).addEdge(2, 5);
unweightedGraph.hasEdge(0, 1);
const unweightedMatrix = new AdjacencyMatrixUnweightedDirected.create(6);
unweightedMatrix.addEdge(0, 1);
unweightedMatrix.addEdge(0, 2);
unweightedMatrix.addEdge(0, 3);
unweightedMatrix.addEdge(2, 4);
unweightedMatrix.addEdge(2, 5);
unweightedMatrix.hasEdge(0, 1);
//=> true
unweightedGraph.hasEdge(0, 4);
unweightedMatrix.hasEdge(0, 4);
//=> false
unweightedGraph.outEdges(2);
unweightedMatrix.outEdges(2);
//=> [4, 5]
unweightedGraph.inEdges(2);
unweightedMatrix.inEdges(2);
//=> [0]
const weightedGraph = new WeightedAdjacencyMatrix({ vertices: 6, pad: -1 });
weightedGraph.addEdge(0, 1, 3);
weightedGraph.hasEdge(0, 1);
const weightedMatrix = Matrix.create(6);
weightedMatrix.addEdge(0, 1, 3);
weightedMatrix.hasEdge(0, 1);
//=> true
weightedGraph.hasEdge(1, 0);
weightedMatrix.hasEdge(1, 0);
//=> false
weightedGraph.getEdge(1, 0);
weightedMatrix.getEdge(1, 0);
//=> 3
```
```
#### Graph
`Graph` extends a provided adjacency structure with methods for traversing, pathfinding, and spanning tree construction that use various
graph algorithms.
`Graph` extends a provided adjacency structure with methods for traversing,
pathfinding, and spanning tree construction that use various graph algorithms.
```javascript
const { GraphMixin, UnweightedAdjacencyList, WeightedAdjacencyMatrixMixin } = require('structurae');
import {
AdjacencyMatrixUnweightedDirected,
AdjacencyMatrixWeightedDirectedMixin,
GraphMixin,
} from "structurae";
// create a graph for directed unweighted graphs that use adjacency list structure
const UnweightedGraph = GraphMixin(UnweightedAdjacencyList);
const UnweightedGraph = GraphMixin(AdjacencyMatrixUnweightedDirected);
// for directed weighted graphs that use adjacency matrix structure
const WeightedGraph = GraphMixin(WeightedAdjacencyMatrixMixin(Int32Array));
const WeightedGraph = GraphMixin(
AdjacencyMatrixWeightedDirectedMixin(Int32Array),
);
```
The traversal is done by a generator function `Graph#traverse` that can be configured to use Breadth-First or Depth-First traversal,
as well as returning vertices on various stages of processing, i.e. only return vertices that are fully processed (`black`), or being
processed (`gray`), or just encountered (`white`):
The traversal is done by a generator function `Graph#traverse` that can be
configured to use Breadth-First or Depth-First traversal, as well as returning
vertices on various stages of processing, i.e. only return vertices that are
fully processed (`black`), or being processed (`gray`), or just encountered
(`white`):
```javascript
const graph = new WeightedGraph({ vertices: 6, edges: 12 });
graph.addEdge(0, 1, 3).addEdge(0, 2, 2).addEdge(0, 3, 1).addEdge(2, 4, 8).addEdge(2, 5, 6);
const graph = WeightedGraph.create(6);
graph.addEdge(0, 1, 3);
graph.addEdge(0, 2, 2);
graph.addEdge(0, 3, 1);
graph.addEdge(2, 4, 8);
graph.addEdge(2, 5, 6);

@@ -871,3 +821,3 @@ // a BFS traversal results

// BFS yeilding only non-encountered ('white') vertices starting from 0
// BFS yeilding only non-encountered ("white") vertices starting from 0
[...graph.traverse(false, 0, false, true)];

@@ -877,5 +827,7 @@ //=> [1, 2, 3, 4, 5]

`Graph#path` returns the list of vertices constituting the shortest path between two given vertices. By default, the class uses
BFS based search for unweighted graphs, and Bellman-Ford algorithm for weighted graphs. However, the method can be configured to use
other algorithms by specifying arguments of the function:
`Graph#path` returns the list of vertices constituting the shortest path between
two given vertices. By default, the class uses BFS based search for unweighted
graphs, and Bellman-Ford algorithm for weighted graphs. However, the method can
be configured to use other algorithms by specifying arguments of the function:
```javascript

@@ -888,58 +840,77 @@ graph.path(0, 5); // uses Bellman-Ford by default

### Grids
#### BinaryGrid
BinaryGrid creates a grid or 2D matrix of bits and provides methods to operate on it:
BinaryGrid creates a grid or 2D matrix of bits and provides methods to operate
on it:
```javascript
const { BinaryGrid } = require('structurae');
import { BinaryGrid } from "structurae";
const bitGrid = new BinaryGrid({ rows: 2, columns: 8 });
bitGrid.set(0, 0).set(0, 2).set(0, 5);
bitGrid.get(0, 0);
// create a grid of 2 rows and 8 columns
const bitGrid = BinaryGrid.create(2, 8);
bitGrid.setValue(0, 0).setValue(0, 2).setValue(0, 5);
bitGrid.getValue(0, 0);
//=> 1
bitGrid.get(0, 1);
bitGrid.getValue(0, 1);
//=> 0
bitGrid.get(0, 2);
bitGrid.getValue(0, 2);
//=> 1
```
BinaryGrid packs bits into numbers like [BitField](https://github.com/zandaqo/structurae#BitField)
and holds them in an ArrayBuffer, thus occupying the smallest possible space.
BinaryGrid packs bits into numbers like
[BitField](https://github.com/zandaqo/structurae#BitField) and holds them in an
ArrayBuffer, thus occupying the smallest possible space.
#### Grid
Grid extends a provided indexed collection class (Array or TypedArrays) to efficiently handle 2 dimensional data without creating
nested arrays. Grid "unrolls" nested arrays into a single array and pads its "columns" to the nearest power of 2 in order to employ
quick lookups with bitwise operations.
Grid extends a provided Array or TypedArray class to efficiently handle 2
dimensional data without creating nested arrays. Grid "unrolls" nested arrays
into a single array and pads its "columns" to the nearest power of 2 in order to
employ quick lookups with bitwise operations.
```javascript
const { GridMixin } = require('structurae');
import { GridMixin } from "structurae";
const ArrayGrid = GridMixin(Array);
// create a grid of 5 rows and 4 columns filled with 0
const grid = new ArrayGrid({rows: 5, columns: 4 });
grid.length
// create a grid of 5 rows and 4 columns
const grid = ArrayGrid.create(5, 4);
grid.length;
//=> 20
grid[0]
grid[0];
//=> 0
// send data as the second parameter to instantiate a grid with data:
const dataGrid = new ArrayGrid({rows: 5, columns: 4 }, [1, 2, 3, 4, 5, 6, 7, 8]);
grid.length
//=> 20
grid[0]
//=> 0
// create a grid from existing data:
const dataGrid = new ArrayGrid([
1,
2,
3,
4,
5,
6,
7,
8,
]);
// set columns number:
dataGrid.columns = 4;
dataGrid.getValue(1, 0);
//=> 5
// you can change dimensions of the grid by setting columns number at any time:
dataGrid.columns = 2;
dataGrid.getValue(1, 0);
//=> 3
```
You can get and set elements using their row and column indexes:
```javascript
grid
//=> ArrayGrid [1, 2, 3, 4, 5, 6, 7, 8]
grid.get(0, 1);
grid.getValue(0, 1);
//=> 2
grid.set(0, 1, 10);
grid.get(0, 1);
grid.setValue(0, 1, 10);
grid.getValue(0, 1);
//=> 10
// use `getIndex` to get an array index of an element at given coordinates

@@ -951,12 +922,14 @@ grid.getIndex(0, 1);

grid.getCoordinates(0);
//=> { row: 0, column: 0 }
//=> [0, 0]
grid.getCoordinates(1);
//=> { row: 0, column: 1 }
//=> [0, 1]
```
A grid can be turned to and from an array of nested arrays using respectively `Grid.fromArrays` and `Grid#toArrays` methods:
A grid can be turned to and from an array of nested arrays using respectively
`Grid.fromArrays` and `Grid#toArrays` methods:
```javascript
const grid = ArrayGrid.fromArrays([[1,2], [3, 4]]);
const grid = ArrayGrid.fromArrays([[1, 2], [3, 4]]);
//=> ArrayGrid [ 1, 2, 3, 4 ]
grid.get(1, 1);
grid.getValue(1, 1);
//=> 4

@@ -968,3 +941,3 @@

//=> ArrayGrid [ 1, 2, 0, 0, 3, 4, 5, 0 ]
grid.get(1, 1);
grid.getValue(1, 1);
//=> 4

@@ -981,19 +954,25 @@

#### SymmetricGrid
SymmetricGrid is a Grid that offers a more compact way of encoding symmetric or triangular square matrices using half as much space.
SymmetricGrid is a Grid that offers a more compact way of encoding symmetric or
triangular square matrices using half as much space.
```javascript
const { SymmetricGrid } = require('structurae');
import { SymmetricGrid } from "structurae";
const grid = new ArrayGrid({rows: 100, columns: 100 });
const grid = ArrayGrid.create(100, 100);
grid.length;
//=> 12800
const symmetricGrid = new SymmetricGrid({ rows: 100 });
const symmetricGrid = SymmetricGrid.create(100);
symmetricGrid.length;
//=> 5050
```
Since the grid is symmetric, it returns the same value for a given pair of coordinates regardless of their position:
Since the grid is symmetric, it returns the same value for a given pair of
coordinates regardless of their position:
```javascript
symmetricGrid.set(0, 5, 10);
symmetricGrid.get(0, 5);
symmetricGrid.setValue(0, 5, 10);
symmetricGrid.getValue(0, 5);
//=> 10
symmetricGrid.get(5, 0);
symmetricGrid.getValue(5, 0);
//=> 10

@@ -1003,16 +982,23 @@ ```

### Sorted Structures
#### BinaryHeap
BinaryHeap extends built-in Array to implement the Binary Heap data structure.
All the mutating methods (push, shift, splice, etc.) do so while maintaining the valid heap structure.
By default, BinaryHeap implements min-heap, but it can be changed by providing a different comparator function:
BinaryHeap extends built-in Array to implement the binary heap data structure.
All the mutating methods (push, shift, splice, etc.) do so while maintaining the
valid heap structure. By default, BinaryHeap implements min-heap, but it can be
changed by providing a different comparator function:
```javascript
const { BinaryHeap } = require('structurae');
import { BinaryHeap } from "structurae";
class MaxHeap extends BinaryHeap {}
MaxHeap.compare = (a, b) => b - a;
MaxHeap.compare = (a, b) => a > b;
```
In addition to all array methods, BinaryHeap provides a few methods to traverse or change the heap:
In addition to all array methods, BinaryHeap provides a few methods to traverse
or change the heap:
```javascript
const heap = new BinaryHeap(10, 1, 20, 3, 9, 8);
heap[0]
heap[0];
//=> 1

@@ -1026,5 +1012,5 @@ heap.left(0); // the left child of the first (minimal) element of the heap

heap.replace(4) // returns the first element and adds a new element in one operation
heap.replace(4); // returns the first element and adds a new element in one operation
//=> 1
heap[0]
heap[0];
//=> 3

@@ -1035,77 +1021,13 @@ heap[0] = 6;

// BinaryHeap [ 4, 6, 8, 10, 9, 20 ]
```
#### SortedCollection
SortedCollection extends a given built-in indexed collection with methods to efficiently handle sorted data.
```javascript
const { SortedMixin } = require('structurae');
const SortedInt32Array = SortedMixin(Int32Array);
```
To create a sorted collection from unsorted array-like objects or items use `from` and `of` static methods respectively:
```js
SortedInt32Array.from(unsorted);
//=> SortedInt32Array [ 2, 3, 4, 5, 9 ]
SortedInt32Array.of(8, 5, 6);
//=> SortedInt32Array [ 5, 6, 8 ]
```
#### SortedArray
`new SortedInt32Array` behaves the same way as `new Int32Array` and should be used with already sorted elements:
```js
new SortedInt32Array(...[ 1, 2, 3, 4, 8 ]);
//=> SortedInt32Array [ 1, 2, 3, 4, 8 ];
new SortedInt32Array(2,3,4);
//=> SortedInt32Array [ 2, 3, 4 ];
```
SortedArray extends Array with methods to efficiently handle sorted data. The
methods that change the contents of an array do so while preserving the sorted
order:
A custom comparison function can be specified on the collection instance to be used for sorting:
```js
//=> SortedInt32Array [ 2, 3, 4, 5, 9 ]
sortedInt32Array.compare = (a, b) => (a > b ? -1 : a < b ? 1 : 0);
sortedInt32Array.sort();
//=> SortedInt32Array [ 9, 5, 4, 3, 2 ]
```
import { SortedArray } from "structurae";
SortedCollection supports all the methods of its base class:
```javascript
//=> SortedInt32Array [ 2, 3, 4, 5, 9 ]
sortedInt32Array.slice(0, 2)
//=> SortedInt32Array [ 2, 3 ]
sortedInt32Array.set([0, 0, 1])
//=> SortedInt32Array [ 0, 0, 1, 5, 9 ]
```
`indexOf` and `includes` use binary search that increasingly outperforms the built-in methods as the size of the collection grows.
SortedCollection provides `isSorted` method to check if the collection is sorted,
and `range` method to get elements of the collection whose values are between the specified range:
```js
//=> SortedInt32Array [ 2, 3, 4, 5, 9 ]
sortedInt32Array.range(3, 5);
// => SortedInt32Array [ 3, 4, 5 ]
sortedInt32Array.range(undefined, 4);
// => SortedInt32Array [ 2, 3, 4 ]
sortedInt32Array.range(4);
// => SortedInt32Array [ 4, 5, 8 ]
// set `subarray` to `true` to use `TypedArray#subarray` for the return value instead of copying it with slice:
sortedInt32Array.range(3, 5, true).buffer === sortedInt32Array.buffer;
// => true;
```
SortedCollection also provides a set of functions to perform common set operations
and find statistics of any sorted array-like objects without converting them to sorted collection.
Check [API documentation](https://github.com/zandaqo/structurae/blob/master/doc/API.md) for more information.
#### SortedArray
SortedArray extends SortedCollection using built-in Array.
SortedArray supports all the methods of Array as well as those provided by SortedCollection.
The methods that change the contents of an array do so while preserving the sorted order:
```js
const { SortedArray } = require('structurae');
const sortedArray = new SortedArray();

@@ -1121,4 +1043,5 @@ sortedArray.push(1);

`uniquify` can be used to remove duplicating elements from the array:
```js
const a = SortedArray.from([ 1, 1, 2, 2, 3, 4 ]);
const a = SortedArray.from([1, 1, 2, 2, 3, 4]);
a.uniquify();

@@ -1128,3 +1051,5 @@ //=> SortedArray [ 1, 2, 3, 4 ]

If the instance property `unique` of an array is set to `true`, the array will behave as a set and avoid duplicating elements:
If the instance property `unique` of an array is set to `true`, the array will
behave as a set and avoid duplicating elements:
```js

@@ -1139,7 +1064,46 @@ const a = new SortedArray();

//=> 2
a
a;
//=> SortedArray [ 1, 2 ]
```
To create a sorted collection from unsorted array-like objects or items use
`from` and `of` static methods respectively:
```js
SortedArray.from([3, 2, 9, 5, 4]);
//=> SortedArray [ 2, 3, 4, 5, 9 ]
SortedArray.of(8, 5, 6);
//=> SortedArray [ 5, 6, 8 ]
```
`new SortedArray` behaves the same way as `new Array` and should be used with
already sorted elements:
```js
new SortedArray(...[1, 2, 3, 4, 8]);
//=> SortedArray [ 1, 2, 3, 4, 8 ];
```
`indexOf` and `includes` use binary search that increasingly outperforms the
built-in methods as the size of the array grows.
SortedArray provides `isSorted` method to check if the collection is sorted, and
`range` method to get elements of the collection whose values are between the
specified range:
```js
//=> SortedArray [ 2, 3, 4, 5, 9 ]
sortedArray.range(3, 5);
// => SortedArray [ 3, 4, 5 ]
sortedArray.range(undefined, 4);
// => SortedArray [ 2, 3, 4 ]
sortedArray.range(4);
// => SortedArray [ 4, 5, 8 ]
```
SortedArray also provides a set of functions to perform common set operations
and find statistics of any sorted array-like objects.
## License
MIT © [Maga D. Zandaqo](http://maga.name)
MIT © [Maga D. Zandaqo](http://maga.name)
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc