001 /*
002 * Copyright (C) 2008 Trustin Heuiseung Lee
003 *
004 * This library is free software; you can redistribute it and/or
005 * modify it under the terms of the GNU Lesser General Public
006 * License as published by the Free Software Foundation; either
007 * version 2.1 of the License, or (at your option) any later version.
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public
015 * License along with this library; if not, write to the Free Software
016 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA
017 */
018 package net.gleamynode.netty.buffer;
019
020 import java.io.IOException;
021 import java.io.InputStream;
022 import java.io.OutputStream;
023 import java.nio.ByteBuffer;
024 import java.nio.ByteOrder;
025 import java.nio.channels.GatheringByteChannel;
026 import java.nio.channels.ScatteringByteChannel;
027
028
029 /**
030 * @author The Netty Project (netty@googlegroups.com)
031 * @author Trustin Lee (trustin@gmail.com)
032 *
033 * @version $Rev$, $Date$
034 *
035 */
036 public class DynamicChannelBuffer extends AbstractChannelBuffer {
037
038 private final int initialCapacity;
039 private final ByteOrder endianness;
040 private ChannelBuffer buffer = ChannelBuffer.EMPTY_BUFFER;
041
042 public DynamicChannelBuffer(int estimatedLength) {
043 this(ByteOrder.BIG_ENDIAN, estimatedLength);
044 }
045
046 public DynamicChannelBuffer(ByteOrder endianness, int estimatedLength) {
047 if (estimatedLength <= 0) {
048 throw new IllegalArgumentException("estimatedLength");
049 }
050 if (endianness == null) {
051 throw new NullPointerException("endianness");
052 }
053
054 initialCapacity = estimatedLength;
055 this.endianness = endianness;
056 }
057
058 public ByteOrder order() {
059 return endianness;
060 }
061
062 public int capacity() {
063 return buffer.capacity();
064 }
065
066 public byte getByte(int index) {
067 return buffer.getByte(index);
068 }
069
070 public short getShort(int index) {
071 return buffer.getShort(index);
072 }
073
074 public int getMedium(int index) {
075 return buffer.getMedium(index);
076 }
077
078 public int getInt(int index) {
079 return buffer.getInt(index);
080 }
081
082 public long getLong(int index) {
083 return buffer.getLong(index);
084 }
085
086 public void getBytes(int index, byte[] dst, int dstIndex, int length) {
087 buffer.getBytes(index, dst, dstIndex, length);
088 }
089
090 public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) {
091 buffer.getBytes(index, dst, dstIndex, length);
092 }
093
094 public void getBytes(int index, ByteBuffer dst) {
095 buffer.getBytes(index, dst);
096 }
097
098 public int getBytes(int index, GatheringByteChannel out, int length)
099 throws IOException {
100 return buffer.getBytes(index, out, length);
101 }
102
103 public void getBytes(int index, OutputStream out, int length)
104 throws IOException {
105 buffer.getBytes(index, out, length);
106 }
107
108 public void setByte(int index, byte value) {
109 buffer.setByte(index, value);
110 }
111
112 public void setShort(int index, short value) {
113 buffer.setShort(index, value);
114 }
115
116 public void setMedium(int index, int value) {
117 buffer.setMedium(index, value);
118 }
119
120 public void setInt(int index, int value) {
121 buffer.setInt(index, value);
122 }
123
124 public void setLong(int index, long value) {
125 buffer.setLong(index, value);
126 }
127
128 public void setBytes(int index, byte[] src, int srcIndex, int length) {
129 buffer.setBytes(index, src, srcIndex, length);
130 }
131
132 public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) {
133 buffer.setBytes(index, src, srcIndex, length);
134 }
135
136 public void setBytes(int index, ByteBuffer src) {
137 buffer.setBytes(index, src);
138 }
139
140 public void setBytes(int index, InputStream in, int length)
141 throws IOException {
142 buffer.setBytes(index, in, length);
143 }
144
145 public int setBytes(int index, ScatteringByteChannel in, int length)
146 throws IOException {
147 return buffer.setBytes(index, in, length);
148 }
149
150 @Override
151 public void writeByte(byte value) {
152 ensureWritableBytes(1);
153 super.writeByte(value);
154 }
155
156 @Override
157 public void writeShort(short value) {
158 ensureWritableBytes(2);
159 super.writeShort(value);
160 }
161
162 @Override
163 public void writeMedium(int value) {
164 ensureWritableBytes(3);
165 super.writeMedium(value);
166 }
167
168 @Override
169 public void writeInt(int value) {
170 ensureWritableBytes(4);
171 super.writeInt(value);
172 }
173
174 @Override
175 public void writeLong(long value) {
176 ensureWritableBytes(8);
177 super.writeLong(value);
178 }
179
180 @Override
181 public void writeBytes(byte[] src, int srcIndex, int length) {
182 ensureWritableBytes(length);
183 super.writeBytes(src, srcIndex, length);
184 }
185
186 @Override
187 public void writeBytes(ChannelBuffer src, int srcIndex, int length) {
188 ensureWritableBytes(length);
189 super.writeBytes(src, srcIndex, length);
190 }
191
192 @Override
193 public void writeBytes(ByteBuffer src) {
194 ensureWritableBytes(src.remaining());
195 super.writeBytes(src);
196 }
197
198 @Override
199 public void writePlaceholder(int length) {
200 ensureWritableBytes(length);
201 super.writePlaceholder(length);
202 }
203
204 public ChannelBuffer duplicate() {
205 return new DuplicatedChannelBuffer(this);
206 }
207
208 public ChannelBuffer copy(int index, int length) {
209 DynamicChannelBuffer copiedBuffer = new DynamicChannelBuffer(endianness, Math.max(length, 64));
210 copiedBuffer.buffer = buffer.copy();
211 if (copiedBuffer.buffer.capacity() == 0) {
212 copiedBuffer.buffer = ChannelBuffer.EMPTY_BUFFER;
213 }
214 return copiedBuffer;
215 }
216
217 public ChannelBuffer slice(int index, int length) {
218 if (index == 0) {
219 return new TruncatedChannelBuffer(this, length);
220 } else {
221 return new SlicedChannelBuffer(this, index, length);
222 }
223 }
224
225 public ByteBuffer toByteBuffer(int index, int length) {
226 return buffer.toByteBuffer(index, length);
227 }
228
229 private void ensureWritableBytes(int requestedBytes) {
230 if (requestedBytes <= writableBytes()) {
231 return;
232 }
233
234 int newCapacity;
235 if (capacity() == 0) {
236 newCapacity = initialCapacity;
237 } else {
238 newCapacity = capacity();
239 }
240 int minNewCapacity = writerIndex() + requestedBytes;
241 while (newCapacity < minNewCapacity) {
242 newCapacity <<= 1;
243 }
244
245 ChannelBuffer newBuffer = ChannelBuffers.buffer(endianness, newCapacity);
246 newBuffer.writeBytes(buffer, readerIndex(), readableBytes());
247 buffer = newBuffer;
248 }
249 }