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

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

Don't extend Lisp in LispObject, static import Lisp wherever
necessary. Patch by Douglas R. Miles.

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