diff options
| author | Dmitry Antipov | 2014-08-29 11:29:47 +0400 |
|---|---|---|
| committer | Dmitry Antipov | 2014-08-29 11:29:47 +0400 |
| commit | 1764ec4414074ea0dcbd912efdfbedb119f8ed3b (patch) | |
| tree | 0d577861c3e8a3e3e7a554adef7bcb04e0de5c38 /src/fns.c | |
| parent | 483dc86ad0e60a1a6da498f9eb95672f286a4ab5 (diff) | |
| download | emacs-1764ec4414074ea0dcbd912efdfbedb119f8ed3b.tar.gz emacs-1764ec4414074ea0dcbd912efdfbedb119f8ed3b.zip | |
Add vectors support to Fsort.
* configure.ac (AC_CHECK_FUNCS): Check for qsort_r.
* src/fns.c (sort_vector, sort_vector_compare): New functions.
(sort_list): Likewise, refactored out of ...
(Fsort): ... adjusted user. Mention vectors in docstring.
(sort_vector_predicate) [!HAVE_QSORT_R]: New variable.
* src/alloc.c (make_save_int_obj): New function.
* src/lisp.h (enum Lisp_Save_Type): New member SAVE_TYPE_INT_OBJ.
(make_save_int_obj): Add prototype.
* test/automated/fns-tests.el (fns-tests-sort): New test.
Diffstat (limited to 'src/fns.c')
| -rw-r--r-- | src/fns.c | 99 |
1 files changed, 92 insertions, 7 deletions
| @@ -1846,13 +1846,12 @@ See also the function `nreverse', which is used more often. */) | |||
| 1846 | wrong_type_argument (Qsequencep, seq); | 1846 | wrong_type_argument (Qsequencep, seq); |
| 1847 | return new; | 1847 | return new; |
| 1848 | } | 1848 | } |
| 1849 | 1849 | ||
| 1850 | DEFUN ("sort", Fsort, Ssort, 2, 2, 0, | 1850 | /* Sort LIST using PREDICATE, preserving original order of elements |
| 1851 | doc: /* Sort LIST, stably, comparing elements using PREDICATE. | 1851 | considered as equal. */ |
| 1852 | Returns the sorted list. LIST is modified by side effects. | 1852 | |
| 1853 | PREDICATE is called with two elements of LIST, and should return non-nil | 1853 | static Lisp_Object |
| 1854 | if the first element should sort before the second. */) | 1854 | sort_list (Lisp_Object list, Lisp_Object predicate) |
| 1855 | (Lisp_Object list, Lisp_Object predicate) | ||
| 1856 | { | 1855 | { |
| 1857 | Lisp_Object front, back; | 1856 | Lisp_Object front, back; |
| 1858 | register Lisp_Object len, tem; | 1857 | register Lisp_Object len, tem; |
| @@ -1877,6 +1876,92 @@ if the first element should sort before the second. */) | |||
| 1877 | return merge (front, back, predicate); | 1876 | return merge (front, back, predicate); |
| 1878 | } | 1877 | } |
| 1879 | 1878 | ||
| 1879 | /* Using GNU qsort_r, we can pass this as a parameter. */ | ||
| 1880 | #ifndef HAVE_QSORT_R | ||
| 1881 | static Lisp_Object sort_vector_predicate; | ||
| 1882 | #endif | ||
| 1883 | |||
| 1884 | /* Comparison function called by qsort. */ | ||
| 1885 | |||
| 1886 | static int | ||
| 1887 | #ifdef HAVE_QSORT_R | ||
| 1888 | sort_vector_compare (const void *p, const void *q, void *arg) | ||
| 1889 | #else | ||
| 1890 | sort_vector_compare (const void *p, const void *q) | ||
| 1891 | #endif /* HAVE_QSORT_R */ | ||
| 1892 | { | ||
| 1893 | bool more, less; | ||
| 1894 | Lisp_Object op, oq, vp, vq; | ||
| 1895 | #ifdef HAVE_QSORT_R | ||
| 1896 | Lisp_Object sort_vector_predicate = *(Lisp_Object *) arg; | ||
| 1897 | #endif | ||
| 1898 | |||
| 1899 | op = *(Lisp_Object *) p; | ||
| 1900 | oq = *(Lisp_Object *) q; | ||
| 1901 | vp = XSAVE_OBJECT (op, 1); | ||
| 1902 | vq = XSAVE_OBJECT (oq, 1); | ||
| 1903 | |||
| 1904 | /* Use recorded element index as a secondary key to | ||
| 1905 | preserve original order. Pretty ugly but works. */ | ||
| 1906 | more = NILP (call2 (sort_vector_predicate, vp, vq)); | ||
| 1907 | less = NILP (call2 (sort_vector_predicate, vq, vp)); | ||
| 1908 | return ((more && !less) ? 1 | ||
| 1909 | : ((!more && less) ? -1 | ||
| 1910 | : XSAVE_INTEGER (op, 0) - XSAVE_INTEGER (oq, 0))); | ||
| 1911 | } | ||
| 1912 | |||
| 1913 | /* Sort VECTOR using PREDICATE, preserving original order of elements | ||
| 1914 | considered as equal. */ | ||
| 1915 | |||
| 1916 | static Lisp_Object | ||
| 1917 | sort_vector (Lisp_Object vector, Lisp_Object predicate) | ||
| 1918 | { | ||
| 1919 | ptrdiff_t i; | ||
| 1920 | EMACS_INT len = ASIZE (vector); | ||
| 1921 | Lisp_Object *v = XVECTOR (vector)->contents; | ||
| 1922 | |||
| 1923 | if (len < 2) | ||
| 1924 | return vector; | ||
| 1925 | /* Record original index of each element to make qsort stable. */ | ||
| 1926 | for (i = 0; i < len; i++) | ||
| 1927 | v[i] = make_save_int_obj (i, v[i]); | ||
| 1928 | |||
| 1929 | /* Setup predicate and sort. */ | ||
| 1930 | #ifdef HAVE_QSORT_R | ||
| 1931 | qsort_r (v, len, word_size, sort_vector_compare, (void *) &predicate); | ||
| 1932 | #else | ||
| 1933 | sort_vector_predicate = predicate; | ||
| 1934 | qsort (v, len, word_size, sort_vector_compare); | ||
| 1935 | #endif /* HAVE_QSORT_R */ | ||
| 1936 | |||
| 1937 | /* Discard indexes and restore original elements. */ | ||
| 1938 | for (i = 0; i < len; i++) | ||
| 1939 | { | ||
| 1940 | Lisp_Object save = v[i]; | ||
| 1941 | /* Use explicit free to offload GC. */ | ||
| 1942 | v[i] = XSAVE_OBJECT (save, 1); | ||
| 1943 | free_misc (save); | ||
| 1944 | } | ||
| 1945 | return vector; | ||
| 1946 | } | ||
| 1947 | |||
| 1948 | DEFUN ("sort", Fsort, Ssort, 2, 2, 0, | ||
| 1949 | doc: /* Sort SEQ, stably, comparing elements using PREDICATE. | ||
| 1950 | Returns the sorted sequence. SEQ should be a list or vector. | ||
| 1951 | If SEQ is a list, it is modified by side effects. PREDICATE | ||
| 1952 | is called with two elements of SEQ, and should return non-nil | ||
| 1953 | if the first element should sort before the second. */) | ||
| 1954 | (Lisp_Object seq, Lisp_Object predicate) | ||
| 1955 | { | ||
| 1956 | if (CONSP (seq)) | ||
| 1957 | seq = sort_list (seq, predicate); | ||
| 1958 | else if (VECTORP (seq)) | ||
| 1959 | seq = sort_vector (seq, predicate); | ||
| 1960 | else if (!NILP (seq)) | ||
| 1961 | wrong_type_argument (Qarrayp, seq); | ||
| 1962 | return seq; | ||
| 1963 | } | ||
| 1964 | |||
| 1880 | Lisp_Object | 1965 | Lisp_Object |
| 1881 | merge (Lisp_Object org_l1, Lisp_Object org_l2, Lisp_Object pred) | 1966 | merge (Lisp_Object org_l1, Lisp_Object org_l2, Lisp_Object pred) |
| 1882 | { | 1967 | { |