source: branches/0.16.x/abcl/src/org/armedbear/lisp/ComplexString.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: 16.9 KB
Line 
1/*
2 * ComplexString.java
3 *
4 * Copyright (C) 2002-2007 Peter Graves
5 * $Id: ComplexString.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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 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 ComplexString extends AbstractString
37{
38  private int capacity;
39  private int fillPointer = -1; // -1 indicates no fill pointer.
40  private boolean isDisplaced;
41
42  // For non-displaced arrays.
43  private char[] chars;
44
45  // For displaced arrays.
46  private AbstractArray array;
47  private int displacement;
48
49  public ComplexString(int capacity)
50  {
51    this.capacity = capacity;
52    chars = new char[capacity];
53    isDisplaced = false;
54  }
55
56  public ComplexString(int capacity, AbstractArray array, int displacement)
57  {
58    this.capacity = capacity;
59    this.array = array;
60    this.displacement = displacement;
61    isDisplaced = true;
62  }
63
64  @Override
65  public LispObject typeOf()
66  {
67    return list(Symbol.STRING, number(capacity()));
68  }
69
70  @Override
71  public LispObject classOf()
72  {
73    return BuiltInClass.STRING;
74  }
75
76  @Override
77  public boolean hasFillPointer()
78  {
79    return fillPointer >= 0;
80  }
81
82  @Override
83  public int getFillPointer()
84  {
85    return fillPointer;
86  }
87
88  @Override
89  public void setFillPointer(int n)
90  {
91    fillPointer = n;
92  }
93
94  @Override
95  public void setFillPointer(LispObject obj) throws ConditionThrowable
96  {
97    if (obj == T)
98      fillPointer = capacity();
99    else
100      {
101        int n = Fixnum.getValue(obj);
102        if (n > capacity())
103          {
104            StringBuffer sb = new StringBuffer("The new fill pointer (");
105            sb.append(n);
106            sb.append(") exceeds the capacity of the vector (");
107            sb.append(capacity());
108            sb.append(").");
109            error(new LispError(sb.toString()));
110          }
111        else if (n < 0)
112          {
113            StringBuffer sb = new StringBuffer("The new fill pointer (");
114            sb.append(n);
115            sb.append(") is negative.");
116            error(new LispError(sb.toString()));
117          }
118        else
119          fillPointer = n;
120      }
121  }
122
123  @Override
124  public boolean isDisplaced()
125  {
126    return isDisplaced;
127  }
128
129  @Override
130  public LispObject arrayDisplacement() throws ConditionThrowable
131  {
132    LispObject value1, value2;
133    if (array != null)
134      {
135        value1 = array;
136        value2 = Fixnum.getInstance(displacement);
137      }
138    else
139      {
140        value1 = NIL;
141        value2 = Fixnum.ZERO;
142      }
143    return LispThread.currentThread().setValues(value1, value2);
144  }
145
146  @Override
147  public char[] chars() throws ConditionThrowable
148  {
149    if (chars != null)
150      return chars;
151    Debug.assertTrue(array != null);
152    char[] copy = new char[capacity];
153    if (array instanceof AbstractString)
154      System.arraycopy(array.chars(), displacement, copy, 0, capacity);
155    else if (array.getElementType() == Symbol.CHARACTER)
156      {
157        for (int i = 0; i < capacity; i++)
158          {
159            LispObject obj = array.AREF(displacement + i);
160            copy[i] = LispCharacter.getValue(obj);
161          }
162      }
163    else
164      type_error(array, Symbol.STRING);
165    return copy;
166  }
167
168  @Override
169  public char[] getStringChars() throws ConditionThrowable
170  {
171    if (fillPointer < 0)
172      return chars();
173    char[] ret = new char[fillPointer];
174    System.arraycopy(chars(), 0, ret, 0, fillPointer);
175    return ret;
176  }
177
178  @Override
179  public boolean equal(LispObject obj) throws ConditionThrowable
180  {
181    if (this == obj)
182      return true;
183    if (obj instanceof AbstractString)
184      {
185        AbstractString string = (AbstractString) obj;
186        if (string.length() != length())
187          return false;
188        for (int i = length(); i-- > 0;)
189          if (string.charAt(i) != charAt(i))
190            return false;
191        return true;
192      }
193    if (obj instanceof NilVector)
194      return obj.equal(this);
195    return false;
196  }
197
198  @Override
199  public boolean equalp(LispObject obj) throws ConditionThrowable
200  {
201    if (this == obj)
202      return true;
203    if (obj instanceof AbstractString)
204      {
205        AbstractString string = (AbstractString) obj;
206        if (string.length() != length())
207          return false;
208        for (int i = length(); i-- > 0;)
209          {
210            if (string.charAt(i) != charAt(i))
211              {
212                if (LispCharacter.toLowerCase(string.charAt(i)) != LispCharacter.toLowerCase(charAt(i)))
213                  return false;
214              }
215          }
216        return true;
217      }
218    if (obj instanceof AbstractBitVector)
219      return false;
220    if (obj instanceof AbstractArray)
221      return obj.equalp(this);
222    return false;
223  }
224
225  @Override
226  public LispObject subseq(int start, int end) throws ConditionThrowable
227  {
228    SimpleString s = new SimpleString(end - start);
229    int i = start, j = 0;
230    while (i < end)
231      s.setCharAt(j++, charAt(i++));
232    return s;
233  }
234
235  @Override
236  public void fill(LispObject obj) throws ConditionThrowable
237  {
238    fill(LispCharacter.getValue(obj));
239  }
240
241  @Override
242  public void fill(char c) throws ConditionThrowable
243  {
244    for (int i = length(); i-- > 0;)
245      setCharAt(i, c);
246  }
247
248  @Override
249  public void shrink(int n) throws ConditionThrowable
250  {
251    if (chars != null)
252      {
253        if (n < capacity)
254          {
255            char[] newArray = new char[n];
256            System.arraycopy(chars, 0, newArray, 0, n);
257            chars = newArray;
258            capacity = n;
259            fillPointer = -1;
260            return;
261          }
262        if (n == capacity)
263          return;
264      }
265    Debug.assertTrue(chars == null);
266    // Displaced array. Copy existing characters.
267    chars = new char[n];
268    if (array instanceof AbstractString)
269      {
270        AbstractString string = (AbstractString) array;
271        for (int i = 0; i < n; i++)
272          {
273            chars[i] = string.charAt(displacement + i);
274          }
275      }
276    else
277      {
278        for (int i = 0; i < n; i++)
279          {
280            LispCharacter character =
281              (LispCharacter) array.AREF(displacement + i);
282            chars[i] = character.value;
283          }
284      }
285    capacity = n;
286    array = null;
287    displacement = 0;
288    isDisplaced = false;
289    fillPointer = -1;
290  }
291
292  @Override
293  public LispObject reverse() throws ConditionThrowable
294  {
295    int length = length();
296    SimpleString result = new SimpleString(length);
297    int i, j;
298    for (i = 0, j = length - 1; i < length; i++, j--)
299      result.setCharAt(i, charAt(j));
300    return result;
301  }
302
303  @Override
304  public LispObject nreverse() throws ConditionThrowable
305  {
306    int i = 0;
307    int j = length() - 1;
308    while (i < j)
309      {
310        char temp = charAt(i);
311        setCharAt(i, charAt(j));
312        setCharAt(j, temp);
313        ++i;
314        --j;
315      }
316    return this;
317  }
318
319  @Override
320  public String getStringValue() throws ConditionThrowable
321  {
322    if (fillPointer >= 0)
323      return new String(chars(), 0, fillPointer);
324    else
325      return new String(chars());
326  }
327
328  @Override
329  public Object javaInstance() throws ConditionThrowable
330  {
331    return new String(chars());
332  }
333
334  @Override
335  public Object javaInstance(Class c) throws ConditionThrowable
336  {
337    return javaInstance();
338  }
339
340  @Override
341  public final int capacity()
342  {
343    return capacity;
344  }
345
346  @Override
347  public final int length()
348  {
349    return fillPointer >= 0 ? fillPointer : capacity;
350  }
351
352  @Override
353  public char charAt(int index) throws ConditionThrowable
354  {
355    if (chars != null)
356      {
357        try
358          {
359            return chars[index];
360          }
361        catch (ArrayIndexOutOfBoundsException e)
362          {
363            badIndex(index, capacity);
364            return 0; // Not reached.
365          }
366      }
367    else
368      return LispCharacter.getValue(array.AREF(index + displacement));
369  }
370
371  @Override
372  public void setCharAt(int index, char c) throws ConditionThrowable
373  {
374    if (chars != null)
375      {
376        try
377          {
378            chars[index] = c;
379          }
380        catch (ArrayIndexOutOfBoundsException e)
381          {
382            badIndex(index, capacity);
383          }
384      }
385    else
386      array.aset(index + displacement, LispCharacter.getInstance(c));
387  }
388
389  @Override
390  public LispObject elt(int index) throws ConditionThrowable
391  {
392    final int limit = length();
393    if (index < 0 || index >= limit)
394      badIndex(index, limit);
395    return LispCharacter.getInstance(charAt(index));
396  }
397
398  // Ignores fill pointer.
399  @Override
400  public LispObject CHAR(int index) throws ConditionThrowable
401  {
402    return LispCharacter.getInstance(charAt(index));
403  }
404
405  // Ignores fill pointer.
406  @Override
407  public LispObject AREF(int index) throws ConditionThrowable
408  {
409    return LispCharacter.getInstance(charAt(index));
410  }
411
412  // Ignores fill pointer.
413  @Override
414  public LispObject AREF(LispObject index) throws ConditionThrowable
415  {
416    return LispCharacter.getInstance(charAt(Fixnum.getValue(index)));
417  }
418
419  @Override
420  public void aset(int index, LispObject newValue) throws ConditionThrowable
421  {
422      setCharAt(index, LispCharacter.getValue(newValue));
423  }
424
425  @Override
426  public void vectorPushExtend(LispObject element)
427    throws ConditionThrowable
428  {
429    if (fillPointer < 0)
430      noFillPointer();
431    if (fillPointer >= capacity)
432      {
433        // Need to extend vector.
434        ensureCapacity(capacity * 2 + 1);
435      }
436    if (chars != null)
437      {
438        chars[fillPointer] = LispCharacter.getValue(element);
439      }
440    else
441      array.aset(fillPointer + displacement, element);
442    ++fillPointer;
443  }
444
445  @Override
446  public LispObject VECTOR_PUSH_EXTEND(LispObject element)
447    throws ConditionThrowable
448  {
449    vectorPushExtend(element);
450    return Fixnum.getInstance(fillPointer - 1);
451  }
452
453  @Override
454  public LispObject VECTOR_PUSH_EXTEND(LispObject element, LispObject extension)
455    throws ConditionThrowable
456  {
457    int ext = Fixnum.getValue(extension);
458    if (fillPointer < 0)
459      noFillPointer();
460    if (fillPointer >= capacity)
461      {
462        // Need to extend vector.
463        ext = Math.max(ext, capacity + 1);
464        ensureCapacity(capacity + ext);
465      }
466    if (chars != null)
467      {
468        chars[fillPointer] = LispCharacter.getValue(element);
469      }
470    else
471      array.aset(fillPointer + displacement, element);
472    return Fixnum.getInstance(fillPointer++);
473  }
474
475  public final void ensureCapacity(int minCapacity) throws ConditionThrowable
476  {
477    if (chars != null)
478      {
479        if (capacity < minCapacity)
480          {
481            char[] newArray = new char[minCapacity];
482            System.arraycopy(chars, 0, newArray, 0, capacity);
483            chars = newArray;
484            capacity = minCapacity;
485          }
486      }
487    else
488      {
489        Debug.assertTrue(array != null);
490        if (capacity < minCapacity ||
491            array.getTotalSize() - displacement < minCapacity)
492          {
493            // Copy array.
494            chars = new char[minCapacity];
495            final int limit =
496              Math.min(capacity, array.getTotalSize() - displacement);
497            if (array instanceof AbstractString)
498              {
499                AbstractString string = (AbstractString) array;
500                for (int i = 0; i < limit; i++)
501                  {
502                    chars[i] = string.charAt(displacement + i);
503                  }
504              }
505            else
506              {
507                for (int i = 0; i < limit; i++)
508                  {
509                    LispCharacter character =
510                      (LispCharacter) array.AREF(displacement + i);
511                    chars[i] = character.value;
512                  }
513              }
514            capacity = minCapacity;
515            array = null;
516            displacement = 0;
517            isDisplaced = false;
518          }
519      }
520  }
521
522  @Override
523  public int sxhash()
524  {
525    int hashCode = 0;
526    final int limit = length();
527    for (int i = 0; i < limit; i++)
528      {
529        try
530          {
531            hashCode += charAt(i);
532          }
533        catch (ConditionThrowable t)
534          {
535            Debug.trace(t);
536          }
537        hashCode += (hashCode << 10);
538        hashCode ^= (hashCode >> 6);
539      }
540    hashCode += (hashCode << 3);
541    hashCode ^= (hashCode >> 11);
542    hashCode += (hashCode << 15);
543    return (hashCode & 0x7fffffff);
544  }
545
546  // For EQUALP hash tables.
547  @Override
548  public int psxhash()
549  {
550    int hashCode = 0;
551    final int limit = length();
552    for (int i = 0; i < limit; i++)
553      {
554        try
555          {
556            hashCode += Character.toUpperCase(charAt(i));
557          }
558        catch (ConditionThrowable t)
559          {
560            Debug.trace(t);
561          }
562        hashCode += (hashCode << 10);
563        hashCode ^= (hashCode >> 6);
564      }
565    hashCode += (hashCode << 3);
566    hashCode ^= (hashCode >> 11);
567    hashCode += (hashCode << 15);
568    return (hashCode & 0x7fffffff);
569  }
570
571  @Override
572  public AbstractVector adjustArray(int newCapacity,
573                                     LispObject initialElement,
574                                     LispObject initialContents)
575    throws ConditionThrowable
576  {
577    if (initialContents != null)
578      {
579        // "If INITIAL-CONTENTS is supplied, it is treated as for MAKE-
580        // ARRAY. In this case none of the original contents of array
581        // appears in the resulting array."
582        char[] newChars = new char[newCapacity];
583        if (initialContents.listp())
584          {
585            LispObject list = initialContents;
586            for (int i = 0; i < newCapacity; i++)
587              {
588                newChars[i] = LispCharacter.getValue(list.car());
589                list = list.cdr();
590              }
591          }
592        else if (initialContents.vectorp())
593          {
594            for (int i = 0; i < newCapacity; i++)
595              newChars[i] = LispCharacter.getValue(initialContents.elt(i));
596          }
597        else
598          type_error(initialContents, Symbol.SEQUENCE);
599        chars = newChars;
600      }
601    else
602      {
603        if (chars == null)
604          {
605            // Displaced array. Copy existing characters.
606            chars = new char[newCapacity];
607            final int limit = Math.min(capacity, newCapacity);
608            if (array instanceof AbstractString)
609              {
610                AbstractString string = (AbstractString) array;
611                for (int i = 0; i < limit; i++)
612                  {
613                    chars[i] = string.charAt(displacement + i);
614                  }
615              }
616            else
617              {
618                for (int i = 0; i < limit; i++)
619                  {
620                    LispCharacter character =
621                      (LispCharacter) array.AREF(displacement + i);
622                    chars[i] = character.value;
623                  }
624              }
625          }
626        else if (capacity != newCapacity)
627          {
628            char[] newElements = new char[newCapacity];
629            System.arraycopy(chars, 0, newElements, 0,
630                             Math.min(capacity, newCapacity));
631            chars = newElements;
632          }
633        if (initialElement != null && capacity < newCapacity)
634          {
635            // Initialize new elements.
636            final char c = LispCharacter.getValue(initialElement);
637            for (int i = capacity; i < newCapacity; i++)
638              chars[i] = c;
639          }
640      }
641    capacity = newCapacity;
642    array = null;
643    displacement = 0;
644    isDisplaced = false;
645    return this;
646  }
647
648  @Override
649  public AbstractVector adjustArray(int newCapacity,
650                                     AbstractArray displacedTo,
651                                     int displacement)
652    throws ConditionThrowable
653  {
654    capacity = newCapacity;
655    array = displacedTo;
656    this.displacement = displacement;
657    chars = null;
658    isDisplaced = true;
659    return this;
660  }
661}
Note: See TracBrowser for help on using the repository browser.