Subversion Repositories JSX

Compare Revisions

Last modification

Ignore whitespace Rev 561 → Rev 562

/trunk/test/array-test.js
56,26 → 56,47
},
 
{
feature: 'BigArray.prototype.toArray()',
description: 'Return the correct value',
feature: 'bigArray.length',
description: 'Getter works',
code: function () {
assertArrayEquals([], new BigArray().toArray());
assertArrayEquals([""], new BigArray("").toArray());
assertArrayEquals(["x"], new BigArray("x").toArray());
assertArrayEquals([23, 42], new BigArray(23, 42).toArray());
var i = Math.pow(2, 53) - 1;
assert(new BigArray(i).length == i);
}
},
{
feature: 'BigArray.length',
description: 'Getter works',
feature: 'bigArray.setLength()',
description: 'Throw <code>jsx.InvalidArgumentError</code>',
code: function () {
var i = Math.pow(2, 53);
assert(new BigArray(i).length == i);
var a = new BigArray();
var failure = jsx.tryThis(
function () {
a.setLength();
},
function (e) {
return (e instanceof jsx.InvalidArgumentError);
}
);
assert(failure);
}
},
 
{
feature: 'BigArray.getLength()',
feature: 'bigArray.setLength()',
description: 'Throw <code>jsx.array.RangeError</code>',
code: function () {
var a = new BigArray();
var failure = jsx.tryThis(
function () {
a.setLength(Math.pow(2, 53));
},
function (e) {
return (e instanceof jsx.array.RangeError);
}
);
assert(failure);
}
},
{
feature: 'bigArray.getLength()',
description: 'Return the correct value',
code: function () {
assert(new BigArray().getLength() === 0);
113,10 → 134,46
assert(typeof new BigArray("x", "y").get(-4) == "undefined");
}
},
{
feature: 'BigArray.prototype.set(Math.pow(2, 53) - 1, 23)',
description: 'Throw <code>jsx.array.RangeError</code> (index too large)',
code: function () {
var a = new BigArray();
var failure = jsx.tryThis(
function () {
a.set(Math.pow(2, 53) - 1, 23);
return false;
},
function (e) {
return (e instanceof jsx.array.RangeError);
});
assert(failure);
}
},
{
feature: 'BigArray.prototype.set(Math.pow(2, 53) - 2, 42)',
description: 'Set element at maximum index',
code: function () {
var a = new BigArray();
var i = Math.pow(2, 53) - 2;
a.set(i, 42);
assert(a.get(i) === 42);
}
},
 
/* TODO: Override and test Array methods that are not MAX_LENGTH-safe */
 
