Skip to content

Commit 17ff345

Browse files
committed
WebUI: filter array elements in-place
Currently JS `Array` have no method to filter element in-place so we provide one which result in better performance and less memory allocations.
1 parent 7297225 commit 17ff345

File tree

5 files changed

+39
-16
lines changed

5 files changed

+39
-16
lines changed

src/webui/www/private/rename_files.html

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,11 @@
254254
document.getElementById("renameOptions").disabled = false;
255255

256256
// Recreate table
257-
let selectedRows = bulkRenameFilesTable.getSelectedRows().map(row => row.rowId.toString());
258-
for (const renamedRow of rows)
259-
selectedRows = selectedRows.filter(selectedRow => selectedRow !== renamedRow.rowId.toString());
257+
const selectedRows = bulkRenameFilesTable.getSelectedRows().map(row => row.rowId.toString());
258+
for (const renamedRow of rows) {
259+
const id = renamedRow.rowId.toString();
260+
window.qBittorrent.Misc.filterInPlace(selectedRows, (row => row !== id));
261+
}
260262
bulkRenameFilesTable.clear();
261263

262264
// Adjust file enumeration count by 1 when replacing single files to prevent naming conflicts

src/webui/www/private/scripts/dynamicTable.js

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -871,13 +871,7 @@ window.qBittorrent.DynamicTable ??= (() => {
871871

872872
updateTable(fullUpdate = false) {
873873
const rows = this.getFilteredAndSortedRows();
874-
875-
for (let i = 0; i < this.selectedRows.length; ++i) {
876-
if (!(this.selectedRows[i] in rows)) {
877-
this.selectedRows.splice(i, 1);
878-
--i;
879-
}
880-
}
874+
window.qBittorrent.Misc.filterInPlace(this.selectedRows, (selectedRow => selectedRow in rows));
881875

882876
if (this.useVirtualList) {
883877
// rerender on table update
@@ -2832,7 +2826,8 @@ window.qBittorrent.DynamicTable ??= (() => {
28322826

28332827
getSelectedRows() {
28342828
const nodes = this.fileTree.toArray();
2835-
return nodes.filter(x => x.checked === 0);
2829+
window.qBittorrent.Misc.filterInPlace(nodes, (node => node.checked === 0));
2830+
return nodes;
28362831
}
28372832

28382833
initColumns() {

src/webui/www/private/scripts/misc.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ window.qBittorrent.Misc ??= (() => {
3434
return {
3535
getHost: getHost,
3636
createDebounceHandler: createDebounceHandler,
37+
filterInPlace: filterInPlace,
3738
friendlyUnit: friendlyUnit,
3839
friendlyDuration: friendlyDuration,
3940
friendlyPercentage: friendlyPercentage,
@@ -90,6 +91,18 @@ window.qBittorrent.Misc ??= (() => {
9091
};
9192
};
9293

94+
const filterInPlace = (array, predicate) => {
95+
let j = 0;
96+
for (let i = 0; i < array.length; ++i) {
97+
if (predicate(array[i])) {
98+
if (i > j)
99+
array[j] = array[i];
100+
++j;
101+
}
102+
}
103+
array.splice(j, (array.length - j));
104+
};
105+
93106
/*
94107
* JS counterpart of the function in src/misc.cpp
95108
*/

src/webui/www/private/views/rss.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@
275275
.map((rowID) => rssFeedTable.getRow(rowID).full_data.dataPath);
276276
// filter children
277277
const reducedDatapaths = selectedDatapaths.filter((path) =>
278-
selectedDatapaths.filter((innerPath) => path.slice(0, innerPath.length) === innerPath).length === 1
278+
selectedDatapaths.filter(innerPath => path.startsWith(innerPath)).length === 1
279279
);
280280
removeItem(reducedDatapaths);
281281
},
@@ -428,7 +428,7 @@
428428
childFeeds.add(row.full_data.dataUid);
429429
}
430430

431-
let visibleArticles = [];
431+
const visibleArticles = [];
432432
for (const feedEntry in feedData) {
433433
if (childFeeds.has(feedEntry)) {
434434
visibleArticles.append(feedData[feedEntry]
@@ -440,12 +440,12 @@
440440
}
441441
// filter read articles if "Unread" feed is selected
442442
if (path === "")
443-
visibleArticles = visibleArticles.filter((a) => !a.isRead);
443+
window.qBittorrent.Misc.filterInPlace(visibleArticles, (article => !article.isRead));
444444

445445
const rssFilterInput = document.getElementById("rssFilterInput");
446446
if (rssFilterInput.value.length > 0) {
447447
const lowerFilter = rssFilterInput.value.toLowerCase();
448-
visibleArticles = visibleArticles.filter((a) => a.title.toLowerCase().includes(lowerFilter));
448+
window.qBittorrent.Misc.filterInPlace(visibleArticles, (article => article.title.toLowerCase().includes(lowerFilter)));
449449
}
450450

451451
let rowID = -1;
@@ -980,7 +980,7 @@
980980
.map((sRow) => rssFeedTable.getRow(sRow).full_data.dataPath);
981981
// filter children
982982
const reducedDatapaths = selectedDatapaths.filter((path) =>
983-
selectedDatapaths.filter(path.startsWith).length === 1
983+
selectedDatapaths.filter(innerPath => path.startsWith(innerPath)).length === 1
984984
);
985985
for (const path of reducedDatapaths)
986986
markItemAsRead(path);

src/webui/www/test/private/misc.test.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,19 @@ import { expect, test, vi } from "vitest";
3030

3131
import "../../private/scripts/misc.js";
3232

33+
test("Test filterInPlace()", () => {
34+
const filterInPlace = (array, predicate) => {
35+
window.qBittorrent.Misc.filterInPlace(array, predicate);
36+
return array;
37+
};
38+
39+
expect(filterInPlace([], (() => true))).toStrictEqual([]);
40+
expect(filterInPlace([], (() => false))).toStrictEqual([]);
41+
expect(filterInPlace([1, 2, 3, 4], (() => true))).toStrictEqual([1, 2, 3, 4]);
42+
expect(filterInPlace([1, 2, 3, 4], (() => false))).toStrictEqual([]);
43+
expect(filterInPlace([1, 2, 3, 4], (x) => { return (x % 2) === 0; })).toStrictEqual([2, 4]);
44+
});
45+
3346
test("Test toFixedPointString()", () => {
3447
const toFixedPointString = window.qBittorrent.Misc.toFixedPointString;
3548

0 commit comments

Comments
 (0)