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 | |
| 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.
| -rw-r--r-- | ChangeLog | 4 | ||||
| -rw-r--r-- | configure.ac | 2 | ||||
| -rw-r--r-- | src/ChangeLog | 11 | ||||
| -rw-r--r-- | src/alloc.c | 11 | ||||
| -rw-r--r-- | src/fns.c | 99 | ||||
| -rw-r--r-- | src/lisp.h | 2 | ||||
| -rw-r--r-- | test/ChangeLog | 4 | ||||
| -rw-r--r-- | test/automated/fns-tests.el | 18 |
8 files changed, 143 insertions, 8 deletions
| @@ -1,3 +1,7 @@ | |||
| 1 | 2014-08-29 Dmitry Antipov <dmantipov@yandex.ru> | ||
| 2 | |||
| 3 | * configure.ac (AC_CHECK_FUNCS): Check for qsort_r. | ||
| 4 | |||
| 1 | 2014-08-28 Ken Brown <kbrown@cornell.edu> | 5 | 2014-08-28 Ken Brown <kbrown@cornell.edu> |
| 2 | 6 | ||
| 3 | * configure.ac (HYBRID_MALLOC): New macro; define to use gmalloc | 7 | * configure.ac (HYBRID_MALLOC): New macro; define to use gmalloc |
diff --git a/configure.ac b/configure.ac index 4f17a55895e..ef3aad21732 100644 --- a/configure.ac +++ b/configure.ac | |||
| @@ -3573,7 +3573,7 @@ select getpagesize setlocale newlocale \ | |||
| 3573 | getrlimit setrlimit shutdown getaddrinfo \ | 3573 | getrlimit setrlimit shutdown getaddrinfo \ |
| 3574 | pthread_sigmask strsignal setitimer \ | 3574 | pthread_sigmask strsignal setitimer \ |
| 3575 | sendto recvfrom getsockname getpeername getifaddrs freeifaddrs \ | 3575 | sendto recvfrom getsockname getpeername getifaddrs freeifaddrs \ |
| 3576 | gai_strerror sync \ | 3576 | gai_strerror sync qsort_r \ |
| 3577 | getpwent endpwent getgrent endgrent \ | 3577 | getpwent endpwent getgrent endgrent \ |
| 3578 | cfmakeraw cfsetspeed copysign __executable_start log2) | 3578 | cfmakeraw cfsetspeed copysign __executable_start log2) |
| 3579 | LIBS=$OLD_LIBS | 3579 | LIBS=$OLD_LIBS |
diff --git a/src/ChangeLog b/src/ChangeLog index 9b3c3d0bd66..c24ca69536f 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,14 @@ | |||
| 1 | 2014-08-29 Dmitry Antipov <dmantipov@yandex.ru> | ||
| 2 | |||
| 3 | Add vectors support to Fsort. | ||
| 4 | * fns.c (sort_vector, sort_vector_compare): New functions. | ||
| 5 | (sort_list): Likewise, refactored out of ... | ||
| 6 | (Fsort): ... adjusted user. Mention vectors in docstring. | ||
| 7 | (sort_vector_predicate) [!HAVE_QSORT_R]: New variable. | ||
| 8 | * alloc.c (make_save_int_obj): New function. | ||
| 9 | * lisp.h (enum Lisp_Save_Type): New member SAVE_TYPE_INT_OBJ. | ||
| 10 | (make_save_int_obj): Add prototype. | ||
| 11 | |||
| 1 | 2014-08-28 Ken Brown <kbrown@cornell.edu> | 12 | 2014-08-28 Ken Brown <kbrown@cornell.edu> |
| 2 | 13 | ||
| 3 | Add support for HYBRID_MALLOC, allowing the use of gmalloc before | 14 | Add support for HYBRID_MALLOC, allowing the use of gmalloc before |
diff --git a/src/alloc.c b/src/alloc.c index 9c81ae2eedf..bb47a24d905 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -3610,6 +3610,17 @@ make_save_ptr_int (void *a, ptrdiff_t b) | |||
| 3610 | return val; | 3610 | return val; |
| 3611 | } | 3611 | } |
| 3612 | 3612 | ||
| 3613 | Lisp_Object | ||
| 3614 | make_save_int_obj (ptrdiff_t a, Lisp_Object b) | ||
| 3615 | { | ||
| 3616 | Lisp_Object val = allocate_misc (Lisp_Misc_Save_Value); | ||
| 3617 | struct Lisp_Save_Value *p = XSAVE_VALUE (val); | ||
| 3618 | p->save_type = SAVE_TYPE_INT_OBJ; | ||
| 3619 | p->data[0].integer = a; | ||
| 3620 | p->data[1].object = b; | ||
| 3621 | return val; | ||
| 3622 | } | ||
| 3623 | |||
| 3613 | #if ! (defined USE_X_TOOLKIT || defined USE_GTK) | 3624 | #if ! (defined USE_X_TOOLKIT || defined USE_GTK) |
| 3614 | Lisp_Object | 3625 | Lisp_Object |
| 3615 | make_save_ptr_ptr (void *a, void *b) | 3626 | make_save_ptr_ptr (void *a, void *b) |
| @@ -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 | { |
diff --git a/src/lisp.h b/src/lisp.h index 98734a55812..7cbbb299896 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -1989,6 +1989,7 @@ enum Lisp_Save_Type | |||
| 1989 | SAVE_TYPE_OBJ_OBJ_OBJ_OBJ | 1989 | SAVE_TYPE_OBJ_OBJ_OBJ_OBJ |
| 1990 | = SAVE_OBJECT + (SAVE_TYPE_OBJ_OBJ_OBJ << SAVE_SLOT_BITS), | 1990 | = SAVE_OBJECT + (SAVE_TYPE_OBJ_OBJ_OBJ << SAVE_SLOT_BITS), |
| 1991 | SAVE_TYPE_PTR_INT = SAVE_POINTER + (SAVE_INTEGER << SAVE_SLOT_BITS), | 1991 | SAVE_TYPE_PTR_INT = SAVE_POINTER + (SAVE_INTEGER << SAVE_SLOT_BITS), |
| 1992 | SAVE_TYPE_INT_OBJ = SAVE_INTEGER + (SAVE_OBJECT << SAVE_SLOT_BITS), | ||
| 1992 | SAVE_TYPE_PTR_OBJ = SAVE_POINTER + (SAVE_OBJECT << SAVE_SLOT_BITS), | 1993 | SAVE_TYPE_PTR_OBJ = SAVE_POINTER + (SAVE_OBJECT << SAVE_SLOT_BITS), |
| 1993 | SAVE_TYPE_PTR_PTR = SAVE_POINTER + (SAVE_POINTER << SAVE_SLOT_BITS), | 1994 | SAVE_TYPE_PTR_PTR = SAVE_POINTER + (SAVE_POINTER << SAVE_SLOT_BITS), |
| 1994 | SAVE_TYPE_FUNCPTR_PTR_OBJ | 1995 | SAVE_TYPE_FUNCPTR_PTR_OBJ |
| @@ -3773,6 +3774,7 @@ extern Lisp_Object make_save_obj_obj_obj_obj (Lisp_Object, Lisp_Object, | |||
| 3773 | extern Lisp_Object make_save_ptr (void *); | 3774 | extern Lisp_Object make_save_ptr (void *); |
| 3774 | extern Lisp_Object make_save_ptr_int (void *, ptrdiff_t); | 3775 | extern Lisp_Object make_save_ptr_int (void *, ptrdiff_t); |
| 3775 | extern Lisp_Object make_save_ptr_ptr (void *, void *); | 3776 | extern Lisp_Object make_save_ptr_ptr (void *, void *); |
| 3777 | extern Lisp_Object make_save_int_obj (ptrdiff_t, Lisp_Object); | ||
| 3776 | extern Lisp_Object make_save_funcptr_ptr_obj (void (*) (void), void *, | 3778 | extern Lisp_Object make_save_funcptr_ptr_obj (void (*) (void), void *, |
| 3777 | Lisp_Object); | 3779 | Lisp_Object); |
| 3778 | extern Lisp_Object make_save_memory (Lisp_Object *, ptrdiff_t); | 3780 | extern Lisp_Object make_save_memory (Lisp_Object *, ptrdiff_t); |
diff --git a/test/ChangeLog b/test/ChangeLog index 7546dd1fb46..70c2af66194 100644 --- a/test/ChangeLog +++ b/test/ChangeLog | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | 2014-08-29 Dmitry Antipov <dmantipov@yandex.ru> | ||
| 2 | |||
| 3 | * automated/fns-tests.el (fns-tests-sort): New test. | ||
| 4 | |||
| 1 | 2014-08-28 Glenn Morris <rgm@gnu.org> | 5 | 2014-08-28 Glenn Morris <rgm@gnu.org> |
| 2 | 6 | ||
| 3 | * automated/python-tests.el (python-shell-calculate-exec-path-2): | 7 | * automated/python-tests.el (python-shell-calculate-exec-path-2): |
diff --git a/test/automated/fns-tests.el b/test/automated/fns-tests.el index d3d921f425f..a6c45443db6 100644 --- a/test/automated/fns-tests.el +++ b/test/automated/fns-tests.el | |||
| @@ -100,3 +100,21 @@ | |||
| 100 | (should (compare-strings "こんにちはコンニチハ" nil nil "こんにちはコンニチハ" nil nil)) | 100 | (should (compare-strings "こんにちはコンニチハ" nil nil "こんにちはコンニチハ" nil nil)) |
| 101 | (should (= (compare-strings "んにちはコンニチハこ" nil nil "こんにちはコンニチハ" nil nil) 1)) | 101 | (should (= (compare-strings "んにちはコンニチハこ" nil nil "こんにちはコンニチハ" nil nil) 1)) |
| 102 | (should (= (compare-strings "こんにちはコンニチハ" nil nil "んにちはコンニチハこ" nil nil) -1))) | 102 | (should (= (compare-strings "こんにちはコンニチハ" nil nil "んにちはコンニチハこ" nil nil) -1))) |
| 103 | |||
| 104 | (ert-deftest fns-tests-sort () | ||
| 105 | (should (equal (sort '(9 5 2 -1 5 3 8 7 4) (lambda (x y) (< x y))) | ||
| 106 | '(-1 2 3 4 5 5 7 8 9))) | ||
| 107 | (should (equal (sort '(9 5 2 -1 5 3 8 7 4) (lambda (x y) (> x y))) | ||
| 108 | '(9 8 7 5 5 4 3 2 -1))) | ||
| 109 | (should (equal (sort '[9 5 2 -1 5 3 8 7 4] (lambda (x y) (< x y))) | ||
| 110 | [-1 2 3 4 5 5 7 8 9])) | ||
| 111 | (should (equal (sort '[9 5 2 -1 5 3 8 7 4] (lambda (x y) (> x y))) | ||
| 112 | [9 8 7 5 5 4 3 2 -1])) | ||
| 113 | (should (equal | ||
| 114 | (sort | ||
| 115 | (vector | ||
| 116 | (cons 8 "xxx") (cons 9 "aaa") (cons 8 "bbb") (cons 9 "zzz") | ||
| 117 | (cons 9 "ppp") (cons 8 "ttt") (cons 8 "eee") (cons 9 "fff")) | ||
| 118 | (lambda (x y) (< (car x) (car y)))) | ||
| 119 | [(8 . "xxx") (8 . "bbb") (8 . "ttt") (8 . "eee") | ||
| 120 | (9 . "aaa") (9 . "zzz") (9 . "ppp") (9 . "fff")]))) | ||