@synnaxlabs/x 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@synnaxlabs/x",
3
3
  "private": false,
4
- "version": "0.11.0",
4
+ "version": "0.12.0",
5
5
  "type": "module",
6
6
  "description": "Common Utilities for Synnax Labs",
7
7
  "repository": "https://github.com/synnaxlabs/synnax/tree/main/x/go",
@@ -26,9 +26,9 @@
26
26
  "@vitest/coverage-v8": "^1.2.2",
27
27
  "vite": "^5.1.2",
28
28
  "vitest": "^1.2.2",
29
- "@synnaxlabs/tsconfig": "0.0.2",
29
+ "@synnaxlabs/vite-plugin": "0.0.1",
30
30
  "eslint-config-synnaxlabs": "0.0.1",
31
- "@synnaxlabs/vite-plugin": "0.0.1"
31
+ "@synnaxlabs/tsconfig": "0.0.2"
32
32
  },
33
33
  "main": "dist/x.cjs.js",
34
34
  "module": "dist/x.es.js",
package/src/deep/memo.ts CHANGED
@@ -1,3 +1,12 @@
1
+ // Copyright 2024 Synnax Labs, Inc.
2
+ //
3
+ // Use of this software is governed by the Business Source License included in the file
4
+ // licenses/BSL.txt.
5
+ //
6
+ // As of the Change Date specified in that file, in accordance with the Business Source
7
+ // License, use of this software will be governed by the Apache License, Version 2.0,
8
+ // included in the file licenses/APL.txt.
9
+
1
10
  import { equal } from "@/deep/equal"
2
11
 
3
12
 
@@ -12,4 +21,4 @@ export const memo = <F extends (...args: any[]) => any>(func: F): F => {
12
21
  return result
13
22
  })
14
23
  return v as F;
15
- }
24
+ }
@@ -1,6 +1,15 @@
1
1
 
