• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

visgl / luma.gl / 25990278810

17 May 2026 12:01PM UTC coverage: 75.092% (+0.2%) from 74.881%
25990278810

push

github

web-flow
feat: Columnar GPU-data stack (#2616)

6711 of 10084 branches covered (66.55%)

Branch coverage included in aggregate %.

625 of 865 new or added lines in 22 files covered. (72.25%)

1 existing line in 1 file now uncovered.

14631 of 18337 relevant lines covered (79.79%)

792.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.08
/modules/arrow/src/arrow/arrow-gpu-vector.ts
1
// luma.gl
2
// SPDX-License-Identifier: MIT
3
// Copyright (c) vis.gl contributors
4

5
import {
6
  Buffer,
7
  Device,
8
  type BufferAttributeLayout,
9
  type BufferLayout,
10
  type BufferProps
11
} from '@luma.gl/core';
12
import {DynamicBuffer, type DynamicBufferProps} from '@luma.gl/engine';
13
import * as arrow from 'apache-arrow';
14
import {isInstanceArrowType, type AttributeArrowType} from './arrow-types';
15
import {
16
  GPUData,
17
  getArrowDataBufferSource,
18
  getArrowTypeByteStride,
19
  getArrowTypeStride,
20
  getArrowVectorBufferSource,
21
  readArrowGPUVectorAsync,
22
  validateArrowGPUDataDirectUpload
23
} from './arrow-gpu-data';
24

25
export {
26
  GPUData,
27
  readArrowGPUVectorAsync,
28
  type GPUDataFromBufferProps
29
} from './arrow-gpu-data';
30

31
/** Buffer creation props forwarded when uploading Arrow vector memory to the GPU. */
32
export type GPUVectorBufferProps = Omit<BufferProps, 'byteLength' | 'data'>;
33
/** Dynamic buffer props forwarded when creating appendable Arrow GPU vectors. */
34
export type GPUVectorDynamicBufferProps = Omit<DynamicBufferProps, 'byteLength' | 'data'>;
35

36
/** @deprecated Use {@link GPUVectorBufferProps}. */
37
export type GPUVectorProps = GPUVectorBufferProps;
38

39
/** Constructor props that upload an Arrow vector into a new GPU buffer. */
40
export type GPUVectorFromArrowProps<T extends arrow.DataType = AttributeArrowType> = {
41
  /** Discriminator for Arrow-vector upload construction. */
42
  type: 'arrow';
43
  /** Name used when this vector is added to an {@link GPUTable}. */
44
  name: string;
45
  /** Device that creates the GPU buffer. */
46
  device: Device;
47
  /** Arrow vector whose value memory is uploaded. */
48
  vector: arrow.Vector<T>;
49
  /** Buffer creation props forwarded to the GPU buffer. */
50
  bufferProps?: GPUVectorBufferProps;
51
};
52

53
/** Constructor props that wrap an existing typed GPU buffer. */
54
export type GPUVectorFromBufferProps<T extends AttributeArrowType = AttributeArrowType> = {
55
  /** Discriminator for existing-buffer construction. */
56
  type: 'buffer';
57
  /** Name used when this vector is added to an {@link GPUTable}. */
58
  name: string;
59
  /** Existing GPU buffer. */
60
  buffer: Buffer;
61
  /** Arrow type that describes the values in the buffer. */
62
  arrowType: T;
63
  /** Number of logical rows in the buffer. */
64
  length: number;
65
  /** Byte offset of the first logical row. */
66
  byteOffset?: number;
67
  /** Bytes between adjacent logical rows. Defaults to the byte width of `arrowType`. */
68
  byteStride?: number;
69
  /**
70
   * Whether this vector should destroy the buffer.
71
   *
72
   * Defaults to `false` for wrapped buffers because ownership remains with the caller unless
73
   * explicitly transferred or opted in.
74
   */
75
  ownsBuffer?: boolean;
76
};
77

78
/** Constructor props that wrap one interleaved GPU buffer as opaque Arrow binary rows. */
79
export type GPUVectorFromInterleavedProps = {
80
  /** Discriminator for interleaved-buffer construction. */
81
  type: 'interleaved';
82
  /** Name used when this vector is added to an {@link GPUTable}. */
83
  name: string;
84
  /** Existing interleaved GPU buffer. */
85
  buffer: Buffer;
86
  /** Number of logical rows in the buffer. */
87
  length: number;
88
  /** Byte offset of the first logical row. */
89
  byteOffset?: number;
90
  /** Bytes between adjacent logical rows. */
91
  byteStride: number;
92
  /** Attribute views stored in each interleaved row. */
93
  attributes: BufferAttributeLayout[];
94
  /**
95
   * Whether this vector should destroy the buffer.
96
   *
97
   * Defaults to `false` for wrapped buffers because ownership remains with the caller unless
98
   * explicitly transferred or opted in.
99
   */
100
  ownsBuffer?: boolean;
101
};
102

103
/** Constructor props that expose pre-existing Arrow GPU data chunks as one logical vector. */
104
export type GPUVectorFromDataProps<T extends arrow.DataType = AttributeArrowType> = {
105
  /** Discriminator for chunk-backed construction. */
106
  type: 'data';
107
  /** Name used when this vector is added to an {@link GPUTable}. */
108
  name: string;
109
  /** Arrow type that describes every chunk in `data`. */
110
  arrowType: T;
111
  /** Existing GPU data chunks to expose through this vector. */
112
  data: GPUData<T>[];
113
  /** Bytes between adjacent logical rows. Defaults to the first chunk stride when available. */
114
  byteStride?: number;
115
  /** Optional buffer layout retained for interleaved chunk collections. */
116
  bufferLayout?: BufferLayout;
117
};
118

119
/** Constructor props for an appendable DynamicBuffer-backed Arrow vector. */
120
export type GPUVectorFromAppendableProps<T extends AttributeArrowType = AttributeArrowType> = {
121
  /** Discriminator for appendable DynamicBuffer-backed construction. */
122
  type: 'appendable';
123
  /** Name used when this vector is added to an {@link GPUTable}. */
124
  name: string;
125
  /** Device that creates the DynamicBuffer. */
126
  device: Device;
127
  /** Arrow type that describes appended Arrow data. */
128
  arrowType: T;
129
  /** Initial row capacity. Defaults to `0`. */
130
  initialCapacityRows?: number;
131
  /** Capacity growth multiplier. Defaults to `1.5`. */
132
  capacityGrowthFactor?: number;
133
  /** DynamicBuffer construction props. */
134
  bufferProps?: GPUVectorDynamicBufferProps;
135
};
136

137
/** Discriminated constructor props for {@link GPUVector}. */
138
export type GPUVectorCreateProps<T extends arrow.DataType = AttributeArrowType> =
139
  | GPUVectorFromArrowProps<T>
140
  | (T extends AttributeArrowType ? GPUVectorFromBufferProps<T> : never)
141
  | GPUVectorFromInterleavedProps
142
  | GPUVectorFromDataProps<T>
143
  | (T extends AttributeArrowType ? GPUVectorFromAppendableProps<T> : never);
144

145
/**
146
 * GPU memory and Arrow type metadata derived from one Arrow vector.
147
 *
148
 * The Arrow vector is a construction input only. GPUVector does not retain
149
 * the source vector; it keeps a GPU buffer plus the type, length, and stride that
150
 * describe the uploaded memory.
151
 *
152
 * Ownership is tracked separately from the buffer reference. Vectors constructed
153
 * from Arrow data allocate and own their buffers. Vectors wrapping an existing
154
 * buffer default to non-owning unless `ownsBuffer` is supplied. In-place
155
 * operations can use {@link transferBufferOwnership} to consume one logical
156
 * vector and return another view that becomes responsible for destroying the
157
 * shared buffer.
158
 */
159
export class GPUVector<T extends arrow.DataType = AttributeArrowType> {
160
  /** Name used when this vector is added to an {@link GPUTable}. */
161
  readonly name: string;
162
  /** Arrow type that describes the uploaded vector memory. */
163
  readonly type: T;
164
  /** Number of logical Arrow vector rows uploaded into the GPU buffer. */
165
  length: number;
166
  /** Number of scalar values per logical vector row. */
167
  readonly stride: number;
168
  /** Byte offset of the first logical row in {@link buffer}. */
169
  readonly byteOffset: number;
170
  /** Bytes between adjacent logical rows in {@link buffer}. */
171
  readonly byteStride: number;
172
  /** Optional GPU buffer layout described by this vector. */
173
  readonly bufferLayout?: BufferLayout;
174
  /** GPU data chunk views preserving the source Arrow vector's chunk boundaries. */
175
  readonly data: GPUData<T>[] = [];
178✔
176
  /** Single concrete GPU buffer when this vector is directly bindable as one buffer. */
177
  private _buffer?: Buffer | DynamicBuffer;
178
  /** Whether this vector is responsible for destroying {@link buffer}. */
179
  private _ownsBuffer: boolean;
180
  /** Whether this vector owns chunk-local GPU buffers rather than one aggregate buffer. */
181
  private _ownsDataChunks = false;
178✔
182
  /** Detached batch-local vectors whose buffers are now owned by this aggregate view. */
183
  private readonly _ownedVectors: GPUVector[] = [];
178✔
184
  /** Capacity growth multiplier for appendable DynamicBuffer-backed vectors. */
185
  private readonly capacityGrowthFactor?: number;
186

187
  /** Creates a GPU representation from an Arrow vector without retaining the source vector. */
188
  constructor(device: Device, vector: arrow.Vector<T>, props?: GPUVectorBufferProps);
189
  /** Creates a GPU representation using discriminated construction props. */
190
  constructor(props: GPUVectorCreateProps<T>);
191
  constructor(
192
    deviceOrProps: Device | GPUVectorCreateProps<any>,
193
    vector?: arrow.Vector<T>,
194
    props: GPUVectorBufferProps = {}
178✔
195
  ) {
196
    const constructionProps =
197
      deviceOrProps instanceof Device
178✔
198
        ? ({
199
            type: 'arrow',
200
            name: 'vector',
201
            device: deviceOrProps,
202
            vector: vector!,
203
            bufferProps: props
204
          } satisfies GPUVectorFromArrowProps<T>)
205
        : deviceOrProps;
206

207
    switch (constructionProps.type) {
178✔
208
      case 'arrow': {
209
        const {name, device, vector: arrowVector, bufferProps = {}} = constructionProps;
109✔
210
        this.name = name;
109✔
211
        this.type = arrowVector.type;
109✔
212
        this.length = arrowVector.length;
109✔
213
        if (arrow.DataType.isUtf8(arrowVector.type)) {
109✔
214
          this.stride = 1;
9✔
215
          this.byteOffset = 0;
9✔
216
          this.byteStride = 1;
9✔
217
          for (const arrowData of arrowVector.data) {
9✔
218
            this.data.push(new GPUData(device, arrowData as arrow.Data<T>, bufferProps));
11✔
219
          }
220
          this._ownsBuffer = false;
9✔
221
          this._ownsDataChunks = true;
9✔
222
          return;
9✔
223
        }
224
        if (!isInstanceArrowType(arrowVector.type)) {
100!
NEW
225
          throw new Error(`GPUVector does not support Arrow type ${arrowVector.type}`);
×
226
        }
227
        this.stride = getArrowVectorStride(arrowVector as arrow.Vector<AttributeArrowType>);
100✔
228
        this.byteOffset = 0;
100✔
229
        this.byteStride = getArrowTypeByteStride(arrowVector.type);
100✔
230
        this._buffer = device.createBuffer({
100✔
231
          usage: Buffer.VERTEX | Buffer.STORAGE | Buffer.COPY_DST | Buffer.COPY_SRC,
232
          ...bufferProps,
233
          data: getArrowVectorBufferSource(arrowVector as any)
234
        });
235
        const dataBuffer = createArrowGPUDataBuffer(this._buffer);
100✔
236
        let byteOffset = 0;
100✔
237
        for (const arrowData of arrowVector.data) {
100✔
238
          const gpuData = new GPUData<T>({
101✔
239
            buffer: dataBuffer,
240
            arrowType: arrowData.type as T,
241
            length: arrowData.length,
242
            byteOffset,
243
            byteStride: this.byteStride,
244
            ownsBuffer: false,
245
            sourceData: arrowData as arrow.Data<T>
246
          });
247
          this.data.push(gpuData);
101✔
248
          byteOffset += arrowData.length * this.byteStride;
101✔
249
        }
250
        this._ownsBuffer = true;
100✔
251
        return;
100✔
252
      }
253

254
      case 'buffer': {
255
        const {
256
          name,
257
          buffer,
258
          arrowType,
259
          length,
260
          byteOffset = 0,
12✔
261
          byteStride = getArrowTypeByteStride(arrowType),
12✔
262
          ownsBuffer = false
12✔
263
        } = constructionProps;
12✔
264
        this.name = name;
12✔
265
        this._buffer = buffer;
12✔
266
        this.type = arrowType;
12✔
267
        this.length = length;
12✔
268
        this.stride = getArrowTypeStride(arrowType);
12✔
269
        this.byteOffset = byteOffset;
12✔
270
        this.byteStride = byteStride;
12✔
271
        const dataBuffer = createArrowGPUDataBuffer(buffer);
12✔
272
        this.data.push(
12✔
273
          new GPUData({
274
            buffer: dataBuffer,
275
            arrowType,
276
            length,
277
            byteOffset,
278
            byteStride,
279
            ownsBuffer: false
280
          }) as GPUData<T>
281
        );
282
        this._ownsBuffer = ownsBuffer;
12✔
283
        return;
12✔
284
      }
285

286
      case 'interleaved': {
287
        const {
288
          name,
289
          buffer,
290
          length,
291
          byteOffset = 0,
3✔
292
          byteStride,
293
          attributes,
294
          ownsBuffer = false
3✔
295
        } = constructionProps;
3✔
296
        this.name = name;
3✔
297
        this._buffer = buffer;
3✔
298
        this.type = new arrow.Binary() as T;
3✔
299
        this.length = length;
3✔
300
        this.stride = byteStride;
3✔
301
        this.byteOffset = byteOffset;
3✔
302
        this.byteStride = byteStride;
3✔
303
        this.bufferLayout = {name, byteStride, attributes};
3✔
304
        const dataBuffer = createArrowGPUDataBuffer(buffer);
3✔
305
        this.data.push(
3✔
306
          new GPUData({
307
            buffer: dataBuffer,
308
            arrowType: this.type,
309
            length,
310
            byteOffset,
311
            byteStride,
312
            ownsBuffer: false
313
          })
314
        );
315
        this._ownsBuffer = ownsBuffer;
3✔
316
        return;
3✔
317
      }
318

319
      case 'data': {
320
        const {name, arrowType, data, byteStride, bufferLayout} = constructionProps;
21✔
321
        if (data.some(chunk => !arrow.util.compareTypes(chunk.type, arrowType))) {
21!
322
          throw new Error('GPUVector data chunks must share the declared Arrow type');
×
323
        }
324

325
        this.name = name;
21✔
326
        this.type = arrowType;
21✔
327
        this.length = data.reduce((length, chunk) => length + chunk.length, 0);
21✔
328
        this.stride = data[0]?.stride ?? getArrowTypeStride(arrowType);
21!
329
        this.byteOffset = data.length === 1 ? data[0].byteOffset : 0;
21!
330
        this.byteStride = byteStride ?? data[0]?.byteStride ?? getArrowTypeByteStride(arrowType);
21!
331
        this.bufferLayout = bufferLayout;
21✔
332
        this.data.push(...data);
21✔
333
        this._buffer = data.length === 1 ? data[0].buffer : undefined;
21!
334
        this._ownsBuffer = false;
21✔
335
        return;
21✔
336
      }
337

338
      case 'appendable': {
339
        const {
340
          name,
341
          device,
342
          arrowType,
343
          initialCapacityRows = 0,
33✔
344
          capacityGrowthFactor = 1.5,
33✔
345
          bufferProps
346
        } = constructionProps;
33✔
347
        if (!isInstanceArrowType(arrowType)) {
33✔
348
          throw new Error(`GPUVector does not support Arrow type ${arrowType}`);
1✔
349
        }
350
        this.name = name;
32✔
351
        this.type = arrowType as unknown as T;
32✔
352
        this.length = 0;
32✔
353
        this.stride = getArrowTypeStride(arrowType);
32✔
354
        this.byteOffset = 0;
32✔
355
        this.byteStride = getArrowTypeByteStride(arrowType);
32✔
356
        this._buffer = new DynamicBuffer(device, {
32✔
357
          usage: Buffer.VERTEX | Buffer.STORAGE | Buffer.COPY_DST | Buffer.COPY_SRC,
358
          ...bufferProps,
359
          id: bufferProps?.id ?? `${name}-appendable-arrow-vector`,
64✔
360
          byteLength: Math.max(1, initialCapacityRows * this.byteStride)
361
        });
362
        this.capacityGrowthFactor = capacityGrowthFactor;
33✔
363
        this._ownsBuffer = true;
33✔
364
        return;
33✔
365
      }
366
    }
367
  }
368

369
  /**
370
   * Directly bindable GPU buffer when this vector has one concrete backing buffer.
371
   *
372
   * Aggregate table vectors may span multiple batch-owned buffers. Those vectors
373
   * intentionally require callers to use {@link data} or batch-local vectors.
374
   */
375
  get buffer(): Buffer | DynamicBuffer {
376
    if (!this._buffer) {
195✔
377
      throw new Error('GPUVector.buffer is unavailable for multi-buffer vectors; use data[]');
2✔
378
    }
379
    return this._buffer;
193✔
380
  }
381

382
  /**
383
   * Whether this vector is responsible for destroying {@link buffer}.
384
   *
385
   * `destroy()` only releases the buffer when this is `true`. This value can
386
   * change when ownership is transferred to another same-buffer view.
387
   */
388
  get ownsBuffer(): boolean {
389
    return this._ownsBuffer || this._ownedVectors.some(vector => vector.ownsBuffer);
5✔
390
  }
391

392
  /**
393
   * Adds one already-materialized GPU data chunk to this logical vector.
394
   *
395
   * This preserves ownership on the supplied {@link GPUData}; the vector
396
   * only aggregates metadata and never adopts or destroys that buffer through
397
   * this method.
398
   */
399
  addData(data: GPUData<T>): this {
400
    if (!arrow.util.compareTypes(data.type, this.type)) {
25!
401
      throw new Error('GPUVector.addData() requires matching Arrow data types');
×
402
    }
403
    if (data.byteStride !== this.byteStride) {
25!
404
      throw new Error('GPUVector.addData() requires matching byteStride');
×
405
    }
406

407
    this.data.push(data);
25✔
408
    this.length += data.length;
25✔
409
    if (this.data.length > 1) {
25!
410
      this._buffer = undefined;
25✔
411
    }
412
    return this;
25✔
413
  }
414

415
  /** Number of rows the appendable backing DynamicBuffer can hold without reallocating. */
416
  get capacityRows(): number | undefined {
417
    return this._buffer instanceof DynamicBuffer
51!
418
      ? Math.floor(this._buffer.byteLength / this.byteStride)
419
      : undefined;
420
  }
421

422
  /** Appends one Arrow Data chunk into this vector's trailing DynamicBuffer-backed data storage. */
423
  addToLastData(data: arrow.Data<T & AttributeArrowType>): this {
424
    if (!(this._buffer instanceof DynamicBuffer)) {
49!
425
      throw new Error('GPUVector.addToLastData() requires appendable vector storage');
×
426
    }
427
    if (!arrow.util.compareTypes(data.type, this.type)) {
49!
428
      throw new Error('GPUVector.addToLastData() requires matching Arrow data types');
×
429
    }
430
    validateArrowGPUDataDirectUpload(this.name, data);
49✔
431

432
    const requiredRows = this.length + data.length;
49✔
433
    this.ensureAppendableCapacity(requiredRows);
49✔
434

435
    const byteOffset = this.length * this.byteStride;
49✔
436
    this._buffer.write(getArrowDataBufferSource(data), byteOffset);
49✔
437
    this.data.push(
49✔
438
      new GPUData({
439
        buffer: this._buffer,
440
        arrowType: data.type,
441
        length: data.length,
442
        byteOffset,
443
        byteStride: this.byteStride,
444
        ownsBuffer: false
445
      }) as GPUData<T>
446
    );
447
    this.length = requiredRows;
49✔
448
    return this;
49✔
449
  }
450

451
  /** @deprecated Use {@link addToLastData}. */
452
  addToLastBatch(data: arrow.Data<T & AttributeArrowType>): this {
453
    return this.addToLastData(data);
×
454
  }
455

456
  /** Appends every Arrow Data chunk from one Arrow vector into appendable batch storage. */
457
  addVectorToLastBatch(vector: arrow.Vector<T & AttributeArrowType>): this {
458
    if (!arrow.util.compareTypes(vector.type, this.type)) {
3!
459
      throw new Error('GPUVector.addVectorToLastBatch() requires matching Arrow data types');
×
460
    }
461
    for (const data of vector.data) {
3✔
462
      this.addToLastData(data as arrow.Data<T & AttributeArrowType>);
4✔
463
    }
464
    return this;
3✔
465
  }
466

467
  /** Clears appendable logical rows while retaining the DynamicBuffer allocation. */
468
  resetLastBatch(): this {
469
    if (!(this._buffer instanceof DynamicBuffer)) {
7!
470
      throw new Error('GPUVector.resetLastBatch() requires appendable vector storage');
×
471
    }
472
    this.length = 0;
7✔
473
    this.data.length = 0;
7✔
474
    return this;
7✔
475
  }
476

477
  /** @internal Retains detached batch-local vector ownership under this aggregate vector. */
478
  retainOwnedVectors(vectors: GPUVector[]): this {
479
    this._ownedVectors.push(...vectors);
1✔
480
    return this;
1✔
481
  }
482

483
  /**
484
   * Transfers buffer ownership to another vector that views the same GPU buffer.
485
   *
486
   * This is intended for in-place operations that consume one logical vector and
487
   * return a new logical interpretation of the same bytes. After transfer,
488
   * destroying this vector will not destroy the buffer; destroying `target` will
489
   * destroy it if this vector previously owned it.
490
   */
491
  transferBufferOwnership(target: GPUVector): void {
492
    if (!this._buffer || !target._buffer || target._buffer !== this._buffer) {
1!
493
      throw new Error('GPUVector ownership can only be transferred to the same buffer');
×
494
    }
495
    target._ownsBuffer = this._ownsBuffer;
1✔
496
    this._ownsBuffer = false;
1✔
497
  }
498

499
  /** Reads the GPU buffer contents back into a single non-null Arrow vector. */
500
  async readAsync(): Promise<arrow.Vector<T>> {
501
    if (this.bufferLayout) {
8✔
502
      throw new Error('GPUVector.readAsync() does not support interleaved vectors');
1✔
503
    }
504

505
    if (arrow.DataType.isUtf8(this.type)) {
7✔
506
      const data = await Promise.all(this.data.map(chunk => chunk.readAsync()));
2✔
507
      return new arrow.Vector(data) as arrow.Vector<T>;
1✔
508
    }
509

510
    if (!this._buffer) {
6!
511
      const data = await Promise.all(this.data.map(chunk => chunk.readAsync()));
×
512
      return new arrow.Vector(data) as arrow.Vector<T>;
×
513
    }
514

515
    return readArrowGPUVectorAsync({
6✔
516
      type: this.type as unknown as AttributeArrowType,
517
      buffer: this._buffer,
518
      length: this.length,
519
      byteOffset: this.byteOffset,
520
      byteStride: this.byteStride
521
    }) as unknown as Promise<arrow.Vector<T>>;
522
  }
523

524
  destroy(): void {
525
    if (this._ownsBuffer && this._buffer) {
158✔
526
      this._buffer.destroy();
144✔
527
      this._ownsBuffer = false;
144✔
528
    }
529
    for (const vector of this._ownedVectors.splice(0)) {
158✔
530
      vector.destroy();
2✔
531
    }
532
    if (this._ownsDataChunks) {
158✔
533
      for (const data of this.data) {
9✔
534
        data.destroy();
11✔
535
      }
536
      this._ownsDataChunks = false;
9✔
537
    }
538
  }
539

540
  private ensureAppendableCapacity(requiredRows: number): void {
541
    if (!(this._buffer instanceof DynamicBuffer)) {
48!
542
      throw new Error('GPUVector append capacity requires DynamicBuffer storage');
×
543
    }
544
    const capacityRows = this.capacityRows ?? 0;
48!
545
    if (requiredRows <= capacityRows) {
48✔
546
      return;
8✔
547
    }
548
    const grownRows = Math.ceil(Math.max(capacityRows, 1) * (this.capacityGrowthFactor ?? 1.5));
40!
549
    const nextCapacityRows = Math.max(requiredRows, grownRows);
48✔
550
    this._buffer.ensureSize(nextCapacityRows * this.byteStride, {preserveData: true});
48✔
551
  }
552
}
553

554
function getArrowVectorStride(vector: arrow.Vector<AttributeArrowType>): number {
555
  return getArrowTypeStride(vector.type);
100✔
556
}
557

558
function createArrowGPUDataBuffer(buffer: Buffer | DynamicBuffer): DynamicBuffer {
559
  return buffer instanceof DynamicBuffer
115!
560
    ? buffer
561
    : new DynamicBuffer(buffer.device, {
562
        buffer,
563
        ownsBuffer: false
564
      });
565
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc