source: branches/0.15.x/abcl/src/org/armedbear/lisp/JavaObject.java

Last change on this file was 11754, checked in by vvoutilainen, 16 years ago

Convert using ClassCastException? to checking instanceof.
Performance tests show this approach to be faster.
Patch by Douglas R. Miles. I modified the patch to
remove tabs, so indentation may be slightly off in places.
That's something that we need to handle separately, abcl
doesn't have a clear indentation policy.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 9.7 KB
Line 
1/*
2 * JavaObject.java
3 *
4 * Copyright (C) 2002-2005 Peter Graves
5 * $Id: JavaObject.java 11754 2009-04-12 10:53:39Z vvoutilainen $
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 *
21 * As a special exception, the copyright holders of this library give you
22 * permission to link this library with independent modules to produce an
23 * executable, regardless of the license terms of these independent
24 * modules, and to copy and distribute the resulting executable under
25 * terms of your choice, provided that you also meet, for each linked
26 * independent module, the terms and conditions of the license of that
27 * module.  An independent module is a module which is not derived from
28 * or based on this library.  If you modify this library, you may extend
29 * this exception to your version of the library, but you are not
30 * obligated to do so.  If you do not wish to do so, delete this
31 * exception statement from your version.
32 */
33
34package org.armedbear.lisp;
35
36import java.math.BigInteger;
37
38public final class JavaObject extends LispObject
39{
40    private final Object obj;
41
42    public JavaObject(Object obj)
43    {
44        this.obj = obj;
45    }
46
47    @Override
48    public LispObject typeOf()
49    {
50        return Symbol.JAVA_OBJECT;
51    }
52
53    @Override
54    public LispObject classOf()
55    {
56        if(obj == null) {
57                return BuiltInClass.JAVA_OBJECT;
58        } else {
59                return JavaClass.findJavaClass(obj.getClass());
60        }
61    }
62
63    @Override
64    public LispObject typep(LispObject type) throws ConditionThrowable
65    {
66        if (type == Symbol.JAVA_OBJECT)
67            return T;
68        if (type == BuiltInClass.JAVA_OBJECT)
69            return T;
70        if(type instanceof JavaClass && obj != null) {
71                return ((JavaClass) type).getJavaClass().isAssignableFrom(obj.getClass()) ? T : NIL;
72        }
73        return super.typep(type);
74    }
75
76    public final Object getObject()
77    {
78        return obj;
79    }
80
81    /** Encapsulates obj, if required.
82     * If obj is a {@link  LispObject}, it's returned as-is.
83     *
84     * @param obj Any java object
85     * @return obj or a new JavaObject encapsulating obj
86     */
87    public final static LispObject getInstance(Object obj) {
88        if (obj == null)
89            return new JavaObject(null);
90       
91        if (obj instanceof LispObject)
92            return (LispObject)obj;
93
94        return new JavaObject(obj);
95    }
96
97    /** Encapsulates obj, if required.
98     * If obj is a {@link LispObject}, it's returned as-is.
99     * If obj is of a type which can be mapped to a lisp type,
100     * an object of the mapped type is returned, if translated is true.
101     *
102     * @param obj
103     * @param translated
104     * @return a LispObject representing or encapsulating obj
105     */
106    public final static LispObject getInstance(Object obj, boolean translated)
107            throws ConditionThrowable
108    {
109        if (! translated)
110            return getInstance(obj);
111
112        if (obj == null) return NIL;
113
114        if (obj instanceof LispObject)
115            return (LispObject)obj;
116
117        if (obj instanceof String)
118            return new SimpleString((String)obj);
119
120        if (obj instanceof Number) {
121            // Number types ordered according to decreasing
122            // estimated chances of occurrance
123
124            if (obj instanceof Integer)
125                return Fixnum.getInstance(((Integer)obj).intValue());
126
127            if (obj instanceof Float)
128                return new SingleFloat((Float)obj);
129
130            if (obj instanceof Double)
131                return new DoubleFloat((Double)obj);
132
133            if (obj instanceof Long)
134                return LispInteger.getInstance(((Long)obj).longValue());
135
136            if (obj instanceof BigInteger)
137                return Bignum.getInstance((BigInteger)obj);
138
139            if (obj instanceof Short)
140                return Fixnum.getInstance(((Short)obj).shortValue());
141
142            if (obj instanceof Byte)
143                return Fixnum.getInstance(((Byte)obj).byteValue());
144            // We don't handle BigDecimal: it doesn't map to a Lisp type
145        }
146
147        if (obj instanceof Boolean)
148            return ((Boolean)obj).booleanValue() ? T : NIL;
149
150        if (obj instanceof Character)
151            return new LispCharacter((Character)obj);
152
153        if (obj instanceof Object[]) {
154            Object[] array = (Object[]) obj;
155            SimpleVector v = new SimpleVector(array.length);
156            for (int i = array.length; i-- > 0;)
157                v.aset(i, JavaObject.getInstance(array[i]));
158            return v;
159        }
160        // TODO
161        // We might want to handle:
162        //  - streams
163        //  - others?
164        return new JavaObject(obj);
165    }
166
167    @Override
168    public Object javaInstance()
169    {
170        return obj;
171    }
172
173    @Override
174    public Object javaInstance(Class c)
175    {
176        return javaInstance();
177    }
178
179    public static final Object getObject(LispObject o)
180        throws ConditionThrowable
181    {
182        if (o instanceof JavaObject)
183                return ((JavaObject)o).obj;       
184        return             // Not reached.
185        type_error(o, Symbol.JAVA_OBJECT);       
186    }
187
188    @Override
189    public final boolean equal(LispObject other)
190    {
191        if (this == other)
192            return true;
193        if (other instanceof JavaObject)
194            return (obj == ((JavaObject)other).obj);
195        return false;
196    }
197
198    @Override
199    public final boolean equalp(LispObject other)
200    {
201        return equal(other);
202    }
203
204    @Override
205    public int sxhash()
206    {
207        return obj == null ? 0 : (obj.hashCode() & 0x7ffffff);
208    }
209
210    @Override
211    public String writeToString() throws ConditionThrowable
212    {
213        if (obj instanceof ConditionThrowable)
214            return obj.toString();
215        final FastStringBuffer sb =
216            new FastStringBuffer(Symbol.JAVA_OBJECT.writeToString());
217        sb.append(' ');
218        sb.append(obj == null ? "null" : obj.getClass().getName());
219        return unreadableString(sb.toString());
220    }
221
222    // ### describe-java-object
223    private static final Primitive DESCRIBE_JAVA_OBJECT =
224        new Primitive("describe-java-object", PACKAGE_JAVA, true)
225    {
226        @Override
227        public LispObject execute(LispObject first, LispObject second)
228            throws ConditionThrowable
229        {
230            if (!(first instanceof JavaObject))
231                return type_error(first, Symbol.JAVA_OBJECT);
232            final Stream stream = checkStream(second);
233            final JavaObject javaObject = (JavaObject) first;
234            final Object obj = javaObject.getObject();
235            final FastStringBuffer sb =
236                new FastStringBuffer(javaObject.writeToString());
237            sb.append(" is an object of type ");
238            sb.append(Symbol.JAVA_OBJECT.writeToString());
239            sb.append(".");
240            sb.append(System.getProperty("line.separator"));
241            sb.append("The wrapped Java object is ");
242            if (obj == null) {
243                sb.append("null.");
244            } else {
245                sb.append("an ");
246                final Class c = obj.getClass();
247                String className = c.getName();
248                if (c.isArray()) {
249                    sb.append("array of ");
250                    if (className.startsWith("[L") && className.endsWith(";")) {
251                        className = className.substring(1, className.length() - 1);
252                        sb.append(className);
253                        sb.append(" objects");
254                    } else if (className.startsWith("[") && className.length() > 1) {
255                        char descriptor = className.charAt(1);
256                        final String type;
257                        switch (descriptor) {
258                            case 'B': type = "bytes"; break;
259                            case 'C': type = "chars"; break;
260                            case 'D': type = "doubles"; break;
261                            case 'F': type = "floats"; break;
262                            case 'I': type = "ints"; break;
263                            case 'J': type = "longs"; break;
264                            case 'S': type = "shorts"; break;
265                            case 'Z': type = "booleans"; break;
266                            default:
267                                type = "unknown type";
268                        }
269                        sb.append(type);
270                    }
271                    sb.append(" with ");
272                    final int length = java.lang.reflect.Array.getLength(obj);
273                    sb.append(length);
274                    sb.append(" element");
275                    if (length != 1)
276                        sb.append('s');
277                    sb.append('.');
278                } else {
279                    sb.append("instance of ");
280                    sb.append(className);
281                    sb.append(':');
282                    sb.append(System.getProperty("line.separator"));
283                    sb.append("  \"");
284                    sb.append(obj.toString());
285                    sb.append('"');
286                }
287            }
288            stream._writeString(sb.toString());
289            return LispThread.currentThread().nothing();
290        }
291    };
292}
Note: See TracBrowser for help on using the repository browser.