AbstractStringBuffer.java 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038
  1. /* AbstractStringBuffer.java -- Growable strings
  2. Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008
  3. Free Software Foundation, Inc.
  4. This file is part of GNU Classpath.
  5. GNU Classpath is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9. GNU Classpath is distributed in the hope that it will be useful, but
  10. WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with GNU Classpath; see the file COPYING. If not, write to the
  15. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. 02110-1301 USA.
  17. Linking this library statically or dynamically with other modules is
  18. making a combined work based on this library. Thus, the terms and
  19. conditions of the GNU General Public License cover the whole
  20. combination.
  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. package java.lang;
  33. import java.io.Serializable;
  34. /**
  35. * This class is based on gnu.classpath.ClasspathStringBuffer but
  36. * is package-private to java.lang so it can be used as the basis
  37. * for StringBuffer and StringBuilder.
  38. * If you modify this, please consider also modifying that code.
  39. */
  40. abstract class AbstractStringBuffer
  41. implements Serializable, CharSequence, Appendable
  42. {
  43. /**
  44. * Index of next available character (and thus the size of the current
  45. * string contents). Note that this has permissions set this way so that
  46. * String can get the value.
  47. *
  48. * @serial the number of characters in the buffer
  49. */
  50. int count;
  51. /**
  52. * The buffer. Note that this has permissions set this way so that String
  53. * can get the value.
  54. *
  55. * @serial the buffer
  56. */
  57. char[] value;
  58. /**
  59. * The default capacity of a buffer.
  60. */
  61. private static final int DEFAULT_CAPACITY = 16;
  62. /**
  63. * Create a new AbstractStringBuffer with default capacity 16.
  64. */
  65. AbstractStringBuffer()
  66. {
  67. this(DEFAULT_CAPACITY);
  68. }
  69. /**
  70. * Create an empty <code>StringBuffer</code> with the specified initial
  71. * capacity.
  72. *
  73. * @param capacity the initial capacity
  74. * @throws NegativeArraySizeException if capacity is negative
  75. */
  76. AbstractStringBuffer(int capacity)
  77. {
  78. value = new char[capacity];
  79. }
  80. /**
  81. * Create a new <code>StringBuffer</code> with the characters in the
  82. * specified <code>String</code>. Initial capacity will be the size of the
  83. * String plus 16.
  84. *
  85. * @param str the <code>String</code> to convert
  86. * @throws NullPointerException if str is null
  87. */
  88. AbstractStringBuffer(String str)
  89. {
  90. count = str.count;
  91. value = new char[count + DEFAULT_CAPACITY];
  92. str.getChars(0, count, value, 0);
  93. }
  94. /**
  95. * Create a new <code>StringBuffer</code> with the characters in the
  96. * specified <code>CharSequence</code>. Initial capacity will be the
  97. * length of the sequence plus 16; if the sequence reports a length
  98. * less than or equal to 0, then the initial capacity will be 16.
  99. *
  100. * @param seq the initializing <code>CharSequence</code>
  101. * @throws NullPointerException if str is null
  102. * @since 1.5
  103. */
  104. AbstractStringBuffer(CharSequence seq)
  105. {
  106. int len = seq.length();
  107. count = len <= 0 ? 0 : len;
  108. value = new char[count + DEFAULT_CAPACITY];
  109. for (int i = 0; i < len; ++i)
  110. value[i] = seq.charAt(i);
  111. }
  112. /**
  113. * Increase the capacity of this <code>StringBuffer</code>. This will
  114. * ensure that an expensive growing operation will not occur until
  115. * <code>minimumCapacity</code> is reached. The buffer is grown to the
  116. * larger of <code>minimumCapacity</code> and
  117. * <code>capacity() * 2 + 2</code>, if it is not already large enough.
  118. *
  119. * @param minimumCapacity the new capacity
  120. * @see #capacity()
  121. */
  122. public void ensureCapacity(int minimumCapacity)
  123. {
  124. ensureCapacity_unsynchronized(minimumCapacity);
  125. }
  126. /**
  127. * Set the length of this StringBuffer. If the new length is greater than
  128. * the current length, all the new characters are set to '\0'. If the new
  129. * length is less than the current length, the first <code>newLength</code>
  130. * characters of the old array will be preserved, and the remaining
  131. * characters are truncated.
  132. *
  133. * @param newLength the new length
  134. * @throws IndexOutOfBoundsException if the new length is negative
  135. * (while unspecified, this is a StringIndexOutOfBoundsException)
  136. * @see #length()
  137. */
  138. public void setLength(int newLength)
  139. {
  140. if (newLength < 0)
  141. throw new StringIndexOutOfBoundsException(newLength);
  142. int valueLength = value.length;
  143. /* Always call ensureCapacity_unsynchronized in order to preserve
  144. copy-on-write semantics. */
  145. ensureCapacity_unsynchronized(newLength);
  146. if (newLength < valueLength)
  147. {
  148. /* If the StringBuffer's value just grew, then we know that
  149. value is newly allocated and the region between count and
  150. newLength is filled with '\0'. */
  151. count = newLength;
  152. }
  153. else
  154. {
  155. /* The StringBuffer's value doesn't need to grow. However,
  156. we should clear out any cruft that may exist. */
  157. while (count < newLength)
  158. value[count++] = '\0';
  159. }
  160. }
  161. /**
  162. * Get the character at the specified index.
  163. *
  164. * @param index the index of the character to get, starting at 0
  165. * @return the character at the specified index
  166. * @throws IndexOutOfBoundsException if index is negative or &gt;= length()
  167. * (while unspecified, this is a StringIndexOutOfBoundsException)
  168. */
  169. public char charAt(int index)
  170. {
  171. if (index < 0 || index >= count)
  172. throw new StringIndexOutOfBoundsException(index);
  173. return value[index];
  174. }
  175. /**
  176. * Get the code point at the specified index. This is like #charAt(int),
  177. * but if the character is the start of a surrogate pair, and the
  178. * following character completes the pair, then the corresponding
  179. * supplementary code point is returned.
  180. * @param index the index of the codepoint to get, starting at 0
  181. * @return the codepoint at the specified index
  182. * @throws IndexOutOfBoundsException if index is negative or &gt;= length()
  183. * @since 1.5
  184. */
  185. public int codePointAt(int index)
  186. {
  187. return Character.codePointAt(value, index, count);
  188. }
  189. /**
  190. * Get the code point before the specified index. This is like
  191. * #codePointAt(int), but checks the characters at <code>index-1</code> and
  192. * <code>index-2</code> to see if they form a supplementary code point.
  193. * @param index the index just past the codepoint to get, starting at 0
  194. * @return the codepoint at the specified index
  195. * @throws IndexOutOfBoundsException if index is negative or &gt;= length()
  196. * @since 1.5
  197. */
  198. public int codePointBefore(int index)
  199. {
  200. // Character.codePointBefore() doesn't perform this check. We
  201. // could use the CharSequence overload, but this is just as easy.
  202. if (index >= count)
  203. throw new IndexOutOfBoundsException();
  204. return Character.codePointBefore(value, index, 1);
  205. }
  206. /**
  207. * Get the specified array of characters. <code>srcOffset - srcEnd</code>
  208. * characters will be copied into the array you pass in.
  209. *
  210. * @param srcOffset the index to start copying from (inclusive)
  211. * @param srcEnd the index to stop copying from (exclusive)
  212. * @param dst the array to copy into
  213. * @param dstOffset the index to start copying into
  214. * @throws NullPointerException if dst is null
  215. * @throws IndexOutOfBoundsException if any source or target indices are
  216. * out of range (while unspecified, source problems cause a
  217. * StringIndexOutOfBoundsException, and dest problems cause an
  218. * ArrayIndexOutOfBoundsException)
  219. * @see System#arraycopy(Object, int, Object, int, int)
  220. */
  221. public void getChars(int srcOffset, int srcEnd,
  222. char[] dst, int dstOffset)
  223. {
  224. if (srcOffset < 0 || srcEnd > count || srcEnd < srcOffset)
  225. throw new StringIndexOutOfBoundsException();
  226. VMSystem.arraycopy(value, srcOffset, dst, dstOffset, srcEnd - srcOffset);
  227. }
  228. /**
  229. * Set the character at the specified index.
  230. *
  231. * @param index the index of the character to set starting at 0
  232. * @param ch the value to set that character to
  233. * @throws IndexOutOfBoundsException if index is negative or &gt;= length()
  234. * (while unspecified, this is a StringIndexOutOfBoundsException)
  235. */
  236. public void setCharAt(int index, char ch)
  237. {
  238. if (index < 0 || index >= count)
  239. throw new StringIndexOutOfBoundsException(index);
  240. // Call ensureCapacity to enforce copy-on-write.
  241. ensureCapacity_unsynchronized(count);
  242. value[index] = ch;
  243. }
  244. /**
  245. * Append the <code>String</code> value of the argument to this
  246. * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
  247. * to <code>String</code>.
  248. *
  249. * @param obj the <code>Object</code> to convert and append
  250. * @return this <code>StringBuffer</code>
  251. * @see String#valueOf(Object)
  252. * @see #append(String)
  253. */
  254. public AbstractStringBuffer append(Object obj)
  255. {
  256. return append(String.valueOf(obj));
  257. }
  258. /**
  259. * Append the <code>String</code> to this <code>StringBuffer</code>. If
  260. * str is null, the String "null" is appended.
  261. *
  262. * @param str the <code>String</code> to append
  263. * @return this <code>StringBuffer</code>
  264. */
  265. public AbstractStringBuffer append(String str)
  266. {
  267. if (str == null)
  268. str = "null";
  269. int len = str.count;
  270. ensureCapacity_unsynchronized(count + len);
  271. str.getChars(0, len, value, count);
  272. count += len;
  273. return this;
  274. }
  275. /**
  276. * Append the <code>StringBuilder</code> value of the argument to this
  277. * <code>StringBuilder</code>. This behaves the same as
  278. * <code>append((Object) stringBuffer)</code>, except it is more efficient.
  279. *
  280. * @param stringBuffer the <code>StringBuilder</code> to convert and append
  281. * @return this <code>StringBuilder</code>
  282. * @see #append(Object)
  283. */
  284. public AbstractStringBuffer append(StringBuffer stringBuffer)
  285. {
  286. if (stringBuffer == null)
  287. return append("null");
  288. synchronized (stringBuffer)
  289. {
  290. int len = stringBuffer.count;
  291. ensureCapacity(count + len);
  292. VMSystem.arraycopy(stringBuffer.value, 0, value, count, len);
  293. count += len;
  294. }
  295. return this;
  296. }
  297. /**
  298. * Append the <code>char</code> array to this <code>StringBuffer</code>.
  299. * This is similar (but more efficient) than
  300. * <code>append(new String(data))</code>, except in the case of null.
  301. *
  302. * @param data the <code>char[]</code> to append
  303. * @return this <code>StringBuffer</code>
  304. * @throws NullPointerException if <code>str</code> is <code>null</code>
  305. * @see #append(char[], int, int)
  306. */
  307. public AbstractStringBuffer append(char[] data)
  308. {
  309. return append(data, 0, data.length);
  310. }
  311. /**
  312. * Append part of the <code>char</code> array to this
  313. * <code>StringBuffer</code>. This is similar (but more efficient) than
  314. * <code>append(new String(data, offset, count))</code>, except in the case
  315. * of null.
  316. *
  317. * @param data the <code>char[]</code> to append
  318. * @param offset the start location in <code>str</code>
  319. * @param count the number of characters to get from <code>str</code>
  320. * @return this <code>StringBuffer</code>
  321. * @throws NullPointerException if <code>str</code> is <code>null</code>
  322. * @throws IndexOutOfBoundsException if offset or count is out of range
  323. * (while unspecified, this is a StringIndexOutOfBoundsException)
  324. */
  325. public AbstractStringBuffer append(char[] data, int offset, int count)
  326. {
  327. if (offset < 0 || count < 0 || offset > data.length - count)
  328. throw new StringIndexOutOfBoundsException();
  329. ensureCapacity_unsynchronized(this.count + count);
  330. VMSystem.arraycopy(data, offset, value, this.count, count);
  331. this.count += count;
  332. return this;
  333. }
  334. /**
  335. * Append the <code>String</code> value of the argument to this
  336. * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
  337. * to <code>String</code>.
  338. *
  339. * @param bool the <code>boolean</code> to convert and append
  340. * @return this <code>StringBuffer</code>
  341. * @see String#valueOf(boolean)
  342. */
  343. public AbstractStringBuffer append(boolean bool)
  344. {
  345. return append(bool ? "true" : "false");
  346. }
  347. /**
  348. * Append the <code>char</code> to this <code>StringBuffer</code>.
  349. *
  350. * @param ch the <code>char</code> to append
  351. * @return this <code>StringBuffer</code>
  352. */
  353. public AbstractStringBuffer append(char ch)
  354. {
  355. ensureCapacity_unsynchronized(count + 1);
  356. value[count++] = ch;
  357. return this;
  358. }
  359. /**
  360. * Append the characters in the <code>CharSequence</code> to this
  361. * buffer.
  362. *
  363. * @param seq the <code>CharSequence</code> providing the characters
  364. * @return this <code>StringBuffer</code>
  365. * @since 1.5
  366. */
  367. public AbstractStringBuffer append(CharSequence seq)
  368. {
  369. return append(seq, 0, seq.length());
  370. }
  371. /**
  372. * Append some characters from the <code>CharSequence</code> to this
  373. * buffer. If the argument is null, the <code>seq</code> is assumed
  374. * to be equal to the string <code>"null"</code>.
  375. *
  376. * @param seq the <code>CharSequence</code> providing the characters
  377. * @param start the starting index
  378. * @param end one past the final index
  379. * @return this <code>StringBuffer</code>
  380. * @since 1.5
  381. */
  382. public AbstractStringBuffer append(CharSequence seq, int start, int end)
  383. {
  384. if (seq == null)
  385. seq = "null";
  386. if (end - start > 0)
  387. {
  388. ensureCapacity_unsynchronized(count + end - start);
  389. for (; start < end; ++start)
  390. value[count++] = seq.charAt(start);
  391. }
  392. return this;
  393. }
  394. /**
  395. * Append the <code>String</code> value of the argument to this
  396. * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
  397. * to <code>String</code>.
  398. *
  399. * @param inum the <code>int</code> to convert and append
  400. * @return this <code>StringBuffer</code>
  401. * @see String#valueOf(int)
  402. */
  403. // This is native in libgcj, for efficiency.
  404. public AbstractStringBuffer append(int inum)
  405. {
  406. return append(String.valueOf(inum));
  407. }
  408. /**
  409. * Append the <code>String</code> value of the argument to this
  410. * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
  411. * to <code>String</code>.
  412. *
  413. * @param lnum the <code>long</code> to convert and append
  414. * @return this <code>StringBuffer</code>
  415. * @see String#valueOf(long)
  416. */
  417. public AbstractStringBuffer append(long lnum)
  418. {
  419. return append(Long.toString(lnum, 10));
  420. }
  421. /**
  422. * Append the <code>String</code> value of the argument to this
  423. * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
  424. * to <code>String</code>.
  425. *
  426. * @param fnum the <code>float</code> to convert and append
  427. * @return this <code>StringBuffer</code>
  428. * @see String#valueOf(float)
  429. */
  430. public AbstractStringBuffer append(float fnum)
  431. {
  432. return append(Float.toString(fnum));
  433. }
  434. /**
  435. * Append the <code>String</code> value of the argument to this
  436. * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
  437. * to <code>String</code>.
  438. *
  439. * @param dnum the <code>double</code> to convert and append
  440. * @return this <code>StringBuffer</code>
  441. * @see String#valueOf(double)
  442. */
  443. public AbstractStringBuffer append(double dnum)
  444. {
  445. return append(Double.toString(dnum));
  446. }
  447. /**
  448. * Append the code point to this <code>StringBuffer</code>.
  449. * This is like #append(char), but will append two characters
  450. * if a supplementary code point is given.
  451. *
  452. * @param code the code point to append
  453. * @return this <code>StringBuffer</code>
  454. * @see Character#toChars(int, char[], int)
  455. * @since 1.5
  456. */
  457. public AbstractStringBuffer appendCodePoint(int code)
  458. {
  459. int len = Character.charCount(code);
  460. ensureCapacity_unsynchronized(count + len);
  461. Character.toChars(code, value, count);
  462. count += len;
  463. return this;
  464. }
  465. /**
  466. * Delete characters from this <code>StringBuffer</code>.
  467. * <code>delete(10, 12)</code> will delete 10 and 11, but not 12. It is
  468. * harmless for end to be larger than length().
  469. *
  470. * @param start the first character to delete
  471. * @param end the index after the last character to delete
  472. * @return this <code>StringBuffer</code>
  473. * @throws StringIndexOutOfBoundsException if start or end are out of bounds
  474. * @since 1.2
  475. */
  476. public AbstractStringBuffer delete(int start, int end)
  477. {
  478. if (start < 0 || start > count || start > end)
  479. throw new StringIndexOutOfBoundsException(start);
  480. if (end > count)
  481. end = count;
  482. ensureCapacity_unsynchronized(count);
  483. if (count - end != 0)
  484. VMSystem.arraycopy(value, end, value, start, count - end);
  485. count -= end - start;
  486. return this;
  487. }
  488. /**
  489. * Delete a character from this <code>StringBuffer</code>.
  490. *
  491. * @param index the index of the character to delete
  492. * @return this <code>StringBuffer</code>
  493. * @throws StringIndexOutOfBoundsException if index is out of bounds
  494. * @since 1.2
  495. */
  496. public AbstractStringBuffer deleteCharAt(int index)
  497. {
  498. return delete(index, index + 1);
  499. }
  500. /**
  501. * Replace characters between index <code>start</code> (inclusive) and
  502. * <code>end</code> (exclusive) with <code>str</code>. If <code>end</code>
  503. * is larger than the size of this StringBuffer, all characters after
  504. * <code>start</code> are replaced.
  505. *
  506. * @param start the beginning index of characters to delete (inclusive)
  507. * @param end the ending index of characters to delete (exclusive)
  508. * @param str the new <code>String</code> to insert
  509. * @return this <code>StringBuffer</code>
  510. * @throws StringIndexOutOfBoundsException if start or end are out of bounds
  511. * @throws NullPointerException if str is null
  512. * @since 1.2
  513. */
  514. public AbstractStringBuffer replace(int start, int end, String str)
  515. {
  516. if (start < 0 || start > count || start > end)
  517. throw new StringIndexOutOfBoundsException(start);
  518. int len = str.count;
  519. // Calculate the difference in 'count' after the replace.
  520. int delta = len - (end > count ? count : end) + start;
  521. ensureCapacity_unsynchronized(count + delta);
  522. if (delta != 0 && end < count)
  523. VMSystem.arraycopy(value, end, value, end + delta, count - end);
  524. str.getChars(0, len, value, start);
  525. count += delta;
  526. return this;
  527. }
  528. /**
  529. * Insert a subarray of the <code>char[]</code> argument into this
  530. * <code>StringBuffer</code>.
  531. *
  532. * @param offset the place to insert in this buffer
  533. * @param str the <code>char[]</code> to insert
  534. * @param str_offset the index in <code>str</code> to start inserting from
  535. * @param len the number of characters to insert
  536. * @return this <code>StringBuffer</code>
  537. * @throws NullPointerException if <code>str</code> is <code>null</code>
  538. * @throws StringIndexOutOfBoundsException if any index is out of bounds
  539. * @since 1.2
  540. */
  541. public AbstractStringBuffer insert(int offset, char[] str, int str_offset, int len)
  542. {
  543. if (offset < 0 || offset > count || len < 0
  544. || str_offset < 0 || str_offset > str.length - len)
  545. throw new StringIndexOutOfBoundsException();
  546. ensureCapacity_unsynchronized(count + len);
  547. VMSystem.arraycopy(value, offset, value, offset + len, count - offset);
  548. VMSystem.arraycopy(str, str_offset, value, offset, len);
  549. count += len;
  550. return this;
  551. }
  552. /**
  553. * Insert the <code>String</code> value of the argument into this
  554. * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
  555. * to <code>String</code>.
  556. *
  557. * @param offset the place to insert in this buffer
  558. * @param obj the <code>Object</code> to convert and insert
  559. * @return this <code>StringBuffer</code>
  560. * @exception StringIndexOutOfBoundsException if offset is out of bounds
  561. * @see String#valueOf(Object)
  562. */
  563. public AbstractStringBuffer insert(int offset, Object obj)
  564. {
  565. return insert(offset, obj == null ? "null" : obj.toString());
  566. }
  567. /**
  568. * Insert the <code>String</code> argument into this
  569. * <code>StringBuffer</code>. If str is null, the String "null" is used
  570. * instead.
  571. *
  572. * @param offset the place to insert in this buffer
  573. * @param str the <code>String</code> to insert
  574. * @return this <code>StringBuffer</code>
  575. * @throws StringIndexOutOfBoundsException if offset is out of bounds
  576. */
  577. public AbstractStringBuffer insert(int offset, String str)
  578. {
  579. if (offset < 0 || offset > count)
  580. throw new StringIndexOutOfBoundsException(offset);
  581. if (str == null)
  582. str = "null";
  583. int len = str.count;
  584. ensureCapacity_unsynchronized(count + len);
  585. VMSystem.arraycopy(value, offset, value, offset + len, count - offset);
  586. str.getChars(0, len, value, offset);
  587. count += len;
  588. return this;
  589. }
  590. /**
  591. * Insert the <code>CharSequence</code> argument into this
  592. * <code>StringBuffer</code>. If the sequence is null, the String
  593. * "null" is used instead.
  594. *
  595. * @param offset the place to insert in this buffer
  596. * @param sequence the <code>CharSequence</code> to insert
  597. * @return this <code>StringBuffer</code>
  598. * @throws IndexOutOfBoundsException if offset is out of bounds
  599. * @since 1.5
  600. */
  601. public AbstractStringBuffer insert(int offset, CharSequence sequence)
  602. {
  603. if (sequence == null)
  604. sequence = "null";
  605. return insert(offset, sequence, 0, sequence.length());
  606. }
  607. /**
  608. * Insert a subsequence of the <code>CharSequence</code> argument into this
  609. * <code>StringBuffer</code>. If the sequence is null, the String
  610. * "null" is used instead.
  611. *
  612. * @param offset the place to insert in this buffer
  613. * @param sequence the <code>CharSequence</code> to insert
  614. * @param start the starting index of the subsequence
  615. * @param end one past the ending index of the subsequence
  616. * @return this <code>StringBuffer</code>
  617. * @throws IndexOutOfBoundsException if offset, start,
  618. * or end are out of bounds
  619. * @since 1.5
  620. */
  621. public AbstractStringBuffer insert(int offset, CharSequence sequence, int start, int end)
  622. {
  623. if (sequence == null)
  624. sequence = "null";
  625. if (start < 0 || end < 0 || start > end || end > sequence.length())
  626. throw new IndexOutOfBoundsException();
  627. int len = end - start;
  628. ensureCapacity_unsynchronized(count + len);
  629. VMSystem.arraycopy(value, offset, value, offset + len, count - offset);
  630. for (int i = start; i < end; ++i)
  631. value[offset++] = sequence.charAt(i);
  632. count += len;
  633. return this;
  634. }
  635. /**
  636. * Insert the <code>char[]</code> argument into this
  637. * <code>StringBuffer</code>.
  638. *
  639. * @param offset the place to insert in this buffer
  640. * @param data the <code>char[]</code> to insert
  641. * @return this <code>StringBuffer</code>
  642. * @throws NullPointerException if <code>data</code> is <code>null</code>
  643. * @throws StringIndexOutOfBoundsException if offset is out of bounds
  644. * @see #insert(int, char[], int, int)
  645. */
  646. public AbstractStringBuffer insert(int offset, char[] data)
  647. {
  648. return insert(offset, data, 0, data.length);
  649. }
  650. /**
  651. * Insert the <code>String</code> value of the argument into this
  652. * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
  653. * to <code>String</code>.
  654. *
  655. * @param offset the place to insert in this buffer
  656. * @param bool the <code>boolean</code> to convert and insert
  657. * @return this <code>StringBuffer</code>
  658. * @throws StringIndexOutOfBoundsException if offset is out of bounds
  659. * @see String#valueOf(boolean)
  660. */
  661. public AbstractStringBuffer insert(int offset, boolean bool)
  662. {
  663. return insert(offset, bool ? "true" : "false");
  664. }
  665. /**
  666. * Insert the <code>char</code> argument into this <code>StringBuffer</code>.
  667. *
  668. * @param offset the place to insert in this buffer
  669. * @param ch the <code>char</code> to insert
  670. * @return this <code>StringBuffer</code>
  671. * @throws StringIndexOutOfBoundsException if offset is out of bounds
  672. */
  673. public AbstractStringBuffer insert(int offset, char ch)
  674. {
  675. if (offset < 0 || offset > count)
  676. throw new StringIndexOutOfBoundsException(offset);
  677. ensureCapacity_unsynchronized(count + 1);
  678. VMSystem.arraycopy(value, offset, value, offset + 1, count - offset);
  679. value[offset] = ch;
  680. count++;
  681. return this;
  682. }
  683. /**
  684. * Insert the <code>String</code> value of the argument into this
  685. * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
  686. * to <code>String</code>.
  687. *
  688. * @param offset the place to insert in this buffer
  689. * @param inum the <code>int</code> to convert and insert
  690. * @return this <code>StringBuffer</code>
  691. * @throws StringIndexOutOfBoundsException if offset is out of bounds
  692. * @see String#valueOf(int)
  693. */
  694. public AbstractStringBuffer insert(int offset, int inum)
  695. {
  696. return insert(offset, String.valueOf(inum));
  697. }
  698. /**
  699. * Insert the <code>String</code> value of the argument into this
  700. * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
  701. * to <code>String</code>.
  702. *
  703. * @param offset the place to insert in this buffer
  704. * @param lnum the <code>long</code> to convert and insert
  705. * @return this <code>StringBuffer</code>
  706. * @throws StringIndexOutOfBoundsException if offset is out of bounds
  707. * @see String#valueOf(long)
  708. */
  709. public AbstractStringBuffer insert(int offset, long lnum)
  710. {
  711. return insert(offset, Long.toString(lnum, 10));
  712. }
  713. /**
  714. * Insert the <code>String</code> value of the argument into this
  715. * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
  716. * to <code>String</code>.
  717. *
  718. * @param offset the place to insert in this buffer
  719. * @param fnum the <code>float</code> to convert and insert
  720. * @return this <code>StringBuffer</code>
  721. * @throws StringIndexOutOfBoundsException if offset is out of bounds
  722. * @see String#valueOf(float)
  723. */
  724. public AbstractStringBuffer insert(int offset, float fnum)
  725. {
  726. return insert(offset, Float.toString(fnum));
  727. }
  728. /**
  729. * Insert the <code>String</code> value of the argument into this
  730. * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
  731. * to <code>String</code>.
  732. *
  733. * @param offset the place to insert in this buffer
  734. * @param dnum the <code>double</code> to convert and insert
  735. * @return this <code>StringBuffer</code>
  736. * @throws StringIndexOutOfBoundsException if offset is out of bounds
  737. * @see String#valueOf(double)
  738. */
  739. public AbstractStringBuffer insert(int offset, double dnum)
  740. {
  741. return insert(offset, Double.toString(dnum));
  742. }
  743. /**
  744. * Finds the first instance of a substring in this StringBuilder.
  745. *
  746. * @param str String to find
  747. * @return location (base 0) of the String, or -1 if not found
  748. * @throws NullPointerException if str is null
  749. * @see #indexOf(String, int)
  750. */
  751. public int indexOf(String str)
  752. {
  753. return indexOf(str, 0);
  754. }
  755. /**
  756. * Finds the first instance of a String in this StringBuffer, starting at
  757. * a given index. If starting index is less than 0, the search starts at
  758. * the beginning of this String. If the starting index is greater than the
  759. * length of this String, or the substring is not found, -1 is returned.
  760. *
  761. * @param str String to find
  762. * @param fromIndex index to start the search
  763. * @return location (base 0) of the String, or -1 if not found
  764. * @throws NullPointerException if str is null
  765. * @since 1.4
  766. */
  767. public int indexOf(String str, int fromIndex)
  768. {
  769. if (fromIndex < 0)
  770. fromIndex = 0;
  771. int limit = count - str.count;
  772. for ( ; fromIndex <= limit; fromIndex++)
  773. if (regionMatches(fromIndex, str))
  774. return fromIndex;
  775. return -1;
  776. }
  777. /**
  778. * Finds the last instance of a substring in this StringBuffer.
  779. *
  780. * @param str String to find
  781. * @return location (base 0) of the String, or -1 if not found
  782. * @throws NullPointerException if str is null
  783. * @see #lastIndexOf(String, int)
  784. * @since 1.4
  785. */
  786. public int lastIndexOf(String str)
  787. {
  788. return lastIndexOf(str, count - str.count);
  789. }
  790. /**
  791. * Finds the last instance of a String in this StringBuffer, starting at a
  792. * given index. If starting index is greater than the maximum valid index,
  793. * then the search begins at the end of this String. If the starting index
  794. * is less than zero, or the substring is not found, -1 is returned.
  795. *
  796. * @param str String to find
  797. * @param fromIndex index to start the search
  798. * @return location (base 0) of the String, or -1 if not found
  799. * @throws NullPointerException if str is null
  800. * @since 1.4
  801. */
  802. public int lastIndexOf(String str, int fromIndex)
  803. {
  804. fromIndex = Math.min(fromIndex, count - str.count);
  805. for ( ; fromIndex >= 0; fromIndex--)
  806. if (regionMatches(fromIndex, str))
  807. return fromIndex;
  808. return -1;
  809. }
  810. /**
  811. * Reverse the characters in this StringBuffer. The same sequence of
  812. * characters exists, but in the reverse index ordering.
  813. *
  814. * @return this <code>StringBuffer</code>
  815. */
  816. public AbstractStringBuffer reverse()
  817. {
  818. // Call ensureCapacity to enforce copy-on-write.
  819. ensureCapacity_unsynchronized(count);
  820. for (int i = count >> 1, j = count - i; --i >= 0; ++j)
  821. {
  822. char c = value[i];
  823. value[i] = value[j];
  824. value[j] = c;
  825. }
  826. return this;
  827. }
  828. /**
  829. * This may reduce the amount of memory used by the StringBuffer,
  830. * by resizing the internal array to remove unused space. However,
  831. * this method is not required to resize, so this behavior cannot
  832. * be relied upon.
  833. * @since 1.5
  834. */
  835. public void trimToSize()
  836. {
  837. int wouldSave = value.length - count;
  838. // Some random heuristics: if we save less than 20 characters, who
  839. // cares.
  840. if (wouldSave < 20)
  841. return;
  842. // If we save more than 200 characters, shrink.
  843. // If we save more than 1/4 of the buffer, shrink.
  844. if (wouldSave > 200 || wouldSave * 4 > value.length)
  845. {
  846. char[] newValue = new char[count];
  847. VMSystem.arraycopy(value, 0, newValue, 0, count);
  848. value = newValue;
  849. }
  850. }
  851. /**
  852. * Return the number of code points between two indices in the
  853. * <code>StringBuffer</code>. An unpaired surrogate counts as a
  854. * code point for this purpose. Characters outside the indicated
  855. * range are not examined, even if the range ends in the middle of a
  856. * surrogate pair.
  857. *
  858. * @param start the starting index
  859. * @param end one past the ending index
  860. * @return the number of code points
  861. * @since 1.5
  862. */
  863. public int codePointCount(int start, int end)
  864. {
  865. if (start < 0 || end >= count || start > end)
  866. throw new StringIndexOutOfBoundsException();
  867. int count = 0;
  868. while (start < end)
  869. {
  870. char base = value[start];
  871. if (base < Character.MIN_HIGH_SURROGATE
  872. || base > Character.MAX_HIGH_SURROGATE
  873. || start == end
  874. || start == count
  875. || value[start + 1] < Character.MIN_LOW_SURROGATE
  876. || value[start + 1] > Character.MAX_LOW_SURROGATE)
  877. {
  878. // Nothing.
  879. }
  880. else
  881. {
  882. // Surrogate pair.
  883. ++start;
  884. }
  885. ++start;
  886. ++count;
  887. }
  888. return count;
  889. }
  890. /**
  891. * Starting at the given index, this counts forward by the indicated
  892. * number of code points, and then returns the resulting index. An
  893. * unpaired surrogate counts as a single code point for this
  894. * purpose.
  895. *
  896. * @param start the starting index
  897. * @param codePoints the number of code points
  898. * @return the resulting index
  899. * @since 1.5
  900. */
  901. public int offsetByCodePoints(int start, int codePoints)
  902. {
  903. while (codePoints > 0)
  904. {
  905. char base = value[start];
  906. if (base < Character.MIN_HIGH_SURROGATE
  907. || base > Character.MAX_HIGH_SURROGATE
  908. || start == count
  909. || value[start + 1] < Character.MIN_LOW_SURROGATE
  910. || value[start + 1] > Character.MAX_LOW_SURROGATE)
  911. {
  912. // Nothing.
  913. }
  914. else
  915. {
  916. // Surrogate pair.
  917. ++start;
  918. }
  919. ++start;
  920. --codePoints;
  921. }
  922. return start;
  923. }
  924. /**
  925. * Increase the capacity of this <code>StringBuilder</code>. This will
  926. * ensure that an expensive growing operation will not occur until
  927. * <code>minimumCapacity</code> is reached. The buffer is grown to the
  928. * larger of <code>minimumCapacity</code> and
  929. * <code>capacity() * 2 + 2</code>, if it is not already large enough.
  930. *
  931. * @param minimumCapacity the new capacity
  932. * @see #capacity()
  933. */
  934. void ensureCapacity_unsynchronized(int minimumCapacity)
  935. {
  936. if (minimumCapacity > value.length)
  937. {
  938. int max = value.length * 2 + 2;
  939. minimumCapacity = (minimumCapacity < max ? max : minimumCapacity);
  940. char[] nb = new char[minimumCapacity];
  941. VMSystem.arraycopy(value, 0, nb, 0, count);
  942. value = nb;
  943. }
  944. }
  945. /**
  946. * Predicate which determines if a substring of this matches another String
  947. * starting at a specified offset for each String and continuing for a
  948. * specified length. This is more efficient than creating a String to call
  949. * indexOf on.
  950. *
  951. * @param toffset index to start comparison at for this String
  952. * @param other non-null String to compare to region of this
  953. * @return true if regions match, false otherwise
  954. * @see #indexOf(String, int)
  955. * @see #lastIndexOf(String, int)
  956. * @see String#regionMatches(boolean, int, String, int, int)
  957. */
  958. private boolean regionMatches(int toffset, String other)
  959. {
  960. int len = other.count;
  961. int index = other.offset;
  962. while (--len >= 0)
  963. if (value[toffset++] != other.value[index++])
  964. return false;
  965. return true;
  966. }
  967. }