source: branches/0.16.x/abcl/src/org/armedbear/lisp/StructureObject.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: 18.0 KB
Line 
1/*
2 * StructureObject.java
3 *
4 * Copyright (C) 2003-2006 Peter Graves
5 * $Id: StructureObject.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
36public final class StructureObject extends LispObject
37{
38  private final StructureClass structureClass;
39  private final LispObject[] slots;
40
41  public StructureObject(Symbol symbol, LispObject[] slots)
42    throws ConditionThrowable
43  {
44    structureClass = (StructureClass) LispClass.findClass(symbol); // Might return null.
45    this.slots = slots;
46  }
47
48  public StructureObject(Symbol symbol, LispObject obj0)
49    throws ConditionThrowable
50  {
51    structureClass = (StructureClass) LispClass.findClass(symbol); // Might return null.
52    LispObject[] slots = new LispObject[1];
53    slots[0] = obj0;
54    this.slots = slots;
55  }
56
57  public StructureObject(Symbol symbol, LispObject obj0, LispObject obj1)
58    throws ConditionThrowable
59  {
60    structureClass = (StructureClass) LispClass.findClass(symbol); // Might return null.
61    LispObject[] slots = new LispObject[2];
62    slots[0] = obj0;
63    slots[1] = obj1;
64    this.slots = slots;
65  }
66
67  public StructureObject(Symbol symbol, LispObject obj0, LispObject obj1,
68                         LispObject obj2)
69    throws ConditionThrowable
70  {
71    structureClass = (StructureClass) LispClass.findClass(symbol); // Might return null.
72    LispObject[] slots = new LispObject[3];
73    slots[0] = obj0;
74    slots[1] = obj1;
75    slots[2] = obj2;
76    this.slots = slots;
77  }
78
79  public StructureObject(Symbol symbol, LispObject obj0, LispObject obj1,
80                         LispObject obj2, LispObject obj3)
81    throws ConditionThrowable
82  {
83    structureClass = (StructureClass) LispClass.findClass(symbol); // Might return null.
84    LispObject[] slots = new LispObject[4];
85    slots[0] = obj0;
86    slots[1] = obj1;
87    slots[2] = obj2;
88    slots[3] = obj3;
89    this.slots = slots;
90  }
91
92  public StructureObject(Symbol symbol, LispObject obj0, LispObject obj1,
93                         LispObject obj2, LispObject obj3, LispObject obj4)
94    throws ConditionThrowable
95  {
96    structureClass = (StructureClass) LispClass.findClass(symbol); // Might return null.
97    LispObject[] slots = new LispObject[5];
98    slots[0] = obj0;
99    slots[1] = obj1;
100    slots[2] = obj2;
101    slots[3] = obj3;
102    slots[4] = obj4;
103    this.slots = slots;
104  }
105
106  public StructureObject(Symbol symbol, LispObject obj0, LispObject obj1,
107                         LispObject obj2, LispObject obj3, LispObject obj4,
108                         LispObject obj5)
109    throws ConditionThrowable
110  {
111    structureClass = (StructureClass) LispClass.findClass(symbol); // Might return null.
112    LispObject[] slots = new LispObject[6];
113    slots[0] = obj0;
114    slots[1] = obj1;
115    slots[2] = obj2;
116    slots[3] = obj3;
117    slots[4] = obj4;
118    slots[5] = obj5;
119    this.slots = slots;
120  }
121
122  public StructureObject(StructureObject obj)
123  {
124    this.structureClass = obj.structureClass;
125    slots = new LispObject[obj.slots.length];
126    for (int i = slots.length; i-- > 0;)
127      slots[i] = obj.slots[i];
128  }
129
130  @Override
131  public LispObject typeOf()
132  {
133    return structureClass.getSymbol();
134  }
135
136  @Override
137  public LispObject classOf()
138  {
139    return structureClass;
140  }
141
142  @Override
143  public LispObject getParts() throws ConditionThrowable
144  {
145    LispObject result = NIL;
146    result = result.push(new Cons("class", structureClass));
147    LispObject effectiveSlots = structureClass.getSlotDefinitions();
148    LispObject[] effectiveSlotsArray = effectiveSlots.copyToArray();
149    Debug.assertTrue(effectiveSlotsArray.length == slots.length);
150    for (int i = 0; i < slots.length; i++)
151      {
152        SimpleVector slotDefinition = (SimpleVector) effectiveSlotsArray[i];
153        LispObject slotName = slotDefinition.AREF(1);
154        result = result.push(new Cons(slotName, slots[i]));
155      }
156    return result.nreverse();
157  }
158
159  @Override
160  public LispObject typep(LispObject type) throws ConditionThrowable
161  {
162    if (type instanceof StructureClass)
163      return memq(type, structureClass.getCPL()) ? T : NIL;
164    if (type == structureClass.getSymbol())
165      return T;
166    if (type == Symbol.STRUCTURE_OBJECT)
167      return T;
168    if (type == BuiltInClass.STRUCTURE_OBJECT)
169      return T;
170    if (type instanceof Symbol)
171      {
172        LispClass c = LispClass.findClass((Symbol)type);
173        if (c != null)
174          return memq(c, structureClass.getCPL()) ? T : NIL;
175      }
176    return super.typep(type);
177  }
178
179  @Override
180  public boolean equalp(LispObject obj) throws ConditionThrowable
181  {
182    if (this == obj)
183      return true;
184    if (obj instanceof StructureObject)
185      {
186        StructureObject o = (StructureObject) obj;
187        if (structureClass != o.structureClass)
188          return false;
189        for (int i = 0; i < slots.length; i++)
190          {
191            if (!slots[i].equalp(o.slots[i]))
192              return false;
193          }
194        return true;
195      }
196    return false;
197  }
198
199  @Override
200  public LispObject getSlotValue_0() throws ConditionThrowable
201  {
202    try
203      {
204        return slots[0];
205      }
206    catch (ArrayIndexOutOfBoundsException e)
207      {
208        return badIndex(0);
209      }
210  }
211
212  @Override
213  public LispObject getSlotValue_1() throws ConditionThrowable
214  {
215    try
216      {
217        return slots[1];
218      }
219    catch (ArrayIndexOutOfBoundsException e)
220      {
221        return badIndex(1);
222      }
223  }
224
225  @Override
226  public LispObject getSlotValue_2() throws ConditionThrowable
227  {
228    try
229      {
230        return slots[2];
231      }
232    catch (ArrayIndexOutOfBoundsException e)
233      {
234        return badIndex(2);
235      }
236  }
237
238  @Override
239  public LispObject getSlotValue_3() throws ConditionThrowable
240  {
241    try
242      {
243        return slots[3];
244      }
245    catch (ArrayIndexOutOfBoundsException e)
246      {
247        return badIndex(3);
248      }
249  }
250
251  @Override
252  public LispObject getSlotValue(int index) throws ConditionThrowable
253  {
254    try
255      {
256        return slots[index];
257      }
258    catch (ArrayIndexOutOfBoundsException e)
259      {
260        return badIndex(index);
261      }
262  }
263
264  @Override
265  public int getFixnumSlotValue(int index) throws ConditionThrowable
266  {
267    try
268      {
269        return Fixnum.getValue(slots[index]);
270      }
271    catch (ArrayIndexOutOfBoundsException e)
272      {
273        badIndex(index);
274        // Not reached.
275        return 0;
276      }
277  }
278
279  @Override
280  public boolean getSlotValueAsBoolean(int index) throws ConditionThrowable
281  {
282    try
283      {
284        return slots[index] != NIL ? true : false;
285      }
286    catch (ArrayIndexOutOfBoundsException e)
287      {
288        badIndex(index);
289        // Not reached.
290        return false;
291      }
292  }
293
294  @Override
295  public void setSlotValue_0(LispObject value)
296    throws ConditionThrowable
297  {
298    try
299      {
300        slots[0] = value;
301      }
302    catch (ArrayIndexOutOfBoundsException e)
303      {
304        badIndex(0);
305      }
306  }
307
308  @Override
309  public void setSlotValue_1(LispObject value)
310    throws ConditionThrowable
311  {
312    try
313      {
314        slots[1] = value;
315      }
316    catch (ArrayIndexOutOfBoundsException e)
317      {
318        badIndex(1);
319      }
320  }
321
322  @Override
323  public void setSlotValue_2(LispObject value)
324    throws ConditionThrowable
325  {
326    try
327      {
328        slots[2] = value;
329      }
330    catch (ArrayIndexOutOfBoundsException e)
331      {
332        badIndex(2);
333      }
334  }
335
336  @Override
337  public void setSlotValue_3(LispObject value)
338    throws ConditionThrowable
339  {
340    try
341      {
342        slots[3] = value;
343      }
344    catch (ArrayIndexOutOfBoundsException e)
345      {
346        badIndex(3);
347      }
348  }
349
350  @Override
351  public void setSlotValue(int index, LispObject value)
352    throws ConditionThrowable
353  {
354    try
355      {
356        slots[index] = value;
357      }
358    catch (ArrayIndexOutOfBoundsException e)
359      {
360        badIndex(index);
361      }
362  }
363
364  private LispObject badIndex(int n) throws ConditionThrowable
365  {
366    FastStringBuffer sb = new FastStringBuffer("Invalid slot index ");
367    sb.append(Fixnum.getInstance(n).writeToString());
368    sb.append(" for ");
369    sb.append(writeToString());
370    return error(new LispError(sb.toString()));
371  }
372
373  @Override
374  public final int psxhash()
375  {
376    return psxhash(4);
377  }
378
379  @Override
380  public final int psxhash(int depth)
381  {
382    int result = mix(structureClass.sxhash(), 7814971);
383    if (depth > 0)
384      {
385        int limit = slots.length;
386        if (limit > 4)
387          limit = 4;
388        for (int i = 0; i < limit; i++)
389          result = mix(slots[i].psxhash(depth - 1), result);
390      }
391    return result & 0x7fffffff;
392  }
393
394  @Override
395  public String writeToString() throws ConditionThrowable
396  {
397    try
398      {
399        final LispThread thread = LispThread.currentThread();
400        // FIXME
401        if (typep(Symbol.RESTART) != NIL)
402          {
403            Symbol PRINT_RESTART = PACKAGE_SYS.intern("PRINT-RESTART");
404            LispObject fun = PRINT_RESTART.getSymbolFunction();
405            StringOutputStream stream = new StringOutputStream();
406            thread.execute(fun, this, stream);
407            return stream.getString().getStringValue();
408          }
409        if (_PRINT_STRUCTURE_.symbolValue(thread) == NIL)
410          return unreadableString(structureClass.getSymbol().writeToString());
411        int maxLevel = Integer.MAX_VALUE;
412        LispObject printLevel = Symbol.PRINT_LEVEL.symbolValue(thread);
413        if (printLevel instanceof Fixnum)
414          maxLevel = ((Fixnum)printLevel).value;
415        LispObject currentPrintLevel =
416          _CURRENT_PRINT_LEVEL_.symbolValue(thread);
417        int currentLevel = Fixnum.getValue(currentPrintLevel);
418        if (currentLevel >= maxLevel && slots.length > 0)
419          return "#";
420        FastStringBuffer sb = new FastStringBuffer("#S(");
421        sb.append(structureClass.getSymbol().writeToString());
422        if (currentLevel < maxLevel)
423          {
424            LispObject effectiveSlots = structureClass.getSlotDefinitions();
425            LispObject[] effectiveSlotsArray = effectiveSlots.copyToArray();
426            Debug.assertTrue(effectiveSlotsArray.length == slots.length);
427            final LispObject printLength = Symbol.PRINT_LENGTH.symbolValue(thread);
428            final int limit;
429            if (printLength instanceof Fixnum)
430              limit = Math.min(slots.length, ((Fixnum)printLength).value);
431            else
432              limit = slots.length;
433            final boolean printCircle =
434              (Symbol.PRINT_CIRCLE.symbolValue(thread) != NIL);
435            for (int i = 0; i < limit; i++)
436              {
437                sb.append(' ');
438                SimpleVector slotDefinition = (SimpleVector) effectiveSlotsArray[i];
439                // FIXME AREF(1)
440                LispObject slotName = slotDefinition.AREF(1);
441                Debug.assertTrue(slotName instanceof Symbol);
442                sb.append(':');
443                sb.append(((Symbol)slotName).name.getStringValue());
444                sb.append(' ');
445                if (printCircle)
446                  {
447                    StringOutputStream stream = new StringOutputStream();
448                    thread.execute(Symbol.OUTPUT_OBJECT.getSymbolFunction(),
449                                   slots[i], stream);
450                    sb.append(stream.getString().getStringValue());
451                  }
452                else
453                  sb.append(slots[i].writeToString());
454              }
455            if (limit < slots.length)
456              sb.append(" ...");
457          }
458        sb.append(')');
459        return sb.toString();
460      }
461    catch (StackOverflowError e)
462      {
463        error(new StorageCondition("Stack overflow."));
464        return null; // Not reached.
465      }
466  }
467
468  // ### structure-object-p object => generalized-boolean
469  private static final Primitive STRUCTURE_OBJECT_P =
470    new Primitive("structure-object-p", PACKAGE_SYS, true, "object")
471    {
472      @Override
473      public LispObject execute(LispObject arg)
474      {
475        return arg instanceof StructureObject ? T : NIL;
476      }
477    };
478
479  // ### structure-length instance => length
480  private static final Primitive STRUCTURE_LENGTH =
481    new Primitive("structure-length", PACKAGE_SYS, true, "instance")
482    {
483      @Override
484      public LispObject execute(LispObject arg) throws ConditionThrowable
485      {
486          if (arg instanceof StructureObject)
487            return Fixnum.getInstance(((StructureObject)arg).slots.length);
488        return type_error(arg, Symbol.STRUCTURE_OBJECT);
489      }
490    };
491
492  // ### structure-ref instance index => value
493  private static final Primitive STRUCTURE_REF =
494    new Primitive("structure-ref", PACKAGE_SYS, true)
495    {
496      @Override
497      public LispObject execute(LispObject first, LispObject second)
498        throws ConditionThrowable
499      {
500    if (first instanceof StructureObject)
501        try
502          {
503            return ((StructureObject)first).slots[Fixnum.getValue(second)];
504          }
505        catch (ArrayIndexOutOfBoundsException e)
506          {
507            // Shouldn't happen.
508            return error(new LispError("Internal error."));
509          }     
510      return type_error(first, Symbol.STRUCTURE_OBJECT);
511      }
512    };
513
514  // ### structure-set instance index new-value => new-value
515  private static final Primitive STRUCTURE_SET =
516    new Primitive("structure-set", PACKAGE_SYS, true)
517    {
518      @Override
519      public LispObject execute(LispObject first, LispObject second,
520                                LispObject third)
521        throws ConditionThrowable
522      {
523         
524            if (first instanceof StructureObject)
525                try
526                  {
527                    ((StructureObject)first).slots[Fixnum.getValue(second)] = third;
528                    return third;
529                  }
530                catch (ArrayIndexOutOfBoundsException e)
531                  {
532                    // Shouldn't happen.
533                    return error(new LispError("Internal error."));
534                  }     
535              return type_error(first, Symbol.STRUCTURE_OBJECT);
536              }     
537    };
538
539  // ### make-structure
540  private static final Primitive MAKE_STRUCTURE =
541    new Primitive("make-structure", PACKAGE_SYS, true)
542    {
543      @Override
544      public LispObject execute(LispObject first, LispObject second)
545        throws ConditionThrowable
546      {
547          return new StructureObject(checkSymbol(first), second);
548      }
549      @Override
550      public LispObject execute(LispObject first, LispObject second,
551                                LispObject third)
552        throws ConditionThrowable
553      {
554          return new StructureObject(checkSymbol(first), second, third);
555      }
556      @Override
557      public LispObject execute(LispObject first, LispObject second,
558                                LispObject third, LispObject fourth)
559        throws ConditionThrowable
560      {
561          return new StructureObject(checkSymbol(first), second, third, fourth);
562      }
563      @Override
564      public LispObject execute(LispObject first, LispObject second,
565                                LispObject third, LispObject fourth,
566                                LispObject fifth)
567        throws ConditionThrowable
568      {
569          return new StructureObject(checkSymbol(first), second, third, fourth,
570                  fifth);
571      }
572      @Override
573      public LispObject execute(LispObject first, LispObject second,
574                                LispObject third, LispObject fourth,
575                                LispObject fifth, LispObject sixth)
576        throws ConditionThrowable
577      {
578          return new StructureObject(checkSymbol(first), second, third, fourth,
579                  fifth, sixth);
580      }
581      @Override
582      public LispObject execute(LispObject first, LispObject second,
583                                LispObject third, LispObject fourth,
584                                LispObject fifth, LispObject sixth,
585                                LispObject seventh)
586        throws ConditionThrowable
587      {
588          return new StructureObject(checkSymbol(first), second, third, fourth,
589                  fifth, sixth, seventh);
590      }
591    };
592
593  // ### %make-structure name slot-values => object
594  private static final Primitive _MAKE_STRUCTURE =
595    new Primitive("%make-structure", PACKAGE_SYS, true)
596    {
597      @Override
598      public LispObject execute(LispObject first, LispObject second)
599        throws ConditionThrowable
600      {
601          return new StructureObject(checkSymbol(first), second.copyToArray());
602      }
603    };
604
605  // ### copy-structure structure => copy
606  private static final Primitive COPY_STRUCTURE =
607    new Primitive(Symbol.COPY_STRUCTURE, "structure")
608    {
609      @Override
610      public LispObject execute(LispObject arg) throws ConditionThrowable
611      {
612          if (arg instanceof StructureObject)
613            return new StructureObject((StructureObject)arg);
614          return type_error(arg, Symbol.STRUCTURE_OBJECT);
615      }
616    };
617}
Note: See TracBrowser for help on using the repository browser.