main.js (15437B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2018 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 hasBigIntSupport = require( '@stdlib/assert/has-bigint-support' ); 26 var setReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' ); 27 var setReadOnlyAccessor = require( '@stdlib/utils/define-nonenumerable-read-only-accessor' ); 28 var bytesPerElement = require( './../../../base/bytes-per-element' ); 29 var iterationOrder = require( './../../../base/iteration-order' ); 30 var strides2order = require( './../../../base/strides2order' ); 31 var isColumnMajorContiguous = require( './is_column_major_contiguous.js' ); 32 var isRowMajorContiguous = require( './is_row_major_contiguous.js' ); 33 var isContiguous = require( './is_contiguous.js' ); 34 var copyFlags = require( './copy_flags.js' ); 35 var igetValue = require( './iget.js' ); 36 var isetValue = require( './iset.js' ); 37 var setValue = require( './set.js' ); 38 var getValue = require( './get.js' ); 39 var toJSON = require( './tojson.js' ); 40 var toString = require( './tostring.js' ); // eslint-disable-line stdlib/no-redeclare 41 var meta2dataview = require( './meta2dataview.js' ); 42 var meta2dataviewPolyfill = require( './meta2dataview.polyfill.js' ); 43 44 45 // MAIN // 46 47 /** 48 * ndarray constructor. 49 * 50 * ## Notes 51 * 52 * - To create a zero-dimensional array, 53 * 54 * ```javascript 55 * var buffer = [ 1 ]; 56 * var shape = []; 57 * var strides = [ 0 ]; 58 * var offset = 0; 59 * 60 * var out = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 61 * ``` 62 * 63 * @constructor 64 * @param {string} dtype - data type 65 * @param {(ArrayLikeObject|TypedArray|Buffer)} buffer - data buffer 66 * @param {NonNegativeIntegerArray} shape - array shape 67 * @param {IntegerArray} strides - array strides 68 * @param {NonNegativeInteger} offset - index offset 69 * @param {string} order - specifies whether an array is row-major (C-style) or column-major (Fortran-style) 70 * @returns {ndarray} ndarray instance 71 * 72 * @example 73 * var buffer = [ 1, 2, 3, 4, 5, 6 ]; 74 * var shape = [ 3, 2 ]; 75 * var strides = [ 2, 1 ]; 76 * var offset = 0; 77 * 78 * var out = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 79 */ 80 function ndarray( dtype, buffer, shape, strides, offset, order ) { 81 var contiguous; 82 var nbytes; 83 var ord; 84 var len; 85 var i; 86 if ( !(this instanceof ndarray) ) { 87 return new ndarray( dtype, buffer, shape, strides, offset, order ); 88 } 89 // Compute the number of elements... 90 len = 1; 91 for ( i = 0; i < shape.length; i++ ) { 92 len *= shape[ i ]; 93 } 94 // Compute the number of bytes... 95 if ( buffer.BYTES_PER_ELEMENT ) { 96 nbytes = buffer.BYTES_PER_ELEMENT * len; 97 } else { 98 nbytes = null; 99 } 100 // Set private properties... 101 this._byteLength = nbytes; 102 this._bytesPerElement = bytesPerElement( dtype ); 103 this._buffer = buffer; 104 this._dtype = dtype; 105 this._length = len; 106 this._ndims = shape.length; 107 this._offset = offset; 108 this._order = order; 109 this._shape = shape; 110 this._strides = strides; 111 this._accessors = Boolean( buffer.get && buffer.set ); 112 113 this._iterationOrder = iterationOrder( strides ); 114 115 // Determine if the array can be stored contiguously: 116 contiguous = isContiguous( len, shape, strides, offset, this._iterationOrder ); // eslint-disable-line max-len 117 118 // Infer the array "order" from the stride array (this is supplementary to the `order` parameter): 119 ord = strides2order( strides ); 120 121 this._flags = { 122 'ROW_MAJOR_CONTIGUOUS': isRowMajorContiguous( ord, contiguous ), 123 'COLUMN_MAJOR_CONTIGUOUS': isColumnMajorContiguous( ord, contiguous ) 124 }; 125 126 // Initialize a property for caching serialized meta data: 127 this.__meta_dataview__ = null; 128 129 return this; 130 } 131 132 /** 133 * Constructor name. 134 * 135 * @name name 136 * @memberof ndarray 137 * @type {string} 138 * @default 'ndarray' 139 * 140 * @example 141 * var str = ndarray.name; 142 * // returns 'ndarray' 143 */ 144 setReadOnly( ndarray, 'name', 'ndarray' ); 145 146 /** 147 * Size (in bytes) of the array (if known). 148 * 149 * @name byteLength 150 * @memberof ndarray.prototype 151 * @type {(NonNegativeInteger|null)} 152 * 153 * @example 154 * var Float64Array = require( '@stdlib/array/float64' ); 155 * 156 * var buffer = new Float64Array( [ 1, 2, 3, 4, 5, 6 ] ); 157 * var shape = [ 3, 2 ]; 158 * var strides = [ 2, 1 ]; 159 * var offset = 0; 160 * 161 * var x = ndarray( 'float64', buffer, shape, strides, offset, 'row-major' ); 162 * 163 * var byteLength = x.byteLength; 164 * // returns 48 165 */ 166 setReadOnlyAccessor( ndarray.prototype, 'byteLength', function get() { 167 return this._byteLength; 168 }); 169 170 /** 171 * Size (in bytes) of each array element (if known). 172 * 173 * @name BYTES_PER_ELEMENT 174 * @memberof ndarray.prototype 175 * @type {(PositiveInteger|null)} 176 * 177 * @example 178 * var Float64Array = require( '@stdlib/array/float64' ); 179 * 180 * var buffer = new Float64Array( [ 1, 2, 3, 4, 5, 6 ] ); 181 * var shape = [ 3, 2 ]; 182 * var strides = [ 2, 1 ]; 183 * var offset = 0; 184 * 185 * var x = ndarray( 'float64', buffer, shape, strides, offset, 'row-major' ); 186 * 187 * var nbytes = x.BYTES_PER_ELEMENT; 188 * // returns 8 189 */ 190 setReadOnlyAccessor( ndarray.prototype, 'BYTES_PER_ELEMENT', function get() { 191 return this._bytesPerElement; 192 }); 193 194 /** 195 * Pointer to the underlying data buffer. 196 * 197 * @name data 198 * @memberof ndarray.prototype 199 * @type {(Array|TypedArray|Buffer)} 200 * 201 * @example 202 * var buffer = [ 1, 2, 3, 4, 5, 6 ]; 203 * var shape = [ 3, 2 ]; 204 * var strides = [ 2, 1 ]; 205 * var offset = 0; 206 * 207 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 208 * 209 * var data = x.data; 210 * // returns [ 1, 2, 3, 4, 5, 6 ] 211 */ 212 setReadOnlyAccessor( ndarray.prototype, 'data', function get() { 213 return this._buffer; 214 }); 215 216 /** 217 * Underlying data type. 218 * 219 * @name dtype 220 * @memberof ndarray.prototype 221 * @type {string} 222 * 223 * @example 224 * var buffer = [ 1, 2, 3, 4, 5, 6 ]; 225 * var shape = [ 3, 2 ]; 226 * var strides = [ 2, 1 ]; 227 * var offset = 0; 228 * 229 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 230 * 231 * var dtype = x.dtype; 232 * // returns 'generic' 233 */ 234 setReadOnlyAccessor( ndarray.prototype, 'dtype', function get() { 235 return this._dtype; 236 }); 237 238 /** 239 * Information about the memory layout of the array. 240 * 241 * @name flags 242 * @memberof ndarray.prototype 243 * @type {Object} 244 * 245 * @example 246 * var buffer = [ 1, 2, 3, 4, 5, 6 ]; 247 * var shape = [ 3, 2 ]; 248 * var strides = [ 2, 1 ]; 249 * var offset = 0; 250 * 251 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 252 * 253 * var flgs = x.flags; 254 * // returns <Object> 255 */ 256 setReadOnlyAccessor( ndarray.prototype, 'flags', function get() { 257 return copyFlags( this._flags ); 258 }); 259 260 /** 261 * Length of the array. 262 * 263 * @name length 264 * @memberof ndarray.prototype 265 * @type {NonNegativeInteger} 266 * 267 * @example 268 * var buffer = [ 1, 2, 3, 4, 5, 6 ]; 269 * var shape = [ 3, 2 ]; 270 * var strides = [ 2, 1 ]; 271 * var offset = 0; 272 * 273 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 274 * 275 * var len = x.length; 276 * // returns 6 277 */ 278 setReadOnlyAccessor( ndarray.prototype, 'length', function get() { 279 return this._length; 280 }); 281 282 /** 283 * Number of dimensions. 284 * 285 * @name ndims 286 * @memberof ndarray.prototype 287 * @type {PositiveInteger} 288 * 289 * @example 290 * var buffer = [ 1, 2, 3, 4, 5, 6 ]; 291 * var shape = [ 3, 2 ]; 292 * var strides = [ 2, 1 ]; 293 * var offset = 0; 294 * 295 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 296 * 297 * var ndims = x.ndims; 298 * // returns 2 299 */ 300 setReadOnlyAccessor( ndarray.prototype, 'ndims', function get() { 301 return this._ndims; 302 }); 303 304 /** 305 * Index offset which specifies the buffer index at which to start iterating over array elements. 306 * 307 * @name offset 308 * @memberof ndarray.prototype 309 * @type {NonNegativeInteger} 310 * 311 * @example 312 * var buffer = [ 1, 2, 3, 4, 5, 6 ]; 313 * var shape = [ 3, 2 ]; 314 * var strides = [ 2, 1 ]; 315 * var offset = 0; 316 * 317 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 318 * 319 * var o = x.offset; 320 * // returns 0 321 */ 322 setReadOnlyAccessor( ndarray.prototype, 'offset', function get() { 323 return this._offset; 324 }); 325 326 /** 327 * Array order. 328 * 329 * ## Notes 330 * 331 * - The array order is either row-major (C-style) or column-major (Fortran-style). 332 * 333 * 334 * @name order 335 * @memberof ndarray.prototype 336 * @type {string} 337 * 338 * @example 339 * var buffer = [ 1, 2, 3, 4, 5, 6 ]; 340 * var shape = [ 3, 2 ]; 341 * var strides = [ 2, 1 ]; 342 * var offset = 0; 343 * 344 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 345 * 346 * var order = x.order; 347 * // returns 'row-major' 348 */ 349 setReadOnlyAccessor( ndarray.prototype, 'order', function get() { 350 return this._order; 351 }); 352 353 /** 354 * Shape of the array. 355 * 356 * @name shape 357 * @memberof ndarray.prototype 358 * @type {NonNegativeIntegerArray} 359 * 360 * @example 361 * var buffer = [ 1, 2, 3, 4, 5, 6 ]; 362 * var shape = [ 3, 2 ]; 363 * var strides = [ 2, 1 ]; 364 * var offset = 0; 365 * 366 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 367 * 368 * var s = x.shape; 369 * // returns [ 3, 2 ] 370 */ 371 setReadOnlyAccessor( ndarray.prototype, 'shape', function get() { 372 return this._shape.slice(); 373 }); 374 375 /** 376 * Index strides which specify how to access data along corresponding array dimensions. 377 * 378 * @name strides 379 * @memberof ndarray.prototype 380 * @type {IntegerArray} 381 * 382 * @example 383 * var buffer = [ 1, 2, 3, 4, 5, 6 ]; 384 * var shape = [ 3, 2 ]; 385 * var strides = [ 2, 1 ]; 386 * var offset = 0; 387 * 388 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 389 * 390 * var s = x.strides; 391 * // returns [ 2, 1 ] 392 */ 393 setReadOnlyAccessor( ndarray.prototype, 'strides', function get() { 394 return this._strides.slice(); 395 }); 396 397 /** 398 * Returns an array element. 399 * 400 * ## Notes 401 * 402 * - The number of indices should **equal** the number of dimensions. Accordingly, for zero-dimensional arrays, no indices should be provided. 403 * 404 * @name get 405 * @memberof ndarray.prototype 406 * @type {Function} 407 * @param {...integer} [idx] - indices 408 * @returns {*} array element 409 * 410 * @example 411 * var buffer = [ 1, 2, 3, 4, 5, 6 ]; 412 * var shape = [ 3, 2 ]; 413 * var strides = [ 2, 1 ]; 414 * var offset = 0; 415 * 416 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 417 * 418 * var v = x.get( 1, 1 ); 419 * // returns 4 420 */ 421 setReadOnly( ndarray.prototype, 'get', getValue ); 422 423 /** 424 * Returns an array element located at a specified linear index. 425 * 426 * ## Notes 427 * 428 * - For zero-dimensional arrays, the input argument is ignored and, for clarity, should not be provided. 429 * 430 * @name iget 431 * @memberof ndarray.prototype 432 * @type {Function} 433 * @param {integer} [idx] - linear index 434 * @returns {*} array element 435 * 436 * @example 437 * var buffer = [ 1, 2, 3, 4, 5, 6 ]; 438 * var shape = [ 3, 2 ]; 439 * var strides = [ 2, 1 ]; 440 * var offset = 0; 441 * 442 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 443 * 444 * var v = x.iget( 3 ); 445 * // returns 4 446 */ 447 setReadOnly( ndarray.prototype, 'iget', igetValue ); 448 449 /** 450 * Sets an array element. 451 * 452 * ## Notes 453 * 454 * - The number of indices should **equal** the number of dimensions. Accordingly, for zero-dimensional arrays, no indices should be provided. 455 * 456 * @name set 457 * @memberof ndarray.prototype 458 * @type {Function} 459 * @param {...integer} [idx] - indices 460 * @param {*} v - value to set 461 * @returns {ndarray} ndarray instance 462 * 463 * @example 464 * var buffer = [ 1, 2, 3, 4, 5, 6 ]; 465 * var shape = [ 3, 2 ]; 466 * var strides = [ 2, 1 ]; 467 * var offset = 0; 468 * 469 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 470 * 471 * var v = x.get( 1, 1 ); 472 * // returns 4 473 * 474 * x.set( 1, 1, 10 ); 475 * 476 * var b = x.data; 477 * // returns [ 1, 2, 3, 10, 5, 6 ] 478 * 479 * v = x.get( 1, 1 ); 480 * // returns 10 481 */ 482 setReadOnly( ndarray.prototype, 'set', setValue ); 483 484 /** 485 * Sets an array element located at a specified linear index. 486 * 487 * ## Notes 488 * 489 * - For zero-dimensional arrays, the first, and only, argument should be the value to set. 490 * 491 * @name iset 492 * @memberof ndarray.prototype 493 * @type {Function} 494 * @param {integer} [idx] - linear index 495 * @param {*} v - value to set 496 * @returns {ndarray} ndarray instance 497 * 498 * @example 499 * var buffer = [ 1, 2, 3, 4, 5, 6 ]; 500 * var shape = [ 3, 2 ]; 501 * var strides = [ 2, 1 ]; 502 * var offset = 0; 503 * 504 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 505 * 506 * var v = x.iget( 3 ); 507 * // returns 4 508 * 509 * x.iset( 3, 10 ); 510 * 511 * var b = x.data; 512 * // returns [ 1, 2, 3, 10, 5, 6 ] 513 * 514 * v = x.iget( 3 ); 515 * // returns 10 516 */ 517 setReadOnly( ndarray.prototype, 'iset', isetValue ); 518 519 /** 520 * Serializes an ndarray as a string. 521 * 522 * ## Notes 523 * 524 * - The method does **not** serialize data outside of the buffer region defined by the array configuration. 525 * 526 * 527 * @name toString 528 * @memberof ndarray.prototype 529 * @type {Function} 530 * @returns {string} serialized ndarray 531 * 532 * @example 533 * var buffer = [ 1, 2, 3, 4, 5, 6, 7, 8 ]; 534 * var shape = [ 3, 2 ]; 535 * var strides = [ 2, 1 ]; 536 * var offset = 2; 537 * 538 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 539 * 540 * var str = x.toString(); 541 * // returns "ndarray( 'generic', [ 3, 4, 5, 6, 7, 8 ], [ 3, 2 ], [ 2, 1 ], 0, 'row-major' )" 542 */ 543 setReadOnly( ndarray.prototype, 'toString', toString ); 544 545 /** 546 * Serializes an ndarray as a JSON object. 547 * 548 * ## Notes 549 * 550 * - `JSON.stringify()` implicitly calls this method when stringifying an `ndarray` instance. 551 * - The method does **not** serialize data outside of the buffer region defined by the array configuration. 552 * 553 * 554 * @name toJSON 555 * @memberof ndarray.prototype 556 * @type {Function} 557 * @returns {Object} serialized ndarray 558 * 559 * @example 560 * var buffer = [ 1, 2, 3, 4, 5, 6, 7, 8 ]; 561 * var shape = [ 3, 2 ]; 562 * var strides = [ 2, 1 ]; 563 * var offset = 2; 564 * 565 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 566 * 567 * var o = x.toJSON(); 568 * // e.g., returns { 'type': 'ndarray', 'dtype': 'generic', 'flags': {...}, 'offset': 0, 'order': 'row-major', 'shape': [ 3, 2 ], 'strides': [ 2, 1 ], 'data': [ 3, 4, 5, 6, 7, 8 ] } 569 */ 570 setReadOnly( ndarray.prototype, 'toJSON', toJSON ); 571 572 /** 573 * Serializes ndarray meta data to a `DataView`. 574 * 575 * ## Notes 576 * 577 * - Meta data format: 578 * 579 * ```text 580 * | <endianness> (1 byte) | <dtype> (2 bytes) | <ndims> (8 bytes) | <shape> (ndims*8 bytes) | <strides> (ndims*8 bytes) | <offset> (8 bytes) | <order> (1 byte) | <mode> (1 byte) | <nsubmodes> (8 bytes) | <submodes> (nsubmodes*1 bytes) | 581 * ``` 582 * 583 * where `strides` and `offset` are in units of bytes. 584 * 585 * - If the endianness is `1`, the byte order is little endian. If the endianness is `0`, the byte order is big endian. 586 * 587 * - Serialization is performed according to host byte order (endianness). 588 * 589 * - Consumers of this method should treat the returned `DataView` as **immutable**. Otherwise, mutation can invalidate meta data and potentially affect other consumers. 590 * 591 * @private 592 * @name __array_meta_dataview__ 593 * @memberof ndarray.prototype 594 * @type {Function} 595 * @returns {DataView} serialized meta data 596 * 597 * @example 598 * var buffer = [ 1, 2, 3, 4, 5, 6, 7, 8 ]; 599 * var shape = [ 3, 2 ]; 600 * var strides = [ 2, 1 ]; 601 * var offset = 2; 602 * 603 * var x = ndarray( 'generic', buffer, shape, strides, offset, 'row-major' ); 604 * 605 * var dv = x.__array_meta_dataview__(); 606 * // returns <DataView> 607 */ 608 setReadOnly( ndarray.prototype, '__array_meta_dataview__', ( hasBigIntSupport() ) ? meta2dataview : meta2dataviewPolyfill ); 609 610 611 // EXPORTS // 612 613 module.exports = ndarray;