001: package net.sourceforge.squirrel_sql.client.session.schemainfo;
002:
003: import java.io.Serializable;
004: import java.util.HashMap;
005:
006: /**
007: * This class was introduced to allow the Syntax plugin
008: * to find out if a token is a column, table, etc without
009: * creating new String objects.
010: * Since syntax highlightning needs a lot of those checks
011: * the usage of this class leads to better performance and
012: * memory finger print.
013: */
014: public class CaseInsensitiveString implements
015: Comparable<CaseInsensitiveString>, Serializable {
016: private static final long serialVersionUID = -4625230597578277614L;
017: private char[] value = new char[0];
018: private int offset = 0;
019: private int count = 0;
020: private int hash = 0;
021: private boolean _isMutable;
022:
023: private static HashMap<Character, Character> upChars;
024: private static HashMap<Character, Character> lcChars;
025:
026: static {
027: if (upChars == null) {
028: upChars = new HashMap<Character, Character>();
029: }
030: if (lcChars == null) {
031: lcChars = new HashMap<Character, Character>();
032: }
033: }
034:
035: public CaseInsensitiveString(String s) {
036: value = new char[s.length()];
037: s.getChars(0, s.length(), value, 0);
038: offset = 0;
039: count = s.length();
040: hash = 0;
041: _isMutable = false;
042: }
043:
044: public CaseInsensitiveString() {
045: _isMutable = true;
046: }
047:
048: public void setCharBuffer(char[] buffer, int beginIndex, int len) {
049: if (false == _isMutable) {
050: throw new UnsupportedOperationException(
051: "This CaseInsensitiveString is immutable");
052: }
053:
054: value = buffer;
055: offset = beginIndex;
056: count = len;
057: hash = 0;
058: }
059:
060: public int hashCode() {
061: int h = hash;
062: if (h == 0) {
063: int off = offset;
064: char val[] = value;
065: int len = count;
066:
067: for (int i = 0; i < len; i++) {
068: h = 31 * h + toUpperCase(val[off++]);
069: }
070: hash = h;
071: }
072: return h;
073: }
074:
075: public boolean equals(Object obj) {
076: if (obj instanceof String) {
077: String other = (String) obj;
078:
079: if (other.length() != count) {
080: return false;
081: }
082:
083: for (int i = 0; i < count; ++i) {
084: char c1 = value[offset + i];
085: char c2 = other.charAt(i);
086:
087: // If characters don't match but case may be ignored,
088: // try converting both characters to uppercase.
089: // If the results match, then the comparison scan should
090: // continue.
091: char u1 = toUpperCase(c1);
092: char u2 = toUpperCase(c2);
093: if (u1 == u2) {
094: continue;
095: }
096: // Unfortunately, conversion to uppercase does not work properly
097: // for the Georgian alphabet, which has strange rules about case
098: // conversion. So we need to make one last check before
099: // exiting.
100: if (Character.toLowerCase(u1) == Character
101: .toLowerCase(u2)) {
102: continue;
103: }
104:
105: return false;
106: }
107: return true;
108: } else if (obj instanceof CaseInsensitiveString) {
109: CaseInsensitiveString other = (CaseInsensitiveString) obj;
110:
111: if (other.count != count) {
112: return false;
113: }
114:
115: for (int i = 0; i < count; ++i) {
116: char c1 = value[offset + i];
117: char c2 = other.value[other.offset + i];
118:
119: // If characters don't match but case may be ignored,
120: // try converting both characters to uppercase.
121: // If the results match, then the comparison scan should
122: // continue.
123: char u1 = Character.toUpperCase(c1);
124: char u2 = Character.toUpperCase(c2);
125: if (u1 == u2) {
126: continue;
127: }
128: // Unfortunately, conversion to uppercase does not work properly
129: // for the Georgian alphabet, which has strange rules about case
130: // conversion. So we need to make one last check before
131: // exiting.
132: if (toLowerCase(u1) == toLowerCase(u2)) {
133: continue;
134: }
135:
136: return false;
137: }
138: return true;
139:
140: } else {
141: return false;
142: }
143: }
144:
145: public String toString() {
146: return new String(value, offset, count);
147: }
148:
149: public int compareTo(CaseInsensitiveString anotherString) {
150: int len1 = count;
151: int len2 = anotherString.count;
152: int n = Math.min(len1, len2);
153: char v1[] = value;
154: char v2[] = anotherString.value;
155: int i = offset;
156: int j = anotherString.offset;
157:
158: if (i == j) {
159: int k = i;
160: int lim = n + i;
161: while (k < lim) {
162: char c1 = v1[k];
163: char c2 = v2[k];
164: if (toLowerCase(c1) != toLowerCase(c2)) {
165: return toLowerCase(c1) - toLowerCase(c2);
166: }
167: k++;
168: }
169: } else {
170: while (n-- != 0) {
171: char c1 = v1[i++];
172: char c2 = v2[j++];
173: if (toLowerCase(c1) != toLowerCase(c2)) {
174: return toLowerCase(c1) - toLowerCase(c2);
175: }
176: }
177: }
178: return len1 - len2;
179: }
180:
181: private char toLowerCase(char c) {
182: char result = c;
183: Character key = Character.valueOf(c);
184: if (lcChars.containsKey(key)) {
185: return lcChars.get(key).charValue();
186: }
187: if (Character.isUpperCase(c)) {
188: result = Character.toLowerCase(c);
189: }
190: lcChars.put(key, Character.valueOf(result));
191: return result;
192: }
193:
194: private char toUpperCase(char c) {
195: char result = c;
196: Character key = Character.valueOf(c);
197: if (upChars.containsKey(key)) {
198: return upChars.get(key).charValue();
199: }
200: if (Character.isLowerCase(c)) {
201: result = Character.toUpperCase(c);
202: }
203: upChars.put(key, Character.valueOf(result));
204: return result;
205: }
206:
207: }
|