source: branches/1.1.x/src/org/armedbear/lisp/SimpleString.java

Last change on this file was 13720, checked in by ehuelsmann, 13 years ago

String hash randomization.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 12.8 KB
Line 
1/*
2 * SimpleString.java
3 *
4 * Copyright (C) 2004-2005 Peter Graves
5 * $Id: SimpleString.java 13720 2012-01-05 21:56:44Z 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., 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
36import static org.armedbear.lisp.Lisp.*;
37
38public final class SimpleString extends AbstractString
39{
40    private int capacity;
41    private char[] chars;
42
43    public SimpleString(LispCharacter c)
44    {
45        chars = new char[1];
46        chars[0] = c.value;
47        capacity = 1;
48    }
49
50    public SimpleString(char c)
51    {
52        chars = new char[1];
53        chars[0] = c;
54        capacity = 1;
55    }
56
57    public SimpleString(int capacity)
58    {
59        this.capacity = capacity;
60        chars = new char[capacity];
61    }
62
63    public SimpleString(String s)
64    {
65        capacity = s.length();
66        chars = s.toCharArray();
67    }
68
69    public SimpleString(StringBuffer sb)
70    {
71        chars = new char[capacity = sb.length()];
72        sb.getChars(0, capacity, chars, 0);
73    }
74
75    public SimpleString(StringBuilder sb)
76    {
77        chars = sb.toString().toCharArray();
78        capacity = chars.length;
79    }
80
81    public SimpleString(char[] chars)
82    {
83        this.chars = chars;
84        capacity = chars.length;
85    }
86
87    @Override
88    public char[] chars()
89    {
90        return chars;
91    }
92
93    @Override
94    public char[] getStringChars()
95    {
96        return chars;
97    }
98
99    @Override
100    public LispObject typeOf()
101    {
102        return list(Symbol.SIMPLE_BASE_STRING, Fixnum.getInstance(capacity));
103    }
104
105    @Override
106    public LispObject classOf()
107    {
108        return BuiltInClass.SIMPLE_BASE_STRING;
109    }
110
111    @Override
112    public LispObject getDescription()
113    {
114        StringBuilder sb = new StringBuilder("A simple-string (");
115        sb.append(capacity);
116        sb.append(") \"");
117        sb.append(chars);
118        sb.append('"');
119        return new SimpleString(sb);
120    }
121
122    @Override
123    public LispObject typep(LispObject type)
124    {
125        if (type == Symbol.SIMPLE_STRING)
126            return T;
127        if (type == Symbol.SIMPLE_ARRAY)
128            return T;
129        if (type == Symbol.SIMPLE_BASE_STRING)
130            return T;
131        if (type == BuiltInClass.SIMPLE_STRING)
132            return T;
133        if (type == BuiltInClass.SIMPLE_ARRAY)
134            return T;
135        if (type == BuiltInClass.SIMPLE_BASE_STRING)
136            return T;
137        return super.typep(type);
138    }
139
140    @Override
141    public LispObject SIMPLE_STRING_P()
142    {
143        return T;
144    }
145
146    @Override
147    public boolean hasFillPointer()
148    {
149        return false;
150    }
151
152    @Override
153    public boolean isAdjustable()
154    {
155        return false;
156    }
157
158    @Override
159    public boolean equal(LispObject obj)
160    {
161        if (this == obj)
162            return true;
163        if (obj instanceof SimpleString) {
164            SimpleString string = (SimpleString) obj;
165            if (string.capacity != capacity)
166                return false;
167            for (int i = capacity; i-- > 0;)
168                if (string.chars[i] != chars[i])
169                    return false;
170            return true;
171        }
172        if (obj instanceof AbstractString) {
173            AbstractString string = (AbstractString) obj;
174            if (string.length() != capacity)
175                return false;
176            for (int i = length(); i-- > 0;)
177                if (string.charAt(i) != chars[i])
178                    return false;
179            return true;
180        }
181        if (obj instanceof NilVector)
182            return obj.equal(this);
183        return false;
184    }
185
186    @Override
187    public boolean equalp(LispObject obj)
188    {
189        if (this == obj)
190            return true;
191        if (obj instanceof SimpleString) {
192            SimpleString string = (SimpleString) obj;
193            if (string.capacity != capacity)
194                return false;
195            for (int i = capacity; i-- > 0;) {
196                if (string.chars[i] != chars[i]) {
197                    if (LispCharacter.toLowerCase(string.chars[i]) != LispCharacter.toLowerCase(chars[i]))
198                        return false;
199                }
200            }
201            return true;
202        }
203        if (obj instanceof AbstractString) {
204            AbstractString string = (AbstractString) obj;
205            if (string.length() != capacity)
206                return false;
207            for (int i = length(); i-- > 0;) {
208                if (string.charAt(i) != chars[i]) {
209                    if (LispCharacter.toLowerCase(string.charAt(i)) != LispCharacter.toLowerCase(chars[i]))
210                        return false;
211                }
212            }
213            return true;
214        }
215        if (obj instanceof AbstractBitVector)
216            return false;
217        if (obj instanceof AbstractArray)
218            return obj.equalp(this);
219        return false;
220    }
221
222    public final SimpleString substring(int start)
223    {
224        return substring(start, capacity);
225    }
226
227    public final SimpleString substring(int start, int end)
228
229    {
230        SimpleString s = new SimpleString(end - start);
231        int i = start, j = 0;
232        try {
233            while (i < end)
234                s.chars[j++] = chars[i++];
235            return s;
236        }
237        catch (ArrayIndexOutOfBoundsException e) {
238            error(new TypeError("Array index out of bounds: " + i));
239            // Not reached.
240            return null;
241        }
242    }
243
244    @Override
245    public final LispObject subseq(int start, int end)
246    {
247        return substring(start, end);
248    }
249
250    @Override
251    public void fill(LispObject obj)
252    {
253        fill(LispCharacter.getValue(obj));
254    }
255
256    @Override
257    public void fill(char c)
258    {
259        for (int i = capacity; i-- > 0;)
260            chars[i] = c;
261    }
262
263    @Override
264    public void shrink(int n)
265    {
266        if (n < capacity) {
267            char[] newArray = new char[n];
268            System.arraycopy(chars, 0, newArray, 0, n);
269            chars = newArray;
270            capacity = n;
271            return;
272        }
273        if (n == capacity)
274            return;
275        error(new LispError());
276    }
277
278    @Override
279    public LispObject reverse()
280    {
281        SimpleString result = new SimpleString(capacity);
282        int i, j;
283        for (i = 0, j = capacity - 1; i < capacity; i++, j--)
284            result.chars[i] = chars[j];
285        return result;
286    }
287
288    @Override
289    public LispObject nreverse()
290    {
291        int i = 0;
292        int j = capacity - 1;
293        while (i < j) {
294            char temp = chars[i];
295            chars[i] = chars[j];
296            chars[j] = temp;
297            ++i;
298            --j;
299        }
300        return this;
301    }
302
303    @Override
304    public String getStringValue()
305    {
306        return String.valueOf(chars);
307    }
308
309    @Override
310    public Object javaInstance()
311    {
312        return String.valueOf(chars);
313    }
314
315    @Override
316    public Object javaInstance(Class c)
317    {
318        return javaInstance();
319    }
320
321    @Override
322    public final int capacity()
323    {
324        return capacity;
325    }
326
327    @Override
328    public final int length()
329    {
330        return capacity;
331    }
332
333    @Override
334    public char charAt(int index)
335    {
336        try {
337            return chars[index];
338        }
339        catch (ArrayIndexOutOfBoundsException e) {
340            badIndex(index, capacity);
341            return 0; // Not reached.
342        }
343    }
344
345    @Override
346    public void setCharAt(int index, char c)
347    {
348        try {
349            chars[index] = c;
350        }
351        catch (ArrayIndexOutOfBoundsException e) {
352            badIndex(index, capacity);
353        }
354    }
355
356    @Override
357    public LispObject elt(int index)
358    {
359        try {
360            return LispCharacter.getInstance(chars[index]);
361        }
362        catch (ArrayIndexOutOfBoundsException e) {
363            badIndex(index, capacity);
364            return NIL; // Not reached.
365        }
366    }
367
368    @Override
369    public LispObject CHAR(int index)
370    {
371        try {
372            return LispCharacter.getInstance(chars[index]);
373        }
374        catch (ArrayIndexOutOfBoundsException e) {
375            badIndex(index, capacity);
376            return NIL; // Not reached.
377        }
378    }
379
380    @Override
381    public LispObject SCHAR(int index)
382    {
383        try {
384            return LispCharacter.getInstance(chars[index]);
385        }
386        catch (ArrayIndexOutOfBoundsException e) {
387            badIndex(index, capacity);
388            return NIL; // Not reached.
389        }
390    }
391
392    @Override
393    public LispObject AREF(int index)
394    {
395        try {
396            return LispCharacter.getInstance(chars[index]);
397        }
398        catch (ArrayIndexOutOfBoundsException e) {
399            badIndex(index, capacity);
400            return NIL; // Not reached.
401        }
402    }
403
404
405    @Override
406    public void aset(int index, LispObject obj)
407    {
408        try {
409            chars[index] = LispCharacter.getValue(obj);
410        }
411        catch (ArrayIndexOutOfBoundsException e) {
412            badIndex(index, capacity);
413        }
414    }
415
416    @Override
417    public int sxhash()
418    {
419        int hashCode = randomStringHashBase;
420        for (int i = 0; i < capacity; i++) {
421            hashCode += chars[i];
422            hashCode += (hashCode << 10);
423            hashCode ^= (hashCode >> 6);
424        }
425        hashCode += (hashCode << 3);
426        hashCode ^= (hashCode >> 11);
427        hashCode += (hashCode << 15);
428        return (hashCode & 0x7fffffff);
429        }
430
431    // For EQUALP hash tables.
432    @Override
433    public int psxhash()
434    {
435        int hashCode = randomStringHashBase;
436        for (int i = 0; i < capacity; i++) {
437            hashCode += Character.toUpperCase(chars[i]);
438            hashCode += (hashCode << 10);
439            hashCode ^= (hashCode >> 6);
440        }
441        hashCode += (hashCode << 3);
442        hashCode ^= (hashCode >> 11);
443        hashCode += (hashCode << 15);
444        return (hashCode & 0x7fffffff);
445    }
446
447    @Override
448    public AbstractVector adjustArray(int newCapacity,
449                                       LispObject initialElement,
450                                       LispObject initialContents)
451
452    {
453        if (initialContents != null) {
454            char[] newChars = new char[newCapacity];
455            if (initialContents.listp()) {
456                LispObject list = initialContents;
457                for (int i = 0; i < newCapacity; i++) {
458                    newChars[i] = LispCharacter.getValue(list.car());
459                    list = list.cdr();
460                }
461            } else if (initialContents.vectorp()) {
462                for (int i = 0; i < newCapacity; i++)
463                    newChars[i] = LispCharacter.getValue(initialContents.elt(i));
464            } else
465                type_error(initialContents, Symbol.SEQUENCE);
466            return new SimpleString(newChars);
467        }
468        if (capacity != newCapacity) {
469            char[] newChars = new char[newCapacity];
470            System.arraycopy(chars, 0, newChars, 0, Math.min(newCapacity, capacity));
471            if (initialElement != null && capacity < newCapacity) {
472                final char c = LispCharacter.getValue(initialElement);
473                for (int i = capacity; i < newCapacity; i++)
474                    newChars[i] = c;
475            }
476            return new SimpleString(newChars);
477        }
478        // No change.
479        return this;
480    }
481
482    @Override
483    public AbstractVector adjustArray(int newCapacity,
484                                       AbstractArray displacedTo,
485                                       int displacement)
486
487    {
488        return new ComplexString(newCapacity, displacedTo, displacement);
489    }
490
491    @Override
492    public String toString()  {
493        return String.valueOf(chars);
494    }
495}
Note: See TracBrowser for help on using the repository browser.