{
feature: 'BigArray.prototype.toArray()',
description: 'Return the correct value',
code: function () {
assertArrayEquals([], new BigArray().toArray());
assertArrayEquals([""], new BigArray("").toArray());
assertArrayEquals(["x"], new BigArray("x").toArray());
assertArrayEquals([23, 42], new BigArray(23, 42).toArray());
}
},
{
feature: 'BigArray.prototype.toString(…)',
description: 'Return the correct value',
code: function () {
/trunk/array.js
28,6 → 28,8
*/
jsx.array = (/** @constructor */ function () {
/* Imports */
var _slice = [].slice;
 
var _jsx = jsx;
var _jsx_object = _jsx.object;
var _defineProperty = _jsx_object.defineProperty;
170,7 → 172,7
{
var index = +value;
 
if (!(isNaN(index) || index == 0 || Math.abs(index) == Number.POSITIVE_INFINITY))
if (!(isNaN(index) || index == 0 || Math.abs(index) == Infinity))
{
index = (index < 0 ? Math.ceil(index) : Math.floor(index));
}
178,6 → 180,23
return (!isNaN(index) && (String(index) == String(value)) ? index : Number.NaN);
}
 
function _toInteger (a)
{
var number = +a;
 
if (isNaN(number))
{
return 0;
}
 
if (number === 0 || number == Infinity || number == -Infinity)
{
return number;
}
 
return (number < 0 ? -1 : 1) * Math.floor(Math.abs(number));
}
 
/**
* An <code>Array</code> whose last elements can be accessed
* by negative index. This additional functionality requires
251,18 → 270,17
}
});
 
var _BIGARRAY_MAX_LENGTH = Math.pow(2, 53);
var _BIGARRAY_MAX_LENGTH = Math.pow(2, 53) - 1;
 
/**
* Array-like object which can hold up to 2<sup>53</sup> elements
* Array-like object which can hold up to 2<sup>53</sup>−1 elements.
*
* @function
* @type jsx.array.BigArray
* @extends Array
* @constructor
*/
var _BigArray = jsx.object.extend(
/**
* @constructor
* @extends Array
* @type __jsx.array.BigArray
* @param {Array|Object} src (optional)
* Array-like object to be converted
269,7 → 287,7
* @return {jsx.arrayBigArray}
*/
function jsx_array_BigArray (src) {
if (!(this instanceof jsx_array_BigArray))
if (!jsx_array_BigArray.isInstance(this))
{
return jsx_array_BigArray.construct(arguments);
}
284,11 → 302,22
* Sets the real length of this array
*
* @param {int} value
* @throws jsx.InvalidArgumentsError
* if the value is not a number
* @throws jsx.array.RangeError
* if the value is less than <code>0</code> or
* greater than {@link BigArray.MAX_LENGTH}
*/
this.setLength = function BigArray_setLength (value) {
if (isNaN(value))
{
return _jsx.throwThis(jsx.InvalidArgumentError,
["Invalid length", value,
"0.." + _BIGARRAY_MAX_LENGTH
+ " (2^" + Math.floor(Math.log(_BIGARRAY_MAX_LENGTH) / Math.log(2)) + ")"],
BigArray_setLength);
}
 
if (value < 0 || value > _BIGARRAY_MAX_LENGTH)
{
return _jsx.throwThis(_RangeError,
383,10 → 412,81
* integer value that can be used as index.
*
* @memberOf jsx.array.BigArray
* @type Number
*/
MAX_LENGTH: _BIGARRAY_MAX_LENGTH,
 
/**
* Returns a <code>BigArray</code> whose elements are
* delimited parts of a string.
*
* Works the same as {@link String.prototype.split}
* except that it returns a <code>BigArray</code>
* instead of an <code>Array</code>.
*
* @requires regexp.js
* @param {String} s
* @return jsx.array.BigArray
* @throws jsx.array.RangeError
* if the string has more parts than
* jsx.array.BigArray.MAX_LENGTH
*/
fromString: function (s, rxDelim) {
/* globalize expression */
if (typeof rxDelim == "string")
{
rxDelim = jsx.regexp.escape(rxDelim);
}
 
rxDelim = new jsx.regexp.RegExp(rxDelim, "g");
 
var a = new this();
var start = 0;
 
var match;
while ((match = rxDelim.exec(s)))
{
a.push(s.substring(start, match.index));
start = match.index + 1;
}
 
a.push(s.substring(start));
 
return a;
},
 
/**
* Returns a <code>BigArray</code> whose elements are
* characters of a string.
*
* @requires regexp.js
* @param {String} s
* @param {RegExp} rxChars (option)
* Regular expression to match characters.
* The default is <code>/[\u0000-\uFFFF]/</code>.
* @return jsx.array.BigArray
* @throws jsx.array.RangeError
* if the string has more characters than
* jsx.array.BigArray.MAX_LENGTH
*/
fromChars: function (s, rxChars) {
/* globalize expression */
rxChars = rxChars
? new jsx.regexp.RegExp(rxChars, "g")
: /[\u0000-\uFFFF]/g;
 
var a = new this();
 
var match;
while ((match = rxChars.exec(s)))
{
a.push(match[0]);
}
 
return a;
},
 
/**
* Determines if a value can be used as internal
* <code>BigArray</code> index.
*
428,11 → 528,30
this.setLength(0);
},
 
deleteElement: function (index) {
this.set(index, void 0);
 
var max_index = -1;
 
if (this.getLength() === index + 1)
{
for (var i in this)
{
if (_BigArray.isIndex(i) && i < index && i > max_index)
{
max_index = i;
}
}
}
 
this.setLength(max_index + 1);
},
 
/**
* @param {int} index
* @return {any} the element of this array at <var>index</var>
*/
"get": function BigArray_get (index) {
get: function BigArray_get (index) {
if (arguments.length < 1)
{
return jsx.throwThis(jsx.InvalidArgumentError,
440,14 → 559,9
BigArray_get);
}
 
if (index < 0)
{
index = this.getLength() + Math.ceil(index);
}
else
{
index = Math.floor(index);
}
index = (index < 0
? this.getLength() + Math.ceil(index)
: Math.floor(index));
 
return this[index];
},
458,7 → 572,7
* @param {int} index
* @param {any} value
*/
"set": function (index, value) {
set: function (index, value) {
var length = this.getLength();
 
if (index < 0)
492,7 → 606,7
* <code>length</code> property, to this array.
*/
setAll: function (src) {
if (_isArray(src) || src instanceof _BigArray)
if (_isArray(src) || _BigArray.isInstance(src))
{
for (var i in src)
{
561,6 → 675,197
},
 
/**
* Adds elements at the end of this array.
*
* @params New elements
* @return {int} the new length
*/
push: function () {
var len = this.getLength();
 
for (var i = 0, argc = arguments.length; i < argc; ++i)
{
var arg = arguments[i];
this.set(len++, arg);
}
 
return len;
},
 
/**
* Returns a part (slice) of this array.
*
* <em>WARNING: Because slices observe element order, returning
* big slices of BigArrays with lengths (maximum index + 1)
* greater than 2³²−1 can take a considerable amount of time.
* Avoid running such code in the main thread. Where order
* does not matter, use {@link #unorderedSlice()} instead.</em>
*
* @param {int} start
* Index of the first element to include in the slice.
* If negative, the absolute value is counted from
* the end of this array.
* @param {int} end (optional)
* Index of the first element not to include in the slice.
* If negative, the absolute value is counted from
* the end of this array. The default is the length
* of this array, therefore omitting this argument
* returns a slice of all elements from the one at index
* <var>start</var>.
* @return jsx.array.BigArray
*/
slice: function (start, end) {
var len = this.getLength();
if (len <= _MAX_ARRAY_LENGTH)
{
return new _BigArray(_slice.call(this, start, end));
}
 
var relativeStart = _toInteger(start);
 
var k = (relativeStart < 0
? Math.max(len + relativeStart, 0)
: Math.min(relativeStart, len));
 
var relativeEnd = (typeof end == "undefined"
? len
: _toInteger(end));
 
var _final = (relativeEnd < 0
? Math.max(len + relativeEnd, 0)
: Math.min(relativeEnd, len));
 
var n = 0;
var part = new _BigArray();
 
while (k < _final)
{
if (k in this)
{
/* Using set() instead of push() avoids repeated getLength() */
part.set(n, this.get(k));
}
 
++k;
++n;
}
 
return part;
},
 
/**
* Modifies this array in place.
*
* @param {int} start
* Index at where to start processing
* @param {int} deleteCount
* Number of elements to delete
* @params {int} _
* Elements to insert
* @return {int} Number of inserted elements
*/
splice: function (start, deleteCount) {
var relativeStart = _toInteger(start);
 
var len = this.getLength();
 
var actualStart = (relativeStart < 0
? Math.max(len + relativeStart, 0)
: min(relativeStart, len));
 
var actualDeleteCount = Math.min(
Math.max(_toInteger(deleteCount), 0),
len - actualStart);
 
for (var i = actualStart; i < actualStart + actualDeleteCount; ++i)
{
this.deleteElement(i);
}
 
var inserted = 0;
 
i = start;
for (var argi = 2, argc = arguments.length; argi < argc; ++argi)
{
this.set(i++, arguments[argi]);
++inserted;
}
 
return inserted;
},
 
/**
* Returns a part (slice) of this array without observing
* index order.
*
* @param {int} start
* Index of the first element to include in the slice.
* If negative, the absolute value is counted from
* the end of this array.
* @param {int} end (optional)
* Index of the first element not to include in the slice.
* If negative, the absolute value is counted from
* the end of this array. The default is the length
* of this array, therefore omitting this argument
* returns a slice of all elements from the one at index
* <var>start</var>.
* @return jsx.array.BigArray
*/
unorderedSlice: function (start, end) {
function _toInteger (a)
{
var number = +a;
 
if (isNaN(number))
{
return 0;
}
 
if (number === 0 || number === Infinity || number === -Infinity)
{
return number;
}
 
return (number < 0 ? -1 : 1) * Math.floor(Math.abs(number));
}
 
var len = this.getLength();
if (len <= _MAX_ARRAY_LENGTH)
{
return new _BigArray(_slice.call(this, start, end));
}
 
var part = new _BigArray();
 
var relativeStart = _toInteger(start);
 
var k = (relativeStart < 0
? Math.max(len + relativeStart, 0)
: Math.min(relativeStart, len));
 
var relativeEnd = (typeof end == "undefined"
? len
: _toInteger(end));
 
var _final = (relativeEnd < 0
? Math.max(len + relativeEnd, 0)
: Math.min(relativeEnd, len));
 
var n = 0;
 
for (var p in this)
{
if (_BigArray.isIndex(p) && p >= k && p < _final)
{
/* Using set() instead of push() avoids repeated getLength() */
part.set(n++, this.get(p));
}
}
 
return part;
},
 
/**
* Returns this <code>BigArray</code> as an {@link Array},
* with extra indexes if necessary.
*