Skip to content

Commit adaccbc

Browse files
author
Ortwin Glueck
committed
This patch reduces the amount of intermediate garbage significantly.
PR: SANDBOX-166 Contributed by: Ortwin Glück Reviewed by: Henri Yandell git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/sandbox/csv/trunk@430324 13f79535-47bb-0310-9956-ffa450edef68
1 parent d7e9458 commit adaccbc

2 files changed

Lines changed: 381 additions & 0 deletions

File tree

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/*
2+
* Copyright 2005 The Apache Software Foundation.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.apache.commons.csv;
17+
18+
/**
19+
* A simple StringBuffer replacement that aims to
20+
* reduce copying as much as possible. The buffer
21+
* grows as necessary.
22+
* This class is not thread safe.
23+
*
24+
* @author Ortwin Glück
25+
*/
26+
public class CharBuffer {
27+
private char[] c;
28+
/**
29+
* Actually used number of characters in the array.
30+
* It is also the index at which
31+
* a new character will be inserted into <code>c</code>.
32+
*/
33+
private int length;
34+
35+
/**
36+
* Creates a new CharBuffer with an initial capacity of 32 characters.
37+
*/
38+
public CharBuffer() {
39+
this(32);
40+
}
41+
42+
/**
43+
* Creates a new CharBuffer with an initial capacity
44+
* of <code>length</code> characters.
45+
*/
46+
public CharBuffer(final int length) {
47+
if (length == 0) throw new IllegalArgumentException("Can't create an empty CharBuffer");
48+
this.c = new char[length];
49+
}
50+
51+
/**
52+
* Empties the buffer. The capacity still remains the same, so no memory is freed.
53+
*/
54+
public void clear() {
55+
length = 0;
56+
}
57+
58+
/**
59+
* Returns the number of characters in the buffer.
60+
* @return the number of characters
61+
*/
62+
public int length() {
63+
return length;
64+
}
65+
66+
/**
67+
* Returns the current capacity of the buffer.
68+
* @return the maximum number of characters that can be stored in this buffer without
69+
* resizing it.
70+
*/
71+
public int capacity() {
72+
return c.length;
73+
}
74+
75+
/**
76+
* Appends the contents of <code>cb</code> to the end of this CharBuffer.
77+
* @param cb the CharBuffer to append or null
78+
*/
79+
public void append(final CharBuffer cb) {
80+
if (cb == null) return;
81+
provideCapacity(length + cb.length);
82+
System.arraycopy(cb.c, 0, c, length, cb.length);
83+
length += cb.length;
84+
}
85+
86+
/**
87+
* Appends <code>s</code> to the end of this CharBuffer.
88+
* This method involves copying the new data once!
89+
* @param s the String to append or null
90+
*/
91+
public void append(final String s) {
92+
if (s == null) return;
93+
append(s.toCharArray());
94+
}
95+
96+
/**
97+
* Appends <code>sb</code> to the end of this CharBuffer.
98+
* This method involves copying the new data once!
99+
* @param sb the StringBuffer to append or null
100+
*/
101+
public void append(final StringBuffer sb) {
102+
if (sb == null) return;
103+
provideCapacity(length + sb.length());
104+
sb.getChars(0, sb.length(), c, length);
105+
length += sb.length();
106+
}
107+
108+
/**
109+
* Appends <code>data</code> to the end of this CharBuffer.
110+
* This method involves copying the new data once!
111+
* @param data the char[] to append or null
112+
*/
113+
public void append(final char[] data) {
114+
if (data == null) return;
115+
provideCapacity(length + data.length);
116+
System.arraycopy(data, 0, c, length, data.length);
117+
length += data.length;
118+
}
119+
120+
/**
121+
* Appends a single character to the end of this CharBuffer.
122+
* This method involves copying the new data once!
123+
* @param data the char to append
124+
*/
125+
public void append(final char data) {
126+
provideCapacity(length + 1);
127+
c[length] = data;
128+
length++;
129+
}
130+
131+
/**
132+
* Shrinks the capacity of the buffer to the current length if necessary.
133+
* This method involves copying the data once!
134+
*/
135+
public void shrink() {
136+
if (c.length == length) return;
137+
char[] newc = new char[length];
138+
System.arraycopy(c, 0, newc, 0, length);
139+
c = newc;
140+
}
141+
142+
/**
143+
* Returns the contents of the buffer as a char[]. The returned array may
144+
* be the internal array of the buffer, so the caller must take care when
145+
* modifying it.
146+
* This method allows to avoid copying if the caller knows the exact capacity
147+
* before.
148+
* @return
149+
*/
150+
public char[] getCharacters() {
151+
if (c.length == length) return c;
152+
char[] chars = new char[length];
153+
System.arraycopy(c, 0, chars, 0, length);
154+
return chars;
155+
}
156+
157+
/**
158+
* Converts the contents of the buffer into a StringBuffer.
159+
* This method involves copying the new data once!
160+
* @return
161+
*/
162+
public StringBuffer toStringBuffer() {
163+
StringBuffer sb = new StringBuffer(length);
164+
sb.append(c, 0, length);
165+
return sb;
166+
}
167+
168+
/**
169+
* Converts the contents of the buffer into a StringBuffer.
170+
* This method involves copying the new data once!
171+
* @return
172+
*/
173+
public String toString() {
174+
return new String(c, 0, length);
175+
}
176+
177+
/**
178+
* Copies the data into a new array of at least <code>capacity</code> size.
179+
* @param capacity
180+
*/
181+
public void provideCapacity(final int capacity) {
182+
if (c.length >= capacity) return;
183+
int newcapacity = capacity;
184+
char[] newc = new char[newcapacity];
185+
System.arraycopy(c, 0, newc, 0, length);
186+
c = newc;
187+
}
188+
}
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
/*
2+
* Copyright 2005 The Apache Software Foundation.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.apache.commons.csv;
17+
18+
import junit.framework.TestCase;
19+
20+
/**
21+
*
22+
* @author Ortwin Glück
23+
*/
24+
public class CharBufferTest extends TestCase {
25+
public void testCreate() {
26+
CharBuffer cb = new CharBuffer();
27+
assertEquals(0, cb.length());
28+
try {
29+
cb = new CharBuffer(0);
30+
fail("Should not be possible");
31+
} catch(IllegalArgumentException e) {
32+
// expected
33+
}
34+
35+
cb = new CharBuffer(128);
36+
assertEquals(0, cb.length());
37+
}
38+
39+
public void testAppendChar() {
40+
CharBuffer cb = new CharBuffer(1);
41+
String expected = "";
42+
for (char c = 'a'; c < 'z'; c++) {
43+
cb.append(c);
44+
expected += c;
45+
assertEquals(expected, cb.toString());
46+
assertEquals(expected.length(), cb.length());
47+
}
48+
}
49+
50+
public void testAppendCharArray() {
51+
CharBuffer cb = new CharBuffer(1);
52+
char[] abcd = "abcd".toCharArray();
53+
String expected = "";
54+
for (int i=0; i<10; i++) {
55+
cb.append(abcd);
56+
expected += "abcd";
57+
assertEquals(expected, cb.toString());
58+
assertEquals(4*(i+1), cb.length());
59+
}
60+
}
61+
62+
public void testAppendString() {
63+
CharBuffer cb = new CharBuffer(1);
64+
String abcd = "abcd";
65+
String expected = "";
66+
for (int i=0; i<10; i++) {
67+
cb.append(abcd);
68+
expected += abcd;
69+
assertEquals(expected, cb.toString());
70+
assertEquals(4*(i+1), cb.length());
71+
}
72+
}
73+
74+
public void testAppendStringBuffer() {
75+
CharBuffer cb = new CharBuffer(1);
76+
StringBuffer abcd = new StringBuffer("abcd");
77+
String expected = "";
78+
for (int i=0; i<10; i++) {
79+
cb.append(abcd);
80+
expected += "abcd";
81+
assertEquals(expected, cb.toString());
82+
assertEquals(4*(i+1), cb.length());
83+
}
84+
}
85+
86+
public void testAppendCharBuffer() {
87+
CharBuffer cb = new CharBuffer(1);
88+
CharBuffer abcd = new CharBuffer(17);
89+
abcd.append("abcd");
90+
String expected = "";
91+
for (int i=0; i<10; i++) {
92+
cb.append(abcd);
93+
expected += "abcd";
94+
assertEquals(expected, cb.toString());
95+
assertEquals(4*(i+1), cb.length());
96+
}
97+
}
98+
99+
public void testShrink() {
100+
String data = "123456789012345678901234567890";
101+
102+
CharBuffer cb = new CharBuffer(data.length() + 100);
103+
assertEquals(data.length() + 100, cb.capacity());
104+
cb.append(data);
105+
assertEquals(data.length() + 100, cb.capacity());
106+
assertEquals(data.length(), cb.length());
107+
cb.shrink();
108+
assertEquals(data.length(), cb.capacity());
109+
assertEquals(data.length(), cb.length());
110+
assertEquals(data, cb.toString());
111+
}
112+
113+
//-- the following test cases have been adapted from the HttpComponents project
114+
//-- written by Oleg Kalnichevski
115+
116+
public void testSimpleAppend() throws Exception {
117+
CharBuffer buffer = new CharBuffer(16);
118+
assertEquals(16, buffer.capacity());
119+
assertEquals(0, buffer.length());
120+
char[] b1 = buffer.getCharacters();
121+
assertNotNull(b1);
122+
assertEquals(0, b1.length);
123+
assertEquals(0, buffer.length());
124+
125+
char[] tmp = new char[] { '1', '2', '3', '4'};
126+
buffer.append(tmp);
127+
assertEquals(16, buffer.capacity());
128+
assertEquals(4, buffer.length());
129+
130+
char[] b2 = buffer.getCharacters();
131+
assertNotNull(b2);
132+
assertEquals(4, b2.length);
133+
for (int i = 0; i < tmp.length; i++) {
134+
assertEquals(tmp[i], b2[i]);
135+
}
136+
assertEquals("1234", buffer.toString());
137+
138+
buffer.clear();
139+
assertEquals(16, buffer.capacity());
140+
assertEquals(0, buffer.length());
141+
}
142+
143+
public void testAppendString2() throws Exception {
144+
CharBuffer buffer = new CharBuffer(8);
145+
buffer.append("stuff");
146+
buffer.append(" and more stuff");
147+
assertEquals("stuff and more stuff", buffer.toString());
148+
}
149+
150+
public void testAppendNull() throws Exception {
151+
CharBuffer buffer = new CharBuffer(8);
152+
153+
buffer.append((StringBuffer)null);
154+
assertEquals("", buffer.toString());
155+
156+
buffer.append((String)null);
157+
assertEquals("", buffer.toString());
158+
159+
buffer.append((CharBuffer)null);
160+
assertEquals("", buffer.toString());
161+
162+
buffer.append((char[])null);
163+
assertEquals("", buffer.toString());
164+
}
165+
166+
public void testAppendCharArrayBuffer() throws Exception {
167+
CharBuffer buffer1 = new CharBuffer(8);
168+
buffer1.append(" and more stuff");
169+
CharBuffer buffer2 = new CharBuffer(8);
170+
buffer2.append("stuff");
171+
buffer2.append(buffer1);
172+
assertEquals("stuff and more stuff", buffer2.toString());
173+
}
174+
175+
public void testAppendSingleChar() throws Exception {
176+
CharBuffer buffer = new CharBuffer(4);
177+
buffer.append('1');
178+
buffer.append('2');
179+
buffer.append('3');
180+
buffer.append('4');
181+
buffer.append('5');
182+
buffer.append('6');
183+
assertEquals("123456", buffer.toString());
184+
}
185+
186+
public void testProvideCapacity() throws Exception {
187+
CharBuffer buffer = new CharBuffer(4);
188+
buffer.provideCapacity(2);
189+
assertEquals(4, buffer.capacity());
190+
buffer.provideCapacity(8);
191+
assertTrue(buffer.capacity() >= 8);
192+
}
193+
}

0 commit comments

Comments
 (0)