@synnaxlabs/x 0.42.1 → 0.43.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/.turbo/turbo-build.log +93 -105
- package/.vscode/settings.json +4 -6
- package/README.md +1 -7
- package/dist/array.cjs +1 -0
- package/dist/array.js +7 -0
- package/dist/base-B5lQIJKc.js +38 -0
- package/dist/base-CTq-lhpU.cjs +1 -0
- package/dist/binary.cjs +1 -1
- package/dist/binary.js +1 -1
- package/dist/bounds.cjs +1 -1
- package/dist/bounds.js +2 -2
- package/dist/box.cjs +1 -1
- package/dist/box.js +1 -1
- package/dist/caseconv.cjs +1 -1
- package/dist/caseconv.js +2 -2
- package/dist/change.cjs +1 -1
- package/dist/change.js +10 -2
- package/dist/compare.cjs +1 -1
- package/dist/compare.js +1 -1
- package/dist/deep.cjs +1 -1
- package/dist/deep.js +92 -79
- package/dist/dimensions.cjs +1 -1
- package/dist/dimensions.js +41 -2
- package/dist/direction.cjs +1 -1
- package/dist/direction.js +1 -1
- package/dist/index-4GlOgZuh.js +99 -0
- package/dist/{direction-C-b6XTeU.cjs → index-B58dnYRu.cjs} +1 -1
- package/dist/index-BMGaoK93.cjs +1 -0
- package/dist/index-BTet04Hd.cjs +6 -0
- package/dist/{scale-DfJe9755.js → index-BUa-NXAX.js} +46 -46
- package/dist/{xy-D_LqxaGt.js → index-C-qYOegc.js} +62 -62
- package/dist/index-C07SBJhr.js +128 -0
- package/dist/{bounds-Bn5_l4Z3.js → index-C9EdKeu1.js} +77 -76
- package/dist/index-CM8ZDZ6s.cjs +1 -0
- package/dist/index-CV2JaHfw.cjs +1 -0
- package/dist/index-CeBvOwG8.cjs +3 -0
- package/dist/index-ClrGyGDp.js +205 -0
- package/dist/index-CqQXXeCI.cjs +1 -0
- package/dist/{location-C3aeu046.js → index-D6V-8SKw.js} +26 -26
- package/dist/index-DBGAIs_7.js +2492 -0
- package/dist/index-DEdq2tza.cjs +1 -0
- package/dist/index-DKMnHBGR.cjs +1 -0
- package/dist/index-Dql5FMcH.js +47 -0
- package/dist/{direction-BL0PhD1k.js → index-DxU1zwsd.js} +1 -1
- package/dist/index-WwMnwoLy.cjs +1 -0
- package/dist/index.cjs +5 -3
- package/dist/index.js +5372 -649
- package/dist/kv.cjs +1 -1
- package/dist/kv.js +45 -2
- package/dist/location.cjs +1 -1
- package/dist/location.js +1 -1
- package/dist/position.cjs +1 -1
- package/dist/position.js +83 -2
- package/dist/record.cjs +1 -1
- package/dist/record.js +8 -10
- package/dist/runtime.cjs +1 -1
- package/dist/runtime.js +27 -2
- package/dist/scale.cjs +1 -1
- package/dist/scale.js +1 -1
- package/dist/schemas-55Usj0Fg.js +3998 -0
- package/dist/schemas-DbXuI2Qr.cjs +27 -0
- package/dist/spatial.cjs +1 -1
- package/dist/spatial.js +25 -18
- package/dist/src/array/index.d.ts +2 -0
- package/dist/src/array/index.d.ts.map +1 -0
- package/dist/src/array/toArray.d.ts +19 -0
- package/dist/src/array/toArray.d.ts.map +1 -0
- package/dist/src/array/toArray.spec.d.ts +2 -0
- package/dist/src/array/toArray.spec.d.ts.map +1 -0
- package/dist/src/binary/codec.d.ts +8 -16
- package/dist/src/binary/codec.d.ts.map +1 -1
- package/dist/src/breaker/breaker.d.ts +6 -6
- package/dist/src/breaker/breaker.d.ts.map +1 -1
- package/dist/src/caseconv/caseconv.d.ts +1 -1
- package/dist/src/caseconv/caseconv.d.ts.map +1 -1
- package/dist/src/change/change.d.ts +3 -3
- package/dist/src/change/change.d.ts.map +1 -1
- package/dist/src/color/color.d.ts +63 -28
- package/dist/src/color/color.d.ts.map +1 -1
- package/dist/src/color/external.d.ts +0 -1
- package/dist/src/color/external.d.ts.map +1 -1
- package/dist/src/color/gradient.d.ts +9 -5
- package/dist/src/color/gradient.d.ts.map +1 -1
- package/dist/src/color/palette.d.ts +14 -6
- package/dist/src/color/palette.d.ts.map +1 -1
- package/dist/src/compare/compare.d.ts +4 -4
- package/dist/src/compare/compare.d.ts.map +1 -1
- package/dist/src/control/control.d.ts +32 -32
- package/dist/src/control/control.d.ts.map +1 -1
- package/dist/src/debounce/debounce.d.ts +1 -1
- package/dist/src/debounce/debounce.d.ts.map +1 -1
- package/dist/src/deep/delete.d.ts +1 -1
- package/dist/src/deep/delete.d.ts.map +1 -1
- package/dist/src/deep/difference.d.ts.map +1 -1
- package/dist/src/deep/equal.d.ts +4 -4
- package/dist/src/deep/equal.d.ts.map +1 -1
- package/dist/src/deep/merge.d.ts +1 -1
- package/dist/src/deep/merge.d.ts.map +1 -1
- package/dist/src/errors/errors.d.ts +62 -36
- package/dist/src/errors/errors.d.ts.map +1 -1
- package/dist/src/index.d.ts +4 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/instance/index.d.ts +2 -0
- package/dist/src/instance/index.d.ts.map +1 -0
- package/dist/src/instance/matcher.d.ts +79 -0
- package/dist/src/instance/matcher.d.ts.map +1 -0
- package/dist/src/instance/matcher.spec.d.ts +2 -0
- package/dist/src/instance/matcher.spec.d.ts.map +1 -0
- package/dist/src/jsonrpc/jsonrpc.d.ts +40 -9
- package/dist/src/jsonrpc/jsonrpc.d.ts.map +1 -1
- package/dist/src/kv/types.d.ts +2 -2
- package/dist/src/kv/types.d.ts.map +1 -1
- package/dist/src/migrate/migrate.d.ts +5 -5
- package/dist/src/migrate/migrate.d.ts.map +1 -1
- package/dist/src/notation/notation.d.ts +1 -1
- package/dist/src/notation/notation.d.ts.map +1 -1
- package/dist/src/primitive/index.d.ts +2 -0
- package/dist/src/primitive/index.d.ts.map +1 -0
- package/dist/src/primitive/primitive.d.ts +39 -0
- package/dist/src/primitive/primitive.d.ts.map +1 -0
- package/dist/src/primitive/primitive.spec.d.ts +2 -0
- package/dist/src/primitive/primitive.spec.d.ts.map +1 -0
- package/dist/src/record.d.ts +2 -2
- package/dist/src/record.d.ts.map +1 -1
- package/dist/src/renderable.d.ts +1 -1
- package/dist/src/renderable.d.ts.map +1 -1
- package/dist/src/replace.d.ts.map +1 -1
- package/dist/src/runtime/detect.d.ts.map +1 -1
- package/dist/src/runtime/os.d.ts +1 -1
- package/dist/src/runtime/os.d.ts.map +1 -1
- package/dist/src/spatial/base.d.ts +10 -10
- package/dist/src/spatial/base.d.ts.map +1 -1
- package/dist/src/spatial/bounds/bounds.d.ts +82 -16
- package/dist/src/spatial/bounds/bounds.d.ts.map +1 -1
- package/dist/src/spatial/box/box.d.ts +7 -7
- package/dist/src/spatial/box/box.d.ts.map +1 -1
- package/dist/src/spatial/dimensions/dimensions.d.ts +5 -5
- package/dist/src/spatial/dimensions/dimensions.d.ts.map +1 -1
- package/dist/src/spatial/direction/direction.d.ts +1 -1
- package/dist/src/spatial/location/location.d.ts +4 -4
- package/dist/src/spatial/location/location.d.ts.map +1 -1
- package/dist/src/spatial/scale/scale.d.ts +11 -11
- package/dist/src/spatial/scale/scale.d.ts.map +1 -1
- package/dist/src/spatial/xy/xy.d.ts +5 -5
- package/dist/src/spatial/xy/xy.d.ts.map +1 -1
- package/dist/src/status/index.d.ts +2 -0
- package/dist/src/status/index.d.ts.map +1 -0
- package/dist/src/status/types.d.ts +11 -0
- package/dist/src/status/types.d.ts.map +1 -0
- package/dist/src/sync/index.d.ts.map +1 -1
- package/dist/src/sync/mutex.d.ts +0 -1
- package/dist/src/sync/mutex.d.ts.map +1 -1
- package/dist/src/telem/gl.d.ts +1 -1
- package/dist/src/telem/gl.d.ts.map +1 -1
- package/dist/src/telem/series.d.ts +468 -62
- package/dist/src/telem/series.d.ts.map +1 -1
- package/dist/src/telem/telem.d.ts +243 -53
- package/dist/src/telem/telem.d.ts.map +1 -1
- package/dist/src/uuid/index.d.ts +2 -0
- package/dist/src/uuid/index.d.ts.map +1 -0
- package/dist/src/uuid/uuid.d.ts +35 -0
- package/dist/src/uuid/uuid.d.ts.map +1 -0
- package/dist/src/uuid/uuid.spec.d.ts +2 -0
- package/dist/src/uuid/uuid.spec.d.ts.map +1 -0
- package/dist/src/zod/external.d.ts +1 -1
- package/dist/src/zod/external.d.ts.map +1 -1
- package/dist/src/zod/nullToUndefined.d.ts +3 -0
- package/dist/src/zod/nullToUndefined.d.ts.map +1 -0
- package/dist/src/zod/nullToUndefined.spec.d.ts +2 -0
- package/dist/src/zod/nullToUndefined.spec.d.ts.map +1 -0
- package/dist/src/zod/util.d.ts +2 -2
- package/dist/src/zod/util.d.ts.map +1 -1
- package/dist/telem.cjs +1 -1
- package/dist/telem.js +1 -1
- package/dist/xy.cjs +1 -1
- package/dist/xy.js +1 -1
- package/dist/zod.cjs +1 -1
- package/dist/zod.js +19 -2
- package/eslint.config.js +1 -1
- package/package.json +16 -14
- package/src/{toArray.ts → array/index.ts} +1 -5
- package/src/array/toArray.spec.ts +56 -0
- package/src/array/toArray.ts +28 -0
- package/src/binary/codec.spec.ts +201 -278
- package/src/binary/codec.ts +20 -76
- package/src/breaker/breaker.ts +3 -3
- package/src/caseconv/caseconv.ts +6 -4
- package/src/change/change.ts +2 -2
- package/src/color/color.spec.ts +121 -2
- package/src/color/color.ts +90 -54
- package/src/color/external.ts +0 -1
- package/src/color/gradient.ts +20 -28
- package/src/color/palette.ts +1 -1
- package/src/compare/compare.ts +5 -5
- package/src/control/control.ts +22 -19
- package/src/debounce/debounce.ts +1 -1
- package/src/deep/delete.ts +5 -4
- package/src/deep/difference.ts +6 -2
- package/src/deep/equal.spec.ts +1 -1
- package/src/deep/equal.ts +5 -5
- package/src/deep/merge.spec.ts +13 -1
- package/src/deep/merge.ts +16 -7
- package/src/deep/path.ts +1 -1
- package/src/errors/errors.ts +65 -44
- package/src/index.ts +4 -1
- package/src/instance/index.ts +10 -0
- package/src/instance/matcher.spec.ts +78 -0
- package/src/instance/matcher.ts +98 -0
- package/src/jsonrpc/jsonrpc.spec.ts +2 -1
- package/src/jsonrpc/jsonrpc.ts +36 -7
- package/src/kv/types.ts +1 -1
- package/src/migrate/migrate.spec.ts +1 -1
- package/src/migrate/migrate.ts +7 -7
- package/src/notation/notation.ts +1 -1
- package/src/primitive/index.ts +10 -0
- package/src/primitive/primitive.spec.ts +126 -0
- package/src/primitive/primitive.ts +82 -0
- package/src/record.ts +3 -5
- package/src/renderable.ts +1 -1
- package/src/replace.ts +9 -0
- package/src/runtime/detect.ts +0 -2
- package/src/runtime/os.ts +1 -1
- package/src/spatial/base.ts +1 -1
- package/src/spatial/bounds/bounds.spec.ts +20 -0
- package/src/spatial/bounds/bounds.ts +101 -18
- package/src/spatial/box/box.ts +1 -1
- package/src/spatial/dimensions/dimensions.ts +3 -3
- package/src/spatial/location/location.ts +1 -1
- package/src/spatial/scale/scale.ts +1 -1
- package/src/spatial/xy/xy.ts +1 -1
- package/src/status/index.ts +10 -0
- package/src/status/types.ts +22 -0
- package/src/sync/index.ts +9 -0
- package/src/sync/mutex.ts +9 -4
- package/src/telem/gl.ts +1 -1
- package/src/telem/series.spec.ts +735 -68
- package/src/telem/series.ts +536 -195
- package/src/telem/telem.spec.ts +60 -7
- package/src/telem/telem.ts +287 -95
- package/src/uuid/index.ts +10 -0
- package/src/uuid/uuid.spec.ts +82 -0
- package/src/uuid/uuid.ts +48 -0
- package/src/zod/external.ts +1 -1
- package/src/zod/nullToUndefined.spec.ts +31 -0
- package/src/zod/nullToUndefined.ts +23 -0
- package/src/zod/util.spec.ts +1 -1
- package/src/zod/util.ts +6 -6
- package/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/vite.config.ts +1 -1
- package/dist/base-BAM2mqCy.cjs +0 -1
- package/dist/base-DFq0vvGn.js +0 -38
- package/dist/bounds-BQo7rvs9.cjs +0 -1
- package/dist/box-0YrQibkB.cjs +0 -1
- package/dist/box-Cc8IzcNo.js +0 -205
- package/dist/change-C-YELKx6.cjs +0 -1
- package/dist/change-DLl6DccR.js +0 -12
- package/dist/dimensions-CRgergMS.js +0 -43
- package/dist/dimensions-D2QGoNXO.cjs +0 -1
- package/dist/external-BPgtxa8d.js +0 -29
- package/dist/external-C-dNgNQw.cjs +0 -1
- package/dist/external-C8TFju8Q.js +0 -29
- package/dist/external-DWQITF5_.cjs +0 -1
- package/dist/external-DqPrWKvU.js +0 -47
- package/dist/external-uXk0Avrg.cjs +0 -1
- package/dist/index-BywOGO8U.js +0 -1074
- package/dist/index-CYYjI7Uf.cjs +0 -1
- package/dist/index-C_6NXBlg.cjs +0 -3
- package/dist/index-Dd8DLyMx.cjs +0 -1
- package/dist/index-DizUWH6z.js +0 -47
- package/dist/index-QGplUHuy.js +0 -98
- package/dist/location-BGl5Ddds.cjs +0 -1
- package/dist/position-Cai5-wi1.cjs +0 -1
- package/dist/position-DIglP1l2.js +0 -85
- package/dist/scale-BtZINJ-A.cjs +0 -1
- package/dist/series-B9JERcqi.js +0 -1977
- package/dist/series-DqJ6f97G.cjs +0 -11
- package/dist/spatial-BSWPzMkK.js +0 -11
- package/dist/spatial-DGpZ2sO3.cjs +0 -1
- package/dist/src/color/transformColorsToHex.d.ts +0 -6
- package/dist/src/color/transformColorsToHex.d.ts.map +0 -1
- package/dist/src/primitive.d.ts +0 -9
- package/dist/src/primitive.d.ts.map +0 -1
- package/dist/src/toArray.d.ts +0 -3
- package/dist/src/toArray.d.ts.map +0 -1
- package/dist/src/zod/integer.d.ts +0 -10
- package/dist/src/zod/integer.d.ts.map +0 -1
- package/dist/src/zod/integer.spec.d.ts +0 -2
- package/dist/src/zod/integer.spec.d.ts.map +0 -1
- package/dist/toArray.cjs +0 -1
- package/dist/toArray.js +0 -5
- package/dist/xy-B7065J2S.cjs +0 -1
- package/src/color/transformColorsToHex.ts +0 -30
- package/src/primitive.ts +0 -46
- package/src/zod/integer.spec.ts +0 -148
- package/src/zod/integer.ts +0 -38
package/src/telem/series.ts
CHANGED
|
@@ -7,12 +7,13 @@
|
|
|
7
7
|
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
|
-
import { z } from "zod";
|
|
10
|
+
import { z } from "zod/v4";
|
|
11
11
|
|
|
12
12
|
import { binary } from "@/binary";
|
|
13
13
|
import { caseconv } from "@/caseconv";
|
|
14
14
|
import { compare } from "@/compare";
|
|
15
15
|
import { id } from "@/id";
|
|
16
|
+
import { instance } from "@/instance";
|
|
16
17
|
import { type math } from "@/math";
|
|
17
18
|
import { bounds } from "@/spatial";
|
|
18
19
|
import {
|
|
@@ -27,7 +28,6 @@ import {
|
|
|
27
28
|
type CrudeTimeStamp,
|
|
28
29
|
DataType,
|
|
29
30
|
isTelemValue,
|
|
30
|
-
type Rate,
|
|
31
31
|
Size,
|
|
32
32
|
type TelemValue,
|
|
33
33
|
TimeRange,
|
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
TimeStamp,
|
|
36
36
|
type TypedArray,
|
|
37
37
|
} from "@/telem/telem";
|
|
38
|
+
import { uuid } from "@/uuid";
|
|
38
39
|
|
|
39
40
|
interface GL {
|
|
40
41
|
control: GLBufferController | null;
|
|
@@ -43,8 +44,9 @@ interface GL {
|
|
|
43
44
|
bufferUsage: GLBufferUsage;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
interface IterableIterator<T> extends Iterator<T>, Iterable<T> {}
|
|
47
48
|
|
|
49
|
+
/** A condensed set of information describing the layout of a series. */
|
|
48
50
|
export interface SeriesDigest {
|
|
49
51
|
key: string;
|
|
50
52
|
dataType: string;
|
|
@@ -58,7 +60,7 @@ export interface SeriesDigest {
|
|
|
58
60
|
capacity: number;
|
|
59
61
|
}
|
|
60
62
|
|
|
61
|
-
interface
|
|
63
|
+
interface BaseSeriesArgs {
|
|
62
64
|
dataType?: CrudeDataType;
|
|
63
65
|
timeRange?: TimeRange;
|
|
64
66
|
sampleOffset?: math.Numeric;
|
|
@@ -67,6 +69,7 @@ interface BaseSeriesProps {
|
|
|
67
69
|
key?: string;
|
|
68
70
|
}
|
|
69
71
|
|
|
72
|
+
/** A value or set of values that a series can be constructed from. */
|
|
70
73
|
export type CrudeSeries =
|
|
71
74
|
| Series
|
|
72
75
|
| ArrayBuffer
|
|
@@ -79,33 +82,19 @@ export type CrudeSeries =
|
|
|
79
82
|
| Date[]
|
|
80
83
|
| TelemValue;
|
|
81
84
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (Array.isArray(value)) return true;
|
|
85
|
-
if (value instanceof ArrayBuffer) return true;
|
|
86
|
-
if (ArrayBuffer.isView(value) && !(value instanceof DataView)) return true;
|
|
87
|
-
if (value instanceof Series) return true;
|
|
88
|
-
return isTelemValue(value);
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
export interface SeriesProps extends BaseSeriesProps {
|
|
85
|
+
/** Arguments for constructing a {@link Series}. */
|
|
86
|
+
export interface SeriesArgs extends BaseSeriesArgs {
|
|
92
87
|
data?: CrudeSeries | null;
|
|
93
88
|
}
|
|
94
89
|
|
|
95
|
-
|
|
90
|
+
/** Arguments for allocating a {@link Series} with a given capacity and data type. */
|
|
91
|
+
export interface SeriesAllocArgs extends BaseSeriesArgs {
|
|
96
92
|
capacity: number;
|
|
97
93
|
dataType: CrudeDataType;
|
|
98
94
|
}
|
|
99
95
|
|
|
100
96
|
const FULL_BUFFER = -1;
|
|
101
97
|
|
|
102
|
-
export interface SeriesMemInfo {
|
|
103
|
-
key: string;
|
|
104
|
-
length: number;
|
|
105
|
-
byteLength: Size;
|
|
106
|
-
glBuffer: boolean;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
98
|
const noopIterableIterator: IterableIterator<never> = {
|
|
110
99
|
[Symbol.iterator]: () => noopIterableIterator,
|
|
111
100
|
next: () => ({ done: true, value: undefined }),
|
|
@@ -137,18 +126,31 @@ const checkAsType = (jsType: JSType, dataType: DataType) => {
|
|
|
137
126
|
throw new Error(`cannot convert series of type ${dataType.toString()} to bigint`);
|
|
138
127
|
};
|
|
139
128
|
|
|
129
|
+
const SERIES_DISCRIMINATOR = "sy_x_telem_series";
|
|
130
|
+
|
|
140
131
|
/**
|
|
141
132
|
* Series is a strongly typed array of telemetry samples backed by an underlying binary
|
|
142
133
|
* buffer.
|
|
143
134
|
*/
|
|
144
|
-
export class Series<T extends TelemValue = TelemValue>
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
/**
|
|
135
|
+
export class Series<T extends TelemValue = TelemValue>
|
|
136
|
+
implements instance.Discriminated
|
|
137
|
+
{
|
|
138
|
+
/**
|
|
139
|
+
* A unique identifier for the series. If specified by the user, it is their
|
|
140
|
+
* responsibility to ensure that it is unique. If not specified, a new ID will be
|
|
141
|
+
* generated.
|
|
142
|
+
*/
|
|
143
|
+
key: string;
|
|
144
|
+
/**
|
|
145
|
+
* A discriminator used for identifying instances of the series class even
|
|
146
|
+
* when bundlers mangle the class name.
|
|
147
|
+
*/
|
|
148
|
+
discriminator: string = SERIES_DISCRIMINATOR;
|
|
149
|
+
/** The data type of the series. */
|
|
148
150
|
readonly dataType: DataType;
|
|
149
151
|
/**
|
|
150
152
|
* A sample offset that can be used to shift the values of all samples upwards or
|
|
151
|
-
* downwards.
|
|
153
|
+
* downwards. Useful to convert series to lower precision data types while preserving
|
|
152
154
|
* the relative range of actual values.
|
|
153
155
|
*/
|
|
154
156
|
sampleOffset: math.Numeric;
|
|
@@ -158,21 +160,30 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
158
160
|
private readonly gl: GL;
|
|
159
161
|
/** The underlying data. */
|
|
160
162
|
private readonly _data: ArrayBuffer;
|
|
163
|
+
/** The time range occupied by the series' data. */
|
|
161
164
|
readonly timeRange: TimeRange = TimeRange.ZERO;
|
|
165
|
+
/**
|
|
166
|
+
* Alignment defines the location of the series relative to other series in a logical
|
|
167
|
+
* group. Useful for defining the position of the series within a channel's data.
|
|
168
|
+
*/
|
|
162
169
|
readonly alignment: bigint = 0n;
|
|
163
170
|
/** A cached minimum value. */
|
|
164
|
-
private
|
|
171
|
+
private cachedMin?: math.Numeric;
|
|
165
172
|
/** A cached maximum value. */
|
|
166
|
-
private
|
|
173
|
+
private cachedMax?: math.Numeric;
|
|
167
174
|
/** The write position of the buffer. */
|
|
168
175
|
private writePos: number = FULL_BUFFER;
|
|
169
176
|
/** Tracks the number of entities currently using this array. */
|
|
170
177
|
private _refCount: number = 0;
|
|
171
178
|
/** Caches the length of the array for variable length data types. */
|
|
172
|
-
private
|
|
179
|
+
private cachedLength?: number;
|
|
173
180
|
/** Caches the indexes of the array for variable length data types. */
|
|
174
181
|
private _cachedIndexes?: number[];
|
|
175
182
|
|
|
183
|
+
/**
|
|
184
|
+
* A zod schema that can be used to validate that a particular value
|
|
185
|
+
* can be constructed into a series.
|
|
186
|
+
*/
|
|
176
187
|
static readonly crudeZ = z.object({
|
|
177
188
|
timeRange: TimeRange.z.optional(),
|
|
178
189
|
dataType: DataType.z,
|
|
@@ -186,10 +197,87 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
186
197
|
glBufferUsage: glBufferUsageZ.optional().default("static").optional(),
|
|
187
198
|
});
|
|
188
199
|
|
|
200
|
+
/**
|
|
201
|
+
* A zod schema that validates and constructs a series from it's crude
|
|
202
|
+
* representation.
|
|
203
|
+
*/
|
|
189
204
|
static readonly z = Series.crudeZ.transform((props) => new Series(props));
|
|
190
|
-
|
|
191
|
-
|
|
205
|
+
/**
|
|
206
|
+
* The Series constructor accepts either a SeriesArgs object or a CrudeSeries value.
|
|
207
|
+
*
|
|
208
|
+
* SeriesArgs interface properties:
|
|
209
|
+
* @property {CrudeSeries | null} [data] - The data to construct the series from. Can be:
|
|
210
|
+
* - A typed array (e.g. Float32Array, Int32Array)
|
|
211
|
+
* - A JS array of numbers, strings, or objects
|
|
212
|
+
* - A single value (number, string, bigint, etc.)
|
|
213
|
+
* - An ArrayBuffer
|
|
214
|
+
* - Another Series instance
|
|
215
|
+
* @property {CrudeDataType} [dataType] - The data type of the series. If not provided,
|
|
216
|
+
* will be inferred from the data. Required when constructing from an ArrayBuffer, or
|
|
217
|
+
* an empty JS array.
|
|
218
|
+
* @property {TimeRange} [timeRange] - The time range occupied by the series' data.
|
|
219
|
+
* Defaults to TimeRange.ZERO.
|
|
220
|
+
* @property {math.Numeric} [sampleOffset] - An offset to apply to each sample value.
|
|
221
|
+
* Useful for converting arrays to lower precision while preserving relative range.
|
|
222
|
+
* Defaults to 0.
|
|
223
|
+
* @property {GLBufferUsage} [glBufferUsage] - The WebGL buffer usage hint. Can be
|
|
224
|
+
* "static" or "dynamic". Defaults to "static".
|
|
225
|
+
* @property {bigint} [alignment] - The logical position of the series relative to other
|
|
226
|
+
* series in a group. Defaults to 0n.
|
|
227
|
+
* @property {string} [key] - A unique identifier for the series. If not provided,
|
|
228
|
+
* a new ID will be generated.
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* // Create a series from a typed array
|
|
232
|
+
* const s1 = new Series(new Float32Array([1, 2, 3]));
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* // Create a series from a JS array with explicit data type
|
|
236
|
+
* const s2 = new Series({ data: [1, 2, 3], dataType: DataType.FLOAT32 });
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* // Create a series from a single value (data type inferred)
|
|
240
|
+
* const s3 = new Series(1); // Creates a FLOAT64 series
|
|
241
|
+
* const s4 = new Series("abc"); // Creates a STRING series
|
|
242
|
+
* const s5 = new Series(1n); // Creates an INT64 series
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* // Create a series from objects (automatically uses JSON data type)
|
|
246
|
+
* const s6 = new Series([{ a: 1, b: "apple" }]);
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* // Create a series with time range and alignment
|
|
250
|
+
* const s7 = new Series({
|
|
251
|
+
* data: new Float32Array([1, 2, 3]),
|
|
252
|
+
* timeRange: new TimeRange(1, 2),
|
|
253
|
+
* alignment: 1n
|
|
254
|
+
* });
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* // Create a series from another series (copies properties)
|
|
258
|
+
* const s8 = new Series(s1);
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* // Create a series with sample offset
|
|
262
|
+
* const s9 = new Series({
|
|
263
|
+
* data: new Float32Array([1, 2, 3]),
|
|
264
|
+
* sampleOffset: 2
|
|
265
|
+
* }); // Values will be 3, 4, 5
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* // Create a series with WebGL buffer usage
|
|
269
|
+
* const s10 = new Series({
|
|
270
|
+
* data: new Float32Array([1, 2, 3]),
|
|
271
|
+
* glBufferUsage: "dynamic"
|
|
272
|
+
* });
|
|
273
|
+
*
|
|
274
|
+
* @throws Error if constructing from an empty JS array without specifying data type
|
|
275
|
+
* @throws Error if constructing from an ArrayBuffer without specifying data type
|
|
276
|
+
* @throws Error if data type cannot be inferred from input
|
|
277
|
+
*/
|
|
278
|
+
constructor(props: SeriesArgs | CrudeSeries) {
|
|
192
279
|
if (isCrudeSeries(props)) props = { data: props };
|
|
280
|
+
props.data ??= [];
|
|
193
281
|
const {
|
|
194
282
|
dataType,
|
|
195
283
|
timeRange,
|
|
@@ -197,14 +285,9 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
197
285
|
glBufferUsage = "static",
|
|
198
286
|
alignment = 0n,
|
|
199
287
|
key = id.create(),
|
|
288
|
+
data,
|
|
200
289
|
} = props;
|
|
201
|
-
|
|
202
|
-
if (
|
|
203
|
-
data instanceof Series ||
|
|
204
|
-
(typeof data === "object" &&
|
|
205
|
-
"isSynnaxSeries" in data &&
|
|
206
|
-
data.isSynnaxSeries === true)
|
|
207
|
-
) {
|
|
290
|
+
if (isSeries(data)) {
|
|
208
291
|
const data_ = data as Series;
|
|
209
292
|
this.key = data_.key;
|
|
210
293
|
this.dataType = data_.dataType;
|
|
@@ -213,11 +296,11 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
213
296
|
this._data = data_._data;
|
|
214
297
|
this.timeRange = data_.timeRange;
|
|
215
298
|
this.alignment = data_.alignment;
|
|
216
|
-
this.
|
|
217
|
-
this.
|
|
299
|
+
this.cachedMin = data_.cachedMin;
|
|
300
|
+
this.cachedMax = data_.cachedMax;
|
|
218
301
|
this.writePos = data_.writePos;
|
|
219
302
|
this._refCount = data_._refCount;
|
|
220
|
-
this.
|
|
303
|
+
this.cachedLength = data_.cachedLength;
|
|
221
304
|
return;
|
|
222
305
|
}
|
|
223
306
|
const isSingle = isTelemValue(data);
|
|
@@ -265,11 +348,11 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
265
348
|
)
|
|
266
349
|
data_ = data_.map((v) => new TimeStamp(v as CrudeTimeStamp).valueOf());
|
|
267
350
|
if (this.dataType.equals(DataType.STRING)) {
|
|
268
|
-
this.
|
|
351
|
+
this.cachedLength = data_.length;
|
|
269
352
|
this._data = new TextEncoder().encode(`${data_.join("\n")}\n`)
|
|
270
353
|
.buffer as ArrayBuffer;
|
|
271
354
|
} else if (this.dataType.equals(DataType.JSON)) {
|
|
272
|
-
this.
|
|
355
|
+
this.cachedLength = data_.length;
|
|
273
356
|
this._data = new TextEncoder().encode(
|
|
274
357
|
`${data_.map((d) => binary.JSON_CODEC.encodeString(d)).join("\n")}\n`,
|
|
275
358
|
).buffer as ArrayBuffer;
|
|
@@ -296,58 +379,54 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
296
379
|
};
|
|
297
380
|
}
|
|
298
381
|
|
|
299
|
-
|
|
300
|
-
|
|
382
|
+
/**
|
|
383
|
+
* Allocates a new series with a given capacity and data type.
|
|
384
|
+
* @param args.capacity the capacity of the series in samples. If the data type is of
|
|
385
|
+
* variable density (i.e. JSON, STRING, BYTES), this is the capacity in bytes.
|
|
386
|
+
* @param args.dataType the data type of the series.
|
|
387
|
+
* @param args.rest the rest of the arguments to pass to the series constructor.
|
|
388
|
+
*/
|
|
389
|
+
static alloc({ capacity, dataType, ...rest }: SeriesAllocArgs): Series {
|
|
390
|
+
if (capacity === 0)
|
|
301
391
|
throw new Error("[Series] - cannot allocate an array of length 0");
|
|
302
|
-
const data = new new DataType(dataType).Array(
|
|
303
|
-
const arr = new Series({
|
|
304
|
-
data: data.buffer,
|
|
305
|
-
dataType,
|
|
306
|
-
...rest,
|
|
307
|
-
});
|
|
392
|
+
const data = new new DataType(dataType).Array(capacity);
|
|
393
|
+
const arr = new Series({ data: data.buffer, dataType, ...rest });
|
|
308
394
|
arr.writePos = 0;
|
|
309
395
|
return arr;
|
|
310
396
|
}
|
|
311
397
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
return new Series({ data, dataType: DataType.TIMESTAMP, timeRange });
|
|
318
|
-
}
|
|
319
|
-
|
|
398
|
+
/**
|
|
399
|
+
* @returns the number of references to this series i.e. the number of times this
|
|
400
|
+
* series has been acquired (by calling acquire) and not released (by calling
|
|
401
|
+
* release).
|
|
402
|
+
*/
|
|
320
403
|
get refCount(): number {
|
|
321
404
|
return this._refCount;
|
|
322
405
|
}
|
|
323
406
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
static fromJSON<T>(data: T[], timeRange?: TimeRange): Series {
|
|
332
|
-
const buffer = new TextEncoder().encode(
|
|
333
|
-
`${data.map((d) => binary.JSON_CODEC.encodeString(d)).join("\n")}\n`,
|
|
334
|
-
) as Uint8Array<ArrayBuffer>;
|
|
335
|
-
return new Series({ data: buffer, dataType: DataType.JSON, timeRange });
|
|
336
|
-
}
|
|
337
|
-
|
|
407
|
+
/**
|
|
408
|
+
* Acquires a reference to this series, optionally buffering its data into the
|
|
409
|
+
* specified buffer controller. This method is useful for managing the life span
|
|
410
|
+
* of series buffered to the GPU.
|
|
411
|
+
* @param gl the buffer controller to buffer the series to. If not provided, the series
|
|
412
|
+
* will not be buffered to the GPU.
|
|
413
|
+
*/
|
|
338
414
|
acquire(gl?: GLBufferController): void {
|
|
339
415
|
this._refCount++;
|
|
340
416
|
if (gl != null) this.updateGLBuffer(gl);
|
|
341
417
|
}
|
|
342
418
|
|
|
419
|
+
/**
|
|
420
|
+
* Releases a reference to this series. If the reference count to the series reaches
|
|
421
|
+
* 0 and the series has been buffered to the GPU, the series will be deleted from
|
|
422
|
+
* the GPU.
|
|
423
|
+
*/
|
|
343
424
|
release(): void {
|
|
344
|
-
if (this._refCount <= 0) {
|
|
345
|
-
console.warn("attempted to release a series with a negative reference count");
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
425
|
this._refCount--;
|
|
349
|
-
if (this.
|
|
426
|
+
if (this.refCount === 0 && this.gl.control != null)
|
|
350
427
|
this.maybeGarbageCollectGLBuffer(this.gl.control);
|
|
428
|
+
else if (this.refCount < 0)
|
|
429
|
+
console.warn("cannot release a series with a negative reference count");
|
|
351
430
|
}
|
|
352
431
|
|
|
353
432
|
/**
|
|
@@ -371,8 +450,8 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
371
450
|
const toWrite = other.subBytes(0, available);
|
|
372
451
|
this.writeToUnderlyingData(toWrite);
|
|
373
452
|
this.writePos += toWrite.byteLength.valueOf();
|
|
374
|
-
if (this.
|
|
375
|
-
this.
|
|
453
|
+
if (this.cachedLength != null) {
|
|
454
|
+
this.cachedLength += toWrite.length;
|
|
376
455
|
this.calculateCachedLength();
|
|
377
456
|
}
|
|
378
457
|
return toWrite.length;
|
|
@@ -383,7 +462,7 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
383
462
|
const available = this.capacity - this.writePos;
|
|
384
463
|
const toWrite = other.sub(0, available);
|
|
385
464
|
this.writeToUnderlyingData(toWrite);
|
|
386
|
-
this.
|
|
465
|
+
this.cachedLength = undefined;
|
|
387
466
|
this.maybeRecomputeMinMax(toWrite);
|
|
388
467
|
this.writePos += toWrite.length;
|
|
389
468
|
return toWrite.length;
|
|
@@ -407,69 +486,92 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
407
486
|
return new this.dataType.Array(this._data);
|
|
408
487
|
}
|
|
409
488
|
|
|
410
|
-
/**
|
|
489
|
+
/**
|
|
490
|
+
* Returns a native JS typed array with the proper data type.
|
|
491
|
+
* If the series is not full, returns a view of the data up to the write position.
|
|
492
|
+
* @returns A typed array containing the series data.
|
|
493
|
+
*/
|
|
411
494
|
get data(): TypedArray {
|
|
412
495
|
if (this.writePos === FULL_BUFFER) return this.underlyingData;
|
|
413
496
|
return new this.dataType.Array(this._data, 0, this.writePos);
|
|
414
497
|
}
|
|
415
498
|
|
|
499
|
+
/**
|
|
500
|
+
* Returns an array of the values in the series as strings.
|
|
501
|
+
* For variable length data types (like STRING or JSON), this decodes the underlying buffer.
|
|
502
|
+
* @returns An array of string representations of the series values.
|
|
503
|
+
*/
|
|
416
504
|
toStrings(): string[] {
|
|
417
|
-
if (
|
|
418
|
-
|
|
419
|
-
return
|
|
505
|
+
if (this.dataType.isVariable)
|
|
506
|
+
return new TextDecoder().decode(this.underlyingData).split("\n").slice(0, -1);
|
|
507
|
+
return Array.from(this).map((d) => d.toString());
|
|
420
508
|
}
|
|
421
509
|
|
|
510
|
+
/**
|
|
511
|
+
* Returns a parsed array of UUIDs from the series.
|
|
512
|
+
* @throws Error if the series does not have a data type of UUID.
|
|
513
|
+
* @returns An array of UUID strings.
|
|
514
|
+
*/
|
|
422
515
|
toUUIDs(): string[] {
|
|
423
516
|
if (!this.dataType.equals(DataType.UUID))
|
|
424
517
|
throw new Error("cannot convert non-uuid series to uuids");
|
|
425
518
|
const den = DataType.UUID.density.valueOf();
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
for (let i = 0; i < this.length; i++) {
|
|
429
|
-
const v = this.underlyingData.slice(i * den, (i + 1) * den);
|
|
430
|
-
const id = Array.from(new Uint8Array(v.buffer), (b) =>
|
|
431
|
-
b.toString(16).padStart(2, "0"),
|
|
432
|
-
)
|
|
433
|
-
.join("")
|
|
434
|
-
.replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, "$1-$2-$3-$4-$5");
|
|
435
|
-
r[i] = id;
|
|
436
|
-
}
|
|
437
|
-
return r;
|
|
519
|
+
const d = new Uint8Array(this.underlyingData.buffer);
|
|
520
|
+
return Array.from({ length: this.length }, (_, i) => uuid.parse(d, i * den));
|
|
438
521
|
}
|
|
439
522
|
|
|
440
|
-
|
|
523
|
+
/**
|
|
524
|
+
* Parses a JSON series into an array of values using the provided zod schema.
|
|
525
|
+
* @template Z The zod schema type.
|
|
526
|
+
* @param schema The zod schema to use to parse the JSON series.
|
|
527
|
+
* @throws Error if the series does not have a data type of JSON.
|
|
528
|
+
* @returns An array of values parsed from the JSON series.
|
|
529
|
+
*/
|
|
530
|
+
parseJSON<Z extends z.ZodType>(schema: Z): Array<z.infer<Z>> {
|
|
441
531
|
if (!this.dataType.equals(DataType.JSON))
|
|
442
532
|
throw new Error("cannot parse non-JSON series as JSON");
|
|
443
|
-
return
|
|
444
|
-
.decode(this.underlyingData)
|
|
445
|
-
.split("\n")
|
|
446
|
-
.slice(0, -1)
|
|
447
|
-
.map((s) => schema.parse(binary.JSON_CODEC.decodeString(s)));
|
|
533
|
+
return this.toStrings().map((s) => schema.parse(binary.JSON_CODEC.decodeString(s)));
|
|
448
534
|
}
|
|
449
535
|
|
|
450
|
-
/**
|
|
536
|
+
/**
|
|
537
|
+
* Returns the capacity of the series in bytes.
|
|
538
|
+
* @returns The size of the underlying buffer in bytes.
|
|
539
|
+
*/
|
|
451
540
|
get byteCapacity(): Size {
|
|
452
541
|
return new Size(this.underlyingData.byteLength);
|
|
453
542
|
}
|
|
454
543
|
|
|
455
|
-
/**
|
|
544
|
+
/**
|
|
545
|
+
* Returns the capacity of the series in samples.
|
|
546
|
+
* For variable length data types, this is the capacity in bytes.
|
|
547
|
+
* @returns The number of samples that can be stored in the series.
|
|
548
|
+
*/
|
|
456
549
|
get capacity(): number {
|
|
457
550
|
if (this.dataType.isVariable) return this.byteCapacity.valueOf();
|
|
458
551
|
return this.dataType.density.length(this.byteCapacity);
|
|
459
552
|
}
|
|
460
553
|
|
|
461
|
-
/**
|
|
554
|
+
/**
|
|
555
|
+
* Returns the length of the series in bytes.
|
|
556
|
+
* For variable length data types, this is the actual number of bytes used.
|
|
557
|
+
* @returns The size of the data in bytes.
|
|
558
|
+
*/
|
|
462
559
|
get byteLength(): Size {
|
|
463
560
|
if (this.writePos === FULL_BUFFER) return this.byteCapacity;
|
|
464
561
|
if (this.dataType.isVariable) return new Size(this.writePos);
|
|
465
562
|
return this.dataType.density.size(this.writePos);
|
|
466
563
|
}
|
|
467
564
|
|
|
468
|
-
/**
|
|
565
|
+
/**
|
|
566
|
+
* Returns the number of samples in this array.
|
|
567
|
+
* For variable length data types, this is calculated by counting newlines.
|
|
568
|
+
* @returns The number of samples in the series.
|
|
569
|
+
*/
|
|
469
570
|
get length(): number {
|
|
470
|
-
if (this.
|
|
571
|
+
if (this.cachedLength != null) return this.cachedLength;
|
|
471
572
|
if (this.dataType.isVariable) return this.calculateCachedLength();
|
|
472
|
-
if (this.writePos === FULL_BUFFER)
|
|
573
|
+
if (this.writePos === FULL_BUFFER)
|
|
574
|
+
return this.byteCapacity.valueOf() / this.dataType.density.valueOf();
|
|
473
575
|
return this.writePos;
|
|
474
576
|
}
|
|
475
577
|
|
|
@@ -484,7 +586,7 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
484
586
|
ci.push(i + 1);
|
|
485
587
|
});
|
|
486
588
|
this._cachedIndexes = ci;
|
|
487
|
-
this.
|
|
589
|
+
this.cachedLength = cl;
|
|
488
590
|
return cl;
|
|
489
591
|
}
|
|
490
592
|
|
|
@@ -515,76 +617,84 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
515
617
|
private calcRawMax(): math.Numeric {
|
|
516
618
|
if (this.length === 0) return -Infinity;
|
|
517
619
|
if (this.dataType.equals(DataType.TIMESTAMP))
|
|
518
|
-
this.
|
|
620
|
+
this.cachedMax = this.data[this.data.length - 1];
|
|
519
621
|
else if (this.dataType.usesBigInt) {
|
|
520
622
|
const d = this.data as BigInt64Array;
|
|
521
|
-
this.
|
|
623
|
+
this.cachedMax = d.reduce((a, b) => (a > b ? a : b));
|
|
522
624
|
} else {
|
|
523
625
|
const d = this.data as Float64Array;
|
|
524
|
-
this.
|
|
626
|
+
this.cachedMax = d.reduce((a, b) => (a > b ? a : b));
|
|
525
627
|
}
|
|
526
|
-
return this.
|
|
628
|
+
return this.cachedMax;
|
|
527
629
|
}
|
|
528
630
|
|
|
529
631
|
/** @returns the maximum value in the array */
|
|
530
632
|
get max(): math.Numeric {
|
|
633
|
+
return this.calcMax();
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
private calcMax(): math.Numeric {
|
|
531
637
|
if (this.dataType.isVariable)
|
|
532
638
|
throw new Error("cannot calculate maximum on a variable length data type");
|
|
533
639
|
if (this.writePos === 0) return -Infinity;
|
|
534
|
-
this.
|
|
535
|
-
return addSamples(this.
|
|
640
|
+
this.cachedMax ??= this.calcRawMax();
|
|
641
|
+
return addSamples(this.cachedMax, this.sampleOffset);
|
|
536
642
|
}
|
|
537
643
|
|
|
538
644
|
private calcRawMin(): math.Numeric {
|
|
539
645
|
if (this.length === 0) return Infinity;
|
|
540
|
-
if (this.dataType.equals(DataType.TIMESTAMP)) this.
|
|
646
|
+
if (this.dataType.equals(DataType.TIMESTAMP)) this.cachedMin = this.data[0];
|
|
541
647
|
else if (this.dataType.usesBigInt) {
|
|
542
648
|
const d = this.data as BigInt64Array;
|
|
543
|
-
this.
|
|
649
|
+
this.cachedMin = d.reduce((a, b) => (a < b ? a : b));
|
|
544
650
|
} else {
|
|
545
651
|
const d = this.data as Float64Array;
|
|
546
|
-
this.
|
|
652
|
+
this.cachedMin = d.reduce((a, b) => (a < b ? a : b));
|
|
547
653
|
}
|
|
548
|
-
return this.
|
|
654
|
+
return this.cachedMin;
|
|
549
655
|
}
|
|
550
656
|
|
|
551
657
|
/** @returns the minimum value in the array */
|
|
552
658
|
get min(): math.Numeric {
|
|
659
|
+
return this.calcMin();
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
private calcMin(): math.Numeric {
|
|
553
663
|
if (this.dataType.isVariable)
|
|
554
664
|
throw new Error("cannot calculate minimum on a variable length data type");
|
|
555
665
|
if (this.writePos === 0) return Infinity;
|
|
556
|
-
this.
|
|
557
|
-
return addSamples(this.
|
|
666
|
+
this.cachedMin ??= this.calcRawMin();
|
|
667
|
+
return addSamples(this.cachedMin, this.sampleOffset);
|
|
558
668
|
}
|
|
559
669
|
|
|
560
|
-
/** @returns the bounds of
|
|
670
|
+
/** @returns the bounds of the series. */
|
|
561
671
|
get bounds(): bounds.Bounds {
|
|
562
|
-
return bounds.construct(Number(this.min), Number(this.max));
|
|
672
|
+
return bounds.construct(Number(this.min), Number(this.max), { makeValid: false });
|
|
563
673
|
}
|
|
564
674
|
|
|
565
675
|
private maybeRecomputeMinMax(update: Series): void {
|
|
566
|
-
if (this.
|
|
567
|
-
const min = update.
|
|
568
|
-
if (min < this.
|
|
676
|
+
if (this.cachedMin != null) {
|
|
677
|
+
const min = update.cachedMin ?? update.calcRawMin();
|
|
678
|
+
if (min < this.cachedMin) this.cachedMin = min;
|
|
569
679
|
}
|
|
570
|
-
if (this.
|
|
571
|
-
const max = update.
|
|
572
|
-
if (max > this.
|
|
680
|
+
if (this.cachedMax != null) {
|
|
681
|
+
const max = update.cachedMax ?? update.calcRawMax();
|
|
682
|
+
if (max > this.cachedMax) this.cachedMax = max;
|
|
573
683
|
}
|
|
574
684
|
}
|
|
575
685
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
get range(): math.Numeric {
|
|
583
|
-
return addSamples(this.max, -this.min);
|
|
584
|
-
}
|
|
585
|
-
|
|
686
|
+
/**
|
|
687
|
+
* @returns the value at the given alignment.
|
|
688
|
+
* @param alignment the alignment to get the value at.
|
|
689
|
+
* @param required throws an error if the value is not found.
|
|
690
|
+
*/
|
|
586
691
|
atAlignment(alignment: bigint, required: true): T;
|
|
587
692
|
|
|
693
|
+
/**
|
|
694
|
+
* @returns the value at the given alignment.
|
|
695
|
+
* @param alignment the alignment to get the value at.
|
|
696
|
+
* @param required throws an error if the value is not found.
|
|
697
|
+
*/
|
|
588
698
|
atAlignment(alignment: bigint, required?: false): T | undefined;
|
|
589
699
|
|
|
590
700
|
atAlignment(alignment: bigint, required?: boolean): T | undefined {
|
|
@@ -596,8 +706,18 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
596
706
|
return this.at(index, required as true);
|
|
597
707
|
}
|
|
598
708
|
|
|
709
|
+
/**
|
|
710
|
+
* @returns the value at the given index.
|
|
711
|
+
* @param index the index to get the value at.
|
|
712
|
+
* @param required throws an error if the value is not found.
|
|
713
|
+
*/
|
|
599
714
|
at(index: number, required: true): T;
|
|
600
715
|
|
|
716
|
+
/**
|
|
717
|
+
* @returns the value at the given index.
|
|
718
|
+
* @param index the index to get the value at.
|
|
719
|
+
* @param required throws an error if the value is not found.
|
|
720
|
+
*/
|
|
601
721
|
at(index: number, required?: false): T | undefined;
|
|
602
722
|
|
|
603
723
|
at(index: number, required?: boolean): T | undefined {
|
|
@@ -659,6 +779,13 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
659
779
|
return left;
|
|
660
780
|
}
|
|
661
781
|
|
|
782
|
+
/**
|
|
783
|
+
* Updates the WebGL buffer for the series if it is not up to date. This method
|
|
784
|
+
* should be called whenever a series has been previously buffered to the GPU and
|
|
785
|
+
* then modified via calls to write().
|
|
786
|
+
* @param gl the buffer controller to update the buffer for. This controller should
|
|
787
|
+
* be the same buffer previously passed to {@method acquire} or {@method updateGLBuffer}.
|
|
788
|
+
*/
|
|
662
789
|
updateGLBuffer(gl: GLBufferController): void {
|
|
663
790
|
this.gl.control = gl;
|
|
664
791
|
if (
|
|
@@ -696,10 +823,23 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
696
823
|
}
|
|
697
824
|
}
|
|
698
825
|
|
|
826
|
+
/**
|
|
827
|
+
* Reinterprets the series as containing strings as its JS primitive type.
|
|
828
|
+
* @throws if the series does not have a data type of STRING or JSON.
|
|
829
|
+
*/
|
|
699
830
|
as(jsType: "string"): Series<string>;
|
|
700
831
|
|
|
832
|
+
/**
|
|
833
|
+
* Reinterprets the series as containing numbers as its JS primitive type.
|
|
834
|
+
* @throws if the series does not have a numeric data type.
|
|
835
|
+
*/
|
|
701
836
|
as(jsType: "number"): Series<number>;
|
|
702
837
|
|
|
838
|
+
/**
|
|
839
|
+
* Reinterprets the series as containing bigints as its JS primitive type.
|
|
840
|
+
* @throws if the series does not have a data type that requires bigints i.e.
|
|
841
|
+
* INT64 and UINT64.
|
|
842
|
+
*/
|
|
703
843
|
as(jsType: "bigint"): Series<bigint>;
|
|
704
844
|
|
|
705
845
|
as<T extends TelemValue>(jsType: "string" | "number" | "bigint"): Series<T> {
|
|
@@ -707,6 +847,7 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
707
847
|
return this as unknown as Series<T>;
|
|
708
848
|
}
|
|
709
849
|
|
|
850
|
+
/** @returns a digest containing information about the series. */
|
|
710
851
|
get digest(): SeriesDigest {
|
|
711
852
|
return {
|
|
712
853
|
key: this.key,
|
|
@@ -716,21 +857,21 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
716
857
|
lower: alignmentDigest(this.alignmentBounds.lower),
|
|
717
858
|
upper: alignmentDigest(this.alignmentBounds.upper),
|
|
718
859
|
},
|
|
719
|
-
timeRange: this.timeRange
|
|
860
|
+
timeRange: this.timeRange.toString(),
|
|
720
861
|
length: this.length,
|
|
721
862
|
capacity: this.capacity,
|
|
722
863
|
};
|
|
723
864
|
}
|
|
724
865
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
866
|
+
/**
|
|
867
|
+
* @returns the alignment bounds of the series, representing the logical space
|
|
868
|
+
* occupied by the series in a group of series. This is typically used to order the
|
|
869
|
+
* series within a channel's data.
|
|
870
|
+
*
|
|
871
|
+
* The lower bound is the alignment of the first sample, and the upper bound is the
|
|
872
|
+
* alignment of the last sample + 1. The lower bound is inclusive, while the upper bound
|
|
873
|
+
* is exclusive.
|
|
874
|
+
*/
|
|
734
875
|
get alignmentBounds(): bounds.Bounds<bigint> {
|
|
735
876
|
return bounds.construct(this.alignment, this.alignment + BigInt(this.length));
|
|
736
877
|
}
|
|
@@ -743,6 +884,12 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
743
884
|
this.gl.control = null;
|
|
744
885
|
}
|
|
745
886
|
|
|
887
|
+
/**
|
|
888
|
+
* @returns the WebGL buffer for the series. This method should only be called after
|
|
889
|
+
* the series has been buffered to the GPU via a call to {@method acquire} or
|
|
890
|
+
* {@method updateGLBuffer}.
|
|
891
|
+
* @throws if the series has not been buffered to the GPU.
|
|
892
|
+
*/
|
|
746
893
|
get glBuffer(): WebGLBuffer {
|
|
747
894
|
if (this.gl.buffer == null) throw new Error("gl buffer not initialized");
|
|
748
895
|
if (!(this.gl.prevBuffer === this.writePos)) console.warn("buffer not updated");
|
|
@@ -759,19 +906,43 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
759
906
|
return new FixedSeriesIterator(this) as Iterator<T>;
|
|
760
907
|
}
|
|
761
908
|
|
|
909
|
+
/**
|
|
910
|
+
* Returns a slice of the series from start to end.
|
|
911
|
+
* @param start The start index (inclusive).
|
|
912
|
+
* @param end The end index (exclusive).
|
|
913
|
+
* @returns A new series containing the sliced data.
|
|
914
|
+
*/
|
|
762
915
|
slice(start: number, end?: number): Series {
|
|
763
916
|
return this.sliceSub(false, start, end);
|
|
764
917
|
}
|
|
765
918
|
|
|
919
|
+
/**
|
|
920
|
+
* Returns a subarray view of the series from start to end.
|
|
921
|
+
* @param start The start index (inclusive).
|
|
922
|
+
* @param end The end index (exclusive).
|
|
923
|
+
* @returns A new series containing the subarray data.
|
|
924
|
+
*/
|
|
766
925
|
sub(start: number, end?: number): Series {
|
|
767
926
|
return this.sliceSub(true, start, end);
|
|
768
927
|
}
|
|
769
928
|
|
|
770
|
-
|
|
929
|
+
/**
|
|
930
|
+
* Returns an iterator over a portion of the series.
|
|
931
|
+
* @param start The start index (inclusive).
|
|
932
|
+
* @param end The end index (exclusive).
|
|
933
|
+
* @returns An iterator over the specified range.
|
|
934
|
+
*/
|
|
935
|
+
subIterator(start: number, end?: number): Iterator<T> {
|
|
771
936
|
return new SubIterator(this, start, end ?? this.length);
|
|
772
937
|
}
|
|
773
938
|
|
|
774
|
-
|
|
939
|
+
/**
|
|
940
|
+
* Returns an iterator over a portion of the series based on alignment.
|
|
941
|
+
* @param start The start alignment (inclusive).
|
|
942
|
+
* @param end The end alignment (exclusive).
|
|
943
|
+
* @returns An iterator over the specified alignment range.
|
|
944
|
+
*/
|
|
945
|
+
subAlignmentIterator(start: bigint, end: bigint): Iterator<T> {
|
|
775
946
|
return new SubIterator(
|
|
776
947
|
this,
|
|
777
948
|
Number(start - this.alignment),
|
|
@@ -807,6 +978,11 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
807
978
|
});
|
|
808
979
|
}
|
|
809
980
|
|
|
981
|
+
/**
|
|
982
|
+
* Creates a new series with a different alignment.
|
|
983
|
+
* @param alignment The new alignment value.
|
|
984
|
+
* @returns A new series with the specified alignment.
|
|
985
|
+
*/
|
|
810
986
|
reAlign(alignment: bigint): Series {
|
|
811
987
|
return new Series({
|
|
812
988
|
data: this.buffer,
|
|
@@ -818,26 +994,44 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
818
994
|
});
|
|
819
995
|
}
|
|
820
996
|
|
|
997
|
+
/**
|
|
998
|
+
* Returns a string representation of the series.
|
|
999
|
+
* For series with more than 10 elements, shows the first 5 and last 5 elements.
|
|
1000
|
+
* @returns A string representation of the series.
|
|
1001
|
+
*/
|
|
821
1002
|
toString(): string {
|
|
822
|
-
let data =
|
|
1003
|
+
let data = `Series(${this.dataType.toString()} ${this.length} [`;
|
|
823
1004
|
if (this.length <= 10) data += Array.from(this).map((v) => v.toString());
|
|
824
1005
|
else {
|
|
825
1006
|
for (let i = 0; i < 5; i++) {
|
|
826
1007
|
data += `${this.at(i)?.toString()}`;
|
|
827
|
-
|
|
1008
|
+
data += ",";
|
|
828
1009
|
}
|
|
829
|
-
data += "
|
|
1010
|
+
data += "...,";
|
|
830
1011
|
for (let i = -5; i < 0; i++) {
|
|
831
1012
|
data += this.at(i)?.toString();
|
|
832
1013
|
if (i < -1) data += ",";
|
|
833
1014
|
}
|
|
834
1015
|
}
|
|
835
|
-
data += "]";
|
|
1016
|
+
data += "])";
|
|
836
1017
|
return data;
|
|
837
1018
|
}
|
|
838
1019
|
}
|
|
839
1020
|
|
|
840
|
-
|
|
1021
|
+
/** @returns true if a Series can be constructed from the given value, and false otherwise. */
|
|
1022
|
+
export const isCrudeSeries = (value: unknown): value is CrudeSeries => {
|
|
1023
|
+
if (value == null) return false;
|
|
1024
|
+
if (Array.isArray(value)) return true;
|
|
1025
|
+
if (value instanceof ArrayBuffer) return true;
|
|
1026
|
+
if (ArrayBuffer.isView(value) && !(value instanceof DataView)) return true;
|
|
1027
|
+
if (value instanceof Series) return true;
|
|
1028
|
+
return isTelemValue(value);
|
|
1029
|
+
};
|
|
1030
|
+
|
|
1031
|
+
/** @returns true if the given value is an instance of the series class. */
|
|
1032
|
+
const isSeries = instance.createMatcher<Series>(SERIES_DISCRIMINATOR, Series);
|
|
1033
|
+
|
|
1034
|
+
class SubIterator<T> implements Iterator<T> {
|
|
841
1035
|
private readonly series: Series;
|
|
842
1036
|
private readonly end: number;
|
|
843
1037
|
private index: number;
|
|
@@ -853,10 +1047,6 @@ class SubIterator<T> implements Iterator<T>, Iterable<T> {
|
|
|
853
1047
|
if (this.index >= this.end) return { done: true, value: undefined };
|
|
854
1048
|
return { done: false, value: this.series.at(this.index++, true) as T };
|
|
855
1049
|
}
|
|
856
|
-
|
|
857
|
-
[Symbol.iterator](): Iterator<T> {
|
|
858
|
-
return this;
|
|
859
|
-
}
|
|
860
1050
|
}
|
|
861
1051
|
|
|
862
1052
|
class StringSeriesIterator implements Iterator<string> {
|
|
@@ -884,15 +1074,11 @@ class StringSeriesIterator implements Iterator<string> {
|
|
|
884
1074
|
const s = this.decoder.decode(this.series.buffer.slice(start, end));
|
|
885
1075
|
return { done: false, value: s };
|
|
886
1076
|
}
|
|
887
|
-
|
|
888
|
-
[Symbol.iterator](): Iterator<TelemValue> {
|
|
889
|
-
return this;
|
|
890
|
-
}
|
|
891
1077
|
}
|
|
892
1078
|
|
|
893
1079
|
class JSONSeriesIterator implements Iterator<unknown> {
|
|
894
1080
|
private readonly wrapped: Iterator<string>;
|
|
895
|
-
private static
|
|
1081
|
+
private static schema = z.record(z.string(), z.unknown());
|
|
896
1082
|
|
|
897
1083
|
constructor(wrapped: Iterator<string>) {
|
|
898
1084
|
this.wrapped = wrapped;
|
|
@@ -903,15 +1089,9 @@ class JSONSeriesIterator implements Iterator<unknown> {
|
|
|
903
1089
|
if (next.done === true) return { done: true, value: undefined };
|
|
904
1090
|
return {
|
|
905
1091
|
done: false,
|
|
906
|
-
value: binary.JSON_CODEC.decodeString(next.value, JSONSeriesIterator.
|
|
1092
|
+
value: binary.JSON_CODEC.decodeString(next.value, JSONSeriesIterator.schema),
|
|
907
1093
|
};
|
|
908
1094
|
}
|
|
909
|
-
|
|
910
|
-
[Symbol.iterator](): Iterator<object> {
|
|
911
|
-
return this;
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
[Symbol.toStringTag] = "JSONSeriesIterator";
|
|
915
1095
|
}
|
|
916
1096
|
|
|
917
1097
|
class FixedSeriesIterator implements Iterator<math.Numeric> {
|
|
@@ -929,17 +1109,59 @@ class FixedSeriesIterator implements Iterator<math.Numeric> {
|
|
|
929
1109
|
value: this.series.at(this.index++, true) as math.Numeric,
|
|
930
1110
|
};
|
|
931
1111
|
}
|
|
932
|
-
|
|
933
|
-
[Symbol.iterator](): Iterator<math.Numeric> {
|
|
934
|
-
return this;
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
[Symbol.toStringTag] = "SeriesIterator";
|
|
938
1112
|
}
|
|
939
1113
|
|
|
1114
|
+
/**
|
|
1115
|
+
* MultiSeries represents a collection of Series instances that share the same data type.
|
|
1116
|
+
* It provides a unified interface for working with multiple series as if they were a single
|
|
1117
|
+
* continuous series.
|
|
1118
|
+
*
|
|
1119
|
+
|
|
1120
|
+
*/
|
|
940
1121
|
export class MultiSeries<T extends TelemValue = TelemValue> implements Iterable<T> {
|
|
1122
|
+
/** The array of series in this collection */
|
|
941
1123
|
readonly series: Array<Series<T>>;
|
|
942
1124
|
|
|
1125
|
+
/**
|
|
1126
|
+
* The MultiSeries constructor accepts an optional array of Series instances. All series
|
|
1127
|
+
* in the collection must have the same data type.
|
|
1128
|
+
*
|
|
1129
|
+
* @example
|
|
1130
|
+
* // Create an empty MultiSeries
|
|
1131
|
+
* const ms1 = new MultiSeries();
|
|
1132
|
+
*
|
|
1133
|
+
* @example
|
|
1134
|
+
* // Create a MultiSeries from multiple numeric series
|
|
1135
|
+
* const s1 = new Series(new Float32Array([1, 2, 3]));
|
|
1136
|
+
* const s2 = new Series(new Float32Array([4, 5, 6]));
|
|
1137
|
+
* const ms2 = new MultiSeries([s1, s2]);
|
|
1138
|
+
*
|
|
1139
|
+
* @example
|
|
1140
|
+
* // Create a MultiSeries from string series
|
|
1141
|
+
* const s3 = new Series(["apple", "banana"]);
|
|
1142
|
+
* const s4 = new Series(["carrot", "date"]);
|
|
1143
|
+
* const ms3 = new MultiSeries([s3, s4]);
|
|
1144
|
+
*
|
|
1145
|
+
* @example
|
|
1146
|
+
* // Create a MultiSeries from JSON series
|
|
1147
|
+
* const s5 = new Series([{ a: 1, b: "apple" }]);
|
|
1148
|
+
* const s6 = new Series([{ a: 2, b: "banana" }]);
|
|
1149
|
+
* const ms4 = new MultiSeries([s5, s6]);
|
|
1150
|
+
*
|
|
1151
|
+
* @example
|
|
1152
|
+
* // Add series to an existing MultiSeries
|
|
1153
|
+
* const ms5 = new MultiSeries();
|
|
1154
|
+
* ms5.push(s1);
|
|
1155
|
+
* ms5.push(s2);
|
|
1156
|
+
*
|
|
1157
|
+
* @example
|
|
1158
|
+
* // Combine two MultiSeries
|
|
1159
|
+
* const ms6 = new MultiSeries([s1]);
|
|
1160
|
+
* const ms7 = new MultiSeries([s2]);
|
|
1161
|
+
* ms6.push(ms7);
|
|
1162
|
+
*
|
|
1163
|
+
* @throws Error if attempting to add a series with a different data type
|
|
1164
|
+
*/
|
|
943
1165
|
constructor(series: Array<Series<T>> = []) {
|
|
944
1166
|
if (series.length !== 0) {
|
|
945
1167
|
const type = series[0].dataType;
|
|
@@ -950,10 +1172,23 @@ export class MultiSeries<T extends TelemValue = TelemValue> implements Iterable<
|
|
|
950
1172
|
this.series = series;
|
|
951
1173
|
}
|
|
952
1174
|
|
|
1175
|
+
/**
|
|
1176
|
+
* Reinterprets the series as containing strings as its JS primitive type.
|
|
1177
|
+
* @throws if the series does not have a data type of STRING or JSON.
|
|
1178
|
+
*/
|
|
953
1179
|
as(jsType: "string"): MultiSeries<string>;
|
|
954
1180
|
|
|
1181
|
+
/**
|
|
1182
|
+
* Reinterprets the series as containing numbers as its JS primitive type.
|
|
1183
|
+
* @throws if the series does not have a numeric data type.
|
|
1184
|
+
*/
|
|
955
1185
|
as(jsType: "number"): MultiSeries<number>;
|
|
956
1186
|
|
|
1187
|
+
/**
|
|
1188
|
+
* Reinterprets the series as containing bigints as its JS primitive type.
|
|
1189
|
+
* @throws if the series does not have a data type that requires bigints i.e.
|
|
1190
|
+
* INT64 and UINT64.
|
|
1191
|
+
*/
|
|
957
1192
|
as(jsType: "bigint"): MultiSeries<bigint>;
|
|
958
1193
|
|
|
959
1194
|
as<T extends TelemValue>(jsType: "string" | "number" | "bigint"): MultiSeries<T> {
|
|
@@ -961,11 +1196,20 @@ export class MultiSeries<T extends TelemValue = TelemValue> implements Iterable<
|
|
|
961
1196
|
return this as unknown as MultiSeries<T>;
|
|
962
1197
|
}
|
|
963
1198
|
|
|
1199
|
+
/**
|
|
1200
|
+
* Returns the data type of the series in this collection. If the collection is empty,
|
|
1201
|
+
* returns DataType.UNKNOWN.
|
|
1202
|
+
*/
|
|
964
1203
|
get dataType(): DataType {
|
|
965
1204
|
if (this.series.length === 0) return DataType.UNKNOWN;
|
|
966
1205
|
return this.series[0].dataType;
|
|
967
1206
|
}
|
|
968
1207
|
|
|
1208
|
+
/**
|
|
1209
|
+
* Returns the combined time range of all series in the collection. If the collection
|
|
1210
|
+
* is empty, returns TimeRange.ZERO. The time range spans from the start of the first
|
|
1211
|
+
* series to the end of the last series.
|
|
1212
|
+
*/
|
|
969
1213
|
get timeRange(): TimeRange {
|
|
970
1214
|
if (this.series.length === 0) return TimeRange.ZERO;
|
|
971
1215
|
return new TimeRange(
|
|
@@ -974,11 +1218,20 @@ export class MultiSeries<T extends TelemValue = TelemValue> implements Iterable<
|
|
|
974
1218
|
);
|
|
975
1219
|
}
|
|
976
1220
|
|
|
1221
|
+
/**
|
|
1222
|
+
* Returns the alignment of the first series in the collection. If the collection is
|
|
1223
|
+
* empty, returns 0n.
|
|
1224
|
+
*/
|
|
977
1225
|
get alignment(): bigint {
|
|
978
1226
|
if (this.series.length === 0) return 0n;
|
|
979
1227
|
return this.series[0].alignment;
|
|
980
1228
|
}
|
|
981
1229
|
|
|
1230
|
+
/**
|
|
1231
|
+
* Returns the alignment bounds of the entire collection. The lower bound is the
|
|
1232
|
+
* alignment of the first series, and the upper bound is the alignment of the last
|
|
1233
|
+
* series + its length. If the collection is empty, returns bounds.construct(0n, 0n).
|
|
1234
|
+
*/
|
|
982
1235
|
get alignmentBounds(): bounds.Bounds<bigint> {
|
|
983
1236
|
if (this.series.length === 0) return bounds.construct(0n, 0n);
|
|
984
1237
|
return bounds.construct(
|
|
@@ -987,27 +1240,49 @@ export class MultiSeries<T extends TelemValue = TelemValue> implements Iterable<
|
|
|
987
1240
|
);
|
|
988
1241
|
}
|
|
989
1242
|
|
|
1243
|
+
/**
|
|
1244
|
+
* Adds a series or another MultiSeries to this collection.
|
|
1245
|
+
* @param series - The series or MultiSeries to add. Must have the same data type
|
|
1246
|
+
* as the existing series in this collection.
|
|
1247
|
+
* @throws Error if the series being added has a different data type
|
|
1248
|
+
*/
|
|
990
1249
|
push(series: Series<T>): void;
|
|
991
1250
|
push(series: MultiSeries<T>): void;
|
|
992
1251
|
|
|
993
1252
|
push(series: Series<T> | MultiSeries<T>): void {
|
|
994
|
-
|
|
995
|
-
|
|
1253
|
+
const invalidDataTypeError = () =>
|
|
1254
|
+
new Error(
|
|
1255
|
+
`cannot push a ${series.dataType.toString()} series to a ${this.dataType.toString()} multi-series`,
|
|
1256
|
+
);
|
|
1257
|
+
const dtsEqual = series.dataType.equals(this.dataType);
|
|
1258
|
+
if (isSeries(series)) {
|
|
1259
|
+
if (this.series.length !== 0 && !dtsEqual) throw invalidDataTypeError();
|
|
1260
|
+
this.series.push(series);
|
|
1261
|
+
} else {
|
|
1262
|
+
if (this.series.length !== 0 && series.series.length !== 0 && !dtsEqual)
|
|
1263
|
+
throw invalidDataTypeError();
|
|
1264
|
+
this.series.push(...series.series);
|
|
1265
|
+
}
|
|
996
1266
|
}
|
|
997
1267
|
|
|
1268
|
+
/**
|
|
1269
|
+
* Returns the total length of all series in the collection.
|
|
1270
|
+
* @returns The sum of the lengths of all series.
|
|
1271
|
+
*/
|
|
998
1272
|
get length(): number {
|
|
999
1273
|
return this.series.reduce((a, b) => a + b.length, 0);
|
|
1000
1274
|
}
|
|
1001
1275
|
|
|
1276
|
+
/**
|
|
1277
|
+
* Returns the value at the specified alignment.
|
|
1278
|
+
* @param alignment - The alignment to get the value at.
|
|
1279
|
+
* @param required - If true, throws an error if the value is not found.
|
|
1280
|
+
* @returns The value at the specified alignment, or undefined if not found.
|
|
1281
|
+
* @throws Error if required is true and the value is not found.
|
|
1282
|
+
*/
|
|
1002
1283
|
atAlignment(alignment: bigint, required: true): T;
|
|
1003
|
-
|
|
1004
1284
|
atAlignment(alignment: bigint, required?: false): T | undefined;
|
|
1005
|
-
|
|
1006
1285
|
atAlignment(alignment: bigint, required?: boolean): T | undefined {
|
|
1007
|
-
if (this.series.length === 0) {
|
|
1008
|
-
if (required) throw new Error(`[series] - no value at alignment ${alignment}`);
|
|
1009
|
-
return undefined;
|
|
1010
|
-
}
|
|
1011
1286
|
for (const ser of this.series)
|
|
1012
1287
|
if (bounds.contains(ser.alignmentBounds, alignment))
|
|
1013
1288
|
return ser.atAlignment(alignment, required as true);
|
|
@@ -1015,10 +1290,15 @@ export class MultiSeries<T extends TelemValue = TelemValue> implements Iterable<
|
|
|
1015
1290
|
return undefined;
|
|
1016
1291
|
}
|
|
1017
1292
|
|
|
1293
|
+
/**
|
|
1294
|
+
* Returns the value at the specified index.
|
|
1295
|
+
* @param index - The index to get the value at.
|
|
1296
|
+
* @param required - If true, throws an error if the value is not found.
|
|
1297
|
+
* @returns The value at the specified index, or undefined if not found.
|
|
1298
|
+
* @throws Error if required is true and the value is not found.
|
|
1299
|
+
*/
|
|
1018
1300
|
at(index: number, required: true): T;
|
|
1019
|
-
|
|
1020
1301
|
at(index: number, required?: false): T | undefined;
|
|
1021
|
-
|
|
1022
1302
|
at(index: number, required: boolean = false): T | undefined {
|
|
1023
1303
|
if (index < 0) index = this.length + index;
|
|
1024
1304
|
for (const ser of this.series) {
|
|
@@ -1029,10 +1309,22 @@ export class MultiSeries<T extends TelemValue = TelemValue> implements Iterable<
|
|
|
1029
1309
|
return undefined;
|
|
1030
1310
|
}
|
|
1031
1311
|
|
|
1312
|
+
/**
|
|
1313
|
+
* Returns an iterator over a portion of the multi-series.
|
|
1314
|
+
* @param start - The start index (inclusive).
|
|
1315
|
+
* @param end - The end index (exclusive).
|
|
1316
|
+
* @returns An iterator over the specified range.
|
|
1317
|
+
*/
|
|
1032
1318
|
subIterator(start: number, end?: number): IterableIterator<T> {
|
|
1033
1319
|
return new MultiSubIterator(this, start, end ?? this.length);
|
|
1034
1320
|
}
|
|
1035
1321
|
|
|
1322
|
+
/**
|
|
1323
|
+
* Returns an iterator over a portion of the multi-series based on alignment.
|
|
1324
|
+
* @param start - The start alignment (inclusive).
|
|
1325
|
+
* @param end - The end alignment (exclusive).
|
|
1326
|
+
* @returns An iterator over the specified alignment range.
|
|
1327
|
+
*/
|
|
1036
1328
|
subAlignmentIterator(start: bigint, end: bigint): IterableIterator<T> {
|
|
1037
1329
|
if (start >= this.alignmentBounds.upper || end <= this.alignmentBounds.lower)
|
|
1038
1330
|
return noopIterableIterator;
|
|
@@ -1059,8 +1351,15 @@ export class MultiSeries<T extends TelemValue = TelemValue> implements Iterable<
|
|
|
1059
1351
|
return new MultiSubIterator(this, startIdx, endIdx);
|
|
1060
1352
|
}
|
|
1061
1353
|
|
|
1354
|
+
/**
|
|
1355
|
+
* Returns an iterator over the specified alignment range and span.
|
|
1356
|
+
* @param start - The start alignment (inclusive).
|
|
1357
|
+
* @param span - The number of samples to include.
|
|
1358
|
+
* @returns An iterator over the specified range.
|
|
1359
|
+
*/
|
|
1062
1360
|
subAlignmentSpanIterator(start: bigint, span: number): IterableIterator<T> {
|
|
1063
1361
|
if (start >= this.alignmentBounds.upper) return noopIterableIterator;
|
|
1362
|
+
span = Math.min(span, Number(this.distance(start, this.alignmentBounds.upper)));
|
|
1064
1363
|
let startIdx = 0;
|
|
1065
1364
|
for (let i = 0; i < this.series.length; i++) {
|
|
1066
1365
|
const ser = this.series[i];
|
|
@@ -1074,18 +1373,32 @@ export class MultiSeries<T extends TelemValue = TelemValue> implements Iterable<
|
|
|
1074
1373
|
return new MultiSubIterator(this, startIdx, startIdx + span);
|
|
1075
1374
|
}
|
|
1076
1375
|
|
|
1376
|
+
/**
|
|
1377
|
+
* Updates the WebGL buffer for all series in the collection.
|
|
1378
|
+
* @param gl - The WebGL buffer controller to use.
|
|
1379
|
+
*/
|
|
1077
1380
|
updateGLBuffer(gl: GLBufferController): void {
|
|
1078
1381
|
this.series.forEach((s) => s.updateGLBuffer(gl));
|
|
1079
1382
|
}
|
|
1080
1383
|
|
|
1384
|
+
/**
|
|
1385
|
+
* Returns the bounds containing the minimum and maximum values across all series.
|
|
1386
|
+
*/
|
|
1081
1387
|
get bounds(): bounds.Bounds {
|
|
1082
1388
|
return bounds.max(this.series.map((s) => s.bounds));
|
|
1083
1389
|
}
|
|
1084
1390
|
|
|
1391
|
+
/**
|
|
1392
|
+
* Returns the sum of the byte lengths of all series.
|
|
1393
|
+
*/
|
|
1085
1394
|
get byteLength(): Size {
|
|
1086
1395
|
return new Size(this.series.reduce((a, b) => a + b.byteLength.valueOf(), 0));
|
|
1087
1396
|
}
|
|
1088
1397
|
|
|
1398
|
+
/**
|
|
1399
|
+
* Returns a combined typed array containing all data from all series.
|
|
1400
|
+
* @returns A typed array containing all data from all series.
|
|
1401
|
+
*/
|
|
1089
1402
|
get data(): TypedArray {
|
|
1090
1403
|
const buf = new this.dataType.Array(this.length);
|
|
1091
1404
|
let offset = 0;
|
|
@@ -1096,30 +1409,60 @@ export class MultiSeries<T extends TelemValue = TelemValue> implements Iterable<
|
|
|
1096
1409
|
return new this.dataType.Array(buf.buffer);
|
|
1097
1410
|
}
|
|
1098
1411
|
|
|
1412
|
+
/**
|
|
1413
|
+
* Traverses the alignment space by a given distance from a start point.
|
|
1414
|
+
* @param start - The starting alignment.
|
|
1415
|
+
* @param dist - The distance to traverse.
|
|
1416
|
+
* @returns The resulting alignment after traversal.
|
|
1417
|
+
*/
|
|
1099
1418
|
traverseAlignment(start: bigint, dist: bigint): bigint {
|
|
1100
1419
|
const b = this.series.map((s) => s.alignmentBounds);
|
|
1101
1420
|
return bounds.traverse(b, start, dist);
|
|
1102
1421
|
}
|
|
1103
1422
|
|
|
1104
|
-
|
|
1105
|
-
|
|
1423
|
+
/**
|
|
1424
|
+
* Acquires a reference to the WebGL buffer for all series.
|
|
1425
|
+
* @param gl - Optional WebGL buffer controller to use.
|
|
1426
|
+
*/
|
|
1427
|
+
acquire(gl?: GLBufferController): void {
|
|
1428
|
+
this.series.forEach((s) => s.acquire(gl));
|
|
1106
1429
|
}
|
|
1107
1430
|
|
|
1431
|
+
/**
|
|
1432
|
+
* Releases the WebGL buffer reference for all series.
|
|
1433
|
+
*/
|
|
1108
1434
|
release(): void {
|
|
1109
1435
|
this.series.forEach((s) => s.release());
|
|
1110
1436
|
}
|
|
1111
1437
|
|
|
1438
|
+
/**
|
|
1439
|
+
* Calculates the number of samples between two alignments in the multi-series.
|
|
1440
|
+
* @param start - The starting alignment.
|
|
1441
|
+
* @param end - The ending alignment.
|
|
1442
|
+
* @returns The distance between the alignments.
|
|
1443
|
+
*/
|
|
1112
1444
|
distance(start: bigint, end: bigint): bigint {
|
|
1113
1445
|
const b = this.series.map((s) => s.alignmentBounds);
|
|
1114
1446
|
return bounds.distance(b, start, end);
|
|
1115
1447
|
}
|
|
1116
1448
|
|
|
1117
|
-
|
|
1449
|
+
/**
|
|
1450
|
+
* Parses a JSON multi-series into an array of values using the provided zod schema.
|
|
1451
|
+
* @template Z - The zod schema type.
|
|
1452
|
+
* @param schema - The zod schema to use to parse the JSON series.
|
|
1453
|
+
* @throws Error if the series does not have a data type of JSON.
|
|
1454
|
+
* @returns An array of values parsed from the JSON series.
|
|
1455
|
+
*/
|
|
1456
|
+
parseJSON<Z extends z.ZodType>(schema: Z): Array<z.infer<Z>> {
|
|
1118
1457
|
if (!this.dataType.equals(DataType.JSON))
|
|
1119
1458
|
throw new Error("cannot parse non-JSON series as JSON");
|
|
1120
1459
|
return this.series.flatMap((s) => s.parseJSON(schema));
|
|
1121
1460
|
}
|
|
1122
1461
|
|
|
1462
|
+
/**
|
|
1463
|
+
* Returns an iterator over all values in the multi-series.
|
|
1464
|
+
* @returns An iterator that yields all values from all series in sequence.
|
|
1465
|
+
*/
|
|
1123
1466
|
[Symbol.iterator](): Iterator<T> {
|
|
1124
1467
|
if (this.series.length === 0)
|
|
1125
1468
|
return {
|
|
@@ -1154,8 +1497,6 @@ class MultiSeriesIterator<T extends TelemValue = TelemValue> implements Iterator
|
|
|
1154
1497
|
[Symbol.iterator](): Iterator<TelemValue | unknown> {
|
|
1155
1498
|
return this;
|
|
1156
1499
|
}
|
|
1157
|
-
|
|
1158
|
-
[Symbol.toStringTag] = "MultiSeriesIterator";
|
|
1159
1500
|
}
|
|
1160
1501
|
|
|
1161
1502
|
class MultiSubIterator<T extends TelemValue = TelemValue>
|