@stdlib/array-index 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/find.js ADDED
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2024 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
+ 'use strict';
20
+
21
+ // MODULES //
22
+
23
+ var cache = require( './cache.js' );
24
+
25
+
26
+ // MAIN //
27
+
28
+ /**
29
+ * Returns an array index object associated with a specified identifier.
30
+ *
31
+ * @private
32
+ * @param {*} id - identifier
33
+ * @returns {(Node|null)} array index object
34
+ */
35
+ function find( id ) { // eslint-disable-line stdlib/no-redeclare
36
+ var node = cache.first();
37
+ while ( node ) {
38
+ if ( node.value.id === id ) {
39
+ return node;
40
+ }
41
+ node = node.next;
42
+ }
43
+ return null;
44
+ }
45
+
46
+
47
+ // EXPORTS //
48
+
49
+ module.exports = find;
package/lib/id.js ADDED
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2024 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
+ 'use strict';
20
+
21
+ // VARIABLES //
22
+
23
+ var COUNTER = -1; // TODO: consider another approach for unique identifier generation. For most cases, this should suffice; however, it is possible that two different libraries, both relying on separate copies of this package, may trigger id collisions in the event that instantiated instances were to interact (e.g., a consumer attempting to free an instance instantiated by another copy of the package, etc).
24
+
25
+
26
+ // MAIN //
27
+
28
+ /**
29
+ * Generates a new identifier.
30
+ *
31
+ * @private
32
+ * @returns {string} identifier
33
+ *
34
+ * @example
35
+ * var v = id();
36
+ * // returns <string>
37
+ */
38
+ function id() {
39
+ COUNTER += 1;
40
+ return COUNTER.toString();
41
+ }
42
+
43
+
44
+ // EXPORTS //
45
+
46
+ module.exports = id;
package/lib/index.js ADDED
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2024 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
+ 'use strict';
20
+
21
+ /**
22
+ * Array index constructor.
23
+ *
24
+ * @module @stdlib/array-index
25
+ *
26
+ * @example
27
+ * var Uint8Array = require( '@stdlib/array-uint8' );
28
+ * var ArrayIndex = require( '@stdlib/array-index' );
29
+ *
30
+ * var x = new Uint8Array( [ 1, 0, 1, 0 ] );
31
+ *
32
+ * var idx = new ArrayIndex( x );
33
+ * // returns <ArrayIndex>
34
+ */
35
+
36
+ // MODULES //
37
+
38
+ var main = require( './main.js' );
39
+
40
+
41
+ // EXPORTS //
42
+
43
+ module.exports = main;
package/lib/main.js ADDED
@@ -0,0 +1,443 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2024 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 */
20
+
21
+ 'use strict';
22
+
23
+ // MODULES //
24
+
25
+ var setReadOnlyAccessor = require( '@stdlib/utils-define-nonenumerable-read-only-accessor' );
26
+ var setReadOnly = require( '@stdlib/utils-define-nonenumerable-read-only-property' );
27
+ var setNonEnumerable = require( '@stdlib/utils-define-nonenumerable-property' );
28
+ var isCollection = require( '@stdlib/assert-is-collection' );
29
+ var isBoolean = require( '@stdlib/assert-is-boolean' ).isPrimitive;
30
+ var isInteger = require( '@stdlib/assert-is-integer' ).isPrimitive;
31
+ var isAccessorArray = require( '@stdlib/array-base-assert-is-accessor-array' );
32
+ var array2json = require( '@stdlib/array-to-json' );
33
+ var dtype = require( '@stdlib/array-dtype' );
34
+ var copy = require( '@stdlib/array-base-copy' );
35
+ var resolveGetter = require( '@stdlib/array-base-resolve-getter' );
36
+ var format = require( '@stdlib/string-format' );
37
+ var defaults = require( './defaults.js' );
38
+ var validate = require( './validate.js' );
39
+ var cache = require( './cache.js' );
40
+ var findArrayIndex = require( './find.js' );
41
+ var generateId = require( './id.js' );
42
+
43
+
44
+ // MAIN //
45
+
46
+ /**
47
+ * Array index constructor.
48
+ *
49
+ * @param {Collection} x - input array
50
+ * @param {Options} [options] - function options
51
+ * @param {boolean} [options.persist=false] - boolean indicating whether to continue persisting an index object after first usage
52
+ * @throws {TypeError} first argument must be an array-like object
53
+ * @throws {TypeError} first argument must be a valid index array
54
+ * @throws {TypeError} options argument must be an object
55
+ * @throws {TypeError} must provide valid options
56
+ * @returns {ArrayIndex} ArrayIndex instance
57
+ *
58
+ * @example
59
+ * var Uint8Array = require( '@stdlib/array-uint8' );
60
+ *
61
+ * var x = new Uint8Array( [ 1, 0, 1, 0 ] );
62
+ *
63
+ * var idx = new ArrayIndex( x );
64
+ * // returns <ArrayIndex>
65
+ */
66
+ function ArrayIndex( x ) {
67
+ var opts;
68
+ var err;
69
+ var get;
70
+ var dt;
71
+ var t;
72
+ var v;
73
+ if ( !(this instanceof ArrayIndex) ) {
74
+ if ( arguments.length > 1 ) {
75
+ return new ArrayIndex( x, arguments[ 1 ] );
76
+ }
77
+ return new ArrayIndex( x );
78
+ }
79
+ if ( !isCollection( x ) ) {
80
+ throw new TypeError( format( 'invalid argument. First argument must be an array-like object. Value: `%s`.', x ) );
81
+ }
82
+ dt = dtype( x );
83
+
84
+ // When provided a "generic" array or an array of an unknown data type, attempt to infer the type of index array...
85
+ if ( dt === 'generic' || dt === null ) {
86
+ get = resolveGetter( x );
87
+ v = get( x, 0 );
88
+
89
+ // Infer the "type" of index array from the first element...
90
+ if ( isBoolean( v ) ) {
91
+ t = 'bool';
92
+ } else if ( isInteger( v ) ) {
93
+ t = 'int';
94
+ } else {
95
+ throw new TypeError( 'invalid argument. First argument must be a valid index array.' );
96
+ }
97
+ } else if ( dt === 'int32' ) {
98
+ t = 'int';
99
+ } else if ( dt === 'uint8' ) {
100
+ t = 'mask';
101
+ } else {
102
+ throw new TypeError( 'invalid argument. First argument must be a valid index array.' );
103
+ }
104
+ // Resolve index options:
105
+ opts = defaults();
106
+ if ( arguments.length > 1 ) {
107
+ err = validate( opts, arguments[ 1 ] );
108
+ if ( err ) {
109
+ throw err;
110
+ }
111
+ }
112
+ // Add the array index to the index cache:
113
+ cache.push({
114
+ 'id': generateId(),
115
+ 'ref': this,
116
+ 'data': x,
117
+ 'type': t,
118
+ 'dtype': dt,
119
+ 'persist': opts.persist
120
+ });
121
+
122
+ // Store a reference to the cache node:
123
+ setReadOnly( this, '_node', cache.last() );
124
+
125
+ // Initialize a boolean flag indicating whether an array index object has been invalidated (i.e., freed):
126
+ setNonEnumerable( this, '_invalidated', false );
127
+
128
+ return this;
129
+ }
130
+
131
+ /**
132
+ * Constructor name.
133
+ *
134
+ * @name name
135
+ * @memberof ArrayIndex
136
+ * @readonly
137
+ * @type {string}
138
+ * @default 'ArrayIndex'
139
+ *
140
+ * @example
141
+ * var str = ArrayIndex.name;
142
+ * // returns 'ArrayIndex'
143
+ */
144
+ setReadOnly( ArrayIndex, 'name', 'ArrayIndex' );
145
+
146
+ /**
147
+ * Frees an array index object associated with a provided identifier.
148
+ *
149
+ * @name free
150
+ * @memberof ArrayIndex
151
+ * @type {Function}
152
+ * @param {string} id - identifier
153
+ * @returns {boolean} boolean indicating whether an array index object was successfully freed
154
+ *
155
+ * @example
156
+ * var Uint8Array = require( '@stdlib/array-uint8' );
157
+ *
158
+ * var idx = new ArrayIndex( new Uint8Array( [ 1, 0, 1, 0 ] ), {
159
+ * 'persist': true
160
+ * });
161
+ * // returns <ArrayIndex>
162
+ *
163
+ * // ...
164
+ *
165
+ * var out = ArrayIndex.free( idx.id );
166
+ * // returns true
167
+ */
168
+ setReadOnly( ArrayIndex, 'free', function free( id ) {
169
+ var node;
170
+ var v;
171
+
172
+ // Retrieve the array index object with the specified identifier:
173
+ node = findArrayIndex( id );
174
+ if ( node === null ) {
175
+ return false;
176
+ }
177
+ v = node.value;
178
+
179
+ // Invalidate the array instance object:
180
+ setReadOnly( v.ref, '_invalidated', true );
181
+
182
+ // Remove the array instance from the cache:
183
+ cache.remove( node );
184
+
185
+ // Remove the reference to the original array:
186
+ v.data = null;
187
+
188
+ return true;
189
+ });
190
+
191
+ /**
192
+ * Returns the array associated with a provided identifier.
193
+ *
194
+ * @name get
195
+ * @memberof ArrayIndex
196
+ * @type {Function}
197
+ * @param {string} id - identifier
198
+ * @returns {(Object|null)} object containing array index data
199
+ *
200
+ * @example
201
+ * var Uint8Array = require( '@stdlib/array-uint8' );
202
+ *
203
+ * var idx = new ArrayIndex( new Uint8Array( [ 1, 0, 1, 0 ] ), {
204
+ * 'persist': true
205
+ * });
206
+ * // returns <ArrayIndex>
207
+ *
208
+ * // ...
209
+ *
210
+ * var o = ArrayIndex.get( idx.id );
211
+ * // returns {...}
212
+ *
213
+ * var d = o.data;
214
+ * // returns <Uint8Array>[ 1, 0, 1, 0 ]
215
+ *
216
+ * var t = o.type;
217
+ * // returns 'mask'
218
+ *
219
+ * var dt = o.dtype;
220
+ * // returns 'uint8'
221
+ */
222
+ setReadOnly( ArrayIndex, 'get', function get( id ) {
223
+ var node;
224
+ var out;
225
+ var v;
226
+
227
+ // Retrieve the array index object with the specified identifier:
228
+ node = findArrayIndex( id );
229
+ if ( node === null ) {
230
+ return null;
231
+ }
232
+ v = node.value;
233
+
234
+ // Assemble the output object:
235
+ out = {
236
+ 'data': v.data,
237
+ 'type': v.type,
238
+ 'dtype': v.dtype
239
+ };
240
+
241
+ // If the array index object should not be persisted, go ahead and remove the object from the cache...
242
+ if ( !v.persist ) {
243
+ ArrayIndex.free( id ); // note: this should come last, after having retrieved all desired array index node data
244
+ }
245
+ return out;
246
+ });
247
+
248
+ /**
249
+ * Returns the underlying array data of array index object.
250
+ *
251
+ * @name data
252
+ * @memberof ArrayIndex.prototype
253
+ * @readonly
254
+ * @type {Collection}
255
+ * @throws {Error} array index is no longer valid
256
+ *
257
+ * @example
258
+ * var Uint8Array = require( '@stdlib/array-uint8' );
259
+ *
260
+ * var idx = new ArrayIndex( new Uint8Array( [ 1, 0, 1, 0 ] ) );
261
+ * // returns <ArrayIndex>
262
+ *
263
+ * var v = idx.data;
264
+ * // returns <Uint8Array>[ 1, 0, 1, 0 ]
265
+ */
266
+ setReadOnlyAccessor( ArrayIndex.prototype, 'data', function get() {
267
+ if ( this._invalidated ) {
268
+ throw new Error( 'invalid operation. This array index instance has already been freed and can no longer be used.' );
269
+ }
270
+ return this._node.value.data;
271
+ });
272
+
273
+ /**
274
+ * Returns the underlying array data type of array index object.
275
+ *
276
+ * @name dtype
277
+ * @memberof ArrayIndex.prototype
278
+ * @readonly
279
+ * @type {string}
280
+ * @throws {Error} array index is no longer valid
281
+ *
282
+ * @example
283
+ * var Uint8Array = require( '@stdlib/array-uint8' );
284
+ *
285
+ * var idx = new ArrayIndex( new Uint8Array( [ 1, 0, 1, 0 ] ) );
286
+ * // returns <ArrayIndex>
287
+ *
288
+ * var t = idx.dtype;
289
+ * // returns 'uint8'
290
+ */
291
+ setReadOnlyAccessor( ArrayIndex.prototype, 'dtype', function get() {
292
+ if ( this._invalidated ) {
293
+ throw new Error( 'invalid operation. This array index instance has already been freed and can no longer be used.' );
294
+ }
295
+ return this._node.value.dtype;
296
+ });
297
+
298
+ /**
299
+ * Returns the identifier associated with an array index object.
300
+ *
301
+ * @name id
302
+ * @memberof ArrayIndex.prototype
303
+ * @readonly
304
+ * @type {string}
305
+ * @throws {Error} array index is no longer valid
306
+ *
307
+ * @example
308
+ * var Uint8Array = require( '@stdlib/array-uint8' );
309
+ *
310
+ * var idx = new ArrayIndex( new Uint8Array( [ 1, 0, 1, 0 ] ) );
311
+ * // returns <ArrayIndex>
312
+ *
313
+ * var id = idx.id;
314
+ * // returns <string>
315
+ */
316
+ setReadOnlyAccessor( ArrayIndex.prototype, 'id', function get() {
317
+ if ( this._invalidated ) {
318
+ throw new Error( 'invalid operation. This array index instance has already been freed and can no longer be used.' );
319
+ }
320
+ return this._node.value.id;
321
+ });
322
+
323
+ /**
324
+ * Returns a boolean indicating if an array index is actively cached.
325
+ *
326
+ * @name isCached
327
+ * @memberof ArrayIndex.prototype
328
+ * @readonly
329
+ * @type {boolean}
330
+ *
331
+ * @example
332
+ * var Uint8Array = require( '@stdlib/array-uint8' );
333
+ *
334
+ * var idx = new ArrayIndex( new Uint8Array( [ 1, 0, 1, 0 ] ) );
335
+ * // returns <ArrayIndex>
336
+ *
337
+ * var out = idx.isCached;
338
+ * // returns true
339
+ */
340
+ setReadOnlyAccessor( ArrayIndex.prototype, 'isCached', function get() {
341
+ return !this._invalidated;
342
+ });
343
+
344
+ /**
345
+ * Returns the type of array index object.
346
+ *
347
+ * @name type
348
+ * @memberof ArrayIndex.prototype
349
+ * @readonly
350
+ * @type {string}
351
+ * @throws {Error} array index is no longer valid
352
+ *
353
+ * @example
354
+ * var Uint8Array = require( '@stdlib/array-uint8' );
355
+ *
356
+ * var idx = new ArrayIndex( new Uint8Array( [ 1, 0, 1, 0 ] ) );
357
+ * // returns <ArrayIndex>
358
+ *
359
+ * var t = idx.type;
360
+ * // returns 'mask'
361
+ */
362
+ setReadOnlyAccessor( ArrayIndex.prototype, 'type', function get() {
363
+ if ( this._invalidated ) {
364
+ throw new Error( 'invalid operation. This array index instance has already been freed and can no longer be used.' );
365
+ }
366
+ return this._node.value.type;
367
+ });
368
+
369
+ /**
370
+ * Serializes an array index object to a string.
371
+ *
372
+ * @name toString
373
+ * @memberof ArrayIndex.prototype
374
+ * @type {Function}
375
+ * @throws {Error} array index is no longer valid
376
+ * @returns {string} serialized array index object
377
+ *
378
+ * @example
379
+ * var Uint8Array = require( '@stdlib/array-uint8' );
380
+ *
381
+ * var idx = new ArrayIndex( new Uint8Array( [ 1, 0, 1, 0 ] ) );
382
+ * // returns <ArrayIndex>
383
+ *
384
+ * var str = idx.toString();
385
+ * // e.g., 'ArrayIndex<0>'
386
+ */
387
+ setReadOnly( ArrayIndex.prototype, 'toString', function toString() {
388
+ var v;
389
+ if ( this._invalidated ) {
390
+ throw new Error( 'invalid operation. This array index instance has already been freed and can no longer be used.' );
391
+ }
392
+ v = this._node.value;
393
+ return 'ArrayIndex<' + v.id + '>';
394
+ });
395
+
396
+ /**
397
+ * Serializes an array index object as a JSON object.
398
+ *
399
+ * ## Notes
400
+ *
401
+ * - `JSON.stringify()` implicitly calls this method when stringifying an `ArrayIndex` instance.
402
+ *
403
+ * @name toJSON
404
+ * @memberof ArrayIndex.prototype
405
+ * @type {Function}
406
+ * @throws {Error} array index is no longer valid
407
+ * @returns {Object} serialized array index object
408
+ *
409
+ * @example
410
+ * var Uint8Array = require( '@stdlib/array-uint8' );
411
+ *
412
+ * var idx = new ArrayIndex( new Uint8Array( [ 1, 0, 1, 0 ] ) );
413
+ * // returns <ArrayIndex>
414
+ *
415
+ * var o = idx.toJSON();
416
+ * // returns { 'type': 'ArrayIndex', 'data': { 'type': 'Uint8Array', 'data': [ 1, 0, 1, 0 ] } }
417
+ */
418
+ setReadOnly( ArrayIndex.prototype, 'toJSON', function toJSON() {
419
+ var v;
420
+ var o;
421
+ if ( this._invalidated ) {
422
+ throw new Error( 'invalid operation. This array index instance has already been freed and can no longer be used.' );
423
+ }
424
+ v = this._node.value;
425
+ if ( v.dtype === 'generic' || v.dtype === null ) {
426
+ if ( isAccessorArray( v.data ) ) {
427
+ o = copy( v.data );
428
+ } else {
429
+ o = v.data;
430
+ }
431
+ } else {
432
+ o = array2json( v.data );
433
+ }
434
+ return {
435
+ 'type': 'ArrayIndex',
436
+ 'data': o
437
+ };
438
+ });
439
+
440
+
441
+ // EXPORTS //
442
+
443
+ module.exports = ArrayIndex;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2024 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
+ 'use strict';
20
+
21
+ // MODULES //
22
+
23
+ var isObject = require( '@stdlib/assert-is-plain-object' );
24
+ var hasOwnProp = require( '@stdlib/assert-has-own-property' );
25
+ var isBoolean = require( '@stdlib/assert-is-boolean' ).isPrimitive;
26
+ var format = require( '@stdlib/string-format' );
27
+
28
+
29
+ // MAIN //
30
+
31
+ /**
32
+ * Validates function options.
33
+ *
34
+ * @private
35
+ * @param {Object} opts - destination object
36
+ * @param {Options} options - function options
37
+ * @param {boolean} [options.persist] - boolean indicating whether to continue persisting an index object after first usage
38
+ * @returns {(Error|null)} null or an error object
39
+ *
40
+ * @example
41
+ * var opts = {};
42
+ * var options = {
43
+ * 'persist': false
44
+ * };
45
+ * var err = validate( opts, options );
46
+ * if ( err ) {
47
+ * throw err;
48
+ * }
49
+ */
50
+ function validate( opts, options ) {
51
+ if ( !isObject( options ) ) {
52
+ return new TypeError( format( 'invalid argument. Options argument must be an object. Value: `%s`.', options ) );
53
+ }
54
+ if ( hasOwnProp( options, 'persist' ) ) {
55
+ opts.persist = options.persist;
56
+ if ( !isBoolean( opts.persist ) ) {
57
+ return new TypeError( format( 'invalid option. `%s` option must be a boolean. Option: `%s`.', 'persist', opts.persist ) );
58
+ }
59
+ }
60
+ return null;
61
+ }
62
+
63
+
64
+ // EXPORTS //
65
+
66
+ module.exports = validate;