2
+ // Copyright 2024 Synnax Labs, Inc.
3
+ //
4
+ // Use of this software is governed by the Business Source License included in the file
5
+ // licenses/BSL.txt.
6
+ //
7
+ // As of the Change Date specified in that file, in accordance with the Business Source
8
+ // License, use of this software will be governed by the Apache License, Version 2.0,
9
+ // included in the file licenses/APL.txt.
10
+
2
11
  export const shallowCopy = <T extends unknown>(obj: T): T => {
3
12
  if (Array.isArray(obj)) return [...obj] as T;
4
13
  if (typeof obj === "object" && obj !== null) return { ...obj } as T;
5
14
  return obj;
6
- }
15
+ }
@@ -21,8 +21,8 @@ describe("Series", () => {
21
21
  expect(a.dataType.toString()).toBe(DataType.FLOAT32.toString());
22
22
  expect(a.length).toEqual(3);
23
23
  expect(a.byteLength).toEqual(Size.bytes(12));
24
- expect(a.byteCap).toEqual(Size.bytes(12));
25
- expect(a.cap).toEqual(3);
24
+ expect(a.byteCapacity).toEqual(Size.bytes(12));
25
+ expect(a.capacity).toEqual(3);
26
26
  const b = new Series({ data: new BigInt64Array([BigInt(1)]) });
27
27
  expect(b.dataType.toString()).toBe(DataType.INT64.toString());
28
28
  const c = new Series({
@@ -55,15 +55,15 @@ describe("Series", () => {
55
55
 
56
56
  describe("allocation", () => {
57
57
  it("should allocate a lazy array", () => {
58
- const series = Series.alloc({ length: 10, dataType: DataType.FLOAT32 });
59
- expect(series.byteCap).toEqual(Size.bytes(40));
60
- expect(series.cap).toEqual(10);
58
+ const series = Series.alloc({ capacity: 10, dataType: DataType.FLOAT32 });
59
+ expect(series.byteCapacity).toEqual(Size.bytes(40));
60
+ expect(series.capacity).toEqual(10);
61
61
  expect(series.length).toEqual(0);
62
62
  expect(series.byteLength).toEqual(Size.bytes(0));
63
63
  });
64
64
  it("should throw an error when attempting to allocate an array of lenght 0", () => {
65
65
  expect(() => {
66
- Series.alloc({ length: 0, dataType: DataType.FLOAT32 });
66
+ Series.alloc({ capacity: 0, dataType: DataType.FLOAT32 });
67
67
  }).toThrow();
68
68
  });
69
69
  });
@@ -87,8 +87,26 @@ describe("Series", () => {
87
87
  });
88
88
  expect(series.at(3)).toBeUndefined();
89
89
  });
90
+ it("should allow the index to be negative", () => {
91
+ const series = new Series({
92
+ data: new Float32Array([1, 2, 3]),
93
+ dataType: DataType.FLOAT32,
94
+ });
95
+ expect(series.at(-1)).toEqual(3);
96
+ });
97
+ it("should throw an error when the index is out of bounds and require is set to true", () => {
98
+ const series = new Series({
99
+ data: new Float32Array([1, 2, 3]),
100
+ dataType: DataType.FLOAT32,
101
+ });
102
+ expect(() => {
103
+ series.at(3, true);
104
+ }).toThrow();
105
+ });
90
106
  });
91
107
 
108
+
109
+
92
110
  describe("slice", () => {
93
111
  it("should slice a lazy array", () => {
94
112
  const a = new Series({
@@ -100,14 +118,14 @@ describe("Series", () => {
100
118
  expect(b.data).toEqual(new Float32Array([2]));
101
119
  expect(b.length).toEqual(1);
102
120
  expect(b.byteLength).toEqual(Size.bytes(4));
103
- expect(b.byteCap).toEqual(Size.bytes(4));
104
- expect(b.cap).toEqual(1);
121
+ expect(b.byteCapacity).toEqual(Size.bytes(4));
122
+ expect(b.capacity).toEqual(1);
105
123
  });
106
124
  });
107
125
 
108
126
  describe("min and max", () => {
109
127
  it("should return a min and max of zero on an allocated array", () => {
110
- const series = Series.alloc({ length: 10, dataType: DataType.FLOAT32 });
128
+ const series = Series.alloc({ capacity: 10, dataType: DataType.FLOAT32 });
111
129
  expect(series.max).toEqual(-Infinity);
112
130
  expect(series.min).toEqual(Infinity);
113
131
  });
@@ -154,8 +172,8 @@ describe("Series", () => {
154
172
 
155
173
  describe("writing", () => {
156
174
  it("should correctly write to an allocated lazy array", () => {
157
- const series = Series.alloc({ length: 10, dataType: DataType.FLOAT32 });
158
- expect(series.byteCap).toEqual(Size.bytes(40));
175
+ const series = Series.alloc({ capacity: 10, dataType: DataType.FLOAT32 });
176
+ expect(series.byteCapacity).toEqual(Size.bytes(40));
159
177
  expect(series.length).toEqual(0);
160
178
  const writeOne = new Series({ data: new Float32Array([1]) });
161
179
  expect(series.write(writeOne)).toEqual(1);
@@ -165,7 +183,7 @@ describe("Series", () => {
165
183
  expect(series.length).toEqual(3);
166
184
  });
167
185
  it("should recompute cached max and min correctly", () => {
168
- const series = Series.alloc({ length: 10, dataType: DataType.FLOAT32 });
186
+ const series = Series.alloc({ capacity: 10, dataType: DataType.FLOAT32 });
169
187
  series.enrich();
170
188
  const writeTwo = new Series({ data: new Float32Array([2, 3]) });
171
189
  series.write(writeTwo);
@@ -174,7 +192,7 @@ describe("Series", () => {
174
192
  });
175
193
  it("should correctly adjust the sample offset of a written array", () => {
176
194
  const series = Series.alloc({
177
- length: 2,
195
+ capacity: 2,
178
196
  dataType: DataType.FLOAT32,
179
197
  timeRange: TimeRange.ZERO,
180
198
  sampleOffset: -3,
@@ -200,7 +218,7 @@ describe("Series", () => {
200
218
  expect(ts.timeRange).toEqual(
201
219
  new TimeRange(TimeStamp.seconds(1), TimeStamp.seconds(6)),
202
220
  );
203
- expect(ts.cap).toEqual(5);
221
+ expect(ts.capacity).toEqual(5);
204
222
  expect(ts.length).toEqual(5);
205
223
  expect(ts.dataType.toString()).toEqual(DataType.TIMESTAMP.toString());
206
224
  expect(ts.data).toEqual(
@@ -233,7 +251,7 @@ describe("Series", () => {
233
251
  expect(buf).toEqual(new Float32Array([1, 2, 3]));
234
252
  });
235
253
  it("should correctly update a buffer when writing to an allocated array", () => {
236
- const series = Series.alloc({ length: 10, dataType: DataType.FLOAT32 });
254
+ const series = Series.alloc({ capacity: 10, dataType: DataType.FLOAT32 });
237
255
  const controller = new MockGLBufferController();
238
256
  series.updateGLBuffer(controller);
239
257
  expect(controller.createBufferMock).toHaveBeenCalledTimes(1);
@@ -249,7 +267,7 @@ describe("Series", () => {
249
267
  expect(controller.bufferDataMock).toHaveBeenCalledTimes(1);
250
268
  expect(controller.bufferSubDataMock).toHaveBeenCalledTimes(1);
251
269
  buf = controller.buffers[series.glBuffer as number];
252
- expect(buf.byteLength).toEqual(series.byteCap.valueOf());
270
+ expect(buf.byteLength).toEqual(series.byteCapacity.valueOf());
253
271
  expect(new Float32Array(buf)[0]).toEqual(1);
254
272
  const writeTwo = new Series({ data: new Float32Array([2, 3]) });
255
273
  series.write(writeTwo);
@@ -257,7 +275,7 @@ describe("Series", () => {
257
275
  expect(controller.bufferDataMock).not.toHaveBeenCalledTimes(2);
258
276
  expect(controller.bufferSubDataMock).toHaveBeenCalledTimes(2);
259
277
  buf = controller.buffers[series.glBuffer as number];
260
- expect(buf.byteLength).toEqual(series.byteCap.valueOf());
278
+ expect(buf.byteLength).toEqual(series.byteCapacity.valueOf());
261
279
  expect(new Float32Array(buf)[0]).toEqual(1);
262
280
  expect(new Float32Array(buf)[1]).toEqual(2);
263
281
  expect(new Float32Array(buf)[2]).toEqual(3);
@@ -286,7 +304,7 @@ describe("Series", () => {
286
304
  series.acquire(controller);
287
305
  expect(controller.createBufferMock).toHaveBeenCalledTimes(2);
288
306
  const buf = controller.buffers[series.glBuffer as number];
289
- expect(buf.byteLength).toEqual(series.byteCap.valueOf());
307
+ expect(buf.byteLength).toEqual(series.byteCapacity.valueOf());
290
308
  });
291
309
  });
292
310
 
@@ -341,7 +359,7 @@ describe("Series", () => {
341
359
 
342
360
  describe("binarySearch", () => {
343
361
  it("should correctly binary search a pre-allocated array", () => {
344
- const series = Series.alloc({ length: 10, dataType: DataType.FLOAT32 });
362
+ const series = Series.alloc({ capacity: 10, dataType: DataType.FLOAT32 });
345
363
  const writeOne = new Series({ data: new Float32Array([1, 2, 3, 4, 5]) });
346
364
  series.write(writeOne);
347
365
  expect(series.binarySearch(3)).toEqual(2);
@@ -62,7 +62,7 @@ export interface SeriesProps extends BaseSeriesProps {
62
62
  }
63
63
 
64
64
  export interface SeriesAllocProps extends BaseSeriesProps {
65
- length: number;
65
+ capacity: number;
66
66
  dataType: CrudeDataType;
67
67
  }
68
68
 
@@ -106,7 +106,7 @@ export class Series {
106
106
  /** Tracks the number of entities currently using this array. */
107
107
  private _refCount: number = 0;
108
108
 
109
- static alloc({ length, dataType, ...props }: SeriesAllocProps): Series {
109
+ static alloc({ capacity: length, dataType, ...props }: SeriesAllocProps): Series {
110
110
  if (length === 0)
111
111
  throw new Error("[Series] - cannot allocate an array of length 0");
112
112
  const data = new new DataType(dataType).Array(length);
@@ -188,13 +188,21 @@ export class Series {
188
188
  throw new Error("cannot release an array with a negative reference count");
189
189
  }
190
190
 
191
+ /**
192
+ * Writes the given series to this series. If the series being written exceeds the
193
+ * remaining of series being written to, only the portion that fits will be written.
194
+ * @param other the series to write to this series. The data type of the series written
195
+ * must be the same as the data type of the series being written to.
196
+ * @returns the number of samples written. If the entire series fits, this value is
197
+ * equal to the length of the series being written.
198
+ */
191
199
  write(other: Series): number {
192
200
  if (!other.dataType.equals(this.dataType))
193
201
  throw new Error("buffer must be of the same type as this array");
194
202
 
195
203
  // We've filled the entire underlying buffer
196
204
  if (this.writePos === FULL_BUFFER) return 0;
197
- const available = this.cap - this.writePos;
205
+ const available = this.capacity - this.writePos;
198
206
 
199
207
  const toWrite = available < other.length ? other.slice(0, available) : other;
200
208
  this.underlyingData.set(toWrite.data as any, this.writePos);
@@ -256,19 +264,19 @@ export class Series {
256
264
  return this._timeRange!;
257
265
  }
258
266
 
259
- /** @returns the capacity of the underlying buffer in bytes. */
260
- get byteCap(): Size {
267
+ /** @returns the capacity of the series in bytes. */
268
+ get byteCapacity(): Size {
261
269
  return new Size(this.buffer.byteLength);
262
270
  }
263
271
 
264
- /** @returns the capacity of the underlying buffer in samples. */
265
- get cap(): number {
266
- return this.dataType.density.length(this.byteCap);
272
+ /** @returns the capacity of the series in samples. */
273
+ get capacity(): number {
274
+ return this.dataType.density.length(this.byteCapacity);
267
275
  }
268
276
 
269
- /** @returns the length of the underlying buffer in samples. */
277
+ /** @returns the length of the series in bytes. */
270
278
  get byteLength(): Size {
271
- if (this.writePos === FULL_BUFFER) return this.byteCap;
279
+ if (this.writePos === FULL_BUFFER) return this.byteCapacity;
272
280
  return this.dataType.density.size(this.writePos);
273
281
  }
274
282
 
@@ -371,9 +379,17 @@ export class Series {
371
379
  return addSamples(this.max, -this.min);
372
380
  }
373
381
 
374
- at(index: number): SampleValue {
382
+ at(index: number, required: true): SampleValue;
383
+
384
+ at(index: number, required?: false): SampleValue | undefined;
385
+
386
+ at(index: number, required?: boolean): SampleValue | undefined {
387
+ if (index < 0) index = this.length + index;
375
388
  const v = this.data[index];
376
- if (v == null) return undefined as any;
389
+ if (v == null) {
390
+ if (required) throw new Error(`[series] - no value at index ${index}`);
391
+ return undefined;
392
+ }
377
393
  return addSamples(v, this.sampleOffset);
378
394
  }
379
395
 
@@ -388,7 +404,7 @@ export class Series {
388
404
  const cf = compare.newF(value);
389
405
  while (left <= right) {
390
406
  const mid = Math.floor((left + right) / 2);
391
- const cmp = cf(this.at(mid), value);
407
+ const cmp = cf(this.at(mid, true), value);
392
408
  if (cmp === 0) return mid;
393
409
  if (cmp < 0) left = mid + 1;
394
410
  else right = mid - 1;
@@ -414,7 +430,7 @@ export class Series {
414
430
  // This means we only need to buffer part of the array.
415
431
  if (this.writePos !== FULL_BUFFER) {
416
432
  if (prevBuffer === 0) {
417
- gl.bufferData(gl.ARRAY_BUFFER, this.byteCap.valueOf(), gl.STATIC_DRAW);
433
+ gl.bufferData(gl.ARRAY_BUFFER, this.byteCapacity.valueOf(), gl.STATIC_DRAW);
418
434
  }
419
435
  const byteOffset = this.dataType.density.size(prevBuffer).valueOf();
420
436
  const slice = this.underlyingData.slice(this.gl.prevBuffer, this.writePos);