source: tags/1.5.0/contrib/jss/collections.lisp

Last change on this file was 15060, checked in by Mark Evenson, 7 years ago

Fix J2LIST
(Olof-Joachim Frahm)

From <https://github.com/armedbear/abcl/pull/50/commits/335405b2ef48da2e4894763ff23824113d29cb5b>.

Merges <https://github.com/armedbear/abcl/pull/50>.

File size: 6.4 KB
Line 
1(in-package :jss)
2
3(defun set-to-list (set)
4  "Convert the java.util.Set named in SET to a Lisp list."
5  (declare (optimize (speed 3) (safety 0)))
6  (with-constant-signature ((iterator "iterator" t) (hasnext "hasNext") (next "next"))
7    (loop with iterator = (iterator set)
8       while (hasNext iterator)
9       for item = (next iterator)
10       collect item)))
11
12(defun jlist-to-list (list)
13  "Convert a LIST implementing java.util.List to a Lisp list."
14  (declare (optimize (speed 3) (safety 0)))
15  (loop :for i :from 0 :below (jcall "size" list)
16     :collecting (jcall "get" list i)))
17
18(defun jarray-to-list (jarray)
19  "Convert the Java array named by JARRARY into a Lisp list."
20  (declare (optimize (speed 3) (safety 0)))
21  (loop :for i :from 0 :below (jarray-length jarray)
22     :collecting (jarray-ref jarray i)))
23
24;;; Deprecated
25;;;
26;;; XXX unclear what sort of list this would actually work on, as it
27;;; certainly doesn't seem to be any of the Java collection types
28;;; (what implements getNext())?
29(defun list-to-list (list)
30  (declare (optimize (speed 3) (safety 0)))
31  (with-constant-signature ((isEmpty "isEmpty") (getfirst "getFirst")
32                            (getNext "getNext"))
33    (loop until (isEmpty list)
34       collect (getFirst list)
35       do (setq list (getNext list)))))
36
37;; Contribution of Luke Hope. (Thanks!)
38
39(defun iterable-to-list (iterable)
40  "Return the items contained the java.lang.Iterable ITERABLE as a list."
41  (declare (optimize (speed 3) (safety 0)))
42  (let ((it (#"iterator" iterable)))
43    (with-constant-signature ((has-next "hasNext")
44                              (next "next"))
45      (loop :while (has-next it)
46         :collect (next it)))))
47
48(defun vector-to-list (vector)
49  "Return the elements of java.lang.Vector VECTOR as a list."
50  (declare (optimize (speed 3) (safety 0)))
51  (with-constant-signature ((has-more "hasMoreElements")
52                            (next "nextElement"))
53    (let ((elements (#"elements" vector)))
54      (loop :while (has-more elements)
55         :collect (next elements)))))
56
57(defun hashmap-to-hashtable (hashmap &rest rest &key (keyfun #'identity) (valfun #'identity) (invert? nil)
58                                                  table 
59                             &allow-other-keys )
60  "Converts the a HASHMAP reference to a java.util.HashMap object to a Lisp hashtable.
61
62The REST paramter specifies arguments to the underlying MAKE-HASH-TABLE call.
63
64KEYFUN and VALFUN specifies functions to be run on the keys and values
65of the HASHMAP right before they are placed in the hashtable.
66
67If INVERT? is non-nil than reverse the keys and values in the resulting hashtable."
68  (let ((keyset (#"keySet" hashmap))
69        (table (or table (apply 'make-hash-table
70                                (loop for (key value) on rest by #'cddr
71                                   unless (member key '(:invert? :valfun :keyfun :table)) 
72                                   collect key and collect value)))))
73    (with-constant-signature ((iterator "iterator" t) (hasnext "hasNext") (next "next"))
74      (loop with iterator = (iterator keyset)
75         while (hasNext iterator)
76         for item = (next iterator)
77         do (if invert?
78                (setf (gethash (funcall valfun (#"get" hashmap item)) table) (funcall keyfun item))
79                (setf (gethash (funcall keyfun item) table) (funcall valfun (#"get" hashmap item)))))
80      table)))
81
82;; ****************************************************************
83;; But needing to remember is annoying
84
85;; Here's a summary I gleaned:
86
87;; java.util.Dictionary -> #"elements" yields java.util.Collections$3
88;; java.util.AbstractCollection -> #"iterator" yields java.util.Iterator?
89;; org.apache.felix.framework.util.CompoundEnumeration  -> implements java.util.Enumeration
90;; java.util.Collections -> doc says #"iterator" yields java.util.Iterator
91;; java.util.Collections$1) -> implements java.util.Iterator
92;; java.util.Collections$2) -> implements java.util.Spliterator (#"iterator" (#"stream" 'StreamSupport <a spliterator>)) -> java.util.Iterator
93;; java.util.Collections$3) -> implements java.util.Enumeration
94;; java.util.Iterator
95;;   ("next" "hasNext")
96;; java.util.Enumeration)
97;;   ("nextElement" "hasMoreElements")
98
99
100(defun j2list (thing)
101  "Attempt to construct a Lisp list out of a Java THING.
102
103THING may be a wide range of Java collection types, their common
104iterators or a Java array."
105  (declare (optimize (speed 3) (safety 0)))
106  (flet ((iterator-collect (iterator)
107     (with-constant-signature ((has-next "hasNext")
108             (next "next"))
109       (loop :while (has-next iterator)
110       :collect (next iterator))))
111   (enumeration-collect (enumeration)
112     (with-constant-signature ((has-next "hasMoreElements")
113             (next "nextElement"))
114       (loop :while (has-next enumeration)
115       :collect (next enumeration))))
116   (map-collect (map)
117     (with-constant-signature ((has-next "hasMoreElements")
118             (next "nextElement"))
119       (let ((keyiterator (#"iterator" (#"keyset" map))))
120         (loop :while (has-next keyiterator)
121         :for key = (next keyiterator)
122                  :collect (cons key (#"get" map key)))))))
123    (let ((isinstance
124           (load-time-value (jmethod "java.lang.Class" "isInstance" "java.lang.Object"))))
125      (cond
126        ((jcall isinstance (load-time-value (ignore-errors (jclass "java.util.AbstractCollection"))) thing)
127         (iterator-collect (#"iterator" thing)))
128        ((jcall isinstance (load-time-value (ignore-errors (jclass "java.util.Iterator"))) thing)
129         (iterator-collect thing))
130        ((jcall isinstance (load-time-value (ignore-errors (jclass "java.util.Enumeration"))) thing)
131         (enumeration-collect thing))
132        ((jcall isinstance (load-time-value (ignore-errors (jclass "java.util.AbstractMap"))) thing)
133         (map-collect thing))
134        ((jcall isinstance (load-time-value (ignore-errors (jclass "java.util.Collections"))) thing)
135         (iterator-collect (#"iterator" thing)))
136        ((jcall isinstance (load-time-value (ignore-errors (jclass "java.util.Spliterator"))) thing)
137         (iterator-collect (#"iterator" (#"stream" 'StreamSupport thing))))
138        ((jcall isinstance (load-time-value (ignore-errors (jclass "java.util.Dictionary"))) thing)
139         (iterator-collect (#"elements" thing)))
140        ((ignore-errors (#"toArray" thing))
141         (coerce (#"toArray" thing) 'list))
142        (t
143         (error "yet another iteration type - fix it: ~a" (jclass-name (jobject-class thing))))))))
Note: See TracBrowser for help on using the repository browser.