Skip to content

Commit f0276bb

Browse files
committed
Add median-of-3 for Array.sort (1/3 of the compares for pre-sorted data)
1 parent 9be2e86 commit f0276bb

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
I2C: Fix readReg to ensure it sends I2C STOP after the read
2525
Puck.js: E.getTemperature(true) will now use the uC's internal temp sensor (previously only external was possible)
2626
Add fast path to xIntArray.indexOf
27+
Add median-of-3 for Array.sort (1/3 of the compares for pre-sorted data)
2728

2829
2v27 : nRF5x: Ensure Bluetooth notifications work correctly when two separate connections use the same handle for their characteristics
2930
nRF5x: Remove handlers from our handlers array when a device is disconnected

src/jswrap_array.c

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,40 @@ NO_INLINE static void _jswrap_array_sort(JsvIterator *head, int n, JsVar *compar
822822

823823
JsvIterator pivot;
824824
jsvIteratorClone(&pivot, head);
825+
#ifndef SAVE_ON_FLASH
826+
if (n>16) {
827+
/* if we have enough elements where using the wrong pivot may be a problem, try a median of 3
828+
to find the best pivot - this can be slower as we have to iterate over all the items in the list */
829+
int midIndex = n>>1;
830+
JsvIterator mid;
831+
jsvIteratorClone(&mid, head);
832+
for (int i=0; i<midIndex; i++) jsvIteratorNext(&mid);
833+
JsvIterator high;
834+
jsvIteratorClone(&high, &mid);
835+
for (int i=midIndex; i<n-1; i++) jsvIteratorNext(&high);
836+
837+
JsVar *lowValue = jsvIteratorGetValue(&pivot);
838+
JsVar *midValue = jsvIteratorGetValue(&mid);
839+
JsVar *highValue = jsvIteratorGetValue(&high);
840+
841+
// now find the median of these three values
842+
JsVarInt lowMid = _jswrap_array_sort_compare(lowValue, midValue, compareFn);
843+
JsVarInt midHigh = _jswrap_array_sort_compare(midValue, highValue, compareFn);
844+
JsVarInt lowHigh = _jswrap_array_sort_compare(lowValue, highValue, compareFn);
845+
if ((lowMid<=0 && midHigh<=0) || (lowHigh<=0 && midHigh>=0)) {
846+
// mid is median
847+
jsvIteratorSetValue(&pivot, midValue);
848+
jsvIteratorSetValue(&mid, lowValue);
849+
} else if ((lowMid>=0 && lowHigh<=0) || (midHigh>=0 && lowHigh>=0)) {
850+
// high is median
851+
jsvIteratorSetValue(&pivot, highValue);
852+
jsvIteratorSetValue(&high, lowValue);
853+
} // else low is median, do nothing
854+
jsvUnLock3(lowValue, midValue, highValue);
855+
jsvIteratorFree(&mid);
856+
jsvIteratorFree(&high);
857+
}
858+
#endif
825859
bool pivotLowest = true; // is the pivot the lowest value in here?
826860
JsVar *pivotValue = jsvIteratorGetValue(&pivot);
827861
/* We're just going to use the first entry (head) as the pivot...
@@ -830,7 +864,7 @@ NO_INLINE static void _jswrap_array_sort(JsvIterator *head, int n, JsVar *compar
830864

831865
int nlo = 0, nhigh = 0;
832866
JsvIterator it;
833-
jsvIteratorClone(&it, head); //
867+
jsvIteratorClone(&it, head);
834868
jsvIteratorNext(&it);
835869

836870

0 commit comments

Comments
 (0)