View Javadoc

1   /*
2    *   Copyright 2004 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   */
17  package org.apache.asn1.ber.digester.rules ;
18  
19  
20  import java.nio.ByteBuffer;
21  
22  import org.apache.commons.lang.ArrayUtils;
23  
24  
25  /***
26   * Gathers bytes from buffers while dynamically growing to accomodate a new size.
27   *
28   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
29   * @version $Rev: 157644 $
30   */
31  public class ByteAccumulator
32  {
33      /*** the default initial size */
34      private static final int DEFAULT_INIT_SIZE = 0 ;
35      /*** the default initial size */
36      private static final int DEFAULT_INCREMENT = 100 ;
37  
38      /*** the accumulator's backing store */
39      private byte[] bs ;
40      /*** the current position of the accumulator */
41      private int pos ;
42      /*** the growth increment used to augment the backing store */
43      private int increment ;
44      /*** the initial size of the backing store */
45      private int initial = DEFAULT_INIT_SIZE ;
46  
47  
48      // -----------------------------------------------------------------------
49      // C O N S T R U C T O R S
50      // -----------------------------------------------------------------------
51  
52      /***
53       * Creates a ByteAccumulator used to gather bytes from various sources
54       * with a default initial size and a default growth increment.
55       */
56      public ByteAccumulator()
57      {
58          bs = ArrayUtils.EMPTY_BYTE_ARRAY ;
59          pos = 0 ;
60          initial = DEFAULT_INIT_SIZE ;
61          increment = DEFAULT_INCREMENT ;
62      }
63  
64  
65      /***
66       * Creates a ByteAccumulator used to gather bytes from various sources
67       * with a default initial size and a default growth increment.
68       *
69       * @param initial the initial size for the backing store
70       */
71      ByteAccumulator( int initial )
72      {
73          if ( initial <= 0 )
74          {
75              bs = ArrayUtils.EMPTY_BYTE_ARRAY ;
76              this.initial = 0 ;
77          }
78          else
79          {
80              bs = new byte[initial] ;
81              this.initial = initial ;
82          }
83  
84          pos = 0 ;
85          increment = DEFAULT_INCREMENT ;
86      }
87  
88  
89      /***
90       * Fills this accumulator with the content of the argument buffer into
91       * this accumulator.  The buffer argument is fully drained when this
92       * operation completes.
93       *
94       * @param buf the buffer to fill into this accumulator
95       */
96      public void fill( ByteBuffer buf )
97      {
98          while ( buf.hasRemaining() )
99          {
100             if ( pos >= bs.length )
101             {
102                 int size = 0 ;
103 
104                 if ( buf.remaining() > increment )
105                 {
106                     size = bs.length + buf.remaining() ;
107                 }
108                 else
109                 {
110                     size = bs.length + increment ;
111                 }
112 
113                 byte[] dest = new byte[ size ] ;
114                 System.arraycopy( bs, 0, dest, 0, bs.length ) ;
115                 bs = dest ;
116             }
117 
118             /*
119              * Find out how much space we have left and if it can hold the
120              * remaining contents of the buffer.
121              */
122             int spaceLeft = bs.length - pos ;
123             if ( buf.remaining() <= spaceLeft )
124             {
125                 int remaining = buf.remaining() ;
126                 buf.get( bs, pos, remaining ) ;
127                 pos += remaining ;
128                 return ;
129             }
130 
131             /*
132              * there are more bytes in the buffer than we have space so we read
133              * as much as we can into the empty space filling it up all the way
134              * until another cycle of this loop allocates more space.
135              */
136             buf.get( bs, pos, spaceLeft ) ;
137             pos += spaceLeft ;
138         }
139     }
140 
141 
142     /***
143      * Wraps a ByteBuffer around the populated bytes of this ByteAccumulator
144      * and resets the backing store to a newly allocated byte array of initial
145      * size.
146      *
147      * @return the compacted byte[] wrapped as a ByteBuffer
148      */
149     public ByteBuffer drain()
150     {
151         ByteBuffer compacted ;
152 
153         if ( pos == bs.length )
154         {
155             compacted = ByteBuffer.wrap( bs ) ;
156         }
157         else
158         {
159             compacted = ByteBuffer.wrap( bs, 0, pos ) ;
160         }
161 
162         if ( initial <= 0 )
163         {
164             bs = ArrayUtils.EMPTY_BYTE_ARRAY ;
165         }
166         else
167         {
168             bs = new byte[initial] ;
169         }
170 
171         pos = 0 ;
172         return compacted ;
173     }
174 
175 
176     /***
177      * Wraps a ByteBuffer around the populated bytes of this ByteAccumulator
178      * and resets the backing store to a newly allocated byte array of initial
179      * size.
180      *
181      * @return the compacted byte[] wrapped as a ByteBuffer
182      */
183     public ByteBuffer drain( int initial )
184     {
185         ByteBuffer compacted ;
186 
187         if ( pos == bs.length )
188         {
189             compacted = ByteBuffer.wrap( bs ) ;
190         }
191         else
192         {
193             compacted = ByteBuffer.wrap( bs, 0, pos ) ;
194         }
195 
196         if ( initial <= 0 )
197         {
198             bs = ArrayUtils.EMPTY_BYTE_ARRAY ;
199         }
200         else
201         {
202             bs = new byte[initial] ;
203         }
204 
205         pos = 0 ;
206         return compacted ;
207     }
208 
209 
210     /***
211      * Allocates memory to handle a capacity without the need to grow.
212      * This serves to control growth for more efficient use.
213      *
214      * @param capacity the capacity to hold without the need to grow
215      */
216     public void ensureCapacity( int capacity )
217     {
218         if ( bs.length < capacity )
219         {
220             byte[] newArray = new byte[capacity] ;
221 
222             if ( bs != ArrayUtils.EMPTY_BYTE_ARRAY )
223             {
224                 System.arraycopy( bs, 0, newArray, 0, pos + 1 ) ;
225             }
226 
227             bs = newArray ;
228         }
229     }
230 
231 
232     /***
233      * The growth increment by which the backing store is augmented.
234      *
235      * @return the number of bytes to grow the backing store by
236      */
237     public int getGrowthIncrement()
238     {
239         return increment ;
240     }
241 
242 
243     /***
244      * The initial size of the backing store.
245      *
246      * @return the initial size in bytes of the backing store
247      */
248     public int getInitialSize()
249     {
250         return initial ;
251     }
252 
253 
254     /***
255      * The current capacity of the backing store which may change as this
256      * accumulator is filled with bytes.
257      *
258      * @return the current capacity in bytes
259      */
260     public int getCapacity()
261     {
262         return bs.length ;
263     }
264 
265 
266     /***
267      * The remaining free space that can be filled before having to grow the
268      * backing store of the accumulator.
269      *
270      * @return the remaining free space until the next growth spurt
271      */
272     public int getRemainingSpace()
273     {
274         return bs.length - pos ;
275     }
276 
277 
278     /***
279      * The current position within the backing store marking the point to
280      * which this accumulator is filled.
281      *
282      * @return the current fill position
283      */
284     public int getPosition()
285     {
286         return pos ;
287     }
288 
289 
290     /***
291      * Gets a compacted copy of this ByteAccumulator's backing store.  The
292      * compacted byte array is equal to the amount of bytes put into this
293      * ByteAccumulator which may still have free space to populate since the
294      * last growth took place.
295      *
296      * @return the compacted copy of this ByteAccumulator
297      */
298 /*
299     public byte[] getCompactedCopy()
300     {
301         byte[] compacted ;
302 
303         if ( pos == bs.length )
304         {
305             compacted = (byte[]) bs.clone() ;
306         }
307         else
308         {
309             compacted = new byte[pos+1] ;
310         }
311 
312         System.arraycopy( bs, 0, compacted, 0, pos + 1 ) ;
313         return compacted ;
314     }
315 */
316 }