View Javadoc

1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.http.util;
29  
30  import java.io.Serializable;
31  
32  import org.apache.http.annotation.NotThreadSafe;
33  
34  /**
35   * A resizable byte array.
36   *
37   * @since 4.0
38   */
39  @NotThreadSafe
40  public final class ByteArrayBuffer implements Serializable {
41  
42      private static final long serialVersionUID = 4359112959524048036L;
43  
44      private byte[] buffer;
45      private int len;
46  
47      /**
48       * Creates an instance of {@link ByteArrayBuffer} with the given initial
49       * capacity.
50       *
51       * @param capacity the capacity
52       */
53      public ByteArrayBuffer(final int capacity) {
54          super();
55          Args.notNegative(capacity, "Buffer capacity");
56          this.buffer = new byte[capacity];
57      }
58  
59      private void expand(final int newlen) {
60          final byte newbuffer[] = new byte[Math.max(this.buffer.length << 1, newlen)];
61          System.arraycopy(this.buffer, 0, newbuffer, 0, this.len);
62          this.buffer = newbuffer;
63      }
64  
65      /**
66       * Appends {@code len} bytes to this buffer from the given source
67       * array starting at index {@code off}. The capacity of the buffer
68       * is increased, if necessary, to accommodate all {@code len} bytes.
69       *
70       * @param   b        the bytes to be appended.
71       * @param   off      the index of the first byte to append.
72       * @param   len      the number of bytes to append.
73       * @throws IndexOutOfBoundsException if {@code off} if out of
74       * range, {@code len} is negative, or
75       * {@code off} + {@code len} is out of range.
76       */
77      public void append(final byte[] b, final int off, final int len) {
78          if (b == null) {
79              return;
80          }
81          if ((off < 0) || (off > b.length) || (len < 0) ||
82                  ((off + len) < 0) || ((off + len) > b.length)) {
83              throw new IndexOutOfBoundsException("off: "+off+" len: "+len+" b.length: "+b.length);
84          }
85          if (len == 0) {
86              return;
87          }
88          final int newlen = this.len + len;
89          if (newlen > this.buffer.length) {
90              expand(newlen);
91          }
92          System.arraycopy(b, off, this.buffer, this.len, len);
93          this.len = newlen;
94      }
95  
96      /**
97       * Appends {@code b} byte to this buffer. The capacity of the buffer
98       * is increased, if necessary, to accommodate the additional byte.
99       *
100      * @param   b        the byte to be appended.
101      */
102     public void append(final int b) {
103         final int newlen = this.len + 1;
104         if (newlen > this.buffer.length) {
105             expand(newlen);
106         }
107         this.buffer[this.len] = (byte)b;
108         this.len = newlen;
109     }
110 
111     /**
112      * Appends {@code len} chars to this buffer from the given source
113      * array starting at index {@code off}. The capacity of the buffer
114      * is increased if necessary to accommodate all {@code len} chars.
115      * <p>
116      * The chars are converted to bytes using simple cast.
117      *
118      * @param   b        the chars to be appended.
119      * @param   off      the index of the first char to append.
120      * @param   len      the number of bytes to append.
121      * @throws IndexOutOfBoundsException if {@code off} if out of
122      * range, {@code len} is negative, or
123      * {@code off} + {@code len} is out of range.
124      */
125     public void append(final char[] b, final int off, final int len) {
126         if (b == null) {
127             return;
128         }
129         if ((off < 0) || (off > b.length) || (len < 0) ||
130                 ((off + len) < 0) || ((off + len) > b.length)) {
131             throw new IndexOutOfBoundsException("off: "+off+" len: "+len+" b.length: "+b.length);
132         }
133         if (len == 0) {
134             return;
135         }
136         final int oldlen = this.len;
137         final int newlen = oldlen + len;
138         if (newlen > this.buffer.length) {
139             expand(newlen);
140         }
141         for (int i1 = off, i2 = oldlen; i2 < newlen; i1++, i2++) {
142             this.buffer[i2] = (byte) b[i1];
143         }
144         this.len = newlen;
145     }
146 
147     /**
148      * Appends {@code len} chars to this buffer from the given source
149      * char array buffer starting at index {@code off}. The capacity
150      * of the buffer is increased if necessary to accommodate all
151      * {@code len} chars.
152      * <p>
153      * The chars are converted to bytes using simple cast.
154      *
155      * @param   b        the chars to be appended.
156      * @param   off      the index of the first char to append.
157      * @param   len      the number of bytes to append.
158      * @throws IndexOutOfBoundsException if {@code off} if out of
159      * range, {@code len} is negative, or
160      * {@code off} + {@code len} is out of range.
161      */
162     public void append(final CharArrayBuffer b, final int off, final int len) {
163         if (b == null) {
164             return;
165         }
166         append(b.buffer(), off, len);
167     }
168 
169     /**
170      * Clears content of the buffer. The underlying byte array is not resized.
171      */
172     public void clear() {
173         this.len = 0;
174     }
175 
176     /**
177      * Converts the content of this buffer to an array of bytes.
178      *
179      * @return byte array
180      */
181     public byte[] toByteArray() {
182         final byte[] b = new byte[this.len];
183         if (this.len > 0) {
184             System.arraycopy(this.buffer, 0, b, 0, this.len);
185         }
186         return b;
187     }
188 
189     /**
190      * Returns the {@code byte} value in this buffer at the specified
191      * index. The index argument must be greater than or equal to
192      * {@code 0}, and less than the length of this buffer.
193      *
194      * @param      i   the index of the desired byte value.
195      * @return     the byte value at the specified index.
196      * @throws     IndexOutOfBoundsException  if {@code index} is
197      *             negative or greater than or equal to {@link #length()}.
198      */
199     public int byteAt(final int i) {
200         return this.buffer[i];
201     }
202 
203     /**
204      * Returns the current capacity. The capacity is the amount of storage
205      * available for newly appended bytes, beyond which an allocation
206      * will occur.
207      *
208      * @return  the current capacity
209      */
210     public int capacity() {
211         return this.buffer.length;
212     }
213 
214     /**
215      * Returns the length of the buffer (byte count).
216      *
217      * @return  the length of the buffer
218      */
219     public int length() {
220         return this.len;
221     }
222 
223     /**
224      * Ensures that the capacity is at least equal to the specified minimum.
225      * If the current capacity is less than the argument, then a new internal
226      * array is allocated with greater capacity. If the {@code required}
227      * argument is non-positive, this method takes no action.
228      *
229      * @param   required   the minimum required capacity.
230      *
231      * @since 4.1
232      */
233     public void ensureCapacity(final int required) {
234         if (required <= 0) {
235             return;
236         }
237         final int available = this.buffer.length - this.len;
238         if (required > available) {
239             expand(this.len + required);
240         }
241     }
242 
243     /**
244      * Returns reference to the underlying byte array.
245      *
246      * @return the byte array.
247      */
248     public byte[] buffer() {
249         return this.buffer;
250     }
251 
252     /**
253      * Sets the length of the buffer. The new length value is expected to be
254      * less than the current capacity and greater than or equal to
255      * {@code 0}.
256      *
257      * @param      len   the new length
258      * @throws     IndexOutOfBoundsException  if the
259      *               {@code len} argument is greater than the current
260      *               capacity of the buffer or less than {@code 0}.
261      */
262     public void setLength(final int len) {
263         if (len < 0 || len > this.buffer.length) {
264             throw new IndexOutOfBoundsException("len: "+len+" < 0 or > buffer len: "+this.buffer.length);
265         }
266         this.len = len;
267     }
268 
269     /**
270      * Returns {@code true} if this buffer is empty, that is, its
271      * {@link #length()} is equal to {@code 0}.
272      * @return {@code true} if this buffer is empty, {@code false}
273      *   otherwise.
274      */
275     public boolean isEmpty() {
276         return this.len == 0;
277     }
278 
279     /**
280      * Returns {@code true} if this buffer is full, that is, its
281      * {@link #length()} is equal to its {@link #capacity()}.
282      * @return {@code true} if this buffer is full, {@code false}
283      *   otherwise.
284      */
285     public boolean isFull() {
286         return this.len == this.buffer.length;
287     }
288 
289     /**
290      * Returns the index within this buffer of the first occurrence of the
291      * specified byte, starting the search at the specified
292      * {@code beginIndex} and finishing at {@code endIndex}.
293      * If no such byte occurs in this buffer within the specified bounds,
294      * {@code -1} is returned.
295      * <p>
296      * There is no restriction on the value of {@code beginIndex} and
297      * {@code endIndex}. If {@code beginIndex} is negative,
298      * it has the same effect as if it were zero. If {@code endIndex} is
299      * greater than {@link #length()}, it has the same effect as if it were
300      * {@link #length()}. If the {@code beginIndex} is greater than
301      * the {@code endIndex}, {@code -1} is returned.
302      *
303      * @param   b            the byte to search for.
304      * @param   from         the index to start the search from.
305      * @param   to           the index to finish the search at.
306      * @return  the index of the first occurrence of the byte in the buffer
307      *   within the given bounds, or {@code -1} if the byte does
308      *   not occur.
309      *
310      * @since 4.1
311      */
312     public int indexOf(final byte b, final int from, final int to) {
313         int beginIndex = from;
314         if (beginIndex < 0) {
315             beginIndex = 0;
316         }
317         int endIndex = to;
318         if (endIndex > this.len) {
319             endIndex = this.len;
320         }
321         if (beginIndex > endIndex) {
322             return -1;
323         }
324         for (int i = beginIndex; i < endIndex; i++) {
325             if (this.buffer[i] == b) {
326                 return i;
327             }
328         }
329         return -1;
330     }
331 
332     /**
333      * Returns the index within this buffer of the first occurrence of the
334      * specified byte, starting the search at {@code 0} and finishing
335      * at {@link #length()}. If no such byte occurs in this buffer within
336      * those bounds, {@code -1} is returned.
337      *
338      * @param   b   the byte to search for.
339      * @return  the index of the first occurrence of the byte in the
340      *   buffer, or {@code -1} if the byte does not occur.
341      *
342      * @since 4.1
343      */
344     public int indexOf(final byte b) {
345         return indexOf(b, 0, this.len);
346     }
347 }