source: branches/0.22.x/abcl/src/org/armedbear/lisp/AbstractArray.java

Last change on this file was 12713, checked in by astalla, 15 years ago

Serialization support for some Lisp types.
For symbols and packages, only the "identity" is serialized, i.e. package name + symbol name.
For packages, it is expected that a package of the same name exists "at the other side".
For symbols, the deserialized symbol is interned in its home package.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 11.2 KB
Line 
1/*
2 * AbstractArray.java
3 *
4 * Copyright (C) 2003-2005 Peter Graves
5 * $Id: AbstractArray.java 12713 2010-05-20 17:58:13Z astalla $
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 static org.armedbear.lisp.Lisp.*;
37
38public abstract class AbstractArray extends LispObject implements java.io.Serializable
39{
40    @Override
41    public LispObject typep(LispObject type)
42    {
43        if (type == Symbol.ARRAY)
44            return T;
45        if (type == BuiltInClass.ARRAY)
46            return T;
47        return super.typep(type);
48    }
49
50    @Override
51    public boolean equalp(LispObject obj)
52    {
53        if (obj instanceof AbstractArray) {
54            AbstractArray a = (AbstractArray) obj;
55            if (getRank() != a.getRank())
56                return false;
57            for (int i = getRank(); i-- > 0;) {
58                if (getDimension(i) != a.getDimension(i))
59                    return false;
60            }
61            for (int i = getTotalSize(); i--> 0;) {
62                if (!AREF(i).equalp(a.AREF(i)))
63                    return false;
64            }
65            return true;
66        }
67        return false;
68    }
69
70    public boolean isDisplaced()
71    {
72        return false;
73    }
74
75    public LispObject arrayDisplacement()
76    {
77        return LispThread.currentThread().setValues(NIL, Fixnum.ZERO);
78    }
79
80    public boolean hasFillPointer()
81    {
82        return false;
83    }
84
85    public int getFillPointer()
86    {
87        noFillPointer();
88        return -1; // Not reached.
89    }
90
91    public void setFillPointer(LispObject fillPointer)
92    {
93        setFillPointer(fillPointer.intValue());
94    }
95
96    public void setFillPointer(int fillPointer)
97    {
98        noFillPointer();
99    }
100
101    public boolean isAdjustable()
102    {
103        return true;
104    }
105
106    public abstract int getRank();
107
108    public abstract LispObject getDimensions();
109
110    public abstract int getDimension(int n);
111
112    public abstract LispObject getElementType();
113
114    public abstract int getTotalSize();
115
116    @Override
117    public abstract void aset(int index, LispObject newValue)
118       ;
119
120    // FIXME Detect overflow!
121    protected static final int computeTotalSize(int[] dimensions)
122    {
123        int size = 1;
124        for (int i = dimensions.length; i-- > 0;)
125            size *= dimensions[i];
126        return size;
127    }
128
129    public int getRowMajorIndex(LispObject[] subscripts)
130
131    {
132        int[] subs = new int[subscripts.length];
133        for (int i = 0; i < subscripts.length; i++) {
134            LispObject subscript = subscripts[i];
135            if (subscript instanceof Fixnum)
136                subs[i] = ((Fixnum)subscript).value;
137            else
138                type_error(subscript, Symbol.FIXNUM);
139        }
140        return getRowMajorIndex(subs);
141    }
142
143    public int getRowMajorIndex(int[] subscripts)
144    {
145        final int rank = getRank();
146        if (rank != subscripts.length) {
147            // ### i18n
148            final String errorMsg =
149                "Wrong number of subscripts (%d) for array of rank %d.";
150            error(new ProgramError(String.format(errorMsg, subscripts.length, rank)));
151        }
152        int sum = 0;
153        int size = 1;
154        for (int i = rank; i-- > 0;) {
155            final int dim = getDimension(i);
156            final int lastSize = size;
157            size *= dim;
158            final int n = subscripts[i];
159            if (n < 0 || n >= dim) {
160                // ### i18n
161                final String errorMsg =
162                    "Invalid index %d for array %s.";
163                error(new ProgramError(String.format(errorMsg, n, writeToString())));
164            }
165            sum += n * lastSize;
166        }
167        return sum;
168    }
169
170    public LispObject get(int[] subscripts)
171    {
172        return AREF(getRowMajorIndex(subscripts));
173    }
174
175    public void set(int[] subscripts, LispObject newValue)
176
177    {
178        aset(getRowMajorIndex(subscripts), newValue);
179    }
180
181    public abstract void fill(LispObject obj);
182
183    public String writeToString(int[] dimv)
184    {
185        StringBuilder sb = new StringBuilder();
186        LispThread thread = LispThread.currentThread();
187        LispObject printReadably = Symbol.PRINT_READABLY.symbolValue(thread);
188        if (printReadably != NIL || Symbol.PRINT_ARRAY.symbolValue(thread) != NIL) {
189            int maxLevel = Integer.MAX_VALUE;
190            if (printReadably != NIL) {
191                for (int i = 0; i < dimv.length - 1; i++) {
192                    if (dimv[i] == 0) {
193                        for (int j = i + 1; j < dimv.length; j++) {
194                            if (dimv[j] != 0) {
195                                error(new PrintNotReadable(list(Keyword.OBJECT,
196                                                                  this)));
197                                return null; // Not reached.
198                            }
199                        }
200                    }
201                }
202            } else {
203                LispObject printLevel = Symbol.PRINT_LEVEL.symbolValue(thread);
204                if (printLevel instanceof Fixnum)
205                    maxLevel = ((Fixnum)printLevel).value;
206            }
207            LispObject currentPrintLevel =
208                _CURRENT_PRINT_LEVEL_.symbolValue(thread);
209            int currentLevel = Fixnum.getValue(currentPrintLevel);
210            if (currentLevel >= maxLevel)
211                return "#";
212            sb.append('#');
213            sb.append(dimv.length);
214            sb.append('A');
215            appendContents(dimv, 0, sb, thread);
216            return sb.toString();
217        }
218        sb.append('(');
219        if (this instanceof SimpleArray_T)
220            sb.append("SIMPLE-");
221        sb.append("ARRAY " + getElementType().writeToString() + " (");
222        for (int i = 0; i < dimv.length; i++) {
223            sb.append(dimv[i]);
224            if (i < dimv.length - 1)
225                sb.append(' ');
226        }
227        sb.append("))");
228        return unreadableString(sb.toString());
229    }
230
231    // Helper for writeToString().
232    private void appendContents(int[] dimensions, int index, StringBuilder sb,
233                                LispThread thread)
234
235    {
236        if (dimensions.length == 0) {
237            if (Symbol.PRINT_CIRCLE.symbolValue(thread) != NIL) {
238                StringOutputStream stream = new StringOutputStream();
239                thread.execute(Symbol.OUTPUT_OBJECT.getSymbolFunction(),
240                               AREF(index), stream);
241                sb.append(stream.getString().getStringValue());
242            } else
243                sb.append(AREF(index).writeToString());
244        } else {
245            final LispObject printReadably =
246                Symbol.PRINT_READABLY.symbolValue(thread);
247            int maxLength = Integer.MAX_VALUE;
248            int maxLevel = Integer.MAX_VALUE;
249            if (printReadably == NIL) {
250                final LispObject printLength =
251                    Symbol.PRINT_LENGTH.symbolValue(thread);
252                if (printLength instanceof Fixnum)
253                    maxLength = ((Fixnum)printLength).value;
254                final LispObject printLevel =
255                    Symbol.PRINT_LEVEL.symbolValue(thread);
256                if (printLevel instanceof Fixnum)
257                    maxLevel = ((Fixnum)printLevel).value;
258            }
259            LispObject currentPrintLevel =
260                _CURRENT_PRINT_LEVEL_.symbolValue(thread);
261            int currentLevel = Fixnum.getValue(currentPrintLevel);
262            if (currentLevel < maxLevel) {
263                final SpecialBindingsMark mark = thread.markSpecialBindings();
264                thread.bindSpecial(_CURRENT_PRINT_LEVEL_, currentPrintLevel.incr());
265                try {
266                    sb.append('(');
267                    int[] dims = new int[dimensions.length - 1];
268                    for (int i = 1; i < dimensions.length; i++)
269                        dims[i-1] = dimensions[i];
270                    int count = 1;
271                    for (int i = 0; i < dims.length; i++)
272                        count *= dims[i];
273                    final int length = dimensions[0];
274                    final int limit = Math.min(length, maxLength);
275                    for (int i = 0; i < limit; i++) {
276                        appendContents(dims, index, sb, thread);
277                        if (i < limit - 1 || limit < length)
278                            sb.append(' ');
279                        index += count;
280                    }
281                    if (limit < length)
282                        sb.append("...");
283                    sb.append(')');
284                }
285                finally {
286                    thread.resetSpecialBindings(mark);
287                }
288            } else
289                sb.append('#');
290        }
291    }
292
293    // For EQUALP hash tables.
294    @Override
295    public int psxhash()
296    {
297        long result = 128387; // Chosen at random.
298        final int rank = getRank();
299        int limit = rank < 4 ? rank : 4;
300        for (int i = 0; i < limit; i++)
301            result = mix(result, getDimension(i));
302        final int length = getTotalSize();
303        limit = length < 4 ? length : 4;
304        for (int i = 0; i < length; i++)
305            result = mix(result, AREF(i).psxhash());
306        return (int) (result & 0x7fffffff);
307    }
308
309    /** Returns a newly allocated array or the current array with
310     * adjusted dimensions.
311     *
312     * @param dims
313     * @param initialElement @c null if none
314     * @param initialContents @c null if none
315     * @return @c this or a new array
316     */
317    public abstract AbstractArray adjustArray(int[] dims,
318                                              LispObject initialElement,
319                                              LispObject initialContents);
320
321    /**
322     *
323     * @param dims
324     * @param displacedTo
325     * @param displacement
326     * @return
327     */
328    public abstract AbstractArray adjustArray(int[] dims,
329                                              AbstractArray displacedTo,
330                                              int displacement);
331}
Note: See TracBrowser for help on using the repository browser.