source: trunk/abcl/src/org/armedbear/lisp/ComplexString.java @ 12557

Last change on this file since 12557 was 12288, checked in by vvoutilainen, 15 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.