/modules/core/petra/petra-string/src/main/java/com/liferay/petra/string/StringBundler.java

https://github.com/kiyoshilee/liferay-portal · Java · 361 lines · 249 code · 90 blank · 22 comment · 64 complexity · 8ea87afab8df488544dd427836de098f MD5 · raw file

  1. /**
  2. * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
  3. *
  4. * This library is free software; you can redistribute it and/or modify it under
  5. * the terms of the GNU Lesser General Public License as published by the Free
  6. * Software Foundation; either version 2.1 of the License, or (at your option)
  7. * any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  12. * details.
  13. */
  14. package com.liferay.petra.string;
  15. import com.liferay.petra.lang.CentralizedThreadLocal;
  16. import java.io.IOException;
  17. import java.io.Serializable;
  18. import java.io.Writer;
  19. import java.lang.ref.Reference;
  20. import java.lang.ref.SoftReference;
  21. /**
  22. * <p>
  23. * See https://issues.liferay.com/browse/LPS-6072.
  24. * </p>
  25. *
  26. * @author Shuyang Zhou
  27. * @author Brian Wing Shun Chan
  28. * @author Preston Crary
  29. */
  30. public class StringBundler implements Serializable {
  31. public static String concat(Object... objects) {
  32. String[] strings = new String[objects.length];
  33. for (int i = 0; i < objects.length; i++) {
  34. strings[i] = String.valueOf(objects[i]);
  35. }
  36. return _toString(strings, strings.length);
  37. }
  38. public static String concat(String... strings) {
  39. for (int i = 0; i < strings.length; i++) {
  40. if (strings[i] == null) {
  41. strings[i] = StringPool.NULL;
  42. }
  43. }
  44. return _toString(strings, strings.length);
  45. }
  46. public StringBundler() {
  47. _array = new String[_DEFAULT_ARRAY_CAPACITY];
  48. }
  49. public StringBundler(int initialCapacity) {
  50. if (initialCapacity <= 0) {
  51. initialCapacity = _DEFAULT_ARRAY_CAPACITY;
  52. }
  53. _array = new String[initialCapacity];
  54. }
  55. public StringBundler(String s) {
  56. _array = new String[_DEFAULT_ARRAY_CAPACITY];
  57. _array[0] = s;
  58. _arrayIndex = 1;
  59. }
  60. public StringBundler(String[] stringArray) {
  61. this(stringArray, 0);
  62. }
  63. public StringBundler(String[] stringArray, int extraSpace) {
  64. _array = new String[stringArray.length + extraSpace];
  65. for (String s : stringArray) {
  66. if ((s != null) && (s.length() > 0)) {
  67. _array[_arrayIndex++] = s;
  68. }
  69. }
  70. }
  71. public StringBundler append(boolean b) {
  72. if (b) {
  73. return append(StringPool.TRUE);
  74. }
  75. return append(StringPool.FALSE);
  76. }
  77. public StringBundler append(char c) {
  78. return append(String.valueOf(c));
  79. }
  80. public StringBundler append(char[] chars) {
  81. if (chars == null) {
  82. return append("null");
  83. }
  84. return append(new String(chars));
  85. }
  86. public StringBundler append(double d) {
  87. return append(String.valueOf(d));
  88. }
  89. public StringBundler append(float f) {
  90. return append(String.valueOf(f));
  91. }
  92. public StringBundler append(int i) {
  93. return append(String.valueOf(i));
  94. }
  95. public StringBundler append(long l) {
  96. return append(String.valueOf(l));
  97. }
  98. public StringBundler append(Object obj) {
  99. return append(String.valueOf(obj));
  100. }
  101. public StringBundler append(String s) {
  102. if (s == null) {
  103. s = StringPool.NULL;
  104. }
  105. if (s.length() == 0) {
  106. return this;
  107. }
  108. if (_arrayIndex >= _array.length) {
  109. expandCapacity(_array.length * 2);
  110. }
  111. _array[_arrayIndex++] = s;
  112. return this;
  113. }
  114. public StringBundler append(String[] stringArray) {
  115. if ((stringArray == null) || (stringArray.length == 0)) {
  116. return this;
  117. }
  118. if ((_array.length - _arrayIndex) < stringArray.length) {
  119. expandCapacity((_array.length + stringArray.length) * 2);
  120. }
  121. for (String s : stringArray) {
  122. if ((s != null) && (s.length() > 0)) {
  123. _array[_arrayIndex++] = s;
  124. }
  125. }
  126. return this;
  127. }
  128. public StringBundler append(StringBundler sb) {
  129. if ((sb == null) || (sb._arrayIndex == 0)) {
  130. return this;
  131. }
  132. if ((_array.length - _arrayIndex) < sb._arrayIndex) {
  133. expandCapacity((_array.length + sb._arrayIndex) * 2);
  134. }
  135. System.arraycopy(sb._array, 0, _array, _arrayIndex, sb._arrayIndex);
  136. _arrayIndex += sb._arrayIndex;
  137. return this;
  138. }
  139. public int capacity() {
  140. return _array.length;
  141. }
  142. public String[] getStrings() {
  143. return _array;
  144. }
  145. public int index() {
  146. return _arrayIndex;
  147. }
  148. public int length() {
  149. int length = 0;
  150. for (int i = 0; i < _arrayIndex; i++) {
  151. length += _array[i].length();
  152. }
  153. return length;
  154. }
  155. public void setIndex(int newIndex) {
  156. if (newIndex < 0) {
  157. throw new ArrayIndexOutOfBoundsException(newIndex);
  158. }
  159. if (newIndex > _array.length) {
  160. String[] newArray = new String[newIndex];
  161. System.arraycopy(_array, 0, newArray, 0, _arrayIndex);
  162. _array = newArray;
  163. }
  164. if (_arrayIndex < newIndex) {
  165. for (int i = _arrayIndex; i < newIndex; i++) {
  166. _array[i] = StringPool.BLANK;
  167. }
  168. }
  169. if (_arrayIndex > newIndex) {
  170. for (int i = newIndex; i < _arrayIndex; i++) {
  171. _array[i] = null;
  172. }
  173. }
  174. _arrayIndex = newIndex;
  175. }
  176. public void setStringAt(String s, int index) {
  177. if ((index < 0) || (index >= _arrayIndex)) {
  178. throw new ArrayIndexOutOfBoundsException(index);
  179. }
  180. _array[index] = s;
  181. }
  182. public String stringAt(int index) {
  183. if ((index < 0) || (index >= _arrayIndex)) {
  184. throw new ArrayIndexOutOfBoundsException(index);
  185. }
  186. return _array[index];
  187. }
  188. @Override
  189. public String toString() {
  190. return _toString(_array, _arrayIndex);
  191. }
  192. public void writeTo(Writer writer) throws IOException {
  193. for (int i = 0; i < _arrayIndex; i++) {
  194. writer.write(_array[i]);
  195. }
  196. }
  197. protected void expandCapacity(int newCapacity) {
  198. String[] newArray = new String[newCapacity];
  199. System.arraycopy(_array, 0, newArray, 0, _arrayIndex);
  200. _array = newArray;
  201. }
  202. private static String _toString(String[] array, int arrayIndex) {
  203. if (arrayIndex == 0) {
  204. return StringPool.BLANK;
  205. }
  206. if (arrayIndex == 1) {
  207. return array[0];
  208. }
  209. if (arrayIndex == 2) {
  210. return array[0].concat(array[1]);
  211. }
  212. if (arrayIndex == 3) {
  213. if (array[0].length() < array[2].length()) {
  214. return array[0].concat(
  215. array[1]
  216. ).concat(
  217. array[2]
  218. );
  219. }
  220. return array[0].concat(array[1].concat(array[2]));
  221. }
  222. int length = 0;
  223. for (int i = 0; i < arrayIndex; i++) {
  224. length += array[i].length();
  225. }
  226. StringBuilder sb = null;
  227. if (length > _THREAD_LOCAL_BUFFER_LIMIT) {
  228. Reference<StringBuilder> reference =
  229. _stringBuilderThreadLocal.get();
  230. if (reference != null) {
  231. sb = reference.get();
  232. }
  233. if (sb == null) {
  234. sb = new StringBuilder(length);
  235. _stringBuilderThreadLocal.set(new SoftReference<>(sb));
  236. }
  237. else if (sb.capacity() < length) {
  238. sb.setLength(length);
  239. }
  240. sb.setLength(0);
  241. }
  242. else {
  243. sb = new StringBuilder(length);
  244. }
  245. for (int i = 0; i < arrayIndex; i++) {
  246. sb.append(array[i]);
  247. }
  248. return sb.toString();
  249. }
  250. private static final int _DEFAULT_ARRAY_CAPACITY = 16;
  251. private static final int _THREAD_LOCAL_BUFFER_LIMIT;
  252. private static final ThreadLocal<Reference<StringBuilder>>
  253. _stringBuilderThreadLocal;
  254. private static final long serialVersionUID = 1L;
  255. static {
  256. int threadLocalBufferLimit = Integer.getInteger(
  257. StringBundler.class.getName() + ".threadlocal.buffer.limit",
  258. Integer.MAX_VALUE);
  259. if ((threadLocalBufferLimit > 0) &&
  260. (threadLocalBufferLimit < Integer.MAX_VALUE)) {
  261. _THREAD_LOCAL_BUFFER_LIMIT = threadLocalBufferLimit;
  262. _stringBuilderThreadLocal = new CentralizedThreadLocal<>(false);
  263. }
  264. else {
  265. _THREAD_LOCAL_BUFFER_LIMIT = Integer.MAX_VALUE;
  266. _stringBuilderThreadLocal = null;
  267. }
  268. }
  269. private String[] _array;
  270. private int _arrayIndex;
  271. }