<commit_before>/* eslint-disable max-len, max-lines */

/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var isStringArray = require( '@stdlib/assert/is-string-array' ).primitives;
var isString = require( '@stdlib/assert/is-string' ).isPrimitive;
var isArrayBuffer = require( '@stdlib/assert/is-arraybuffer' );
var isFunction = require( '@stdlib/assert/is-function' );
var isInteger = require( '@stdlib/assert/is-integer' ).isPrimitive;
var isObject = require( '@stdlib/assert/is-object' );
var isCollection = require( '@stdlib/assert/is-collection' );
var hasOwnProp = require( '@stdlib/assert/has-own-property' );
var hasIteratorSymbolSupport = require( '@stdlib/assert/has-iterator-symbol-support' );
var propertiesIn = require( '@stdlib/utils/properties-in' );
var typedarray = require( '@stdlib/array/typed' );
var Int8Array = require( '@stdlib/array/int8' );
var getDtype = require( '@stdlib/array/dtype' );
var setReadWriteAccessor = require( '@stdlib/utils/define-read-write-accessor' );
var setReadOnlyAccessor = require( '@stdlib/utils/define-read-only-accessor' );
var defineProperty = require( '@stdlib/utils/define-property' );
var floor = require( '@stdlib/math/base/special/floor' );
var ITERATOR_SYMBOL = require( '@stdlib/symbol/iterator' );
var contains = require( './contains.js' );
var hasDistinctElements = require( './has_distinct_elements.js' );
var validate = require( './validate.js' );
var ascending = require( './ascending.js' );
var fromIterator = require( './from_iterator.js' );
var fromIteratorMap = require( './from_iterator_map.js' );


// VARIABLES //

var RESERVED_PROPS = propertiesIn( new Int8Array( 0 ) );
var HAS_ITERATOR_SYMBOL = hasIteratorSymbolSupport();


// MAIN //

