|
|
|
=======
|
|
|
|
Sorting
|
|
|
|
=======
|
|
|
|
|
|
|
|
This document summarizes the sorting algorithms used in the implementation.
|
|
|
|
|
|
|
|
Sorting algorithms are needed for:
|
|
|
|
|
|
|
|
* ``Array.prototype.sort()``
|
|
|
|
|
|
|
|
* Sorting array indexed keys for ``JSON.stringify()`` when an Array
|
|
|
|
``replacer`` is given
|
|
|
|
|
|
|
|
See:
|
|
|
|
|
|
|
|
* http://en.wikipedia.org/wiki/Sorting_algorithm#Comparison_of_algorithms
|
|
|
|
|
|
|
|
Array.prototype.sort()
|
|
|
|
======================
|
|
|
|
|
|
|
|
Some desirable qualities:
|
|
|
|
|
|
|
|
* Small code footprint
|
|
|
|
|
|
|
|
* Bounded C recursion
|
|
|
|
|
|
|
|
* In-place sorting (no large temporary allocations)
|
|
|
|
|
|
|
|
* O(n log n) average performance (weaker)
|
|
|
|
|
|
|
|
* O(n log n) worst case performance (stronger)
|
|
|
|
|
|
|
|
* Stability (don't reorder elements which compare equal)
|
|
|
|
|
|
|
|
C recursion is effectively bounded if recursion depth is O(log n) for a small
|
|
|
|
constant. For instance, for 2^32 elements and a small constant, there would
|
|
|
|
be less than 100 recursive invocations which is good enough in most
|
|
|
|
environments.
|
|
|
|
|
|
|
|
``Array.prototype.sort()`` has some additional concerns:
|
|
|
|
|
|
|
|
* Value comparison is relatively expensive and involves coercion and/or
|
|
|
|
comparison function calls. Unless coercion results are cached, elements
|
|
|
|
will usually be coerced multiple times.
|
|
|
|
|
|
|
|
* ``undefined`` and non-existent array elements need to be treated specially.
|
|
|
|
This special behavior is encapsulated in the ``SortCompare()``
|
|
|
|
specification algorithm.
|
|
|
|
|
|
|
|
* Exchanging elements is cheap for an object with an array part.
|
|
|
|
|
|
|
|
* Exchanging elements is very expensive for an object without an array
|
|
|
|
part, requiring ``[[Get]]``, ``[[Put]]``, and ``[[Delete]]`` calls and
|
|
|
|
may invoke setters/getters.
|
|
|
|
|
|
|
|
Current algorithm used is quick sort with randomized pivot selection.
|
|
|
|
Quick sort is O(n log n) average case but O(n^2) worst case, and is
|
|
|
|
not a stable sort. Recursion depth is O(n) in the worst case. There
|
|
|
|
is currently no fast path for array parts.
|
|
|
|
|
|
|
|
Random pivot is used to minimize the chance of the worst case O(n^2)
|
|
|
|
behavior without resorting to more complex (and large code footprint)
|
|
|
|
pivot selection algorithms. Crafting malicious inputs to cause worst
|
|
|
|
case O(n^2) behavior is possible because the random number generator
|
|
|
|
is not cryptographic strength.
|
|
|
|
|
|
|
|
The current solution is a placeholder, and the sorting algorithm may
|
|
|
|
need to be changed entirely. Getting a O(log n) recursion depth is
|
|
|
|
important because without it, sorting will fail in unlucky causes, as
|
|
|
|
it may be important to limit stack growth in some embedded environments.
|
|
|
|
Getting a O(n log n) worst case behavior would be nice, but not critical.
|
|
|
|
|
|
|
|
DUK_ENUM_SORT_ARRAY_INDICES
|
|
|
|
===========================
|
|
|
|
|
|
|
|
This sorting need arises in ``JSON.stringify()`` when the ``replacer``
|
|
|
|
argument is an Array. In this case the replacer must be enumerated in
|
|
|
|
increasing array index order; E5.1 Section 15.12.3, first algorithm,
|
|
|
|
step 4.b.ii:
|
|
|
|
|
|
|
|
For each value v of a property of replacer that has an array index
|
|
|
|
property name. The properties are enumerated in the ascending array
|
|
|
|
index order of their names.
|
|
|
|
|
|
|
|
This must hold even for sparse arrays, i.e. arrays without an array part.
|
|
|
|
Such arrays don't necessarily have their array index keys in the correct
|
|
|
|
ascending order, so they need to be sorted for enumeration. The enumeration
|
|
|
|
API flag ``DUK_ENUM_SORT_ARRAY_INDICES`` provides the necessary behavior.
|
|
|
|
The expected data size for this sorting need is relatively small, and the
|
|
|
|
elements are expected to be almost always already in order.
|
|
|
|
|
|
|
|
Current algorithm used is insertion sort, which works well in-place and
|
|
|
|
handles already (almost) ordered cases efficiently.
|