protected function quickSort(callable $cb)
{
$sfa = new SplFixedArray(count($this));
// Create an auxiliary stack
$stack = new SplStack();
// initialize top of stack
// push initial values of l and h to stack
$stack->push([0, count($sfa) - 1]);
$first = true;
// Keep popping from stack while is not empty
while (!$stack->isEmpty()) {
// Pop h and l
list($lo, $hi) = $stack->pop();
if ($first) {
// Start our partition iterator on the original data
$partition = new LimitIterator($this->sfa, $lo, $hi - $lo);
} else {
$partition = new LimitIterator($sfa, $lo, $hi - $lo);
}
$ii = $partition->getInnerIterator();
// Set pivot element at its correct position in sorted array
$x = $ii[$hi];
$i = $lo - 1;
foreach ($partition as $j => $el) {
if ($cb($ii[$j], $x) <= 0) {
// Bump up the index of the last low hit, and swap
$i++;
$temp = $sfa[$i];
$sfa[$i] = $el;
$sfa[$j] = $temp;
} elseif ($first) {
$sfa[$j] = $el;
}
}
$sfa[$hi] = $x;
// Set the pivot element
$pivot = $i + 1;
// Swap the last hi with the second-last hi
$sfa[$hi] = $sfa[$pivot];
$sfa[$pivot] = $x;
// If there are elements on left side of pivot, then push left
// side to stack
if ($pivot - 1 > $lo) {
$stack->push([$lo, $pivot - 1]);
}
// If there are elements on right side of pivot, then push right
// side to stack
if ($pivot + 1 < $hi) {
$stack->push([$pivot + 1, $hi]);
}
}
return new static($sfa);
}