/**
* Returns a named typed tuple factory.
*
* @param {StringArray} names - field (property) names
* @param {Options} [options] - options
* @param {string} [options.dtype="float64"] - default data type
* @param {string} [options.name="tuple"] - tuple name
* @throws {TypeError} must provide an array of strings
* @throws {TypeError} must provide distinct field names
* @throws {Error} cannot provide a reserved field (property) name
* @throws {TypeError} must provide valid options
* @throws {Error} must provide a recognized data type
* @returns {Function} factory function
*
* @example
* var point = factory( [ 'x', 'y' ] );
*
* var p = point( [ 1.0, -1.0 ] );
*
* var x = p[ 0 ];
* // returns 1.0
*
* x = p.x;
* // returns 1.0
*
* var y = p[ 1 ];
* // returns -1.0
*
* y = p.y;
* // returns -1.0
*/
function factory( names, options ) { // eslint-disable-line max-lines-per-function, stdlib/jsdoc-require-throws-tags
	var nfields;
	var fields;
	var opts;
	var err;
	var i;
	if ( !isStringArray( names ) ) {
		throw new TypeError( 'invalid argument. Must provide an array of strings. Value: `' + names + '`.' );
	}
	if ( !hasDistinctElements( names ) ) {
		throw new TypeError( 'invalid argument. Field names must be distinct. Value: `' + names + '`.' );
	}
	fields = names.slice();
	nfields = fields.length;
	for ( i = 0; i < nfields; i++ ) {
		if ( contains( RESERVED_PROPS, fields[ i ] ) ) {
			throw new Error( 'invalid argument. Provided field name is reserved. Name: `' + fields[ i ] + '`.' );
		}
	}
	opts = {
		'dtype': 'float64',
		'name': 'tuple'
	};
	if ( arguments.length > 1 ) {
		err = validate( opts, options );
		if ( err ) {
			throw err;
		}
	}

	/**
	* Returns a named typed tuple.
	*
	* @private
	* @param {(TypedArray|ArrayLikeObject|ArrayBuffer|Iterable)} [arg] - a typed array, array-like object, buffer, or an iterable
	* @param {NonNegativeInteger} [byteOffset=0] - byte offset
	* @param {string} [dtype] - data type
	* @throws {TypeError} must provide a recognized data type
	* @throws {RangeError} arguments must be compatible with tuple length
	* @returns {TypedArray} named typed tuple
	*/
	function namedtypedtuple() { // eslint-disable-line max-lines-per-function
		var indices;
		var dtype;
		var nargs;
		var tuple;
		var i;

		nargs = arguments.length;
		if ( nargs <= 0 ) {
			tuple = typedarray( nfields, opts.dtype );
		} else if ( nargs === 1 ) {
			if ( isString( arguments[ 0 ] ) ) {
				// Arguments: [ dtype ]
				tuple = typedarray( nfields, arguments[ 0 ] );
			} else if ( isArrayBuffer( arguments[ 0 ] ) ) {
				// Arguments: [ ArrayBuffer ]
				tuple = typedarray( arguments[ 0 ], 0, nfields, opts.dtype );
			} else {
				// Arguments: [ TypedArray|ArrayLikeObject|Iterable ]
				tuple = typedarray( arguments[ 0 ], opts.dtype );
			}
		} else if ( nargs === 2 ) {
			if ( isArrayBuffer( arguments[ 0 ] ) ) {
				if ( isString( arguments[ 1 ] ) ) {
					// Arguments: [ ArrayBuffer, dtype ]
					tuple = typedarray( arguments[ 0 ], 0, nfields, arguments[ 1 ] );
				} else {
					// Arguments: [ ArrayBuffer, byteOffset ]
					tuple = typedarray( arguments[ 0 ], arguments[ 1 ], nfields, opts.dtype );
				}
			} else {
				// Arguments: [ TypedArray|ArrayLikeObject|Iterable, dtype ]
				tuple = typedarray( arguments[ 0 ], arguments[ 1 ] );
			}
		} else {
			// Arguments: [ ArrayBuffer, byteOffset, dtype ]
			tuple = typedarray( arguments[ 0 ], arguments[ 1 ], nfields, arguments[ 2 ] );
		}
		if ( tuple.length !== nfields ) {
			throw new RangeError( 'invalid arguments. Arguments are incompatible with number of tuple fields. Number of fields: `' + nfields + '`. Number of data elements: `' + tuple.length + '`.' );
		}
		dtype = getDtype( tuple );

		indices = []; // indirect index look-up table
		for ( i = 0; i < nfields; i++ ) {
			indices.push( i );
			setReadWriteAccessor( tuple, fields[ i ], getter( i ), setter( i ) );
		}
		tuple.name = opts.name;
		setReadOnlyAccessor( tuple, 'fields', getFields );
		setReadOnlyAccessor( tuple, 'orderedFields', orderedFields );

		// Note: keep in alphabetical order
		tuple.entries = entries;
		tuple.every = every;
		tuple.filter = filter;
		tuple.find = find;
		tuple.findIndex = findIndex;
		tuple.findField = findField;
		tuple.forEach = forEach;
		tuple.ind2key = ind2key;
		tuple.key2ind = key2ind;
		tuple.keys = keys;
		tuple.map = map;
		tuple.reduce = reduce;
		tuple.reduceRight = reduceRight;
		tuple.reverse = reverse;
		tuple.slice = slice;
		tuple.some = some;
		tuple.sort = sort;
		tuple.subtuple = subtuple;
		tuple.toJSON = toJSON;
		tuple.toString = toString;

		return tuple;

		/**
		* Returns an accessor to retrieve a tuple value.
		*
		* @private
		* @param {NonNegativeInteger} i - tuple index
		* @returns {Function} accessor
		*/
		function getter( i ) {
			return get;

			/**
			* Returns a tuple value.
			*
			* @private
			* @returns {number} tuple value
			*/
			function get() {
				return tuple[ indices[ i ] ];
			}
		}

		/**
		* Returns an accessor to set a tuple value.
		*
		* @private
		* @param {NonNegativeInteger} i - tuple index
		* @returns {Function} accessor
		*/
		function setter( i ) {
			return set;

			/**
			* Sets a tuple value.
			*
			* @private
			* @param {number} v - value to set
			*/
			function set( v ) {
				tuple[ indices[ i ] ] = v;
			}
		}

		/**
		* Returns the list of tuple fields.
		*
		* @private
		* @memberof tuple
		* @returns {StringArray} tuple fields
		*/
		function getFields() {
			return fields.slice();
		}

		/**
		* Returns the list of tuple fields in index order.
		*
		* @private
		* @memberof tuple
		* @returns {StringArray} tuple fields
		*/
		function orderedFields() {
			var out;
			var i;
			out = fields.slice();
			for ( i = 0; i < nfields; i++ ) {
				out[ i ] = fields[ indices[i] ];
			}
			return out;
		}

		// Note: keep functions which follow in alphabetical order

		/**
		* Returns an iterator for iterating over tuple key-value pairs.
		*
		* @private
		* @memberof tuple
		* @throws {TypeError} `this` must be the host tuple
		* @returns {Iterator} iterator
		*/
		function entries() {
			var self;
			var iter;
			var FLG;
			var i;

			self = this; // eslint-disable-line no-invalid-this
			if ( self !== tuple ) {
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}

			// Initialize the iteration index:
			i = -1;

			// Create an iterator protocol-compliant object:
			iter = {};
			defineProperty( iter, 'next', {
				'configurable': false,
				'enumerable': false,
				'writable': false,
				'value': next
			});
			defineProperty( iter, 'return', {
				'configurable': false,
				'enumerable': false,
				'writable': false,
				'value': end
			});
			if ( HAS_ITERATOR_SYMBOL ) {
				defineProperty( iter, ITERATOR_SYMBOL, {
					'configurable': false,
					'enumerable': false,
					'writable': false,
					'value': factory
				});
			}
			return iter;

			/**
			* Returns an iterator protocol-compliant object containing the next iterated value.
			*
			* @private
			* @returns {Object} iterator protocol-compliant object
			*/
			function next() {
				i += 1;
				if ( FLG || i >= nfields ) {
					return {
						'done': true
					};
				}
				return {
					'value': [ i, fields[ indices[ i ] ], tuple[ i ] ],
					'done': false
				};
			}

			/**
			* Finishes an iterator.
			*
			* @private
			* @param {*} [value] - value to return
			* @returns {Object} iterator protocol-compliant object
			*/
			function end( value ) {
				FLG = true;
				if ( arguments.length ) {
					return {
						'value': value,
						'done': true
					};
				}
				return {
					'done': true
				};
			}

			/**
			* Returns a new iterator.
			*
			* @private
			* @returns {Iterator} iterator
			*/
			function factory() {
				return self.entries();
			}
		}

		/**
		* Tests whether all tuple elements pass a test implemented by a predicate function.
		*
		* @private
		* @memberof tuple
		* @param {Function} predicate - predicate function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @throws {TypeError} first argument must be a function
		* @returns {boolean} boolean indicating if all elements pass
		*/
		function every( predicate, thisArg ) {
			var bool;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			if ( !isFunction( predicate ) ) {
				throw new TypeError( 'invalid argument. First argument must be a function. Value: `' + predicate + '`.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				bool = predicate.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( !bool ) {
					return false;
				}
			}
			return true;
		}

		/**
		* Creates a new tuple which includes those elements for which a predicate function returns a truthy value.
		*
		* ## Notes
		*
		* -   The returned tuple has the same data type as the host tuple.
		* -   If a predicate function does not return a truthy value for any tuple element, the function returns `null`.
		*
		* @private
		* @memberof tuple
		* @param {Function} predicate - filter (predicate) function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @throws {TypeError} first argument must be a function
		* @returns {(TypedArray|null)} new tuple
		*/
		function filter( predicate, thisArg ) {
			var bool;
			var tmp;
			var f;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			if ( !isFunction( predicate ) ) {
				throw new TypeError( 'invalid argument. First argument must be a function. Value: `' + predicate + '`.' );
			}
			tmp = [];
			f = [];
			for ( i = 0; i < nfields; i++ ) {
				bool = predicate.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( bool ) {
					f.push( fields[ indices[i] ] );
					tmp.push( tuple[ i ] );
				}
			}
			if ( f.length === nfields ) {
				return namedtypedtuple( tmp, dtype );
			}
			if ( f.length ) {
				return factory( f, opts )( tmp );
			}
			return null;
		}

		/**
		* Returns the first tuple element for which a provided predicate function returns a truthy value.
		*
		* @private
		* @memberof tuple
		* @param {Function} predicate - predicate function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @throws {TypeError} first argument must be a function
		* @returns {(number|void)} tuple element
		*/
		function find( predicate, thisArg ) {
			var bool;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			if ( !isFunction( predicate ) ) {
				throw new TypeError( 'invalid argument. First argument must be a function. Value: `' + predicate + '`.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				bool = predicate.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( bool ) {
					return tuple[ i ];
				}
			}
		}

		/**
		* Returns the index of the first tuple element for which a provided predicate function returns a truthy value.
		*
		* ## Notes
		*
		* -   If the predicate function never returns a truthy value, the function returns `-1`.
		*
		* @private
		* @memberof tuple
		* @param {Function} predicate - predicate function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @throws {TypeError} first argument must be a function
		* @returns {integer} tuple index or `-1`
		*/
		function findIndex( predicate, thisArg ) {
			var bool;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			if ( !isFunction( predicate ) ) {
				throw new TypeError( 'invalid argument. First argument must be a function. Value: `' + predicate + '`.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				bool = predicate.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( bool ) {
					return i;
				}
			}
			return -1;
		}

		/**
		* Returns the field of the first tuple element for which a provided predicate function returns a truthy value.
		*
		* ## Notes
		*
		* -   If the predicate function never returns a truthy value, the function returns `undefined`.
		*
		* @private
		* @memberof tuple
		* @param {Function} predicate - predicate function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @throws {TypeError} first argument must be a function
		* @returns {(string|void)} tuple field name or `undefined`
		*/
		function findField( predicate, thisArg ) {
			var bool;
			var f;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			if ( !isFunction( predicate ) ) {
				throw new TypeError( 'invalid argument. First argument must be a function. Value: `' + predicate + '`.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				f = fields[ indices[ i ] ];
				bool = predicate.call( thisArg, tuple[ i ], i, f, tuple );
				if ( bool ) {
					return f;
				}
			}
		}

		/**
		* Invokes a callback for each tuple element.
		*
		* @private
		* @memberof tuple
		* @param {Function} fcn - function to invoke
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @throws {TypeError} first argument must be a function
		*/
		function forEach( fcn, thisArg ) {
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			if ( !isFunction( fcn ) ) {
				throw new TypeError( 'invalid argument. First argument must be a function. Value: `' + fcn + '`.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				fcn.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
			}
		}

		/**
		* Converts a tuple index to a field name.
		*
		* ## Notes
		*
		* -   If provided an out-of-bounds index, the function returns `undefined`.
		* -   If provided a negative tuple index, the function resolves the index relative to the last tuple element.
		*
		* @private
		* @memberof tuple
		* @param {integer} ind - tuple index
		* @throws {TypeError} `this` must be the host tuple
		* @returns {(string|void)} field name or undefined
		*/
		function ind2key( ind ) {
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			if ( !isInteger( ind ) ) {
				throw new TypeError( 'invalid argument. First argument must be an integer. Value: `' + ind + '`.' );
			}
			if ( ind < 0 ) {
				ind = nfields - ind;
			}
			if ( ind < 0 || ind >= nfields ) {
				return;
			}
			return fields[ indices[ ind ] ];
		}

		/**
		* Converts a field name to a tuple index.
		*
		* ## Notes
		*
		* -   If provided an unknown field name, the function returns `-1`.
		*
		* @private
		* @memberof tuple
		* @param {string} key - field name
		* @throws {TypeError} `this` must be the host tuple<commit_msg>Add missing throws annotation and update error message<commit_after>/* eslint-disable max-len, max-lines */

/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var isStringArray = require( '@stdlib/assert/is-string-array' ).primitives;
var isString = require( '@stdlib/assert/is-string' ).isPrimitive;
var isArrayBuffer = require( '@stdlib/assert/is-arraybuffer' );
var isFunction = require( '@stdlib/assert/is-function' );
var isInteger = require( '@stdlib/assert/is-integer' ).isPrimitive;
var isObject = require( '@stdlib/assert/is-object' );
var isCollection = require( '@stdlib/assert/is-collection' );
var hasOwnProp = require( '@stdlib/assert/has-own-property' );
var hasIteratorSymbolSupport = require( '@stdlib/assert/has-iterator-symbol-support' );
var propertiesIn = require( '@stdlib/utils/properties-in' );
var typedarray = require( '@stdlib/array/typed' );
var Int8Array = require( '@stdlib/array/int8' );
var getDtype = require( '@stdlib/array/dtype' );
var setReadWriteAccessor = require( '@stdlib/utils/define-read-write-accessor' );
var setReadOnlyAccessor = require( '@stdlib/utils/define-read-only-accessor' );
var defineProperty = require( '@stdlib/utils/define-property' );
var floor = require( '@stdlib/math/base/special/floor' );
var ITERATOR_SYMBOL = require( '@stdlib/symbol/iterator' );
var contains = require( './contains.js' );
var hasDistinctElements = require( './has_distinct_elements.js' );
var validate = require( './validate.js' );
var ascending = require( './ascending.js' );
var fromIterator = require( './from_iterator.js' );
var fromIteratorMap = require( './from_iterator_map.js' );


// VARIABLES //

var RESERVED_PROPS = propertiesIn( new Int8Array( 0 ) );
var HAS_ITERATOR_SYMBOL = hasIteratorSymbolSupport();


// MAIN //

/**
* Returns a named typed tuple factory.
*
* @param {StringArray} names - field (property) names
* @param {Options} [options] - options
* @param {string} [options.dtype="float64"] - default data type
* @param {string} [options.name="tuple"] - tuple name
* @throws {TypeError} must provide an array of strings
* @throws {TypeError} must provide distinct field names
* @throws {Error} cannot provide a reserved field (property) name
* @throws {TypeError} must provide valid options
* @throws {Error} must provide a recognized data type
* @returns {Function} factory function
*
* @example
* var point = factory( [ 'x', 'y' ] );
*
* var p = point( [ 1.0, -1.0 ] );
*
* var x = p[ 0 ];
* // returns 1.0
*
* x = p.x;
* // returns 1.0
*
* var y = p[ 1 ];
* // returns -1.0
*
* y = p.y;
* // returns -1.0
*/
function factory( names, options ) { // eslint-disable-line max-lines-per-function, stdlib/jsdoc-require-throws-tags
	var nfields;
	var fields;
	var opts;
	var err;
	var i;
	if ( !isStringArray( names ) ) {
		throw new TypeError( 'invalid argument. Must provide an array of strings. Value: `' + names + '`.' );
	}
	if ( !hasDistinctElements( names ) ) {
		throw new TypeError( 'invalid argument. Field names must be distinct. Value: `' + names + '`.' );
	}
	fields = names.slice();
	nfields = fields.length;
	for ( i = 0; i < nfields; i++ ) {
		if ( contains( RESERVED_PROPS, fields[ i ] ) ) {
			throw new Error( 'invalid argument. Provided field name is reserved. Name: `' + fields[ i ] + '`.' );
		}
	}
	opts = {
		'dtype': 'float64',
		'name': 'tuple'
	};
	if ( arguments.length > 1 ) {
		err = validate( opts, options );
		if ( err ) {
			throw err;
		}
	}

	/**
	* Returns a named typed tuple.
	*
	* @private
	* @param {(TypedArray|ArrayLikeObject|ArrayBuffer|Iterable)} [arg] - a typed array, array-like object, buffer, or an iterable
	* @param {NonNegativeInteger} [byteOffset=0] - byte offset
	* @param {string} [dtype] - data type
	* @throws {TypeError} must provide a recognized data type
	* @throws {RangeError} arguments must be compatible with tuple length
	* @returns {TypedArray} named typed tuple
	*/
	function namedtypedtuple() { // eslint-disable-line max-lines-per-function
		var indices;
		var dtype;
		var nargs;
		var tuple;
		var i;

		nargs = arguments.length;
		if ( nargs <= 0 ) {
			tuple = typedarray( nfields, opts.dtype );
		} else if ( nargs === 1 ) {
			if ( isString( arguments[ 0 ] ) ) {
				// Arguments: [ dtype ]
				tuple = typedarray( nfields, arguments[ 0 ] );
			} else if ( isArrayBuffer( arguments[ 0 ] ) ) {
				// Arguments: [ ArrayBuffer ]
				tuple = typedarray( arguments[ 0 ], 0, nfields, opts.dtype );
			} else {
				// Arguments: [ TypedArray|ArrayLikeObject|Iterable ]
				tuple = typedarray( arguments[ 0 ], opts.dtype );
			}
		} else if ( nargs === 2 ) {
			if ( isArrayBuffer( arguments[ 0 ] ) ) {
				if ( isString( arguments[ 1 ] ) ) {
					// Arguments: [ ArrayBuffer, dtype ]
					tuple = typedarray( arguments[ 0 ], 0, nfields, arguments[ 1 ] );
				} else {
					// Arguments: [ ArrayBuffer, byteOffset ]
					tuple = typedarray( arguments[ 0 ], arguments[ 1 ], nfields, opts.dtype );
				}
			} else {
				// Arguments: [ TypedArray|ArrayLikeObject|Iterable, dtype ]
				tuple = typedarray( arguments[ 0 ], arguments[ 1 ] );
			}
		} else {
			// Arguments: [ ArrayBuffer, byteOffset, dtype ]
			tuple = typedarray( arguments[ 0 ], arguments[ 1 ], nfields, arguments[ 2 ] );
		}
		if ( tuple.length !== nfields ) {
			throw new RangeError( 'invalid arguments. Arguments are incompatible with number of tuple fields. Number of fields: `' + nfields + '`. Number of data elements: `' + tuple.length + '`.' );
		}
		dtype = getDtype( tuple );

		indices = []; // indirect index look-up table
		for ( i = 0; i < nfields; i++ ) {
			indices.push( i );
			setReadWriteAccessor( tuple, fields[ i ], getter( i ), setter( i ) );
		}
		tuple.name = opts.name;
		setReadOnlyAccessor( tuple, 'fields', getFields );
		setReadOnlyAccessor( tuple, 'orderedFields', orderedFields );

		// Note: keep in alphabetical order
		tuple.entries = entries;
		tuple.every = every;
		tuple.filter = filter;
		tuple.find = find;
		tuple.findIndex = findIndex;
		tuple.findField = findField;
		tuple.forEach = forEach;
		tuple.ind2key = ind2key;
		tuple.key2ind = key2ind;
		tuple.keys = keys;
		tuple.map = map;
		tuple.reduce = reduce;
		tuple.reduceRight = reduceRight;
		tuple.reverse = reverse;
		tuple.slice = slice;
		tuple.some = some;
		tuple.sort = sort;
		tuple.subtuple = subtuple;
		tuple.toJSON = toJSON;
		tuple.toString = toString;

		return tuple;

		/**
		* Returns an accessor to retrieve a tuple value.
		*
		* @private
		* @param {NonNegativeInteger} i - tuple index
		* @returns {Function} accessor
		*/
		function getter( i ) {
			return get;

			/**
			* Returns a tuple value.
			*
			* @private
			* @returns {number} tuple value
			*/
			function get() {
				return tuple[ indices[ i ] ];
			}
		}

		/**
		* Returns an accessor to set a tuple value.
		*
		* @private
		* @param {NonNegativeInteger} i - tuple index
		* @returns {Function} accessor
		*/
		function setter( i ) {
			return set;

			/**
			* Sets a tuple value.
			*
			* @private
			* @param {number} v - value to set
			*/
			function set( v ) {
				tuple[ indices[ i ] ] = v;
			}
		}

		/**
		* Returns the list of tuple fields.
		*
		* @private
		* @memberof tuple
		* @returns {StringArray} tuple fields
		*/
		function getFields() {
			return fields.slice();
		}

		/**
		* Returns the list of tuple fields in index order.
		*
		* @private
		* @memberof tuple
		* @returns {StringArray} tuple fields
		*/
		function orderedFields() {
			var out;
			var i;
			out = fields.slice();
			for ( i = 0; i < nfields; i++ ) {
				out[ i ] = fields[ indices[i] ];
			}
			return out;
		}

		// Note: keep functions which follow in alphabetical order

		/**
		* Returns an iterator for iterating over tuple key-value pairs.
		*
		* @private
		* @memberof tuple
		* @throws {TypeError} `this` must be the host tuple
		* @returns {Iterator} iterator
		*/
		function entries() {
			var self;
			var iter;
			var FLG;
			var i;

			self = this; // eslint-disable-line no-invalid-this
			if ( self !== tuple ) {
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}

			// Initialize the iteration index:
			i = -1;

			// Create an iterator protocol-compliant object:
			iter = {};
			defineProperty( iter, 'next', {
				'configurable': false,
				'enumerable': false,
				'writable': false,
				'value': next
			});
			defineProperty( iter, 'return', {
				'configurable': false,
				'enumerable': false,
				'writable': false,
				'value': end
			});
			if ( HAS_ITERATOR_SYMBOL ) {
				defineProperty( iter, ITERATOR_SYMBOL, {
					'configurable': false,
					'enumerable': false,
					'writable': false,
					'value': factory
				});
			}
			return iter;

			/**
			* Returns an iterator protocol-compliant object containing the next iterated value.
			*
			* @private
			* @returns {Object} iterator protocol-compliant object
			*/
			function next() {
				i += 1;
				if ( FLG || i >= nfields ) {
					return {
						'done': true
					};
				}
				return {
					'value': [ i, fields[ indices[ i ] ], tuple[ i ] ],
					'done': false
				};
			}

			/**
			* Finishes an iterator.
			*
			* @private
			* @param {*} [value] - value to return
			* @returns {Object} iterator protocol-compliant object
			*/
			function end( value ) {
				FLG = true;
				if ( arguments.length ) {
					return {
						'value': value,
						'done': true
					};
				}
				return {
					'done': true
				};
			}

			/**
			* Returns a new iterator.
			*
			* @private
			* @returns {Iterator} iterator
			*/
			function factory() {
				return self.entries();
			}
		}

		/**
		* Tests whether all tuple elements pass a test implemented by a predicate function.
		*
		* @private
		* @memberof tuple
		* @param {Function} predicate - predicate function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @throws {TypeError} first argument must be a function
		* @returns {boolean} boolean indicating if all elements pass
		*/
		function every( predicate, thisArg ) {
			var bool;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			if ( !isFunction( predicate ) ) {
				throw new TypeError( 'invalid argument. First argument must be a function. Value: `' + predicate + '`.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				bool = predicate.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( !bool ) {
					return false;
				}
			}
			return true;
		}

		/**
		* Creates a new tuple which includes those elements for which a predicate function returns a truthy value.
		*
		* ## Notes
		*
		* -   The returned tuple has the same data type as the host tuple.
		* -   If a predicate function does not return a truthy value for any tuple element, the function returns `null`.
		*
		* @private
		* @memberof tuple
		* @param {Function} predicate - filter (predicate) function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @throws {TypeError} first argument must be a function
		* @returns {(TypedArray|null)} new tuple
		*/
		function filter( predicate, thisArg ) {
			var bool;
			var tmp;
			var f;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			if ( !isFunction( predicate ) ) {
				throw new TypeError( 'invalid argument. First argument must be a function. Value: `' + predicate + '`.' );
			}
			tmp = [];
			f = [];
			for ( i = 0; i < nfields; i++ ) {
				bool = predicate.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( bool ) {
					f.push( fields[ indices[i] ] );
					tmp.push( tuple[ i ] );
				}
			}
			if ( f.length === nfields ) {
				return namedtypedtuple( tmp, dtype );
			}
			if ( f.length ) {
				return factory( f, opts )( tmp );
			}
			return null;
		}

		/**
		* Returns the first tuple element for which a provided predicate function returns a truthy value.
		*
		* @private
		* @memberof tuple
		* @param {Function} predicate - predicate function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @throws {TypeError} first argument must be a function
		* @returns {(number|void)} tuple element
		*/
		function find( predicate, thisArg ) {
			var bool;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			if ( !isFunction( predicate ) ) {
				throw new TypeError( 'invalid argument. First argument must be a function. Value: `' + predicate + '`.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				bool = predicate.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( bool ) {
					return tuple[ i ];
				}
			}
		}

		/**
		* Returns the index of the first tuple element for which a provided predicate function returns a truthy value.
		*
		* ## Notes
		*
		* -   If the predicate function never returns a truthy value, the function returns `-1`.
		*
		* @private
		* @memberof tuple
		* @param {Function} predicate - predicate function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @throws {TypeError} first argument must be a function
		* @returns {integer} tuple index or `-1`
		*/
		function findIndex( predicate, thisArg ) {
			var bool;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			if ( !isFunction( predicate ) ) {
				throw new TypeError( 'invalid argument. First argument must be a function. Value: `' + predicate + '`.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				bool = predicate.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( bool ) {
					return i;
				}
			}
			return -1;
		}

		/**
		* Returns the field of the first tuple element for which a provided predicate function returns a truthy value.
		*
		* ## Notes
		*
		* -   If the predicate function never returns a truthy value, the function returns `undefined`.
		*
		* @private
		* @memberof tuple
		* @param {Function} predicate - predicate function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @throws {TypeError} first argument must be a function
		* @returns {(string|void)} tuple field name or `undefined`
		*/
		function findField( predicate, thisArg ) {
			var bool;
			var f;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			if ( !isFunction( predicate ) ) {
				throw new TypeError( 'invalid argument. First argument must be a function. Value: `' + predicate + '`.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				f = fields[ indices[ i ] ];
				bool = predicate.call( thisArg, tuple[ i ], i, f, tuple );
				if ( bool ) {
					return f;
				}
			}
		}

		/**
		* Invokes a callback for each tuple element.
		*
		* @private
		* @memberof tuple
		* @param {Function} fcn - function to invoke
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @throws {TypeError} first argument must be a function
		*/
		function forEach( fcn, thisArg ) {
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			if ( !isFunction( fcn ) ) {
				throw new TypeError( 'invalid argument. First argument must be a function. Value: `' + fcn + '`.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				fcn.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
			}
		}

		/**
		* Converts a tuple index to a field name.
		*
		* ## Notes
		*
		* -   If provided an out-of-bounds index, the function returns `undefined`.
		* -   If provided a negative tuple index, the function resolves the index relative to the last tuple element.
		*
		* @private
		* @memberof tuple
		* @param {integer} ind - tuple index
		* @throws {TypeError} `this` must be the host tuple
		* @throws {TypeError} must provide an integer
		* @returns {(string|void)} field name or undefined
		*/
		function ind2key( ind ) {
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			if ( !isInteger( ind ) ) {
				throw new TypeError( 'invalid argument. Must provide an integer. Value: `' + ind + '`.' );
			}
			if ( ind < 0 ) {
				ind = nfields - ind;
			}
			if ( ind < 0 || ind >= nfields ) {
				return;
			}
			return fields[ indices[ ind ] ];
		}

		/**
		* Converts a field name to a tuple index.
		*
		* ## Notes
		*
		* -   If provided an unknown field name, the function returns `-1`.
		*
		* @private
		* @memberof tuple
		* @param {string} key - field name
		* @throws {TypeError} `this` must be the host tuple
{'fraction_non_alphanumeric': 0.13754298218193187, 'fraction_numerical': 0.00437636761487965, 'mean_word_length': 2.852216748768473, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2651007', 'n_tokens_mistral': 13081, 'n_tokens_neox': 11148, 'n_words': 3712}