source: branches/0.17.x/abcl/src/org/armedbear/lisp/ComplexString.java

Last change on this file was 12255, checked in by ehuelsmann, 16 years ago

Rename ConditionThrowable? to ControlTransfer? and remove

try/catch blocks which don't have anything to do with
non-local transfer of control.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 15.9 KB
Line 
1/*
2 * ComplexString.java
3 *
4 * Copyright (C) 2002-2007 Peter Graves
5 * $Id: ComplexString.java 12255 2009-11-06 22:36:32Z ehuelsmann $
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)
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()
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()
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()
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)
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)
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)
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)
237  {
238    fill(LispCharacter.getValue(obj));
239  }
240
241  @Override
242  public void fill(char c)
243  {
244    for (int i = length(); i-- > 0;)
245      setCharAt(i, c);
246  }
247
248  @Override
249  public void shrink(int n)
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()
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()
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()
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()
330  {
331    return new String(chars());
332  }
333
334  @Override
335  public Object javaInstance(Class c)
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)
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)
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)
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)
401  {
402    return LispCharacter.getInstance(charAt(index));
403  }
404
405  // Ignores fill pointer.
406  @Override
407  public LispObject AREF(int index)
408  {
409    return LispCharacter.getInstance(charAt(index));
410  }
411
412  // Ignores fill pointer.
413  @Override
414  public LispObject AREF(LispObject index)
415  {
416    return LispCharacter.getInstance(charAt(Fixnum.getValue(index)));
417  }
418
419  @Override
420  public void aset(int index, LispObject newValue)
421  {
422      setCharAt(index, LispCharacter.getValue(newValue));
423  }
424
425  @Override
426  public void vectorPushExtend(LispObject element)
427
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
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
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)
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        hashCode += charAt(i);
530        hashCode += (hashCode << 10);
531        hashCode ^= (hashCode >> 6);
532      }
533    hashCode += (hashCode << 3);
534    hashCode ^= (hashCode >> 11);
535    hashCode += (hashCode << 15);
536    return (hashCode & 0x7fffffff);
537  }
538
539  // For EQUALP hash tables.
540  @Override
541  public int psxhash()
542  {
543    int hashCode = 0;
544    final int limit = length();
545    for (int i = 0; i < limit; i++)
546      {
547        hashCode += Character.toUpperCase(charAt(i));
548        hashCode += (hashCode << 10);
549        hashCode ^= (hashCode >> 6);
550      }
551    hashCode += (hashCode << 3);
552    hashCode ^= (hashCode >> 11);
553    hashCode += (hashCode << 15);
554    return (hashCode & 0x7fffffff);
555  }
556
557  @Override
558  public AbstractVector adjustArray(int newCapacity,
559                                     LispObject initialElement,
560                                     LispObject initialContents)
561
562  {
563    if (initialContents != null)
564      {
565        // "If INITIAL-CONTENTS is supplied, it is treated as for MAKE-
566        // ARRAY. In this case none of the original contents of array
567        // appears in the resulting array."
568        char[] newChars = new char[newCapacity];
569        if (initialContents.listp())
570          {
571            LispObject list = initialContents;
572            for (int i = 0; i < newCapacity; i++)
573              {
574                newChars[i] = LispCharacter.getValue(list.car());
575                list = list.cdr();
576              }
577          }
578        else if (initialContents.vectorp())
579          {
580            for (int i = 0; i < newCapacity; i++)
581              newChars[i] = LispCharacter.getValue(initialContents.elt(i));
582          }
583        else
584          type_error(initialContents, Symbol.SEQUENCE);
585        chars = newChars;
586      }
587    else
588      {
589        if (chars == null)
590          {
591            // Displaced array. Copy existing characters.
592            chars = new char[newCapacity];
593            final int limit = Math.min(capacity, newCapacity);
594            if (array instanceof AbstractString)
595              {
596                AbstractString string = (AbstractString) array;
597                for (int i = 0; i < limit; i++)
598                  {
599                    chars[i] = string.charAt(displacement + i);
600                  }
601              }
602            else
603              {
604                for (int i = 0; i < limit; i++)
605                  {
606                    LispCharacter character =
607                      (LispCharacter) array.AREF(displacement + i);
608                    chars[i] = character.value;
609                  }
610              }
611          }
612        else if (capacity != newCapacity)
613          {
614            char[] newElements = new char[newCapacity];
615            System.arraycopy(chars, 0, newElements, 0,
616                             Math.min(capacity, newCapacity));
617            chars = newElements;
618          }
619        if (initialElement != null && capacity < newCapacity)
620          {
621            // Initialize new elements.
622            final char c = LispCharacter.getValue(initialElement);
623            for (int i = capacity; i < newCapacity; i++)
624              chars[i] = c;
625          }
626      }
627    capacity = newCapacity;
628    array = null;
629    displacement = 0;
630    isDisplaced = false;
631    return this;
632  }
633
634  @Override
635  public AbstractVector adjustArray(int newCapacity,
636                                     AbstractArray displacedTo,
637                                     int displacement)
638
639  {
640    capacity = newCapacity;
641    array = displacedTo;
642    this.displacement = displacement;
643    chars = null;
644    isDisplaced = true;
645    return this;
646  }
647}
Note: See TracBrowser for help on using the repository browser.