001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2000,2008 Oracle. All rights reserved.
005: *
006: * $Id: FastOutputStream.java,v 1.21.2.2 2008/01/07 15:14:21 cwl Exp $
007: */
008:
009: package com.sleepycat.util;
010:
011: import java.io.IOException;
012: import java.io.OutputStream;
013: import java.io.UnsupportedEncodingException;
014:
015: /**
016: * A replacement for ByteArrayOutputStream that does not synchronize every
017: * byte read.
018: *
019: * <p>This class extends {@link OutputStream} and its <code>write()</code>
020: * methods allow it to be used as a standard output stream. In addition, it
021: * provides <code>writeFast()</code> methods that are not declared to throw
022: * <code>IOException</code>. <code>IOException</code> is never thrown by this
023: * class.</p>
024: *
025: * @author Mark Hayes
026: */
027: public class FastOutputStream extends OutputStream {
028:
029: /**
030: * The default initial size of the buffer if no initialSize parameter is
031: * specified. This constant is 100 bytes.
032: */
033: public static final int DEFAULT_INIT_SIZE = 100;
034:
035: /**
036: * The default amount that the buffer is increased when it is full. This
037: * constant is zero, which means to double the current buffer size.
038: */
039: public static final int DEFAULT_BUMP_SIZE = 0;
040:
041: private int len;
042: private int bumpLen;
043: private byte[] buf;
044:
045: /*
046: * We can return the same byte[] for 0 length arrays.
047: */
048: private static byte[] ZERO_LENGTH_BYTE_ARRAY = new byte[0];
049:
050: /**
051: * Creates an output stream with default sizes.
052: */
053: public FastOutputStream() {
054:
055: initBuffer(DEFAULT_INIT_SIZE, DEFAULT_BUMP_SIZE);
056: }
057:
058: /**
059: * Creates an output stream with a default bump size and a given initial
060: * size.
061: *
062: * @param initialSize the initial size of the buffer.
063: */
064: public FastOutputStream(int initialSize) {
065:
066: initBuffer(initialSize, DEFAULT_BUMP_SIZE);
067: }
068:
069: /**
070: * Creates an output stream with a given bump size and initial size.
071: *
072: * @param initialSize the initial size of the buffer.
073: *
074: * @param bumpSize the amount to increment the buffer.
075: */
076: public FastOutputStream(int initialSize, int bumpSize) {
077:
078: initBuffer(initialSize, bumpSize);
079: }
080:
081: /**
082: * Creates an output stream with a given initial buffer and a default
083: * bump size.
084: *
085: * @param buffer the initial buffer; will be owned by this object.
086: */
087: public FastOutputStream(byte[] buffer) {
088:
089: buf = buffer;
090: bumpLen = DEFAULT_BUMP_SIZE;
091: }
092:
093: /**
094: * Creates an output stream with a given initial buffer and a given
095: * bump size.
096: *
097: * @param buffer the initial buffer; will be owned by this object.
098: *
099: * @param bumpSize the amount to increment the buffer. If zero (the
100: * default), the current buffer size will be doubled when the buffer is
101: * full.
102: */
103: public FastOutputStream(byte[] buffer, int bumpSize) {
104:
105: buf = buffer;
106: bumpLen = bumpSize;
107: }
108:
109: private void initBuffer(int bufferSize, int bumpLen) {
110: buf = new byte[bufferSize];
111: this .bumpLen = bumpLen;
112: }
113:
114: // --- begin ByteArrayOutputStream compatible methods ---
115:
116: public int size() {
117:
118: return len;
119: }
120:
121: public void reset() {
122:
123: len = 0;
124: }
125:
126: public void write(int b) throws IOException {
127:
128: writeFast(b);
129: }
130:
131: public void write(byte[] fromBuf) throws IOException {
132:
133: writeFast(fromBuf);
134: }
135:
136: public void write(byte[] fromBuf, int offset, int length)
137: throws IOException {
138:
139: writeFast(fromBuf, offset, length);
140: }
141:
142: public void writeTo(OutputStream out) throws IOException {
143:
144: out.write(buf, 0, len);
145: }
146:
147: public String toString() {
148:
149: return new String(buf, 0, len);
150: }
151:
152: public String toString(String encoding)
153: throws UnsupportedEncodingException {
154:
155: return new String(buf, 0, len, encoding);
156: }
157:
158: public byte[] toByteArray() {
159:
160: if (len == 0) {
161: return ZERO_LENGTH_BYTE_ARRAY;
162: } else {
163: byte[] toBuf = new byte[len];
164: System.arraycopy(buf, 0, toBuf, 0, len);
165:
166: return toBuf;
167: }
168: }
169:
170: // --- end ByteArrayOutputStream compatible methods ---
171:
172: /**
173: * Equivalent to <code>write(int)<code> but does not throw
174: * <code>IOException</code>.
175: * @see #write(int)
176: */
177: public final void writeFast(int b) {
178:
179: if (len + 1 > buf.length)
180: bump(1);
181:
182: buf[len++] = (byte) b;
183: }
184:
185: /**
186: * Equivalent to <code>write(byte[])<code> but does not throw
187: * <code>IOException</code>.
188: * @see #write(byte[])
189: */
190: public final void writeFast(byte[] fromBuf) {
191:
192: int needed = len + fromBuf.length - buf.length;
193: if (needed > 0)
194: bump(needed);
195:
196: System.arraycopy(fromBuf, 0, buf, len, fromBuf.length);
197: len += fromBuf.length;
198: }
199:
200: /**
201: * Equivalent to <code>write(byte[],int,int)<code> but does not throw
202: * <code>IOException</code>.
203: * @see #write(byte[],int,int)
204: */
205: public final void writeFast(byte[] fromBuf, int offset, int length) {
206:
207: int needed = len + length - buf.length;
208: if (needed > 0)
209: bump(needed);
210:
211: System.arraycopy(fromBuf, offset, buf, len, length);
212: len += length;
213: }
214:
215: /**
216: * Returns the buffer owned by this object.
217: *
218: * @return the buffer.
219: */
220: public byte[] getBufferBytes() {
221:
222: return buf;
223: }
224:
225: /**
226: * Returns the offset of the internal buffer.
227: *
228: * @return always zero currently.
229: */
230: public int getBufferOffset() {
231:
232: return 0;
233: }
234:
235: /**
236: * Returns the length used in the internal buffer, i.e., the offset at
237: * which data will be written next.
238: *
239: * @return the buffer length.
240: */
241: public int getBufferLength() {
242:
243: return len;
244: }
245:
246: /**
247: * Ensure that at least the given number of bytes are available in the
248: * internal buffer.
249: *
250: * @param sizeNeeded the number of bytes desired.
251: */
252: public void makeSpace(int sizeNeeded) {
253:
254: int needed = len + sizeNeeded - buf.length;
255: if (needed > 0)
256: bump(needed);
257: }
258:
259: /**
260: * Skip the given number of bytes in the buffer.
261: *
262: * @param sizeAdded number of bytes to skip.
263: */
264: public void addSize(int sizeAdded) {
265:
266: len += sizeAdded;
267: }
268:
269: private void bump(int needed) {
270:
271: /* Double the buffer if the bumpLen is zero. */
272: int bump = (bumpLen > 0) ? bumpLen : buf.length;
273:
274: byte[] toBuf = new byte[buf.length + needed + bump];
275:
276: System.arraycopy(buf, 0, toBuf, 0, len);
277:
278: buf = toBuf;
279: }
280: }
|