aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Antipov2014-08-29 11:29:47 +0400
committerDmitry Antipov2014-08-29 11:29:47 +0400
commit1764ec4414074ea0dcbd912efdfbedb119f8ed3b (patch)
tree0d577861c3e8a3e3e7a554adef7bcb04e0de5c38
parent483dc86ad0e60a1a6da498f9eb95672f286a4ab5 (diff)
downloademacs-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--ChangeLog4
-rw-r--r--configure.ac2
-rw-r--r--src/ChangeLog11
-rw-r--r--src/alloc.c11
-rw-r--r--src/fns.c99
-rw-r--r--src/lisp.h2
-rw-r--r--test/ChangeLog4
-rw-r--r--test/automated/fns-tests.el18
8 files changed, 143 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index 07fd290f4e0..a998e4d2054 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
12014-08-29 Dmitry Antipov <dmantipov@yandex.ru>
2
3 * configure.ac (AC_CHECK_FUNCS): Check for qsort_r.
4
12014-08-28 Ken Brown <kbrown@cornell.edu> 52014-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 \
3573getrlimit setrlimit shutdown getaddrinfo \ 3573getrlimit setrlimit shutdown getaddrinfo \
3574pthread_sigmask strsignal setitimer \ 3574pthread_sigmask strsignal setitimer \
3575sendto recvfrom getsockname getpeername getifaddrs freeifaddrs \ 3575sendto recvfrom getsockname getpeername getifaddrs freeifaddrs \
3576gai_strerror sync \ 3576gai_strerror sync qsort_r \
3577getpwent endpwent getgrent endgrent \ 3577getpwent endpwent getgrent endgrent \
3578cfmakeraw cfsetspeed copysign __executable_start log2) 3578cfmakeraw cfsetspeed copysign __executable_start log2)
3579LIBS=$OLD_LIBS 3579LIBS=$OLD_LIBS
diff --git a/src/ChangeLog b/src/ChangeLog
index 9b3c3d0bd66..c24ca69536f 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,14 @@
12014-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
12014-08-28 Ken Brown <kbrown@cornell.edu> 122014-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
3613Lisp_Object
3614make_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)
3614Lisp_Object 3625Lisp_Object
3615make_save_ptr_ptr (void *a, void *b) 3626make_save_ptr_ptr (void *a, void *b)
diff --git a/src/fns.c b/src/fns.c
index 2e2acf84b95..8845a43fc4b 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -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
1850DEFUN ("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. */
1852Returns the sorted list. LIST is modified by side effects. 1852
1853PREDICATE is called with two elements of LIST, and should return non-nil 1853static Lisp_Object
1854if the first element should sort before the second. */) 1854sort_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
1881static Lisp_Object sort_vector_predicate;
1882#endif
1883
1884/* Comparison function called by qsort. */
1885
1886static int
1887#ifdef HAVE_QSORT_R
1888sort_vector_compare (const void *p, const void *q, void *arg)
1889#else
1890sort_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
1916static Lisp_Object
1917sort_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
1948DEFUN ("sort", Fsort, Ssort, 2, 2, 0,
1949 doc: /* Sort SEQ, stably, comparing elements using PREDICATE.
1950Returns the sorted sequence. SEQ should be a list or vector.
1951If SEQ is a list, it is modified by side effects. PREDICATE
1952is called with two elements of SEQ, and should return non-nil
1953if 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
1880Lisp_Object 1965Lisp_Object
1881merge (Lisp_Object org_l1, Lisp_Object org_l2, Lisp_Object pred) 1966merge (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,
3773extern Lisp_Object make_save_ptr (void *); 3774extern Lisp_Object make_save_ptr (void *);
3774extern Lisp_Object make_save_ptr_int (void *, ptrdiff_t); 3775extern Lisp_Object make_save_ptr_int (void *, ptrdiff_t);
3775extern Lisp_Object make_save_ptr_ptr (void *, void *); 3776extern Lisp_Object make_save_ptr_ptr (void *, void *);
3777extern Lisp_Object make_save_int_obj (ptrdiff_t, Lisp_Object);
3776extern Lisp_Object make_save_funcptr_ptr_obj (void (*) (void), void *, 3778extern Lisp_Object make_save_funcptr_ptr_obj (void (*) (void), void *,
3777 Lisp_Object); 3779 Lisp_Object);
3778extern Lisp_Object make_save_memory (Lisp_Object *, ptrdiff_t); 3780extern 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 @@
12014-08-29 Dmitry Antipov <dmantipov@yandex.ru>
2
3 * automated/fns-tests.el (fns-tests-sort): New test.
4
12014-08-28 Glenn Morris <rgm@gnu.org> 52014-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")])))