Passed
Push — master ( 8d43c8...457e33 )
by Night
01:12
created

src/ub.arrays.core.js   F

Complexity

Total Complexity 293
Complexity/F 4.13

Size

Lines of Code 1331
Function Count 71

Duplication

Duplicated Lines 123
Ratio 9.24 %

Importance

Changes 2
Bugs 2 Features 0
Metric Value
cc 0
eloc 732
nc 1
dl 123
loc 1331
rs 1.868
c 2
b 2
f 0
wmc 293
mnd 6
bc 271
fnc 71
bpm 3.8169
cpm 4.1266
noi 14

71 Functions

Rating   Name   Duplication   Size   Complexity  
B arrayFuncs.merge 0 44 7
A arrayFuncs.indexOf 0 12 4
A arrayFuncs.addRange 0 18 3
B arrayFuncs.addArray 0 22 7
A arrayFuncs.within 0 22 4
A arrayFuncs.containsAny 0 4 1
A arrayFuncs.moveToArray 0 18 4
A arrayFuncs.count 16 16 5
B arrayFuncs.removeAndInsert 0 44 8
A arrayFuncs.replaceMany 0 15 5
A arrayFuncs.moveSlotDown 0 15 3
B arrayFuncs.moveToTop 23 41 8
A arrayFuncs.removeLastX 0 22 4
B arrayFuncs.moveToBottom 26 43 8
A arrayFuncs.contains 0 7 2
B arrayFuncs.replace 0 19 6
B arrayFuncs.containsAll 0 16 7
A arrayFuncs.last 0 8 2
A arrayFuncs.firstExisting 0 10 3
A arrayFuncs.addToStart 0 5 1
A arrayFuncs.swap 0 6 1
A arrayFuncs.removeLast 0 14 3
A arrayFuncs.moveUp 0 15 2
A arrayFuncs.removeEdges 0 7 2
A arrayFuncs.moveSlotUp 0 15 3
A arrayFuncs.splitAt 0 10 3
C arrayFuncs.replaceRange 0 37 9
A arrayFuncs.removeFirst 0 14 3
A arrayFuncs.or 0 7 2
A arrayFuncs.replaceOnce 0 9 3
A arrayFuncs.insertOne 0 8 1
A arrayFuncs.insertArray 0 16 3
A arrayFuncs.insertOneOrAdd 0 13 3
A arrayFuncs.lastX 0 5 1
A arrayFuncs.moveDown 0 16 3
A arrayFuncs.add 0 5 1
A arrayFuncs.addOnce 0 12 2
A arrayFuncs.removeOnce 0 8 2
A arrayFuncs.removePart 0 6 1
A arrayFuncs.indexOfNot 0 12 4
A arrayFuncs.lastIndexOfNot 12 12 4
A arrayFuncs.insertArrayAfter 0 9 2
A arrayFuncs.addManyTimes 0 14 3
A arrayFuncs.setFirst 0 8 2
B arrayFuncs.remove 0 21 6
A arrayFuncs.first 0 8 2
A arrayFuncs.random 0 11 2
B arrayFuncs.indexOfArray 0 26 6
A arrayFuncs.setLast 0 8 2
A arrayFuncs.removeFirstX 0 22 4
A arrayFuncs.findOrAdd 0 14 2
A arrayFuncs.lastIndexOf 12 12 4
A arrayFuncs.part 0 11 5
A arrayFuncs.next 0 11 5
A arrayFuncs.getByMatchingArray 0 5 2
F arrayFuncs._indexedQuickSort 0 118 21
A arrayFuncs.pickMatching 17 17 5
A arrayFuncs.transpose 0 15 4
A arrayFuncs.splitAtEvery 0 12 4
B arrayFuncs.trim 0 30 7
A arrayFuncs.quickSort 0 16 3
B arrayFuncs.trimLeft 0 27 6
A arrayFuncs.trimRight 0 24 4
A arrayFuncs.page 0 22 2
A arrayFuncs.indexedQuickSort 0 20 3
A arrayFuncs.prev 0 11 4
A arrayFuncs.setByMatchingArray 0 9 2
F arrayFuncs._quickSort 0 70 21
A arrayFuncs.pick 17 17 4
A arrayFuncs.props 0 12 4
A arrayFuncs.where 0 14 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like src/ub.arrays.core.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/** global: UB */
2
/** global: Buffer */
3
4
/*! ARRAY UTILS */
5
6
var arrayFuncs = {
7
8
	merge: function(){
9
		var arr = this;
10
		var val1 = arr[0];
11
12
		// if array of strings
13
		if (val1.isString()){
14
			return val1.join("");
15
		}
16
17
		// if array of arrays
18
		if (val1.isArray()){
19
			var merged = [];
20
			for (var a = 0, al = arr.length; a<al; a++){
21
				merged.addArray(arr[a]);
22
			}
23
			return merged;
24
		}
25
26
		// if array of Buffers
27
		//removeIf(nodejs)
28
		if (val1 instanceof Buffer){
29
30
			// calc the total length of all buffers
31
			var buffers = arr;
32
			var len = 0;
33
			for(var b = 0, bl = buffers.length; b < bl; b++) {
34
				len += buffers[b].length;
35
			}
36
37
			// create a new buffer of that length
38
			var mega = new Buffer(len);
39
40
			// write all buffers into the mega buffer
41
			var cur = 0;
42
			for(var b = 0, bl = buffers.length; b < bl; b++) {
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable bl already seems to be declared on line 33. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
Comprehensibility Naming Best Practice introduced by
The variable b already seems to be declared on line 33. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
43
				buffers[b].copy(mega, cur, 0);
44
				cur += buffers[b].length;
45
			}
46
			return mega;
47
		}
48
		//endRemoveIf(nodejs)
49
50
		return null;
51
	},
52
	
53
	indexOf: function(value){
54
		var list = this;
55
		if (list.length === 0) {
56
			return -1;
57
		}
58
		for (var a = 0, al = list.length;a<al;a++){
59
			if (list[a] == value){
60
				return a;
61
			}
62
		}
63
		return -1;
64
	},
65
	indexOfNot: function(value){
66
		var list = this;
67
		if (list.length === 0) {
68
			return -1;
69
		}
70
		for (var a = 0, al = list.length;a<al;a++){
71
			if (list[a] != value){
72
				return a;
73
			}
74
		}
75
		return -1;
76
	},
77 View Code Duplication
	lastIndexOf: function(value){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
78
		var list = this;
79
		if (list.length === 0) {
80
			return -1;
81
		}
82
		for (var a = list.length-1;a>=0;a--){
83
			if (list[a] == value){
84
				return a;
85
			}
86
		}
87
		return -1;
88
	},
89 View Code Duplication
	lastIndexOfNot: function(value){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
90
		var list = this;
91
		if (list.length === 0) {
92
			return -1;
93
		}
94
		for (var a = list.length-1;a>=0;a--){
95
			if (list[a] != value){
96
				return a;
97
			}
98
		}
99
		return -1;
100
	},
101
	
102 View Code Duplication
	count: function(value, not = false){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
103
		var list = this;
104
		var total = 0;
105
		for (var a = 0, al = list.length;a<al;a++){
106
			if (not) {
107
				if (list[a] != value) {
108
					total++;
109
				}
110
			}else {
111
				if (list[a] == value) {
112
					total++;
113
				}
114
			}
115
		}
116
		return total;
117
	},
118
	or: function(list2){
119
		var list = this;
120
		if (Exists(list)) {
121
			return list;
122
		}
123
		return list2;
124
	},
125
	
126
	part: function(start, end){
127
		var list = this;
128
		
129
		// quickly exit if no items or no results possible
130
		if (list == null || list.length === 0 || start > end || start >= list.length) {
131
			return [];
132
		}
133
		
134
		// just get the part we need
135
		return list.slice(start, end + 1);
136
	},
137
	
138
	swap: function(slot1, slot2){
139
		var list = this;
140
		var temp = list[slot2];
141
		list[slot2] = list[slot1];
142
		list[slot1] = temp;
143
	},
144
145
	add: function(item){
146
		var list = this;
147
		list.push(item);
148
		return list.length - 1;
149
	},
150
	addToStart: function(item){
151
		var list = this;
152
		list.unshift(item);
153
		return 0;
154
	},
155
	/** return false if item exists, true if item does not */
156
	addOnce: function(value){
157
		var list = this;
158
		
159
		// return false if item exists
160
		if (list.indexOf(value) > -1) {
161
			return false;
162
		}
163
		
164
		// add if not found
165
		list.push(value);
166
		return true;
167
	},
168
	
169
	addArray: function(toAdd, addAtSlot = -1, modifyMain = true){
170
		var list = this;
171
		
172
		if (toAdd != null && toAdd.length > 0) {
173
			if (!modifyMain) {
174
				list = list.concat(); /// shallow clone
175
			}
176
			
177
			// set length first so allocates memory (maybe?)
178
			var origLen = list.length;
179
			if (addAtSlot === -1){
180
				list.length += toAdd.length;
181
			}
182
			
183
			// set all slots
184
			var next = addAtSlot === -1 ? origLen : addAtSlot;
185
			for (var a = 0, al = toAdd.length;a<al;a++, next++){
186
				list[next] = toAdd[a];
187
			}
188
		}
189
		return list;
190
	},
191
	
192
	/** adds the given value many times */
193
	addManyTimes: function(val, times){
194
		var list = this;
195
		
196
		if (times <= 0) {
197
			return list;
198
		}
199
		
200
		var n = list.length;
201
		for (var t = 0;t<times;t++){
202
			list[n++] = val;
203
		}
204
		
205
		return list;
206
	},
207
	
208
	addRange: function(toAdd, startSlot, endSlot){
209
		var list = this;
210
		
211
		// exit if no work
212
		if (endSlot < startSlot) {
213
			return;
214
		}
215
		
216
		// per wanted slot of the `add` array
217
		startSlot = startSlot.limitToArray(toAdd);
218
		endSlot = endSlot.limitToArray(toAdd);
219
		for (var s = startSlot;s <= endSlot;s++){
220
			
221
			// add into `main` array
222
			list.push(toAdd[s]);
223
			
224
		}
225
	},
226
	
227
	/** returns final index of added item, or index of already existing item */
228
	findOrAdd: function(value){
229
		var list = this;
230
		
231
		// return index of item if exists
232
		var i = list.indexOf(value);
233
		if (i > -1) {
234
			return i;
235
		}
236
		
237
		// add if not found
238
		i = list.length;
239
		list[i] = value;
240
		return i;
241
	},
242
	
243
	insertOne: function(item, slot){
244
		var list = this;
245
		
246
		// adds one slot at the given point
247
		// modifies the main array
248
		
249
		list.splice(slot, 0, item);
250
	},
251
252
	/** if slot = -1 or outside the array, the item is added to the END of the array.
253
	 * Otherwise the item is added at the given slot. */
254
	insertOneOrAdd: function(item, slot){
255
		var list = this;
256
		
257
		// adds one slot at the given point
258
		// modifies the main array
259
		
260
		if (slot < 0 || slot >= list.length) {
261
			list.push(item);
262
			return list.length - 1;
263
		}
264
		list.splice(slot, 0, item);
265
		return slot;
266
	},
267
	insertArray: function(newItems, slot, returnNew = true){
268
		var list = this;
269
		
270
		// adds many slots at the given point
271
		// returns a new array
272
		if(returnNew){
273
			return list.slice(0, slot).concat(newItems).concat(list.slice(slot));
274
		}
275
		
276
		// adds many slots at the given point
277
		// modifies the main array
278
		for (var a = 0, al = newItems.length;a<al;a++){
279
			list.splice(slot++, 0, newItems[a]);
280
		}
281
		return list;
282
	},
283
	insertArrayAfter: function(newItems, after){
284
		var list = this;
285
		if (list.isLast(after)) {
286
			list.addArray(newItems);
287
		} else {
288
			var i = list.indexOf(after);
289
			list.insertArray(i + 1, newItems);
290
		}
291
	},
292
	
293
294
	removeAndInsert: function(from, to){
295
		var list = this;
296
		
297
		// ensure slots within array
298
		var al = list.length;
299
		from = from.limitTo(0, al - 1);
300
		to = to.limitTo(0, al - 1);
301
		if (to < from) {
302
			var i1 = to;
303
			var i2 = from;
304
		}else {
305
			i1 = from;
306
			i2 = to;
307
		}
308
		
309
		// fill unaffected header
310
		var result = [];
311
		if(i1 > 0){
312
			for (var a = 0;a<i1;a++){
313
				result[a] = list[a];
314
			}
315
		}
316
		
317
		// fill "to"
318
		result[to] = list[from];
319
		
320
		// fill between from and to
321
		if(to < from){
322
			for (a = to + 1; a <= from; a++) {
323
				result[a] = list[a - 1];
324
			}
325
		}else {
326
			for (a = from; a < to; a++) {
327
				result[a] = list[a + 1];
328
			}
329
		}
330
		
331
		// fill unaffected footer
332
		for (var a = i2 + 1;a<al;a++){
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable a already seems to be declared on line 312. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
333
			result[a] = list[a];
334
		}
335
		
336
		return result;
337
	},
338
	
339
	/** replace a range of items with a given array */
340
	replaceRange: function(replaceStartSlot, replaceEndSlot, newItems, returnNew = true){
341
		var list = this;
342
		
343
		
344
		// simply remove a single item
345
		if (replaceStartSlot == replaceEndSlot && newItems.length === 0) {
346
			if (returnNew) {
347
				list = list.concat();
348
			}
349
			list.splice(replaceStartSlot, 1);
350
			return list;
351
			
352
		// simply replace a single item
353
		}else if (replaceStartSlot == replaceEndSlot && newItems.length === 1) {
354
			if (returnNew) {
355
				list = list.concat();
356
			}
357
			list[replaceStartSlot] = newItems[0];
358
			return list;
359
			
360
		}
361
		
362
		// alt method if returning a new array
363
		if(returnNew){
364
			return list.slice(0, replaceStartSlot).concat(newItems).concat(list.slice(replaceEndSlot + 1));
365
		}
366
		
367
		// remove many
368
		list.splice(replaceStartSlot, (replaceEndSlot - replaceStartSlot) + 1);
369
		
370
		// insert many
371
		var slot = replaceStartSlot;
372
		for (var a = 0, al = newItems.length;a<al;a++){
373
			list.splice(slot++, 0, newItems[a]);
374
		}
375
		return list;
376
	},
377
	
378
	replace: function(find, replace, stringReplace = false){
379
		var list = this;
380
		for (var i = 0, il = list.length;i<il;i++){
381
			if (stringReplace){
382
383
				// replace substring within string items
384
				var str = list[i];
385
				if (str && str.constructor === String) {
386
					list[i] = str.replaceAll(find, replace);
387
				}
388
			}else{
389
390
				// replace entire items
391
				if (list[i] == find) {
392
					list[i] = replace;
393
				}
394
			}
395
		}
396
	},
397
	replaceOnce: function(find, replace){
398
		var list = this;
399
		for (var i = 0, il = list.length;i<il;i++){
400
			if (list[i] == find) {
401
				list[i] = replace;
402
				return;
403
			}
404
		}
405
	},
406
	replaceMany: function(findArray, replaceArray){
407
		var list = this;
408
		if (findArray.length != replaceArray.length){
409
			return;
410
		}
411
		for (var i = 0, il = list.length;i<il;i++){
412
			for (var f = 0, fl = findArray.length;f<fl;f++){
413
				var find = findArray[f];
414
				if (list[i] == find) {
415
					list[i] = replaceArray[f];
416
					break;
417
				}
418
			}
419
		}
420
	},
421
	
422
	
423
	remove: function(value, stringReplace = false){
424
		var list = this;
425
		for (var i = 0, il = list.length;i<il;i++){
426
			if (stringReplace){
427
428
				// remove substring within string items
429
				var str = list[i];
430
				if (str && str.constructor === String) {
431
					list[i] = str.removeAll(value);
432
				}
433
			}else{
434
435
				// remove entire items
436
				if (list[i] == value) {
437
					list.splice(i, 1);
438
					i--;
439
					il--;
440
				}
441
			}
442
		}
443
	},
444
	removeOnce: function(val){
445
		var list = this;
446
		var i = list.indexOf(val);
447
		if (i > -1) {
448
			list.splice(i, 1);
449
		}
450
		return i;
451
	},
452
	removeFirst: function(returnNew = false){
453
		var list = this;
454
455
		// return new
456
		if (returnNew) {
457
			return list.slice(1);
458
		}
459
460
		// modify existing
461
		if (list.length > 0) {
462
			list.splice(0, 1);
463
		}
464
		return list;
465
	},
466
	removeFirstX: function(count, returnNew = false){
467
		var list = this;
468
		
469
		// if fewer items than wanted, clear entire array
470
		if (list.length < count) {
471
			if (returnNew) {
472
				return [];
473
			}
474
			list.length = 0;
475
			return list;
476
		}
477
		
478
		// delete X items from start
479
		// return new
480
		if (returnNew) {
481
			return list.slice(count);
482
		}
483
484
		// modify existing
485
		list.splice(0, count);
486
		return list;
487
	},
488
	removeLast: function(returnNew = false){
489
		var list = this;
490
491
		// return new
492
		if (returnNew) {
493
			return list.slice(0, list.length - 1);
494
		}
495
496
		// modify existing
497
		if (list.length > 0) {
498
			list.splice( - 1, 1);
499
		}
500
		return list;
501
	},
502
	removeLastX: function(count, returnNew = false){
503
		var list = this;
504
		
505
		// if fewer items than wanted, clear entire array
506
		if (list.length < count) {
507
			if (returnNew) {
508
				return [];
509
			}
510
			list.length = 0;
511
			return list;
512
		}
513
		
514
		// delete X items from end
515
		// return new
516
		if (returnNew) {
517
			return list.slice(0, list.length - count);
518
		}
519
		
520
		// modify existing
521
		list.splice( -count, count);
522
		return list;
523
	},
524
	
525
	removeEdges: function(fromLeftEdge, fromRightEdge){
526
		var list = this;
527
		if ((list.length - fromLeftEdge - fromRightEdge) <= 0) {
528
			return [];
529
		}
530
		return list.slice(fromLeftEdge, list.length - fromRightEdge);
531
	},
532
	
533
	removePart: function(start, end){
534
		var list = this;
535
		start = start.limitToArray(list);
536
		end = end.limitToArray(list);
537
		list.splice(start, (end-start)+1);
538
	},
539
	
540
	
541
	splitAt: function(slot, includeSlot = false, includeInFirst = false){
542
		var list = this;
543
		if (includeSlot) {
544
			if (includeInFirst) {
545
				return [list.slice(0, slot + 1), list.slice(slot + 1)];
546
			}
547
			return [list.slice(0, slot), list.slice(slot)];
548
		}
549
		return [list.slice(0, slot), list.slice(slot+1)];
550
	},
551
	splitAtEvery: function(seperator){
552
		var list = this;
553
		var splits = [];
554
		var lastSlot = 0;
555
		for (var a = 0, al = list.length;a<al;a++){
556
			if (list[a] == seperator && a > lastSlot) {
557
				splits.push(list.slice(lastSlot, a));
558
				lastSlot = a + 1;
559
			}
560
		}
561
		return splits;
562
	},
563
	
564
	moveToTop: function(slot, returnNew = false){
565
		var list = this;
566
567 View Code Duplication
		if (returnNew){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
568
569
			// ALWAYS RETURNS NEW ARRAY
570
			
571
			// exit quickly if slot not in array
572
			var al = list.length;
573
			if (slot < 0 || slot >= al) {
574
				return list.concat();
575
			}
576
			
577
			// create new array with slot on top
578
			var newArr = [list[slot]];
579
			var n = 1;
580
			
581
			// add all other slots
582
			for (var a = 0;a<al;a++){
583
				if (a != slot) {
584
					newArr[n++] = list[a];
585
				}
586
			}
587
588
			return newArr;
589
		}
590
591
592
		// MODIFIES ARRAY IN PLACE
593
		
594
		// exit quickly if slot not in array
595
		var al = list.length;
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable al already seems to be declared on line 572. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
596
		if (slot < 0 || slot >= al) {
597
			return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
598
		}
599
		
600
		// delete and re-add slot
601
		var val = list[slot];
602
		list.splice(slot, 1);
603
		list.unshift(val);
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
604
	},
605
	moveToBottom: function(slot, returnNew = false){
606
		var list = this;
607
608 View Code Duplication
		if (returnNew){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
609
610
			// ALWAYS RETURNS NEW ARRAY
611
			
612
			// exit quickly if slot not in array
613
			var al = list.length;
614
			if (slot < 0 || slot >= al) {
615
				return list.concat();
616
			}
617
			
618
			// create new array with slot on top
619
			var newArr = [];
620
			var n = 0;
621
			
622
			// add all other slots
623
			for (var a = 0;a<al;a++){
624
				if (a != slot) {
625
					newArr[n++] = list[a];
626
				}
627
			}
628
			
629
			// add slot to bottom
630
			newArr[n++] = list[slot];
0 ignored issues
show
Unused Code introduced by
The assignment to variable n seems to be never used. Consider removing it.
Loading history...
631
			return newArr;
632
633
		}
634
635
		// MODIFIES ARRAY IN PLACE
636
		
637
		// exit quickly if slot not in array
638
		var al = list.length;
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable al already seems to be declared on line 613. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
639
		if (slot < 0 || slot >= al) {
640
			return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
641
		}
642
		
643
		// delete and re-add slot
644
		var val = list[slot];
645
		list.splice(slot, 1);
646
		list.push(val);
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
647
	},
648
	moveUp: function(item){
649
		var list = this;
650
		
651
		// MODIFIES ARRAY IN PLACE
652
		
653
		// exit quickly if slot not in array, or already on top
654
		var slot = list.indexOf(item);
655
		if (slot <= 0) {
656
			return false;
657
		}
658
		
659
		// move one up
660
		list.swap(slot, slot - 1);
661
		return true;
662
	},
663
	moveDown: function(item){
664
		var list = this;
665
		
666
		// MODIFIES ARRAY IN PLACE
667
		
668
		// exit quickly if slot not in array, or already at bottom
669
		var al = list.length;
670
		var slot = list.indexOf(item);
671
		if (slot < 0 || slot >= (al - 1)) {
672
			return false;
673
		}
674
		
675
		// move one down
676
		list.swap(slot, slot + 1);
677
		return true;
678
	},
679
	moveSlotUp: function(slot){
680
		var list = this;
681
		
682
		// MODIFIES ARRAY IN PLACE
683
		
684
		// exit quickly if slot not in array, or already on top
685
		var al = list.length;
686
		if (slot <= 0 || slot >= al) {
687
			return false;
688
		}
689
		
690
		// move one up
691
		list.swap(slot, slot - 1);
692
		return true;
693
	},
694
	moveSlotDown: function(slot){
695
		var list = this;
696
		
697
		// MODIFIES ARRAY IN PLACE
698
		
699
		// exit quickly if slot not in array, or already at bottom
700
		var al = list.length;
701
		if (slot < 0 || slot >= (al - 1)) {
702
			return false;
703
		}
704
		
705
		// move one down
706
		list.swap(slot, slot + 1);
707
		return true;
708
	},
709
	/** Move an item from the given list, to the start/end of the target list */
710
	moveToArray: function(item, toList, evenIfExists = false, addToEnd = true){
711
		var list = this;
712
		
713
		// remove from source list
714
		RemoveOne(list, item);
715
		
716
		// add to target list
717
		if (evenIfExists || toList.indexOf(item) === -1) {
718
			if (addToEnd) {
719
				toList.push(item);
720
			}else{
721
				toList.unshift(item);
722
			}
723
			return true;
724
		}
725
		
726
		return false;
727
	},
728
729
	
730
	contains: function(value){
731
		var list = this;
732
		if (list.length === 1) {
733
			return list[0] == value;
734
		}
735
		return list.indexOf(value) > -1;
736
	},
737
	containsAny: function(values){
738
		var list = this;
739
		return IndexOfAny(list, values) > -1;
740
	},
741
	containsAll: function(values){
742
		var list = this;
743
		
744
		// exit if either null
745
		if (list == null || values == null || list.length === 0 || values.length === 0) {
746
			return false;
747
		}
748
		
749
		// check if all found
750
		for (var f = 0, fl = values.length;f<fl;f++){
751
			if (list.indexOf(values[f]) === -1) {
752
				return false;
753
			}
754
		}
755
		return true;
756
	},
757
	
758
759
	indexOfArray: function(containsArr){
760
		var list = this;
761
		
762
		// returns index of containing list in main array
763
		
764
		if (list.length < containsArr.length) {
765
			return -1;
766
		}
767
		
768
		var cl = containsArr.length;
769
		for (var a = 0, al = list.length - (cl - 1);a<al;a++){
770
			
771
			var allMatch = true;
772
			for (var c = 0;c<cl;c++){
773
				if (list[a+c] != containsArr[c]) {
774
					allMatch = false;
775
					break;
776
				}
777
			}
778
			
779
			if (allMatch) {
780
				return a;
781
			}
782
		}
783
		return -1;
784
	},
785
786
	
787
	/** Returns the nearest existing slot value in the array. Returns `ifNoSlots` if the array is empty. */
788
	within: function(slot, ifNoSlots = null){
789
		var list = this;
790
		
791
		// return null if array empty
792
		var len = list.length;
793
		if (len === 0) {
794
			return ifNoSlots;
795
		}
796
		
797
		// return first slot if index negative
798
		if (slot < 0) {
799
			return list[0];
800
		}
801
		
802
		// return last slot if index more than last slot
803
		if (slot >= len) {
804
			return list[len - 1];
805
		}
806
		
807
		// return given slot if within array
808
		return list[slot];
809
	},
810
	
811
	first: function(list){
812
		var list = this;
813
		var len = list.length;
814
		if (len === 0) {
815
			return null;
816
		}
817
		return list[0];
818
	},
819
	firstExisting: function(slots, blankVal = null){
820
		var list = this;
821
		for (var s = 0, sl = slots.length;s<sl;s++){
822
			var val;
823
			if ((val = list[slots[s]]) != blankVal) {
824
				return val;
825
			}
826
		}
827
		return null;
828
	},
829
	last: function(list){
830
		var list = this;
831
		var len = list.length;
832
		if (len === 0) {
833
			return null;
834
		}
835
		return list[len-1];
836
	},
837
	lastX: function(count){
838
		var list = this;
839
		var s = (0).max(list.length - count);
840
		return list.slice(s, list.length);
841
	},
842
	setFirst: function(value){
843
		var list = this;
844
		var len = list.length;
845
		if (len === 0) {
846
			return;
847
		}
848
		list[0] = value;
849
	},
850
	setLast: function(value){
851
		var list = this;
852
		var len = list.length;
853
		if (len === 0) {
854
			return;
855
		}
856
		list[len-1] = value;
857
	},
858
	
859
	random: function(list){
860
		var list = this;
861
		
862
		// return null if array empty
863
		if (list.length === 0) {
864
			return null;
865
		}
866
		
867
		// return random slot within array
868
		return list[parseInt(Math.random() * 1000000) % list.length];
869
	},
870
871 View Code Duplication
	pick: function(slots){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
872
		var list = this;
873
		var out = [];
874
		
875
		if (!slots){
876
			return out;
877
		}
878
879
		for (var i = 0, il = slots.length;i<il;i++){
880
			id = slots[i];
0 ignored issues
show
Bug introduced by
The variable id seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.id.
Loading history...
881
			val = list[id];
0 ignored issues
show
Bug introduced by
The variable val seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.val.
Loading history...
882
			if (val != null) {
883
				out.push(val);
884
			}
885
		}
886
		return out;
887
	},
888
889 View Code Duplication
	pickMatching: function(slots, evenIfNull = false){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
890
		var list = this;
891
		var out = [];
892
		
893
		if (!slots){
894
			return out;
895
		}
896
		
897
		for (var i = 0, il = slots.length;i<il;i++){
898
			id = slots[i];
0 ignored issues
show
Bug introduced by
The variable id seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.id.
Loading history...
899
			val = list[id];
0 ignored issues
show
Bug introduced by
The variable val seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.val.
Loading history...
900
			if (val != null || evenIfNull) {
901
				out[id] = val;
902
			}
903
		}
904
		return out;
905
	},
906
907
	/** Get the data of `list`, by searching `indexID` in `indexArr`, or return `defaultVal` if not found */
908
	getByMatchingArray: function(indexArr, indexID, defaultVal = null){
909
		var list = this;
910
		var slot = indexArr.indexOf(indexID);
911
		return slot === -1 ? defaultVal : list[slot];
912
	},
913
	/** Set the data of `list`, by searching `indexID` in `indexArr` */
914
	setByMatchingArray: function(indexArr, indexID, data){
915
		var list = this;
916
		var slot = indexArr.indexOf(indexID);
917
		if (slot === -1) {
918
			return false;
919
		}
920
		list[slot] = data;
921
		return true;
922
	},
923
	
924
	page: function(page, pageLength, invisibleRows = null){
925
		var list = this;
926
		
927
		// ensure page no. in limits
928
		var lastPage = Math.ceil(list.length / pageLength);
929
		page = page.limitTo(0, lastPage - 1);
930
		
931
		// get first/last row in page
932
		var pageStart = page*pageLength;/// 0-based - first row in page
933
		var pageEnd = (pageStart + pageLength) - 1;/// 0-based - last row in page
934
		
935
		// get on-page rows
936
		var visibleRows = list.part(pageStart, pageLength);
937
		
938
		// get off-page rows
939
		if (invisibleRows) {
940
			invisibleRows.addRange(list, 0, pageStart - 1);
941
			invisibleRows.addRange(list, pageEnd + 1, list.length - 1);
942
		}
943
		
944
		return visibleRows;
945
	},
946
	
947
	trim: function(returnNew = false, trimVal = null){
948
		var list = this;
949
		var first = list.indexOfNot(trimVal);
950
		if (first === -1) {
951
952
			// return new
953
			if (returnNew) {
954
				return [];
955
			}
956
957
			// modify existing
958
			list.length = 0;
959
		}else{
960
961
			// return new
962
			var last = list.lastIndexOfNot(trimVal);
963
			if (returnNew) {
964
				return list.part(first, last);
965
			}
966
967
			// modify existing
968
			if (first != -1 && first != 0){
969
				list.removePart(0, first-1);
970
			}
971
			if (last != -1){
972
				list.length = last - first + 1; 
973
			}
974
		}
975
		return list;
976
	},
977
978
	trimLeft: function(returnNew = false, trimVal = null){
979
		var list = this;
980
		var first = list.indexOfNot(trimVal);
981
		if (first === -1) {
982
983
			// return new
984
			if (returnNew) {
985
				return [];
986
			}
987
988
			// modify existing
989
			list.length = 0;
990
991
		}else{
992
993
			// return new
994
			if (returnNew) {
995
				return list.afterIndex(first);
996
			}
997
998
			// modify existing
999
			if (first != -1 && first != 0){
1000
				list.removePart(0, first-1);
1001
			}
1002
		}
1003
		return list;
1004
	},
1005
	trimRight: function(returnNew = false, trimVal = null){
1006
		var list = this;
1007
		var last = list.indexOfNot(trimVal, true);
1008
		if (last === -1) {
1009
1010
			// return new
1011
			if (returnNew) {
1012
				return [];
1013
			}
1014
			
1015
			// modify existing
1016
			list.length = 0;
1017
		}else{
1018
1019
			// return new
1020
			if (returnNew) {
1021
				return list.beforeIndex(last);
1022
			}
1023
1024
			// modify existing
1025
			list.length = last + 1;
1026
		}
1027
		return list;
1028
	},
1029
	
1030
	transpose: function() {
1031
		var arr = this;
1032
		var transposed = [];
1033
		
1034
		for (var r = 0; r < arr.length; r++) {
1035
			for (var c = 0; c < arr[r].length; c++) {
1036
				if (transposed[c] == null) {
1037
					transposed[c] = [];
1038
				}
1039
				transposed[c][r] = arr[r][c];
1040
			}
1041
		}
1042
		
1043
		return transposed;
1044
	},
1045
	
1046
	
1047
	// fast sorting
1048
	quickSort: function(ascending = true){
1049
		var input = this;
1050
		
1051
		var len = input.length;
1052
		if (len >= 2) {
1053
			
1054
			// sort in place
1055
			input._quickSort(0, len - 1, 0);
1056
			
1057
			// flip if descending wanted
1058
			if (!ascending) {
1059
				input.reverse();
1060
			}
1061
			
1062
		}
1063
	},
1064
1065
	indexedQuickSort: function(ascending = true){
1066
		var input = this;
1067
		
1068
		var len = input.length;
1069
		if (len >= 2) {
1070
			
1071
			// indexed sort
1072
			var index = UB.newArray(0, input.length);
1073
			input._indexedQuickSort(index, 0, len - 1, 0);
1074
			
1075
			// flip if descending wanted
1076
			if (!ascending) {
1077
				index.reverse();
1078
			}
1079
			
1080
			return index;
1081
		}
1082
		
1083
		return null;
1084
	},
1085
	
1086
	/** INTERNAL FUNCTION, do not use directly */
1087
	_quickSort: function(left, right, d){
1088
		var input = this;
1089
		if (left >= right){
1090
			return;
1091
		}
1092
		var j = right, i = left;
1093
		var size = right - left;
1094
		//var pivotPoint = input[uint((right>>>1) + (left>>>1))], t;
1095
		var pivotPoint = input[((right>>>1) + (left>>>1)) >>> 0], t;
1096
		do {
1097
			if (size < 9) {
1098
				pivotPoint = input[left];
1099
				do {
1100
					do {
1101
						left++;
1102
						if (input[left] < pivotPoint) {
1103
							pivotPoint = input[left];
1104
							do { // this section can be improved.
1105
								input[left--] = input[left];
1106
							} while (left > i && pivotPoint < input[left]);
1107
							input[left] = pivotPoint;
1108
						}
1109
					} while (left < right);
1110
					i++;
1111
					left = i;
1112
					pivotPoint = input[left];
1113
				} while (i < right);
1114
				return;
1115
			}
1116
			while (left < right) {
1117
				if (input[right] > pivotPoint){
1118
					do { right--; }
1119
					while (input[right] > pivotPoint);
1120
				}
1121
				if (input[left] < pivotPoint){
1122
					do { left++; }
1123
					while (input[left] < pivotPoint);
1124
				}
1125
				if (left < right) {
1126
					t = input[left];
1127
					input[left] = input[right];
1128
					input[right] = t;
1129
					left++;
1130
					right--;
1131
				}
1132
			}
1133
			if (right) {
1134
				if (left === right) {
1135
					if (input[left] < pivotPoint){
1136
						left++;
1137
					}else if (input[right] > pivotPoint){
1138
						right--;
1139
					}
1140
				}
1141
				if (i < right) {
1142
					input._quickSort(i, right, d + 1);
1143
				}
1144
			}
1145
			left |= int(!left) & int(!right);
1146
			if (j <= left){
1147
				return;
1148
			}
1149
			i = left;
1150
			right = j;
1151
			//pivotPoint = input[uint((right >>> 1) + (left >>> 1))];
1152
			pivotPoint = input[((right >>> 1) + (left >>> 1)) >>> 0];
1153
			size = right - left;
1154
			d++;
1155
		} while (true);
1156
	},
1157
1158
	/** INTERNAL FUNCTION, do not use directly */
1159
	_indexedQuickSort: function(indexed, left, right, d){
1160
		var input = this;
1161
		if (left >= right){
1162
			return;
1163
		}
1164
		
1165
		// status
1166
		var j;
1167
		var i;
1168
		var size = (j = right) - (i = left);
1169
		//var pivotPoint = (input[uint((right>>>1) + (left>>>1))]);
1170
		var pivotPoint = (input[((right>>>1) + (left>>>1)) >>> 0]);
1171
		
1172
		// temps
1173
		var pivotIndex;
1174
		var temp;
1175
		var temp2;
1176
		
1177
		do {
1178
			
1179
			//{ part 1
1180
			if (size < 9) {
1181
				pivotPoint = input[left];
1182
				do {
1183
					do {
1184
						left++;
1185
						temp = input[left];
1186
						if (temp < pivotPoint) {
1187
							
1188
							pivotIndex = indexed[left];
1189
							pivotPoint = temp;
1190
							
1191
							do {
1192
								
1193
								// change vals
1194
								input[left] = input[left - 1];
1195
								
1196
								// change indices
1197
								indexed[left] = indexed[left - 1];
1198
								
1199
								left--;
1200
								
1201
							} while (left > i && pivotPoint < input[left]);
1202
							
1203
							// change vals
1204
							input[left] = pivotPoint;
1205
							
1206
							// change indices
1207
							indexed[left] = pivotIndex;
1208
						}
1209
					} while (left < right);
1210
					i++;
1211
					pivotPoint = input[left = i];
1212
				} while (i < right);
1213
				return;
1214
			}
1215
			//}
1216
			
1217
			//{ part 2
1218
			while (left < right) {
1219
				if (input[right] > pivotPoint) {
1220
					do {
1221
						right--;
1222
					} while (input[right] > pivotPoint);
1223
				}
1224
				if (input[left] < pivotPoint) {
1225
					do {
1226
						left++;
1227
					} while (input[left] < pivotPoint);
1228
				}
1229
				if (left < right) {
1230
					
1231
					// flip values
1232
					temp = input[left];
1233
					input[left] = input[right];
1234
					input[right] = temp;
1235
					
1236
					// flip indices
1237
					temp2 = indexed[left];
1238
					indexed[left] = indexed[right];
1239
					indexed[right] = temp2;
1240
					
1241
					left++;
1242
					right--;
1243
				}
1244
			}
1245
			//}
1246
			
1247
			//{ part 2
1248
			if (right) {
1249
				if (left === right) {
1250
					if (input[left] < pivotPoint) {
1251
						left++;
1252
					}else if (input[right] > pivotPoint) {
1253
						right--;
1254
					}
1255
				}
1256
				if (i < right) {
1257
					
1258
					// recurse
1259
					input._indexedQuickSort(indexed, i, right, d + 1);
1260
					
1261
				}
1262
			}
1263
			//}
1264
			
1265
			left |= int(!left) & int(!right);
1266
			if (j <= left) {
1267
				return;
1268
			}
1269
			i = left;
1270
			right = j;
1271
			//pivotPoint = input[uint((right >>> 1) + (left >>> 1))];
1272
			pivotPoint = input[((right >>> 1) + (left >>> 1)) >>> 0];
1273
			size = right - left;
1274
			d++;
1275
		} while (true);
1276
	},
1277
	
1278
	
1279
	next: function(obj, wrap = false){
1280
		var list = this;
1281
		if (list == null) {
1282
			return null;
1283
		}
1284
		var i = list.indexOf(obj);
1285
		if (i > -1) {
1286
			return (wrap && i >= (list.length - 1)) ? list[0] : list[i + 1];
1287
		}
1288
		return null;
1289
	},
1290
	prev: function(obj, wrap = false){
1291
		var list = this;
1292
		if (list == null) {
1293
			return null;
1294
		}
1295
		var i = list.indexOf(obj);
1296
		if (i > 0) {
1297
			return wrap ? list[list.length - 1] : list[i - 1];
1298
		}
1299
		return null;
1300
	},
1301
	
1302
	
1303
	where: function(callback){
1304
		var list = this;
1305
		if (list == null) {
1306
			return null;
1307
		}
1308
		var results = [];
1309
		for (var i = 0; i<list.length; i++){
1310
			var obj = list[i];
1311
			if (callback(obj) == true){
1312
				results.push(obj);
1313
			}
1314
		}
1315
		return results;
1316
	},
1317
	
1318
	props: function(prop, defaultVal = null){
1319
		var list = this;
1320
		if (list == null) {
1321
			return null;
1322
		}
1323
		var results = [];
1324
		for (var i = 0; i<list.length; i++){
1325
			var obj = list[i];
1326
			results.push(obj != null ? obj[prop] : defaultVal);
1327
		}
1328
		return results;
1329
	},
1330
	
1331
	
1332
	none:null
1333
};
1334
1335
// register funcs
1336
UB.registerFuncs(Array.prototype, arrayFuncs);
1337