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);
    }