1 9 package javolution.lang; 10 11 import java.io.IOException; 12 13 import j2me.io.Serializable; 14 import j2me.lang.CharSequence; 15 import j2me.lang.Comparable; 16 17 import javolution.JavolutionError; 18 import javolution.realtime.Realtime; 19 import javolution.realtime.RealtimeObject; 20 import javolution.util.FastComparator; 21 import javolution.util.FastMap; 22 23 63 public abstract class Text extends RealtimeObject implements CharSequence, 64 Comparable, Serializable { 65 66 69 private static final FastMap INTERN_TEXT = new FastMap(); 70 71 74 public static final Text EMPTY = Text.valueOf("").intern(); 75 76 79 public static final Text NULL = Text.valueOf("null").intern(); 80 81 84 int _count; 85 86 89 int _hashCode; 90 91 94 private Text() { 95 } 96 97 106 public static Text valueOf(Object obj) { 107 if (obj instanceof String) { 108 return StringWrapper.newInstance((String) obj); 109 } else if (obj instanceof Realtime) { 110 return ((Realtime) obj).toText(); 111 } else if (obj instanceof CharSequence) { 112 final CharSequence csq = (CharSequence) obj; 113 return Text.valueOf(csq, 0, csq.length()); 114 } else if (obj != null) { 115 return StringWrapper.newInstance(obj.toString()); 116 } else { 117 return NULL; 118 } 119 } 120 121 131 public static Text valueOf(CharSequence csq, int start, int end) { 132 if ((start < 0) || (end < 0) || (start > end) || (end > csq.length())) 133 throw new IndexOutOfBoundsException(); 134 final int length = end - start; 135 if (length <= Primitive.BLOCK_SIZE) { 136 Primitive text = Primitive.newInstance(length); 137 for (int i = 0; i < length;) { 138 text._data[i] = csq.charAt(start + i++); 139 } 140 return text; 141 } else { 142 final int middle = start + (length >> 1); 143 Composite text = Composite.newInstance(Text.valueOf(csq, start, 144 middle), Text.valueOf(csq, middle, end)); 145 return text; 146 } 147 } 148 149 156 public static Text valueOf(char[] chars) { 157 return valueOf(chars, 0, chars.length); 158 } 159 160 171 public static Text valueOf(char[] chars, int offset, int length) { 172 if ((offset < 0) || (length < 0) || ((offset + length) > chars.length)) 173 throw new IndexOutOfBoundsException(); 174 if (length <= Primitive.BLOCK_SIZE) { 175 Primitive text = Primitive.newInstance(length); 176 for (int i = 0; i < length;) { 177 text._data[i] = chars[offset + i++]; 178 } 179 return text; 180 } else { 181 final int middle = offset + (length >> 1); 182 Composite text = Composite.newInstance(Text.valueOf(chars, offset, 183 middle - offset), Text.valueOf(chars, middle, offset 184 + length - middle)); 185 return text; 186 } 187 } 188 189 197 public static Text valueOf(boolean b) { 198 return b ? TRUE : FALSE; 199 } 200 201 private static final Text TRUE = Text.valueOf("true").intern(); 202 203 private static final Text FALSE = Text.valueOf("false").intern(); 204 205 212 public static Text valueOf(char c) { 213 if ((c < 128) && (ASCII[c] != null)) 214 return ASCII[c]; 215 Primitive text = Primitive.newInstance(1); 216 text._data[0] = c; 217 Text textIntern = text.intern(); 218 if (c < 128) { 219 ASCII[c] = textIntern; 220 } 221 return textIntern; 222 } 223 private static final Text[] ASCII = new Text[128]; 224 225 232 public static Text valueOf(int i) { 233 try { 234 Primitive text = Primitive.newInstance(0); 235 TypeFormat.format(i, text); 236 return text; 237 } catch (IOException e) { 238 throw new JavolutionError(e); 239 } 240 } 241 242 250 public static Text valueOf(int i, int radix) { 251 try { 252 Primitive text = Primitive.newInstance(0); 253 TypeFormat.format(i, radix, text); 254 return text; 255 } catch (IOException e) { 256 throw new JavolutionError(e); 257 } 258 } 259 260 267 public static Text valueOf(long l) { 268 try { 269 Primitive text = Primitive.newInstance(0); 270 TypeFormat.format(l, text); 271 return text; 272 } catch (IOException e) { 273 throw new JavolutionError(e); 274 } 275 } 276 277 285 public static Text valueOf(long l, int radix) { 286 try { 287 Primitive text = Primitive.newInstance(0); 288 TypeFormat.format(l, radix, text); 289 return text; 290 } catch (IOException e) { 291 throw new JavolutionError(e); 292 } 293 } 294 295 312 313 330 331 357 358 363 public final int length() { 364 return _count; 365 } 366 367 376 public final Text concat(Text that) { 377 if (this._count == 0) { 378 return that; 379 } else if (that._count == 0) { 380 return this; 381 } else if (((that._count << 1) < this._count) 382 && (this instanceof Composite)) { Composite thisComposite = (Composite) this; 384 if (thisComposite._head._count > thisComposite._tail._count) { 385 return Composite.newInstance(thisComposite._head, 386 thisComposite._tail.concat(that)); 387 } else { 388 return Composite.newInstance(this, that); 389 } 390 } else if (((this._count << 1) < that._count) 391 && (that instanceof Composite)) { Composite thatComposite = (Composite) that; 393 if (thatComposite._head._count < thatComposite._tail._count) { 394 return Composite.newInstance(this.concat(thatComposite._head), 395 thatComposite._tail); 396 } else { 397 return Composite.newInstance(this, that); 398 } 399 } else { return Composite.newInstance(this, that); 401 } 402 } 403 404 412 public final Text subtext(int start) { 413 return subtext(start, length()); 414 } 415 416 426 public final Text insert(int index, Text txt) { 427 return ((index << 1) < _count) ? this.subtext(0, index).concat(txt) 429 .concat(this.subtext(index)) : this.subtext(0, index).concat( 430 txt.concat(this.subtext(index))); 431 } 432 433 442 public final Text delete(int start, int end) { 443 return this.subtext(0, start).concat(this.subtext(end)); 444 } 445 446 454 public final Text replace(Text target, Text replacement) { 455 int i = indexOf(target); 456 return (i < 0) ? this : this.subtext(0, i).concat(replacement).concat( 458 this.subtext(i + target.length()).replace(target, 459 replacement)); 460 } 461 462 471 public final CharSequence subSequence(int start, int end) { 472 return this.subtext(start, end); 473 } 474 475 483 public final int indexOf(CharSequence csq) { 484 return indexOf(csq, 0); 485 } 486 487 498 public final int indexOf(CharSequence csq, int fromIndex) { 499 500 final int csqLength = csq.length(); 502 final int min = Math.max(0, fromIndex); 503 final int max = _count - csqLength; 504 if (csqLength == 0) { 505 return (min > max) ? -1 : min; 506 } 507 508 final char c = csq.charAt(0); 510 for (int i = indexOf(c, min); (i >= 0) && (i <= max); i = indexOf(c, 511 ++i)) { 512 boolean match = true; 513 for (int j = 1; j < csqLength; j++) { 514 if (this.charAt(i + j) != csq.charAt(j)) { 515 match = false; 516 break; 517 } 518 } 519 if (match) { 520 return i; 521 } 522 } 523 return -1; 524 } 525 526 534 public final int lastIndexOf(CharSequence csq) { 535 return lastIndexOf(csq, _count); 536 } 537 538 548 public final int lastIndexOf(CharSequence csq, int fromIndex) { 549 550 final int csqLength = csq.length(); 552 final int min = 0; 553 final int max = Math.min(fromIndex, _count - csqLength); 554 if (csqLength == 0) { 555 return (min > max) ? -1 : max; 556 } 557 558 final char c = csq.charAt(0); 560 for (int i = lastIndexOf(c, max); (i >= 0); i = lastIndexOf(c, --i)) { 561 boolean match = true; 562 for (int j = 1; j < csqLength; j++) { 563 if (this.charAt(i + j) != csq.charAt(j)) { 564 match = false; 565 break; 566 } 567 } 568 if (match) { 569 return i; 570 } 571 } 572 return -1; 573 574 } 575 576 584 public final boolean startsWith(CharSequence prefix) { 585 return startsWith(prefix, 0); 586 } 587 588 596 public final boolean endsWith(CharSequence suffix) { 597 return startsWith(suffix, length() - suffix.length()); 598 } 599 600 608 public final boolean startsWith(CharSequence prefix, int index) { 609 final int prefixLength = prefix.length(); 610 if ((index >= 0) && (index <= (this.length() - prefixLength))) { 611 for (int i = 0, j = index; i < prefixLength;) { 612 if (prefix.charAt(i++) != this.charAt(j++)) { 613 return false; 614 } 615 } 616 return true; 617 } else { 618 return false; 619 } 620 } 621 622 630 public final Text trim() { 631 int first = 0; int last = length() - 1; while ((first <= last) && (charAt(first) <= ' ')) { 634 first++; 635 } 636 while ((last >= first) && (charAt(last) <= ' ')) { 637 last--; 638 } 639 return subtext(first, last + 1); 640 } 641 642 650 public final Text intern() { 651 Text text = (Text) INTERN_TEXT.get(this); if (text == null) { 653 synchronized (INTERN_TEXT) { 654 text = (Text) INTERN_TEXT.get(this); if (text == null) { 656 text = this; 657 text.moveHeap(); 658 INTERN_TEXT.put(text, text); 659 } 660 } 661 } 662 return text; 663 } 664 665 673 public final boolean contentEquals(CharSequence csq) { 674 if (csq.length() != _count) 675 return false; 676 for (int i = 0; i < _count;) { 677 if (this.charAt(i) != csq.charAt(i++)) 678 return false; 679 } 680 return true; 681 } 682 683 691 public final boolean contentEqualsIgnoreCase(CharSequence csq) { 692 if (this._count != csq.length()) 693 return false; 694 for (int i = 0; i < _count;) { 695 char u1 = this.charAt(i); 696 char u2 = csq.charAt(i++); 697 if (u1 != u2) { 698 u1 = Character.toUpperCase(u1); 699 u2 = Character.toUpperCase(u2); 700 if ((u1 != u2) 701 && (Character.toLowerCase(u1) != Character 702 .toLowerCase(u2))) 703 return false; 704 705 } 706 } 707 return true; 708 } 709 710 721 public final boolean equals(Object obj) { 722 if (this == obj) 723 return true; 724 if (!(obj instanceof Text)) 725 return false; 726 final Text that = (Text) obj; 727 if (this._count != that._count) 728 return false; 729 for (int i = 0; i < _count;) { 730 if (this.charAt(i) != that.charAt(i++)) 731 return false; 732 } 733 return true; 734 } 735 736 741 public final int hashCode() { 742 if (_hashCode != 0) 743 return _hashCode; 744 int h = _hashCode; 745 final int length = this.length(); 746 for (int i = 0; i < length;) { 747 h = 31 * h + charAt(i++); 748 } 749 return _hashCode = h; 750 } 751 752 761 public final int compareTo(Object csq) { 762 return FastComparator.LEXICAL.compare(this, csq); 763 } 764 765 771 public final Text toText() { 772 return this; 773 } 774 775 781 public final Text copy() { 782 return Text.valueOf(this, 0, _count); 783 } 784 785 790 public abstract int depth(); 791 792 800 public abstract char charAt(int index); 801 802 812 public abstract int indexOf(char c, int fromIndex); 813 814 825 public abstract int lastIndexOf(char c, int fromIndex); 826 827 837 public abstract Text subtext(int start, int end); 838 839 850 public abstract void getChars(int start, int end, char dest[], int destPos); 851 852 858 public abstract Text toLowerCase(); 859 860 866 public abstract Text toUpperCase(); 867 868 873 public abstract String stringValue(); 874 875 878 private static final class Primitive extends Text implements Appendable { 879 880 883 private static final int BLOCK_SIZE = 32; 884 885 888 private static final Factory FACTORY = new Factory() { 889 890 public Object create() { 891 return new Primitive(); 892 } 893 }; 894 895 898 private final char[] _data = new char[BLOCK_SIZE]; 899 900 903 private Primitive() { 904 } 905 906 911 private static Primitive newInstance(int length) { 912 Primitive text = (Primitive) FACTORY.object(); 913 text._count = length; 914 text._hashCode = 0; 915 return text; 916 } 917 918 public int depth() { 920 return 0; 921 } 922 923 public char charAt(int index) { 925 if (index >= _count) 926 throw new IndexOutOfBoundsException(); 927 return _data[index]; 928 } 929 930 public int indexOf(char c, int fromIndex) { 932 for (int i = Math.max(fromIndex, 0); i < _count; i++) { 933 if (_data[i] == c) 934 return i; 935 } 936 return -1; 937 } 938 939 public int lastIndexOf(char c, int fromIndex) { 941 for (int i = Math.min(fromIndex, _count - 1); i >= 0; i--) { 942 if (_data[i] == c) 943 return i; 944 } 945 return -1; 946 } 947 948 public Text subtext(int start, int end) { 950 if ((start == 0) && (end == _count)) 951 return this; 952 if ((start < 0) || (start > end) || (end > _count)) 953 throw new IndexOutOfBoundsException(); 954 if (start == end) 955 return Text.EMPTY; 956 Primitive text = Primitive.newInstance(end - start); 957 for (int i = start, j = 0; i < end;) { 958 text._data[j++] = _data[i++]; 959 } 960 return text; 961 } 962 963 public void getChars(int start, int end, char dest[], int destPos) { 965 if ((end > _count) || (end < start)) 966 throw new IndexOutOfBoundsException(); 967 for (int i = start, j = destPos; i < end;) { 968 dest[j++] = _data[i++]; 969 } 970 } 971 972 public Text toLowerCase() { 974 Primitive text = newInstance(_count); 975 for (int i = 0; i < _count;) { 976 text._data[i] = Character.toLowerCase(_data[i++]); 977 } 978 return text; 979 } 980 981 public Text toUpperCase() { 983 Primitive text = newInstance(_count); 984 for (int i = 0; i < _count;) { 985 text._data[i] = Character.toUpperCase(_data[i++]); 986 } 987 return text; 988 } 989 990 public String stringValue() { 992 return new String(_data, 0, _count); 993 } 994 995 public Appendable append(char c) throws IOException { 997 _data[_count++] = c; 998 return this; 999 } 1000 1001 public Appendable append(CharSequence csq) throws IOException { 1003 return append(csq, 0, csq.length()); 1004 } 1005 1006 public Appendable append(CharSequence csq, int start, int end) 1008 throws IOException { 1009 for (int i = start; i < end;) { 1010 _data[_count++] = csq.charAt(i++); 1011 } 1012 return this; 1013 } 1014 1015 } 1016 1017 1020 private static final class Composite extends Text { 1021 1022 1025 private static final Factory FACTORY = new Factory() { 1026 1027 public Object create() { 1028 return new Composite(); 1029 } 1030 }; 1031 1032 1035 private Text _head; 1036 1037 1040 private Text _tail; 1041 1042 1045 private Composite() { 1046 } 1047 1048 1055 private static Composite newInstance(Text head, Text tail) { 1056 Composite text = (Composite) FACTORY.object(); 1057 text._hashCode = 0; 1058 text._count = head._count + tail._count; 1059 text._head = head; 1060 text._tail = tail; 1061 return text; 1062 } 1063 1064 public int depth() { 1066 return Math.max(_head.depth(), _tail.depth()) + 1; 1067 } 1068 1069 public char charAt(int index) { 1071 return (index < _head._count) ? _head.charAt(index) : _tail 1072 .charAt(index - _head._count); 1073 } 1074 1075 public int indexOf(char c, int fromIndex) { 1077 final int cesure = _head._count; 1078 if (fromIndex < cesure) { 1079 final int headIndex = _head.indexOf(c, fromIndex); 1080 if (headIndex >= 0) 1081 return headIndex; } 1083 final int tailIndex = _tail.indexOf(c, fromIndex - cesure); 1084 return (tailIndex >= 0) ? tailIndex + cesure : -1; 1085 } 1086 1087 public int lastIndexOf(char c, int fromIndex) { 1089 final int cesure = _head._count; 1090 if (fromIndex >= cesure) { 1091 final int tailIndex = _tail.lastIndexOf(c, fromIndex - cesure); 1092 if (tailIndex >= 0) 1093 return tailIndex + cesure; } 1095 return _head.lastIndexOf(c, fromIndex); 1096 } 1097 1098 public Text subtext(int start, int end) { 1100 final int cesure = _head._count; 1101 if (end <= cesure) 1102 return _head.subtext(start, end); 1103 if (start >= cesure) 1104 return _tail.subtext(start - cesure, end - cesure); 1105 if ((start == 0) && (end == _count)) 1106 return this; 1107 return _head.subtext(start, cesure).concat( 1109 _tail.subtext(0, end - cesure)); 1110 } 1111 1112 public void getChars(int start, int end, char dest[], int destPos) { 1114 final int cesure = _head._count; 1115 if (end <= cesure) { 1116 _head.getChars(start, end, dest, destPos); 1117 } else if (start >= cesure) { 1118 _tail.getChars(start - cesure, end - cesure, dest, destPos); 1119 } else { _head.getChars(start, cesure, dest, destPos); 1121 _tail.getChars(0, end - cesure, dest, destPos + cesure - start); 1122 } 1123 } 1124 1125 public Text toLowerCase() { 1127 return newInstance(_head.toLowerCase(), _tail.toLowerCase()); 1128 } 1129 1130 public Text toUpperCase() { 1132 return newInstance(_head.toUpperCase(), _tail.toUpperCase()); 1133 } 1134 1135 public String stringValue() { 1137 char[] data = new char[_count]; 1138 this.getChars(0, _count, data, 0); 1139 return new String(data, 0, _count); 1140 } 1141 1142 public boolean move(ObjectSpace os) { 1144 if (super.move(os)) { 1145 _head.move(os); 1146 _tail.move(os); 1147 return true; 1148 } 1149 return false; 1150 } 1151 } 1152 1153 1156 private static final class StringWrapper extends Text { 1157 1158 1161 private static final Factory FACTORY = new Factory() { 1162 1163 public Object create() { 1164 return new StringWrapper(); 1165 } 1166 }; 1167 1168 1171 private String _string; 1172 1173 1176 private int _offset; 1177 1178 1181 private StringWrapper() { 1182 } 1183 1184 1190 private static StringWrapper newInstance(String str) { 1191 StringWrapper text = (StringWrapper) FACTORY.object(); 1192 text._count = str.length(); 1193 text._hashCode = 0; 1194 text._string = str; 1195 text._offset = 0; 1196 return text; 1197 } 1198 1199 public int depth() { 1201 return 0; 1202 } 1203 1204 public char charAt(int index) { 1206 if ((index >= _count) || (index < 0)) 1207 throw new IndexOutOfBoundsException(); 1208 return _string.charAt(_offset + index); 1209 } 1210 1211 public int indexOf(char c, int fromIndex) { 1213 for (int i = Math.max(fromIndex, 0); i < _count; i++) { 1214 if (_string.charAt(_offset + i) == c) 1215 return i; 1216 } 1217 return -1; 1218 } 1219 1220 public int lastIndexOf(char c, int fromIndex) { 1222 for (int i = Math.min(fromIndex, _count - 1); i >= 0; i--) { 1223 if (_string.charAt(_offset + i) == c) 1224 return i; 1225 } 1226 return -1; 1227 } 1228 1229 public Text subtext(int start, int end) { 1231 if ((start == 0) && (end == _count)) 1232 return this; 1233 if ((start < 0) || (start > end) || (end > _count)) 1234 throw new IndexOutOfBoundsException(); 1235 if (start == end) 1236 return Text.EMPTY; 1237 StringWrapper text = (StringWrapper) FACTORY.object(); 1238 text._count = end - start; 1239 text._hashCode = 0; 1240 text._string = _string; 1241 text._offset = _offset + start; 1242 return text; 1243 } 1244 1245 public void getChars(int start, int end, char dest[], int destPos) { 1247 if ((end > _count) || (end < start) || (start < 0)) 1248 throw new IndexOutOfBoundsException(); 1249 _string.getChars(start + _offset, end + _offset, dest, destPos); 1250 } 1251 1252 public Text toLowerCase() { 1254 return copy().toLowerCase(); } 1256 1257 public Text toUpperCase() { 1259 return copy().toUpperCase(); } 1261 1262 public String stringValue() { 1264 if ((_offset == 0) && (_count == _string.length())) 1265 return _string; 1266 return _string.substring(_offset, _offset + _count); 1267 } 1268 1269 } 1270} | Popular Tags |