1 9 package javolution.text; 10 11 import j2me.io.Serializable; 12 import j2me.lang.CharSequence; 13 import j2me.lang.Comparable; 14 import j2mex.realtime.MemoryArea; 15 16 import javolution.Javolution; 17 import javolution.context.Realtime; 18 import javolution.context.RealtimeObject; 19 import javolution.lang.Immutable; 20 import javolution.util.FastComparator; 21 import javolution.util.FastMap; 22 import javolution.xml.XMLFormat; 23 import javolution.xml.stream.XMLStreamException; 24 25 71 public abstract class Text extends RealtimeObject implements CharSequence , 72 Comparable , Serializable, Immutable { 73 74 77 private static final FastMap INTERN_INSTANCES = new FastMap() 78 .setKeyComparator(FastComparator.LEXICAL); 79 80 private static String _tmpString; 81 82 private static final Runnable INTERN_STRING = new Runnable () { 83 public void run() { 84 StringWrapper txt = new StringWrapper(); 85 txt._count = _tmpString.length(); 86 txt._string = _tmpString; 87 INTERN_INSTANCES.put(_tmpString, txt); 88 } 89 }; 90 91 94 public static final Text EMPTY = Text.intern(""); 95 96 99 public static final Text NULL = Text.intern("null"); 100 101 106 protected static final XMLFormatXML = new XMLFormat(Javolution 107 .j2meGetClass("javolution.text.Text")) { 108 109 public Object newInstance(Class cls, 110 javolution.xml.XMLFormat.InputElement xml) 111 throws XMLStreamException { 112 CharSequence csq = xml.getAttribute("value"); 113 return csq != null ? Text.valueOf(csq) : Text.EMPTY; 114 } 115 116 public void read(InputElement xml, Object obj) 117 throws XMLStreamException { 118 } 120 121 public void write(Object obj, OutputElement xml) 122 throws XMLStreamException { 123 xml.setAttribute("value", (Text) obj); 124 } 125 }; 126 127 130 int _count; 131 132 135 int _hashCode; 136 137 140 private Text() { 141 } 142 143 152 public static Text valueOf(Object obj) { 153 if (obj instanceof Realtime) { 154 return ((Realtime) obj).toText(); 155 } else if (obj instanceof String ) { 156 return StringWrapper.newInstance((String ) obj); 157 } else if (obj instanceof CharSequence ) { 158 final CharSequence csq = (CharSequence ) obj; 159 return Text.valueOf(csq, 0, csq.length()); 160 } else if (obj != null) { 161 return StringWrapper.newInstance(obj.toString()); 162 } else { 163 return NULL; 164 } 165 } 166 167 177 public static Text valueOf(CharSequence csq, int start, int end) { 178 if ((start < 0) || (end < 0) || (start > end) || (end > csq.length())) 179 throw new IndexOutOfBoundsException (); 180 if (csq instanceof TextBuilder) 181 return valueOf((TextBuilder) csq, start, end); 182 final int length = end - start; 183 if (length <= Primitive.BLOCK_SIZE) { 184 Primitive text = Primitive.newInstance(length); 185 for (int i = 0; i < length;) { 186 text._data[i] = csq.charAt(start + i++); 187 } 188 return text; 189 } else { 190 final int middle = start + (length >> 1); 191 Composite text = Composite.newInstance(Text.valueOf(csq, start, 192 middle), Text.valueOf(csq, middle, end)); 193 return text; 194 } 195 } 196 197 static Text valueOf(TextBuilder tb, int start, int end) { 199 final int length = end - start; 200 if (length <= Primitive.BLOCK_SIZE) { 201 Primitive text = Primitive.newInstance(length); 202 if ((start & TextBuilder.M0) + length <= TextBuilder.C0) { 203 char[] chars = tb.charsAt(start); 205 System.arraycopy(chars, start & TextBuilder.M0, text._data, 0, 206 length); 207 } else { for (int i = 0; i < length;) { 209 text._data[i] = tb.charAt(start + i++); 210 } 211 } 212 return text; 213 } else { int middle = (start + (length >> 1)); 215 if ((middle & ~TextBuilder.M0) > start) { 216 middle &= ~TextBuilder.M0; 217 } 218 Composite text = Composite.newInstance(Text.valueOf(tb, start, 219 middle), Text.valueOf(tb, middle, end)); 220 return text; 221 } 222 } 223 224 231 public static Text valueOf(char[] chars) { 232 return valueOf(chars, 0, chars.length); 233 } 234 235 246 public static Text valueOf(char[] chars, int offset, int length) { 247 if ((offset < 0) || (length < 0) || ((offset + length) > chars.length)) 248 throw new IndexOutOfBoundsException (); 249 if (length <= Primitive.BLOCK_SIZE) { 250 Primitive text = Primitive.newInstance(length); 251 for (int i = 0; i < length;) { 252 text._data[i] = chars[offset + i++]; 253 } 254 return text; 255 } else { 256 final int middle = offset + (length >> 1); 257 Composite text = Composite.newInstance(Text.valueOf(chars, offset, 258 middle - offset), Text.valueOf(chars, middle, offset 259 + length - middle)); 260 return text; 261 } 262 } 263 264 272 public static Text valueOf(boolean b) { 273 return b ? TRUE : FALSE; 274 } 275 276 private static final Text TRUE = Text.intern("true"); 277 278 private static final Text FALSE = Text.intern("false"); 279 280 287 public static Text valueOf(char c) { 288 if ((c < 128) && (ASCII[c] != null)) 289 return ASCII[c]; 290 Primitive text = Primitive.newInstance(1); 291 text._data[0] = c; 292 Text textIntern = Text.intern(text); 293 if (c < 128) { 294 ASCII[c] = textIntern; 295 } 296 return textIntern; 297 } 298 299 private static final Text[] ASCII = new Text[128]; 300 301 308 public static Text valueOf(int i) { 309 TextBuilder tmp = TextBuilder.newInstance(); 310 tmp.append(i); 311 Text txt = tmp.toText(); 312 TextBuilder.recycle(tmp); 313 return txt; 314 } 315 316 324 public static Text valueOf(int i, int radix) { 325 TextBuilder tmp = TextBuilder.newInstance(); 326 tmp.append(i, radix); 327 Text txt = tmp.toText(); 328 TextBuilder.recycle(tmp); 329 return txt; 330 } 331 332 339 public static Text valueOf(long l) { 340 TextBuilder tmp = TextBuilder.newInstance(); 341 tmp.append(l); 342 Text txt = tmp.toText(); 343 TextBuilder.recycle(tmp); 344 return txt; 345 } 346 347 355 public static Text valueOf(long l, int radix) { 356 TextBuilder tmp = TextBuilder.newInstance(); 357 tmp.append(l, radix); 358 Text txt = tmp.toText(); 359 TextBuilder.recycle(tmp); 360 return txt; 361 } 362 363 378 379 394 395 400 public final int length() { 401 return _count; 402 } 403 404 411 public final Text plus(Object obj) { 412 return this.concat(Text.valueOf(obj)); 413 } 414 415 424 public final Text concat(Text that) { 425 if (this._count == 0) { 426 return that; 427 } else if (that._count == 0) { 428 return this; 429 } else { 430 return this.concat(that, (Factory.Pool) Composite.FACTORY 431 .currentPool()); 432 } 433 } 434 435 private final Text concat(Text that, Factory.Pool pool) { 436 if (((this._count << 1) < that._count) && (that instanceof Composite)) { 439 Composite thatComposite = (Composite) that; 441 if (thatComposite._head._count > thatComposite._tail._count) { 442 thatComposite = thatComposite.rightRotation(pool); 444 } 445 return Composite.newInstance( 446 this.concat(thatComposite._head, pool), 447 thatComposite._tail, pool); 448 } else if (((that._count << 1) < this._count) 449 && (this instanceof Composite)) { 450 Composite thisComposite = (Composite) this; 452 if (thisComposite._tail._count > thisComposite._head._count) { 453 thisComposite = thisComposite.leftRotation(pool); 455 } 456 return Composite.newInstance(thisComposite._head, 457 thisComposite._tail.concat(that, pool), pool); 458 } else { return Composite.newInstance(this, that, pool); 460 } 461 } 462 463 471 public final Text subtext(int start) { 472 return subtext(start, length()); 473 } 474 475 485 public final Text insert(int index, Text txt) { 486 return ((index << 1) < _count) ? this.subtext(0, index).concat(txt) 488 .concat(this.subtext(index)) : this.subtext(0, index).concat( 489 txt.concat(this.subtext(index))); 490 } 491 492 501 public final Text delete(int start, int end) { 502 return this.subtext(0, start).concat(this.subtext(end)); 503 } 504 505 513 public final Text replace(CharSequence target, CharSequence replacement) { 514 int i = indexOf(target); 515 return (i < 0) ? this : this.subtext(0, i).concat(Text.valueOf(replacement)).concat( 517 this.subtext(i + target.length()).replace(target, 518 replacement)); 519 } 520 521 529 public final Text replace(CharSet charSet, CharSequence replacement) { 530 int i = indexOfAny(charSet); 531 return (i < 0) ? this : this.subtext(0, i).concat(Text.valueOf(replacement)).concat( 533 this.subtext(i + 1).replace(charSet, replacement)); 534 } 535 536 545 public final CharSequence subSequence(int start, int end) { 546 return this.subtext(start, end); 547 } 548 549 557 public final int indexOf(CharSequence csq) { 558 return indexOf(csq, 0); 559 } 560 561 572 public final int indexOf(CharSequence csq, int fromIndex) { 573 574 final int csqLength = csq.length(); 576 final int min = Math.max(0, fromIndex); 577 final int max = _count - csqLength; 578 if (csqLength == 0) { 579 return (min > max) ? -1 : min; 580 } 581 582 final char c = csq.charAt(0); 584 for (int i = indexOf(c, min); (i >= 0) && (i <= max); i = indexOf(c, 585 ++i)) { 586 boolean match = true; 587 for (int j = 1; j < csqLength; j++) { 588 if (this.charAt(i + j) != csq.charAt(j)) { 589 match = false; 590 break; 591 } 592 } 593 if (match) { 594 return i; 595 } 596 } 597 return -1; 598 } 599 600 608 public final int lastIndexOf(CharSequence csq) { 609 return lastIndexOf(csq, _count); 610 } 611 612 622 public final int lastIndexOf(CharSequence csq, int fromIndex) { 623 624 final int csqLength = csq.length(); 626 final int min = 0; 627 final int max = Math.min(fromIndex, _count - csqLength); 628 if (csqLength == 0) { 629 return (min > max) ? -1 : max; 630 } 631 632 final char c = csq.charAt(0); 634 for (int i = lastIndexOf(c, max); (i >= 0); i = lastIndexOf(c, --i)) { 635 boolean match = true; 636 for (int j = 1; j < csqLength; j++) { 637 if (this.charAt(i + j) != csq.charAt(j)) { 638 match = false; 639 break; 640 } 641 } 642 if (match) { 643 return i; 644 } 645 } 646 return -1; 647 648 } 649 650 658 public final boolean startsWith(CharSequence prefix) { 659 return startsWith(prefix, 0); 660 } 661 662 670 public final boolean endsWith(CharSequence suffix) { 671 return startsWith(suffix, length() - suffix.length()); 672 } 673 674 682 public final boolean startsWith(CharSequence prefix, int index) { 683 final int prefixLength = prefix.length(); 684 if ((index >= 0) && (index <= (this.length() - prefixLength))) { 685 for (int i = 0, j = index; i < prefixLength;) { 686 if (prefix.charAt(i++) != this.charAt(j++)) { 687 return false; 688 } 689 } 690 return true; 691 } else { 692 return false; 693 } 694 } 695 696 704 public final Text trim() { 705 int first = 0; int last = length() - 1; while ((first <= last) && (charAt(first) <= ' ')) { 708 first++; 709 } 710 while ((last >= first) && (charAt(last) <= ' ')) { 711 last--; 712 } 713 return subtext(first, last + 1); 714 } 715 716 722 public static Text intern(final CharSequence csq) { 723 Text text = (Text) INTERN_INSTANCES.get(csq); if (text != null) 725 return text; 726 return Text.intern(csq.toString()); 727 } 728 729 735 public static Text intern(final String str) { 736 Text text = (Text) INTERN_INSTANCES.get(str); if (text != null) 738 return text; 739 synchronized (INTERN_INSTANCES) { 740 text = (Text) INTERN_INSTANCES.get(str); 742 if (text != null) 743 return text; 744 _tmpString = str; 745 MemoryArea.getMemoryArea(INTERN_INSTANCES).executeInArea( 746 INTERN_STRING); 747 } 748 return (Text) INTERN_INSTANCES.get(str); 749 } 750 751 759 public final boolean contentEquals(CharSequence csq) { 760 if (csq.length() != _count) 761 return false; 762 for (int i = 0; i < _count;) { 763 if (this.charAt(i) != csq.charAt(i++)) 764 return false; 765 } 766 return true; 767 } 768 769 777 public final boolean contentEqualsIgnoreCase(CharSequence csq) { 778 if (this._count != csq.length()) 779 return false; 780 for (int i = 0; i < _count;) { 781 char u1 = this.charAt(i); 782 char u2 = csq.charAt(i++); 783 if (u1 != u2) { 784 u1 = Character.toUpperCase(u1); 785 u2 = Character.toUpperCase(u2); 786 if ((u1 != u2) 787 && (Character.toLowerCase(u1) != Character 788 .toLowerCase(u2))) 789 return false; 790 791 } 792 } 793 return true; 794 } 795 796 807 public final boolean equals(Object obj) { 808 if (this == obj) 809 return true; 810 if (!(obj instanceof Text)) 811 return false; 812 final Text that = (Text) obj; 813 if (this._count != that._count) 814 return false; 815 for (int i = 0; i < _count;) { 816 if (this.charAt(i) != that.charAt(i++)) 817 return false; 818 } 819 return true; 820 } 821 822 827 public final int hashCode() { 828 if (_hashCode != 0) 829 return _hashCode; 830 int h = _hashCode; 831 final int length = this.length(); 832 for (int i = 0; i < length;) { 833 h = 31 * h + charAt(i++); 834 } 835 return _hashCode = h; 836 } 837 838 847 public final int compareTo(Object csq) { 848 return ((FastComparator) FastComparator.LEXICAL).compare(this, csq); 849 } 850 851 857 public final Text toText() { 858 return this; 859 } 860 861 867 public final Text copy() { 868 return Text.valueOf(this, 0, _count); 869 } 870 871 876 public abstract int depth(); 877 878 886 public abstract char charAt(int index); 887 888 898 public abstract int indexOf(char c, int fromIndex); 899 900 911 public abstract int lastIndexOf(char c, int fromIndex); 912 913 923 public abstract Text subtext(int start, int end); 924 925 936 public abstract void getChars(int start, int end, char dest[], int destPos); 937 938 944 public abstract Text toLowerCase(); 945 946 952 public abstract Text toUpperCase(); 953 954 959 public abstract String stringValue(); 960 961 965 974 public static Text valueOf(char c, int length) { 975 if (length < 0) 976 throw new IndexOutOfBoundsException (); 977 if (length <= Primitive.BLOCK_SIZE) { 978 Primitive text = Primitive.newInstance(length); 979 for (int i = 0; i < length;) { 980 text._data[i++] = c; 981 } 982 return text; 983 } else { 984 final int middle = (length >> 1); 985 return Composite.newInstance(Text.valueOf(c, middle), Text.valueOf( 986 c, length - middle)); 987 } 988 } 989 990 996 public final boolean isBlank() { 997 return isBlank(0, length()); 998 } 999 1000 1007 public final boolean isBlank(int start, int length) { 1008 for (; start < length; start++) { 1009 if (charAt(start) > ' ') 1010 return false; 1011 } 1012 return true; 1013 } 1014 1015 1021 public final Text trimStart() { 1022 int first = 0; int last = length() - 1; while ((first <= last) && (charAt(first) <= ' ')) { 1025 first++; 1026 } 1027 return subtext(first, last + 1); 1028 } 1029 1030 1037 public final Text trimEnd() { 1038 int first = 0; int last = length() - 1; while ((last >= first) && (charAt(last) <= ' ')) { 1041 last--; 1042 } 1043 return subtext(first, last + 1); 1044 } 1045 1046 1056 public final Text padLeft(int len) { 1057 return padLeft(len, ' '); 1058 } 1059 1060 1072 public final Text padLeft(int len, char c) { 1073 final int padSize = (len <= length()) ? 0 : len - length(); 1074 return this.insert(0, Text.valueOf(c, padSize)); 1075 } 1076 1077 1087 public final Text padRight(int len) { 1088 return padRight(len, ' '); 1089 } 1090 1091 1103 public final Text padRight(int len, char c) { 1104 final int padSize = (len <= length()) ? 0 : len - length(); 1105 return this.concat(Text.valueOf(c, padSize)); 1106 } 1107 1108 1116 public final int indexOfAny(CharSet charSet) { 1117 return indexOfAny(charSet, 0, length()); 1118 } 1119 1120 1129 public final int indexOfAny(CharSet charSet, int start) { 1130 return indexOfAny(charSet, start, length() - start); 1131 } 1132 1133 1143 public final int indexOfAny(CharSet charSet, int start, int length) { 1144 final int stop = start + length; 1145 for (int i = start; i < stop; i++) { 1146 if (charSet.contains(charAt(i))) 1147 return i; 1148 } 1149 return -1; 1150 } 1151 1152 1160 public final int lastIndexOfAny(CharSet charSet) { 1161 return lastIndexOfAny(charSet, 0, length()); 1162 } 1163 1164 1173 public final int lastIndexOfAny(CharSet charSet, int start) { 1174 return lastIndexOfAny(charSet, start, length() - start); 1175 } 1176 1177 1187 public final int lastIndexOfAny(CharSet charSet, int start, int length) { 1188 for (int i = start + length; --i >= start;) { 1189 if (charSet.contains(charAt(i))) 1190 return i; 1191 } 1192 return -1; 1193 } 1194 1195 1198 1201 private static final class Primitive extends Text { 1202 1203 1206 private static final int BLOCK_SIZE = 1 << TextBuilder.D0; 1207 1208 1211 private static final Factory FACTORY = new Factory() { 1212 1213 public Object create() { 1214 return new Primitive(); 1215 } 1216 }; 1217 1218 1221 private final char[] _data = new char[BLOCK_SIZE]; 1222 1223 1226 private Primitive() { 1227 } 1228 1229 1234 private static Primitive newInstance(int length) { 1235 return newInstance(length, (Factory.Pool) FACTORY.currentPool()); 1236 } 1237 1238 private static Primitive newInstance(int length, Factory.Pool pool) { 1239 Primitive text = (Primitive) pool.next(); 1240 text._count = length; 1241 text._hashCode = 0; 1242 return text; 1243 } 1244 1245 public int depth() { 1247 return 0; 1248 } 1249 1250 public char charAt(int index) { 1252 if (index >= _count) 1253 throw new IndexOutOfBoundsException (); 1254 return _data[index]; 1255 } 1256 1257 public int indexOf(char c, int fromIndex) { 1259 for (int i = Math.max(fromIndex, 0); i < _count; i++) { 1260 if (_data[i] == c) 1261 return i; 1262 } 1263 return -1; 1264 } 1265 1266 public int lastIndexOf(char c, int fromIndex) { 1268 for (int i = Math.min(fromIndex, _count - 1); i >= 0; i--) { 1269 if (_data[i] == c) 1270 return i; 1271 } 1272 return -1; 1273 } 1274 1275 public Text subtext(int start, int end) { 1277 if ((start == 0) && (end == _count)) 1278 return this; 1279 if ((start < 0) || (start > end) || (end > _count)) 1280 throw new IndexOutOfBoundsException (); 1281 if (start == end) 1282 return Text.EMPTY; 1283 Primitive text = Primitive.newInstance(end - start); 1284 for (int i = start, j = 0; i < end;) { 1285 text._data[j++] = _data[i++]; 1286 } 1287 return text; 1288 } 1289 1290 public void getChars(int start, int end, char dest[], int destPos) { 1292 if ((end > _count) || (end < start)) 1293 throw new IndexOutOfBoundsException (); 1294 for (int i = start, j = destPos; i < end;) { 1295 dest[j++] = _data[i++]; 1296 } 1297 } 1298 1299 public Text toLowerCase() { 1301 Primitive text = newInstance(_count); 1302 for (int i = 0; i < _count;) { 1303 text._data[i] = Character.toLowerCase(_data[i++]); 1304 } 1305 return text; 1306 } 1307 1308 public Text toUpperCase() { 1310 Primitive text = newInstance(_count); 1311 for (int i = 0; i < _count;) { 1312 text._data[i] = Character.toUpperCase(_data[i++]); 1313 } 1314 return text; 1315 } 1316 1317 public String stringValue() { 1319 return new String (_data, 0, _count); 1320 } 1321 } 1322 1323 1326 private static final class Composite extends Text { 1327 1328 1331 private static final Factory FACTORY = new Factory() { 1332 1333 public Object create() { 1334 return new Composite(); 1335 } 1336 }; 1337 1338 1341 private Text _head; 1342 1343 1346 private Text _tail; 1347 1348 1351 private Composite() { 1352 } 1353 1354 1361 private static Composite newInstance(Text head, Text tail) { 1362 return newInstance(head, tail, (Factory.Pool) FACTORY.currentPool()); 1363 } 1364 1365 private static Composite newInstance(Text head, Text tail, 1366 Factory.Pool pool) { 1367 Composite text = (Composite) pool.next(); 1368 text._hashCode = 0; 1369 text._count = head._count + tail._count; 1370 text._head = head; 1371 text._tail = tail; 1372 return text; 1373 } 1374 1375 1382 private Composite rightRotation(Factory.Pool pool) { 1383 if (!(this._head instanceof Composite)) 1385 return this; Composite P = (Composite) this._head; 1387 Text A = P._head; 1388 Text B = P._tail; 1389 Text C = this._tail; 1390 return Composite.newInstance(A, Composite.newInstance(B, C, pool), 1391 pool); 1392 } 1393 1394 1401 private Composite leftRotation(Factory.Pool pool) { 1402 if (!(this._tail instanceof Composite)) 1404 return this; Composite Q = (Composite) this._tail; 1406 Text B = Q._head; 1407 Text C = Q._tail; 1408 Text A = this._head; 1409 return Composite.newInstance(Composite.newInstance(A, B, pool), C, 1410 pool); 1411 } 1412 1413 public int depth() { 1415 return Math.max(_head.depth(), _tail.depth()) + 1; 1416 } 1417 1418 public char charAt(int index) { 1420 return (index < _head._count) ? _head.charAt(index) : _tail 1421 .charAt(index - _head._count); 1422 } 1423 1424 public int indexOf(char c, int fromIndex) { 1426 final int cesure = _head._count; 1427 if (fromIndex < cesure) { 1428 final int headIndex = _head.indexOf(c, fromIndex); 1429 if (headIndex >= 0) 1430 return headIndex; } 1432 final int tailIndex = _tail.indexOf(c, fromIndex - cesure); 1433 return (tailIndex >= 0) ? tailIndex + cesure : -1; 1434 } 1435 1436 public int lastIndexOf(char c, int fromIndex) { 1438 final int cesure = _head._count; 1439 if (fromIndex >= cesure) { 1440 final int tailIndex = _tail.lastIndexOf(c, fromIndex - cesure); 1441 if (tailIndex >= 0) 1442 return tailIndex + cesure; } 1444 return _head.lastIndexOf(c, fromIndex); 1445 } 1446 1447 public Text subtext(int start, int end) { 1449 final int cesure = _head._count; 1450 if (end <= cesure) 1451 return _head.subtext(start, end); 1452 if (start >= cesure) 1453 return _tail.subtext(start - cesure, end - cesure); 1454 if ((start == 0) && (end == _count)) 1455 return this; 1456 return _head.subtext(start, cesure).concat( 1458 _tail.subtext(0, end - cesure)); 1459 } 1460 1461 public void getChars(int start, int end, char dest[], int destPos) { 1463 final int cesure = _head._count; 1464 if (end <= cesure) { 1465 _head.getChars(start, end, dest, destPos); 1466 } else if (start >= cesure) { 1467 _tail.getChars(start - cesure, end - cesure, dest, destPos); 1468 } else { _head.getChars(start, cesure, dest, destPos); 1470 _tail.getChars(0, end - cesure, dest, destPos + cesure - start); 1471 } 1472 } 1473 1474 public Text toLowerCase() { 1476 return newInstance(_head.toLowerCase(), _tail.toLowerCase()); 1477 } 1478 1479 public Text toUpperCase() { 1481 return newInstance(_head.toUpperCase(), _tail.toUpperCase()); 1482 } 1483 1484 public String stringValue() { 1486 char[] data = new char[_count]; 1487 this.getChars(0, _count, data, 0); 1488 return new String (data, 0, _count); 1489 } 1490 1491 public boolean move(ObjectSpace os) { 1493 if (super.move(os)) { 1494 _head.move(os); 1495 _tail.move(os); 1496 return true; 1497 } 1498 return false; 1499 } 1500 } 1501 1502 1505 private static final class StringWrapper extends Text { 1506 1507 1510 private static final Factory FACTORY = new Factory() { 1511 1512 public Object create() { 1513 return new StringWrapper(); 1514 } 1515 }; 1516 1517 1520 private String _string; 1521 1522 1525 private int _offset; 1526 1527 1530 private StringWrapper() { 1531 } 1532 1533 1539 private static StringWrapper newInstance(String str) { 1540 StringWrapper text = (StringWrapper) FACTORY.object(); 1541 text._count = str.length(); 1542 text._hashCode = 0; 1543 text._string = str; 1544 text._offset = 0; 1545 return text; 1546 } 1547 1548 public int depth() { 1550 return 0; 1551 } 1552 1553 public char charAt(int index) { 1555 if ((index >= _count) || (index < 0)) 1556 throw new IndexOutOfBoundsException (); 1557 return _string.charAt(_offset + index); 1558 } 1559 1560 public int indexOf(char c, int fromIndex) { 1562 for (int i = Math.max(fromIndex, 0); i < _count; i++) { 1563 if (_string.charAt(_offset + i) == c) 1564 return i; 1565 } 1566 return -1; 1567 } 1568 1569 public int lastIndexOf(char c, int fromIndex) { 1571 for (int i = Math.min(fromIndex, _count - 1); i >= 0; i--) { 1572 if (_string.charAt(_offset + i) == c) 1573 return i; 1574 } 1575 return -1; 1576 } 1577 1578 public Text subtext(int start, int end) { 1580 if ((start == 0) && (end == _count)) 1581 return this; 1582 if ((start < 0) || (start > end) || (end > _count)) 1583 throw new IndexOutOfBoundsException (); 1584 if (start == end) 1585 return Text.EMPTY; 1586 StringWrapper text = (StringWrapper) FACTORY.object(); 1587 text._count = end - start; 1588 text._hashCode = 0; 1589 text._string = _string; 1590 text._offset = _offset + start; 1591 return text; 1592 } 1593 1594 public void getChars(int start, int end, char dest[], int destPos) { 1596 if ((end > _count) || (end < start) || (start < 0)) 1597 throw new IndexOutOfBoundsException (); 1598 _string.getChars(start + _offset, end + _offset, dest, destPos); 1599 } 1600 1601 public Text toLowerCase() { 1603 return copy().toLowerCase(); } 1605 1606 public Text toUpperCase() { 1608 return copy().toUpperCase(); } 1610 1611 public String stringValue() { 1613 if ((_offset == 0) && (_count == _string.length())) 1614 return _string; 1615 return _string.substring(_offset, _offset + _count); 1616 } 1617 1618 } 1619} | Popular Tags |