Skip to content

Commit

Permalink
Merge pull request #9113 from johnspackman/arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
cajus committed Aug 23, 2016
2 parents 8f49c5e + 1bd5628 commit a1b580e
Show file tree
Hide file tree
Showing 4 changed files with 233 additions and 11 deletions.
44 changes: 39 additions & 5 deletions framework/source/class/qx/data/Array.js
Expand Up @@ -141,13 +141,14 @@ qx.Class.define("qx.data.Array",
/**
* Concatenates the current and the given array into a new one.
*
* @param array {Array} The javaScript array which should be concatenated
* @param array {qx.data.Array|Array} The javaScript array which should be concatenated
* to the current array.
*
* @return {qx.data.Array} A new array containing the values of both former
* arrays.
*/
concat: function(array) {
array = qx.lang.Array.toNativeArray(array);
if (array) {
var newArray = this.__array.concat(array);
} else {
Expand Down Expand Up @@ -422,6 +423,26 @@ qx.Class.define("qx.data.Array",
}
return (new qx.data.Array(returnArray));
},


/**
* Efficiently replaces the array with the contents of src; this will suppress the
* change event if the array contents are the same, and will make sure that only
* one change event is fired
*
* @param src {qx.data.Array|Array} the new value to set the array to
*/
replace: function(src) {
src = qx.lang.Array.toNativeArray(src);
if (this.equals(src)) {
return;
}
var args = [ 0, this.getLength() ];
src.forEach(function(item) {
args.push(item);
});
this.splice.apply(this, args);
},


/**
Expand Down Expand Up @@ -759,9 +780,7 @@ qx.Class.define("qx.data.Array",
append : function(array)
{
// qooxdoo array support
if (array instanceof qx.data.Array) {
array = array.toArray();
}
array = qx.lang.Array.toNativeArray(array);

// this check is important because opera throws an uncatchable error if
// apply is called without an array as argument.
Expand Down Expand Up @@ -805,6 +824,20 @@ qx.Class.define("qx.data.Array",
},


/**
* Removes all elements which are listed in the array.
*
* @param array {Array} the elements of this array will be excluded from this one
*/
exclude : function(array)
{
array = qx.lang.Array.toNativeArray(array);
array.forEach(function(item) {
this.remove(item);
}, this);
},


/**
* Remove the given item.
*
Expand Down Expand Up @@ -836,9 +869,10 @@ qx.Class.define("qx.data.Array",
return false;
}

array = qx.lang.Array.toNativeArray(array);
for (var i = 0; i < this.length; i++)
{
if (this.getItem(i) !== array.getItem(i)) {
if (this.getItem(i) !== array[i]) {
return false;
}
}
Expand Down
90 changes: 86 additions & 4 deletions framework/source/class/qx/lang/Array.js
Expand Up @@ -287,6 +287,13 @@ qx.Bootstrap.define("qx.lang.Array",
*/
append : function(arr1, arr2)
{
if (arr1 instanceof qx.data.Array) {
return arr1.append(arr2);
}
if (arr2 instanceof qx.data.Array) {
arr2 = arr2.toArray();
}

// this check is important because opera throws an uncatchable error if apply is called without
// an arr as second argument.
if (qx.core.Environment.get("qx.debug"))
Expand All @@ -311,6 +318,10 @@ qx.Bootstrap.define("qx.lang.Array",
*/
exclude : function(arr1, arr2)
{
if (arr1 instanceof qx.data.Array) {
return arr1.exclude(arr1, arr2);
}

// this check is important because opera throws an uncatchable error if apply is called without
// an arr as second argument.
if (qx.core.Environment.get("qx.debug"))
Expand All @@ -319,13 +330,12 @@ qx.Bootstrap.define("qx.lang.Array",
qx.core.Assert && qx.core.Assert.assertArray(arr2, "The second parameter must be an array.");
}

for (var i=0, il=arr2.length, index; i<il; i++)
{
index = arr1.indexOf(arr2[i]);
arr2.forEach(function(item) {
var index = arr1.indexOf(item);
if (index != -1) {
arr1.splice(index, 1);
}
}
});

return arr1;
},
Expand All @@ -340,6 +350,10 @@ qx.Bootstrap.define("qx.lang.Array",
*/
remove : function(arr, obj)
{
if (arr instanceof qx.data.Array) {
return arr.remove(obj);
}

var i = arr.indexOf(obj);

if (i != -1)
Expand Down Expand Up @@ -372,6 +386,11 @@ qx.Bootstrap.define("qx.lang.Array",
*/
equals : function(arr1, arr2)
{
if (arr1 instanceof qx.data.Array) {
return arr1.equals(arr2);
}
arr2 = qx.lang.Array.toNativeArray(arr2);

var length = arr1.length;

if (length !== arr2.length) {
Expand Down Expand Up @@ -593,6 +612,69 @@ qx.Bootstrap.define("qx.lang.Array",
}

return range;
},


/**
* Replaces the contents of the array `dest`
*
* @param dest {Array|qx.data.Array} the array to edit (if null then a new array is created)
* @param src {Array|qx.data.Array} the array to copy from, or null
* @return {Array} the edited array (or the new array, if dest is null)
*/
replace: function(dest, src) {
if (dest instanceof qx.data.Array) {
return dest.replace(src);
}

if (src === null) {
if (dest === null) {
return null;
} else {
return [];
}
}

src = qx.lang.Array.toNativeArray(src);
if (dest === null) {
dest = src.slice(0);
} else {
var args = [ 0, dest.length ];
src.forEach(function(item) {
args.push(item);
});
dest.splice.apply(dest, args);
}
return dest;
},


/**
* Returns a native array from src where possible; qx.data.Array is converted to its native array,
* in which case unless `clone` parameter is set to true the rules of qx.data.Array.toArray should
* be followed, ie that the array should not be manipulated directly.
*
* @param src {qx.data.Array|Array} the object to return as an array
* @param clone{Boolean?} whether to make the returned array a clone, ie editable by the calling code
* @return {Array}
*/
toNativeArray: function(src, clone) {
if (src === undefined || src === null) {
return src;
}
if (src instanceof qx.data.Array) {
if (clone) {
return src.toArray().slice(0);
}
return src.toArray();
}
if (qx.lang.Type.isArray(src)) {
if (clone) {
return src.slice(0);
}
return src;
}
return [ src ];
}
}
});
38 changes: 36 additions & 2 deletions framework/source/class/qx/test/data/DataArray.js
Expand Up @@ -142,6 +142,10 @@ qx.Class.define("qx.test.data.DataArray",
var b = this.__a.concat(["four", "five"]);
this.assertEquals("one two three four five", b.join(" "), "Concat does not work");
b.dispose();

var b = this.__a.concat(new qx.data.Array(["four", "five"]));
this.assertEquals("one two three four five", b.join(" "), "Concat does not work");
b.dispose();
},


Expand All @@ -159,6 +163,25 @@ qx.Class.define("qx.test.data.DataArray",
this.assertEquals("two", slice.getItem(1), "Slice does not work");
slice.dispose();
},


testReplace: function() {
var numFired = 0;
var id = this.__a.addListener("change", function() {
numFired++;
});

this.__a.replace([ "one", "two", "three" ]);
this.assertEquals(0, numFired);
this.__a.replace([ "one", "three" ]);
this.assertEquals(1, numFired);
this.assertArrayEquals([ "one", "three" ], this.__a.toArray());
this.__a.replace(new qx.data.Array([ "two", "four" ]));
this.assertEquals(2, numFired);
this.assertArrayEquals([ "two", "four" ], this.__a.toArray());

this.__a.removeListenerById(id);
},


testPop: function() {
Expand Down Expand Up @@ -399,6 +422,17 @@ qx.Class.define("qx.test.data.DataArray",
this.assertEquals("sechs", this.__a.getItem(5), "append does not work");
dArray.dispose();
},


testExclude: function() {
var tmp = new qx.data.Array([ "one", "two", "three", "four", "five" ]);
tmp.exclude([ "two", "four" ]);
this.assertArrayEquals(tmp.toArray(), [ "one", "three", "five" ]);

var tmp = new qx.data.Array([ "one", "two", "three", "four", "five" ]);
tmp.exclude(new qx.data.Array([ "one", "three", "five" ]));
this.assertArrayEquals(tmp.toArray(), [ "two", "four" ]);
},


testRemove: function() {
Expand All @@ -412,10 +446,10 @@ qx.Class.define("qx.test.data.DataArray",

testEquals: function() {
var a = new qx.data.Array("one", "two", "three");

this.assertTrue(this.__a.equals(a), "equals does not work.");

a.dispose();

this.assertTrue(this.__a.equals([ "one", "two", "three" ]), "equals does not work.");
},


Expand Down
72 changes: 72 additions & 0 deletions framework/source/class/qx/test/lang/Array.js
Expand Up @@ -32,9 +32,17 @@ qx.Class.define("qx.test.lang.Array",
this.assertNotUndefined(qx.lang.Array.append);
var a = [ 1, 2, 3 ];
qx.lang.Array.append(a, [ 4, 5, 6 ]);
this.assertJsonEquals(a, [ 1, 2, 3, 4, 5, 6 ]);

var a = [ 1, 2, 3 ];
qx.lang.Array.append(a, new qx.data.Array([ 4, 5, 6 ]));
this.assertJsonEquals(a, [ 1, 2, 3, 4, 5, 6 ]);

var a = new qx.data.Array([ 1, 2, 3 ]);
qx.lang.Array.append(a, [ 4, 5, 6 ]);
this.assertJsonEquals(a.toArray(), [ 1, 2, 3, 4, 5, 6 ]);
a.dispose();

var error = false;

try {
Expand All @@ -45,6 +53,22 @@ qx.Class.define("qx.test.lang.Array",

this.assert(error);
},


testExclude : function() {
var a = [ 1, 2, 3, 4, 5 ];
qx.lang.Array.exclude(a, [ 2, 4 ]);
this.assertJsonEquals([ 1, 3, 5 ], a);

var a = [ 1, 2, 3, 4, 5 ];
qx.lang.Array.exclude(a, new qx.data.Array([ 1, 3, 5 ]));
this.assertJsonEquals([ 2, 4 ], a);

var a = new qx.data.Array([ 1, 2, 3, 4, 5 ]);
qx.lang.Array.exclude(a, [ 1, 3, 5 ]);
this.assertJsonEquals([ 2, 4 ], a.toArray());
a.dispose();
},


testMinNumeric : function()
Expand Down Expand Up @@ -102,6 +126,12 @@ qx.Class.define("qx.test.lang.Array",

this.assertJsonEquals(a, [ -3, -2, -1, 0, 1, 3 ]);
this.assertEquals(6, a.length);

var da = new qx.data.Array([ -3, -2, -1, 0, 1, 2, 3 ]);
qx.lang.Array.remove(da, 2);

this.assertJsonEquals(da.toArray(), [ -3, -2, -1, 0, 1, 3 ]);
this.assertEquals(6, da.length);
},


Expand All @@ -122,6 +152,48 @@ qx.Class.define("qx.test.lang.Array",

this.assertJsonEquals(a, []);
this.assertEquals(0, a.length);
},


testContains: function() {
var a = [ -3, -2, -1, 0, 1, 2, 3 ];
var da = new qx.data.Array(a);

this.assertTrue(qx.lang.Array.contains(a, -2));
this.assertFalse(qx.lang.Array.contains(a, -10));
this.assertTrue(qx.lang.Array.contains(da, -2));
this.assertFalse(qx.lang.Array.contains(da, -10));

da.dispose();
},


testEquals : function() {
var a = [ -3, -2, -1, 0, 1, 2, 3 ];
var da = new qx.data.Array(a);

this.assertFalse(da.toArray() === a);
this.assertTrue(qx.lang.Array.equals(a, da));
this.assertTrue(qx.lang.Array.equals(da, a));
this.assertFalse(qx.lang.Array.equals(a, [ 4, 5, 6 ]));
},


testReplace: function() {
var a = [ 1, 2, 3 ];
var tmp = qx.lang.Array.replace(a, [ "one", "two", "three" ]);
this.assertTrue(a === tmp);
this.assertArrayEquals([ "one", "two", "three" ], a);
},


testToNativeArray : function() {
var da = new qx.data.Array([ 1, 2, 3 ]);
var na = qx.lang.Array.toNativeArray(da);
this.assertTrue(da.toArray() === na);
na = qx.lang.Array.toNativeArray(da, true);
this.assertTrue(da.toArray() !== na);
this.assertArrayEquals([ 1, 2, 3 ], na);
}
}
});

0 comments on commit a1b580e

Please sign in to comment.