1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2000,2008 Oracle. All rights reserved. 5 * 6 * $Id: FastOutputStream.java,v 12.8 2008/01/08 20:58:39 bostic Exp $ 7 */ 8 9package com.sleepycat.util; 10 11import java.io.IOException; 12import java.io.OutputStream; 13import java.io.UnsupportedEncodingException; 14 15/** 16 * A replacement for ByteArrayOutputStream that does not synchronize every 17 * byte read. 18 * 19 * <p>This class extends {@link OutputStream} and its <code>write()</code> 20 * methods allow it to be used as a standard output stream. In addition, it 21 * provides <code>writeFast()</code> methods that are not declared to throw 22 * <code>IOException</code>. <code>IOException</code> is never thrown by this 23 * class.</p> 24 * 25 * @author Mark Hayes 26 */ 27public class FastOutputStream extends OutputStream { 28 29 /** 30 * The default initial size of the buffer if no initialSize parameter is 31 * specified. This constant is 100 bytes. 32 */ 33 public static final int DEFAULT_INIT_SIZE = 100; 34 35 /** 36 * The default amount that the buffer is increased when it is full. This 37 * constant is zero, which means to double the current buffer size. 38 */ 39 public static final int DEFAULT_BUMP_SIZE = 0; 40 41 private int len; 42 private int bumpLen; 43 private byte[] buf; 44 45 /* 46 * We can return the same byte[] for 0 length arrays. 47 */ 48 private static byte[] ZERO_LENGTH_BYTE_ARRAY = new byte[0]; 49 50 /** 51 * Creates an output stream with default sizes. 52 */ 53 public FastOutputStream() { 54 55 initBuffer(DEFAULT_INIT_SIZE, DEFAULT_BUMP_SIZE); 56 } 57 58 /** 59 * Creates an output stream with a default bump size and a given initial 60 * size. 61 * 62 * @param initialSize the initial size of the buffer. 63 */ 64 public FastOutputStream(int initialSize) { 65 66 initBuffer(initialSize, DEFAULT_BUMP_SIZE); 67 } 68 69 /** 70 * Creates an output stream with a given bump size and initial size. 71 * 72 * @param initialSize the initial size of the buffer. 73 * 74 * @param bumpSize the amount to increment the buffer. 75 */ 76 public FastOutputStream(int initialSize, int bumpSize) { 77 78 initBuffer(initialSize, bumpSize); 79 } 80 81 /** 82 * Creates an output stream with a given initial buffer and a default 83 * bump size. 84 * 85 * @param buffer the initial buffer; will be owned by this object. 86 */ 87 public FastOutputStream(byte[] buffer) { 88 89 buf = buffer; 90 bumpLen = DEFAULT_BUMP_SIZE; 91 } 92 93 /** 94 * Creates an output stream with a given initial buffer and a given 95 * bump size. 96 * 97 * @param buffer the initial buffer; will be owned by this object. 98 * 99 * @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} 281