@stdlib/array-struct-factory 0.1.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/lib/main.js ADDED
@@ -0,0 +1,573 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2025 The Stdlib Authors.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ /* eslint-disable no-restricted-syntax, no-invalid-this, max-len, max-lines-per-function */
20
+
21
+ 'use strict';
22
+
23
+ // MODULES //
24
+
25
+ var isStructConstructorLike = require( '@stdlib/assert-is-struct-constructor-like' );
26
+ var isNonNegativeInteger = require( '@stdlib/assert-is-nonnegative-integer' ).isPrimitive;
27
+ var isInteger = require( '@stdlib/assert-is-integer' ).isPrimitive;
28
+ var isArrayBuffer = require( '@stdlib/assert-is-arraybuffer' );
29
+ var isCollection = require( '@stdlib/assert-is-collection' );
30
+ var isFunction = require( '@stdlib/assert-is-function' );
31
+ var isObject = require( '@stdlib/assert-is-object' );
32
+ var isPrototypeOf = require( '@stdlib/assert-is-prototype-of' ); // eslint-disable-line stdlib/no-redeclare
33
+ var hasIteratorSymbolSupport = require( '@stdlib/assert-has-iterator-symbol-support' );
34
+ var hasProp = require( '@stdlib/assert-has-property' );
35
+ var contains = require( '@stdlib/array-base-assert-contains' );
36
+ var setReadOnly = require( '@stdlib/utils-define-nonenumerable-read-only-property' );
37
+ var setReadOnlyAccessor = require( '@stdlib/utils-define-nonenumerable-read-only-accessor' );
38
+ var ITERATOR_SYMBOL = require( '@stdlib/symbol-iterator' );
39
+ var ArrayBuffer = require( '@stdlib/array-buffer' );
40
+ var Uint8Array = require( '@stdlib/array-uint8' );
41
+ var getter = require( '@stdlib/array-base-getter' );
42
+ var accessorGetter = require( '@stdlib/array-base-accessor-getter' );
43
+ var gcopy = require( '@stdlib/blas-base-gcopy' ).ndarray;
44
+ var structFactory = require( '@stdlib/dstructs-struct' );
45
+ var format = require( '@stdlib/string-format' );
46
+ var fromArray = require( './from_array.js' );
47
+ var fromIterator = require( './from_iterator.js' );
48
+
49
+
50
+ // VARIABLES //
51
+
52
+ var HAS_ITERATOR_SYMBOL = hasIteratorSymbolSupport();
53
+ var CTOR_NAME = 'StructArray';
54
+
55
+
56
+ // MAIN //
57
+
58
+ /**
59
+ * Returns a constructor for creating arrays having a fixed-width composite data type.
60
+ *
61
+ * @param {(Function|Array<Object>)} arg - struct constructor or struct schema
62
+ * @throws {TypeError} first argument must be either a struct constructor or struct schema
63
+ * @returns {Function} constructor
64
+ *
65
+ * @example
66
+ * var Complex128 = require( '@stdlib/complex-float64-ctor' );
67
+ * var structFactory = require( '@stdlib/dstructs-struct' );
68
+ *
69
+ * var schema1 = [
70
+ * {
71
+ * 'name': 're',
72
+ * 'type': 'float64'
73
+ * },
74
+ * {
75
+ * 'name': 'im',
76
+ * 'type': 'float64'
77
+ * }
78
+ * ];
79
+ *
80
+ * // Create a struct constructor for storing real and imaginary components:
81
+ * var Components = structFactory( schema1 );
82
+ *
83
+ * var schema2 = [
84
+ * {
85
+ * 'type': 'union',
86
+ * 'fields': [
87
+ * {
88
+ * 'name': 'value',
89
+ * 'type': 'complex128'
90
+ * },
91
+ * {
92
+ * 'name': 'components',
93
+ * 'type': Components
94
+ * }
95
+ * ]
96
+ * }
97
+ * ];
98
+ *
99
+ * // Create a struct constructor for storing a double-precision complex number:
100
+ * var Complex128Struct = structFactory( schema2 );
101
+ *
102
+ * // Create an array constructor for storing complex numbers:
103
+ * var Complex128Array = factory( Complex128Struct );
104
+ *
105
+ * // Create a new array:
106
+ * var x = new Complex128Array( 10 );
107
+ * // returns <StructArray>
108
+ *
109
+ * // Retrieve the first element:
110
+ * var v1 = x.get( 0 );
111
+ *
112
+ * // Resolve the complex number stored within the first element:
113
+ * var z1 = v1.value;
114
+ * // returns <Complex128>[ 0.0, 0.0 ]
115
+ *
116
+ * // Resolve the individual real and imaginary components:
117
+ * var z2 = v1.components;
118
+ *
119
+ * var re = z2.re;
120
+ * // returns 0.0
121
+ *
122
+ * var im = z2.im;
123
+ * // returns 0.0
124
+ *
125
+ * // Create a new complex number struct:
126
+ * var z3 = new Complex128Struct({
127
+ * 'value': new Complex128( 3.0, 5.0 )
128
+ * });
129
+ *
130
+ * // Update the first element of the array:
131
+ * x.set( z3, 0 );
132
+ *
133
+ * // As `v1` is a view on same memory as the first element, resolve the complex number stored within the element:
134
+ * var z4 = v1.value;
135
+ * // returns <Complex128>[ 3.0, 5.0 ]
136
+ */
137
+ function factory( arg ) { // eslint-disable-line stdlib/jsdoc-require-throws-tags
138
+ var BYTES_PER_ELEMENT;
139
+ var LAYOUT;
140
+ var FIELDS;
141
+ var Struct;
142
+
143
+ // FIXME: add option support for strict input object validation (e.g., throw whenever non-struct properties are included on an object passed to `set`)
144
+
145
+ if ( isCollection( arg ) ) {
146
+ Struct = structFactory( arg ); // NOTE: delegate to `structFactory` to perform input validation
147
+ } else if ( isStructConstructorLike( arg ) ) {
148
+ Struct = arg;
149
+ } else {
150
+ throw new TypeError( format( 'invalid argument. First argument must be either a struct constructor or struct schema. Value: `%s`.', arg ) );
151
+ }
152
+ BYTES_PER_ELEMENT = Struct.byteLength;
153
+ LAYOUT = Struct.layout; // TODO: consider whether to lazily materialize the struct layout, as this could potentially be a long string (hence increased memory consumption) depending on the complexity of the struct
154
+ FIELDS = Struct.fields;
155
+
156
+ /**
157
+ * Constructor which returns an array having a fixed-width composite data type.
158
+ *
159
+ * @private
160
+ * @constructor
161
+ * @param {(NonNegativeInteger|Collection|ArrayBuffer|Iterable)} [arg] - length, typed array, array-like object, buffer, or an iterable
162
+ * @param {NonNegativeInteger} [byteOffset=0] - byte offset
163
+ * @param {NonNegativeInteger} [length] - view length
164
+ * @throws {TypeError} must provide a valid first argument
165
+ * @throws {TypeError} second argument must be a nonnegative integer
166
+ * @throws {TypeError} third argument must be a nonnegative integer
167
+ * @throws {RangeError} must provide sufficient memory to accommodate byte offset and view length requirements
168
+ * @throws {RangeError} second argument must be a multiple of struct byte length
169
+ * @throws {RangeError} second argument must not exceeds the ArrayBuffer bounds
170
+ * @throws {TypeError} view length must be a positive multiple of struct byte length
171
+ * @throws {TypeError} an input array must contain valid elements
172
+ * @returns {StructArray} struct array instance
173
+ */
174
+ function StructArray( arg, byteOffset, length ) {
175
+ var nargs;
176
+ var buf;
177
+ var len;
178
+ var tmp;
179
+
180
+ nargs = arguments.length;
181
+ if ( !( this instanceof StructArray) ) {
182
+ if ( nargs === 0 ) {
183
+ return new StructArray();
184
+ }
185
+ if ( nargs === 1 ) {
186
+ return new StructArray( arg );
187
+ }
188
+ if ( nargs === 2 ) {
189
+ return new StructArray( arg, byteOffset );
190
+ }
191
+ return new StructArray( arg, byteOffset, length );
192
+ }
193
+
194
+ // Case: new StructArray()
195
+ if ( nargs === 0 ) {
196
+ buf = new ArrayBuffer( 0 );
197
+ len = 0;
198
+ }
199
+ // Case: new StructArray( arg )
200
+ else if ( nargs === 1 ) {
201
+ // Case: new StructArray( length )
202
+ if ( isNonNegativeInteger( arg ) ) {
203
+ buf = new ArrayBuffer( arg*BYTES_PER_ELEMENT );
204
+ len = arg;
205
+ }
206
+ // Case: new StructArray( collection )
207
+ else if ( isCollection( arg ) ) {
208
+ len = arg.length;
209
+ buf = fromArray( Struct, new ArrayBuffer( len*BYTES_PER_ELEMENT ), arg );
210
+ if ( buf === null ) {
211
+ throw new TypeError( format( 'invalid argument. Each element of a provided input array must be a valid object or a struct instance having the same layout as elements in the desired output array.' ) );
212
+ }
213
+ }
214
+ // Case: new StructArray( ArrayBuffer )
215
+ else if ( isArrayBuffer( arg ) ) {
216
+ buf = arg;
217
+ len = buf.byteLength / BYTES_PER_ELEMENT;
218
+ if ( !isInteger( len ) ) {
219
+ throw new RangeError( format( 'invalid argument. ArrayBuffer byte length must be a multiple of %u. Byte length: `%u`.', BYTES_PER_ELEMENT, buf.byteLength ) );
220
+ }
221
+ }
222
+ // Case: new StructArray( iterable )
223
+ else if ( isObject( arg ) ) {
224
+ if ( HAS_ITERATOR_SYMBOL === false ) {
225
+ throw new TypeError( format( 'invalid argument. Environment lacks Symbol.iterator support. First argument must be a length, ArrayBuffer, typed array, or array-like object. Value: `%s`.', arg ) );
226
+ }
227
+ if ( !isFunction( arg[ ITERATOR_SYMBOL ] ) ) {
228
+ throw new TypeError( format( 'invalid argument. First argument must be a length, ArrayBuffer, typed array, array-like object, or an iterable. Value: `%s`.', arg ) );
229
+ }
230
+ buf = arg[ ITERATOR_SYMBOL ]();
231
+ if ( !isFunction( buf.next ) ) {
232
+ throw new TypeError( format( 'invalid argument. First argument must be a length, ArrayBuffer, typed array, array-like object, or an iterable. Value: `%s`.', arg ) );
233
+ }
234
+ tmp = fromIterator( buf );
235
+ len = tmp.length;
236
+ buf = fromArray( Struct, new ArrayBuffer( len*BYTES_PER_ELEMENT ), tmp );
237
+ if ( buf === null ) {
238
+ throw new TypeError( format( 'invalid argument. Each element of a provided input iterable must be either a valid object or a struct instance having the same layout as elements in the desired output array.' ) );
239
+ }
240
+ }
241
+ // Case: new StructArray( ???? )
242
+ else {
243
+ throw new TypeError( format( 'invalid argument. First argument must be a length, ArrayBuffer, typed array, array-like object, or an iterable. Value: `%s`.', arg ) );
244
+ }
245
+ }
246
+ // Case: new StructArray( ArrayBuffer, byteOffset[, length] )
247
+ else {
248
+ buf = arguments[ 0 ];
249
+ if ( !isArrayBuffer( buf ) ) {
250
+ throw new TypeError( format( 'invalid argument. First argument must be an ArrayBuffer. Value: `%s`.', arg ) );
251
+ }
252
+ if ( !isNonNegativeInteger( byteOffset ) ) {
253
+ throw new TypeError( format( 'invalid argument. Second argument must be a nonnegative integer. Value: `%s`.', byteOffset ) );
254
+ }
255
+ if ( !isInteger( byteOffset/BYTES_PER_ELEMENT ) ) {
256
+ throw new RangeError( format( 'invalid argument. Second argument must be a multiple of %u. Value: `%u`.', BYTES_PER_ELEMENT, byteOffset ) );
257
+ }
258
+ if ( byteOffset >= buf.byteLength ) {
259
+ throw new RangeError( format( 'invalid argument. Second argument exceeds the bounds of the ArrayBuffer. Value: `%s`.', byteOffset ) );
260
+ }
261
+ // Case: new StructArray( ArrayBuffer, byteOffset )
262
+ if ( nargs === 2 ) {
263
+ len = ( buf.byteLength - byteOffset ) / BYTES_PER_ELEMENT;
264
+ if ( !isInteger( len ) ) {
265
+ throw new RangeError( format( 'invalid argument. ArrayBuffer view byte length must be a multiple of %u. View byte length: `%u`.', BYTES_PER_ELEMENT, buf.byteLength-byteOffset ) );
266
+ }
267
+ }
268
+ // Case: new StructArray( ArrayBuffer, byteOffset, length )
269
+ else {
270
+ len = length;
271
+ if ( !isNonNegativeInteger( len ) ) {
272
+ throw new TypeError( format( 'invalid argument. Third argument must be a nonnegative integer. Value: `%s`.', len ) );
273
+ }
274
+ if ( (len*BYTES_PER_ELEMENT) > (buf.byteLength-byteOffset) ) {
275
+ throw new RangeError( format( 'invalid arguments. ArrayBuffer has insufficient capacity. Either decrease the array length or provide a bigger buffer. Minimum capacity: `%u`.', len*BYTES_PER_ELEMENT ) );
276
+ }
277
+ }
278
+ }
279
+ setReadOnly( this, '_buffer', buf );
280
+ setReadOnly( this, '_byteOffset', byteOffset || 0 );
281
+ setReadOnly( this, '_byteLength', len*BYTES_PER_ELEMENT );
282
+ setReadOnly( this, '_length', len );
283
+ return this;
284
+ }
285
+
286
+ /**
287
+ * Size (in bytes) of each array element.
288
+ *
289
+ * @private
290
+ * @name BYTES_PER_ELEMENT
291
+ * @memberof StructArray
292
+ * @readonly
293
+ * @type {PositiveInteger}
294
+ */
295
+ setReadOnly( StructArray, 'BYTES_PER_ELEMENT', BYTES_PER_ELEMENT );
296
+
297
+ /**
298
+ * Constructor name.
299
+ *
300
+ * @private
301
+ * @name name
302
+ * @memberof StructArray
303
+ * @readonly
304
+ * @type {string}
305
+ */
306
+ setReadOnly( StructArray, 'name', CTOR_NAME );
307
+
308
+ /**
309
+ * Element constructor.
310
+ *
311
+ * @private
312
+ * @name struct
313
+ * @memberof StructArray
314
+ * @readonly
315
+ * @type {Function}
316
+ */
317
+ setReadOnly( StructArray, 'struct', Struct );
318
+
319
+ /**
320
+ * Pointer to the underlying data buffer.
321
+ *
322
+ * @private
323
+ * @name buffer
324
+ * @memberof StructArray.prototype
325
+ * @readonly
326
+ * @type {ArrayBuffer}
327
+ */
328
+ setReadOnlyAccessor( StructArray.prototype, 'buffer', function get() {
329
+ return this._buffer;
330
+ });
331
+
332
+ /**
333
+ * Size (in bytes) of the array.
334
+ *
335
+ * @private
336
+ * @name byteLength
337
+ * @memberof StructArray.prototype
338
+ * @readonly
339
+ * @type {NonNegativeInteger}
340
+ */
341
+ setReadOnlyAccessor( StructArray.prototype, 'byteLength', function get() {
342
+ return this._byteLength;
343
+ });
344
+
345
+ /**
346
+ * Offset (in bytes) of the array from the start of its underlying `ArrayBuffer`.
347
+ *
348
+ * @private
349
+ * @name byteOffset
350
+ * @memberof StructArray.prototype
351
+ * @readonly
352
+ * @type {NonNegativeInteger}
353
+ */
354
+ setReadOnlyAccessor( StructArray.prototype, 'byteOffset', function get() {
355
+ return this._byteOffset;
356
+ });
357
+
358
+ /**
359
+ * Size (in bytes) of each array element.
360
+ *
361
+ * @private
362
+ * @name BYTES_PER_ELEMENT
363
+ * @memberof StructArray.prototype
364
+ * @readonly
365
+ * @type {PositiveInteger}
366
+ */
367
+ setReadOnly( StructArray.prototype, 'BYTES_PER_ELEMENT', StructArray.BYTES_PER_ELEMENT );
368
+
369
+ /**
370
+ * Returns an array element.
371
+ *
372
+ * @private
373
+ * @name get
374
+ * @memberof StructArray.prototype
375
+ * @type {Function}
376
+ * @param {NonNegativeInteger} idx - element index
377
+ * @throws {TypeError} `this` must be a struct array instance
378
+ * @throws {TypeError} must provide a nonnegative integer
379
+ * @returns {(*|void)} array element
380
+ */
381
+ setReadOnly( StructArray.prototype, 'get', function get( idx ) {
382
+ if ( !isStructArray( this ) ) {
383
+ throw new TypeError( format( 'invalid invocation. `this` is not a %s.', CTOR_NAME ) );
384
+ }
385
+ if ( !isNonNegativeInteger( idx ) ) {
386
+ throw new TypeError( format( 'invalid argument. Must provide a nonnegative integer. Value: `%s`.', idx ) );
387
+ }
388
+ if ( idx >= this._length ) {
389
+ return;
390
+ }
391
+ return new Struct( this._buffer, this._byteOffset+( idx*BYTES_PER_ELEMENT ), BYTES_PER_ELEMENT );
392
+ });
393
+
394
+ /**
395
+ * Number of array elements.
396
+ *
397
+ * @private
398
+ * @name length
399
+ * @memberof StructArray.prototype
400
+ * @readonly
401
+ * @type {NonNegativeInteger}
402
+ */
403
+ setReadOnlyAccessor( StructArray.prototype, 'length', function get() {
404
+ return this._length;
405
+ });
406
+
407
+ /**
408
+ * Sets an array element.
409
+ *
410
+ * ## Notes
411
+ *
412
+ * - When provided a struct array, we must check whether the source array shares the same buffer as the target array and whether the underlying memory overlaps. In particular, we are concerned with the following scenario:
413
+ *
414
+ * ```text
415
+ * buf: ---------------------
416
+ * src: ---------------------
417
+ * ```
418
+ *
419
+ * In the above, as we copy values from `src`, we will overwrite values in the `src` view, resulting in duplicated values copied into the end of `buf`, which is not intended. Hence, to avoid overwriting source values, we must **copy** source values to a temporary array.
420
+ *
421
+ * In the other overlapping scenario,
422
+ *
423
+ * ```text
424
+ * buf: ---------------------
425
+ * src: ---------------------
426
+ * ```
427
+ *
428
+ * by the time we begin copying into the overlapping region, we are copying from the end of `src`, a non-overlapping region, which means we don't run the risk of copying copied values, rather than the original `src` values, as intended.
429
+ *
430
+ * @private
431
+ * @name set
432
+ * @memberof StructArray.prototype
433
+ * @type {Function}
434
+ * @param {(Collection|StructArray|Struct|Object)} value - value(s)
435
+ * @param {NonNegativeInteger} [i=0] - element index at which to start writing values
436
+ * @throws {TypeError} `this` must be a struct array instance
437
+ * @throws {TypeError} index argument must be a nonnegative integer
438
+ * @throws {RangeError} index argument is out-of-bounds
439
+ * @throws {RangeError} target array lacks sufficient storage to accommodate source values
440
+ * @throws {TypeError} must provide a valid object or a struct instance having the same layout as elements in the target array
441
+ * @returns {void}
442
+ */
443
+ setReadOnly( StructArray.prototype, 'set', function set( value ) {
444
+ var bbytes;
445
+ var sbytes;
446
+ var sbuf;
447
+ var opts;
448
+ var idx;
449
+ var buf;
450
+ var tmp;
451
+ var get;
452
+ var nb;
453
+ var N;
454
+ var s;
455
+ var f;
456
+ var i;
457
+ var j;
458
+ if ( !isStructArray( this ) ) {
459
+ throw new TypeError( format( 'invalid invocation. `this` is not a %s.', CTOR_NAME ) );
460
+ }
461
+ buf = this._buffer;
462
+ if ( arguments.length > 1 ) {
463
+ idx = arguments[ 1 ];
464
+ if ( !isNonNegativeInteger( idx ) ) {
465
+ throw new TypeError( format( 'invalid argument. Index argument must be a nonnegative integer. Value: `%s`.', idx ) );
466
+ }
467
+ } else {
468
+ idx = 0;
469
+ }
470
+ opts = {
471
+ 'format': 'layout'
472
+ };
473
+ nb = Struct.byteLength;
474
+
475
+ if ( isCollection( value ) && !contains( FIELDS, 'length' ) ) { // note: when one of the fields is 'length', we always assume that a provided value with a 'length' property is a struct and/or data object as there doesn't seem to be a surefire way to distinguish such an object from a regular array-like object (including accessor arrays)
476
+ N = value.length;
477
+ if ( idx+N > this._length ) {
478
+ throw new RangeError( 'invalid arguments. Target array lacks sufficient storage to accommodate source values.' );
479
+ }
480
+ sbuf = value;
481
+ if ( sbuf.get && sbuf.set ) {
482
+ get = accessorGetter( 'default' );
483
+ } else {
484
+ get = getter( 'default' );
485
+ }
486
+ // Check for overlapping memory...
487
+ j = this._byteOffset + (idx*BYTES_PER_ELEMENT);
488
+ if (
489
+ sbuf.buffer === buf &&
490
+ (
491
+ sbuf.byteOffset < j &&
492
+ sbuf.byteOffset+sbuf.byteLength > j
493
+ )
494
+ ) {
495
+ // FIXME: add optimization when `value` is a StructArray sharing the same buffer and having the same layout; in which case, we can simply copy `src` bytes to a temporary array and then copy those bytes into the target array, without needing to intermediate struct instance materialization
496
+
497
+ // We need to copy source values...
498
+ tmp = [];
499
+ for ( i = 0; i < N; i++ ) {
500
+ tmp.push( get( value, i ) );
501
+ }
502
+ sbuf = tmp;
503
+ get = getter( 'default' );
504
+ }
505
+ for ( i = 0; i < N; idx++, i++ ) {
506
+ this.set( get( sbuf, i ), idx ); // note: this likely isn't the most performant approach, but it avoids having to replicate branching logic for handling struct instances vs data objects
507
+ }
508
+ return;
509
+ }
510
+ if ( idx >= this._length ) {
511
+ throw new RangeError( format( 'invalid argument. Index argument is out-of-bounds. Value: `%u`.', idx ) );
512
+ }
513
+ if ( !isObject( value ) ) {
514
+ throw new TypeError( format( 'invalid argument. Must provide either a valid object or a struct instance. Value: `%s`.', value ) );
515
+ }
516
+ // Check for a struct instance having a matching layout...
517
+ if ( value.toString( opts ) === LAYOUT ) {
518
+ // Explicitly copy the bytes of the input struct instance to the corresponding array element...
519
+ sbuf = Struct.viewOf( value );
520
+ sbytes = new Uint8Array( sbuf.buffer, sbuf.byteOffset, nb );
521
+ bbytes = new Uint8Array( buf, this._byteOffset+( idx*BYTES_PER_ELEMENT ), nb );
522
+ gcopy( nb, sbytes, 1, 0, bbytes, 1, 0 );
523
+ return;
524
+ }
525
+ // Create a struct instance view for the target element:
526
+ s = new Struct( buf, this._byteOffset+( idx*BYTES_PER_ELEMENT ), nb );
527
+
528
+ // Assign field values from the input object (accounting for both own and inherited properties)...
529
+ for ( i = 0; i < FIELDS.length; i++ ) {
530
+ f = FIELDS[ i ];
531
+ if ( hasProp( value, f ) ) {
532
+ s[ f ] = value[ f ];
533
+ }
534
+ }
535
+ });
536
+
537
+ /**
538
+ * Element constructor.
539
+ *
540
+ * @private
541
+ * @name struct
542
+ * @memberof StructArray.prototype
543
+ * @readonly
544
+ * @type {Function}
545
+ */
546
+ setReadOnly( StructArray.prototype, 'struct', Struct );
547
+
548
+ return StructArray;
549
+
550
+ /**
551
+ * Returns a boolean indicating if a value is a struct array.
552
+ *
553
+ * @private
554
+ * @param {*} value - value to test
555
+ * @returns {boolean} boolean indicating if a value is a struct array
556
+ */
557
+ function isStructArray( value ) {
558
+ return (
559
+ typeof value === 'object' &&
560
+ value !== null &&
561
+ (
562
+ value.constructor.name === CTOR_NAME ||
563
+ isPrototypeOf( value, StructArray.prototype )
564
+ ) &&
565
+ value.BYTES_PER_ELEMENT === BYTES_PER_ELEMENT
566
+ );
567
+ }
568
+ }
569
+
570
+
571
+ // EXPORTS //
572
+
573
+ module.exports = factory;
package/package.json ADDED
@@ -0,0 +1,89 @@
1
+ {
2
+ "name": "@stdlib/array-struct-factory",
3
+ "version": "0.1.0",
4
+ "description": "Return a constructor for creating arrays having a fixed-width composite data type.",
5
+ "license": "Apache-2.0",
6
+ "author": {
7
+ "name": "The Stdlib Authors",
8
+ "url": "https://github.com/stdlib-js/stdlib/graphs/contributors"
9
+ },
10
+ "contributors": [
11
+ {
12
+ "name": "The Stdlib Authors",
13
+ "url": "https://github.com/stdlib-js/stdlib/graphs/contributors"
14
+ }
15
+ ],
16
+ "main": "./lib",
17
+ "directories": {
18
+ "lib": "./lib",
19
+ "dist": "./dist"
20
+ },
21
+ "types": "./docs/types",
22
+ "scripts": {},
23
+ "homepage": "https://stdlib.io",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git://github.com/stdlib-js/array-struct-factory.git"
27
+ },
28
+ "bugs": {
29
+ "url": "https://github.com/stdlib-js/stdlib/issues"
30
+ },
31
+ "dependencies": {
32
+ "@stdlib/array-base-accessor-getter": "^0.2.2",
33
+ "@stdlib/array-base-assert-contains": "^0.2.2",
34
+ "@stdlib/array-base-getter": "^0.2.2",
35
+ "@stdlib/array-buffer": "^0.2.2",
36
+ "@stdlib/array-uint8": "^0.2.2",
37
+ "@stdlib/assert-has-iterator-symbol-support": "^0.2.2",
38
+ "@stdlib/assert-has-property": "^0.2.2",
39
+ "@stdlib/assert-is-arraybuffer": "^0.2.2",
40
+ "@stdlib/assert-is-collection": "^0.2.2",
41
+ "@stdlib/assert-is-function": "^0.2.2",
42
+ "@stdlib/assert-is-integer": "^0.2.2",
43
+ "@stdlib/assert-is-nonnegative-integer": "^0.2.2",
44
+ "@stdlib/assert-is-object": "^0.2.2",
45
+ "@stdlib/assert-is-prototype-of": "^0.2.2",
46
+ "@stdlib/assert-is-struct-constructor-like": "^0.1.0",
47
+ "@stdlib/blas-base-gcopy": "^0.2.2",
48
+ "@stdlib/dstructs-struct": "github:stdlib-js/dstructs-struct#main",
49
+ "@stdlib/string-format": "^0.2.2",
50
+ "@stdlib/symbol-iterator": "^0.2.2",
51
+ "@stdlib/utils-define-nonenumerable-read-only-accessor": "^0.2.3",
52
+ "@stdlib/utils-define-nonenumerable-read-only-property": "^0.2.2",
53
+ "@stdlib/error-tools-fmtprodmsg": "^0.2.2"
54
+ },
55
+ "devDependencies": {},
56
+ "engines": {
57
+ "node": ">=0.10.0",
58
+ "npm": ">2.7.0"
59
+ },
60
+ "os": [
61
+ "aix",
62
+ "darwin",
63
+ "freebsd",
64
+ "linux",
65
+ "macos",
66
+ "openbsd",
67
+ "sunos",
68
+ "win32",
69
+ "windows"
70
+ ],
71
+ "keywords": [
72
+ "stdlib",
73
+ "stdtypes",
74
+ "types",
75
+ "data",
76
+ "structure",
77
+ "array",
78
+ "typed",
79
+ "typed array",
80
+ "typed-array",
81
+ "factory",
82
+ "struct",
83
+ "composite"
84
+ ],
85
+ "funding": {
86
+ "type": "opencollective",
87
+ "url": "https://opencollective.com/stdlib"
88
+ }
89
+ }