Home | History | Annotate | Download | only in util
      1 /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
      2  *
      3  * This program and the accompanying materials are made available under
      4  * the terms of the Common Public License v1.0 which accompanies this distribution,
      5  * and is available at http://www.eclipse.org/legal/cpl-v10.html
      6  *
      7  * $Id: ByteArrayOStream.java,v 1.1.1.1 2004/05/09 16:57:52 vlad_r Exp $
      8  */
      9 package com.vladium.util;
     10 
     11 import java.io.IOException;
     12 import java.io.OutputStream;
     13 
     14 import com.vladium.util.asserts.$assert;
     15 
     16 // ----------------------------------------------------------------------------
     17 /**
     18  * An unsynchronized version of java.io.ByteArrayOutputStream that can expose
     19  * the underlying byte array without a defensive clone and can also be converted
     20  * to a {@link ByteArrayIStream} without intermediate array copies.<p>
     21  *
     22  * All argument validation is disabled in release mode.<p>
     23  *
     24  * NOTE: copy-on-write not supported
     25  *
     26  * @author (C) 2001, Vlad Roubtsov
     27  */
     28 public
     29 final class ByteArrayOStream extends OutputStream
     30 {
     31     // public: ................................................................
     32 
     33     /**
     34      * Callee takes ownership of 'buf'.
     35      */
     36     public ByteArrayOStream (final int initialCapacity)
     37     {
     38         if ($assert.ENABLED)
     39             $assert.ASSERT (initialCapacity >= 0, "negative initial capacity: " + initialCapacity);
     40 
     41         m_buf = new byte [initialCapacity];
     42     }
     43 
     44     public final ByteArrayIStream toByteIStream ()
     45     {
     46         return new ByteArrayIStream (m_buf, m_pos);
     47     }
     48 
     49     public final void write2 (final int b1, final int b2)
     50     {
     51         final int pos = m_pos;
     52         final int capacity = pos + 2;
     53         byte [] mbuf = m_buf;
     54         final int mbuflen = mbuf.length;
     55 
     56         if (mbuflen < capacity)
     57         {
     58             final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)];
     59 
     60             if (pos < NATIVE_COPY_THRESHOLD)
     61                 for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i];
     62             else
     63                 System.arraycopy (mbuf, 0, newbuf, 0, pos);
     64 
     65             m_buf = mbuf = newbuf;
     66         }
     67 
     68         mbuf [pos] = (byte) b1;
     69         mbuf [pos + 1] = (byte) b2;
     70         m_pos = capacity;
     71     }
     72 
     73     public final void write3 (final int b1, final int b2, final int b3)
     74     {
     75         final int pos = m_pos;
     76         final int capacity = pos + 3;
     77         byte [] mbuf = m_buf;
     78         final int mbuflen = mbuf.length;
     79 
     80         if (mbuflen < capacity)
     81         {
     82             final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)];
     83 
     84             if (pos < NATIVE_COPY_THRESHOLD)
     85                 for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i];
     86             else
     87                 System.arraycopy (mbuf, 0, newbuf, 0, pos);
     88 
     89             m_buf = mbuf = newbuf;
     90         }
     91 
     92         mbuf [pos] = (byte) b1;
     93         mbuf [pos + 1] = (byte) b2;
     94         mbuf [pos + 2] = (byte) b3;
     95         m_pos = capacity;
     96     }
     97 
     98     public final void write4 (final int b1, final int b2, final int b3, final int b4)
     99     {
    100         final int pos = m_pos;
    101         final int capacity = pos + 4;
    102         byte [] mbuf = m_buf;
    103         final int mbuflen = mbuf.length;
    104 
    105         if (mbuflen < capacity)
    106         {
    107             final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)];
    108 
    109             if (pos < NATIVE_COPY_THRESHOLD)
    110                 for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i];
    111             else
    112                 System.arraycopy (mbuf, 0, newbuf, 0, pos);
    113 
    114             m_buf = mbuf = newbuf;
    115         }
    116 
    117         mbuf [pos] = (byte) b1;
    118         mbuf [pos + 1] = (byte) b2;
    119         mbuf [pos + 2] = (byte) b3;
    120         mbuf [pos + 3] = (byte) b4;
    121         m_pos = capacity;
    122     }
    123 
    124     public final void writeTo (final OutputStream out)
    125         throws IOException
    126     {
    127         out.write (m_buf, 0, m_pos);
    128     }
    129 
    130 //    public final void readFully (final InputStream in)
    131 //        throws IOException
    132 //    {
    133 //        while (true)
    134 //        {
    135 //            int chunk = in.available ();
    136 //
    137 //            System.out.println ("available = " + chunk);
    138 //
    139 //            // TODO: this case is handled poorly (on EOF)
    140 //            if (chunk == 0) chunk = READ_CHUNK_SIZE;
    141 //
    142 //            // read at least 'available' bytes: extend the capacity as needed
    143 //
    144 //            int free = m_buf.length - m_pos;
    145 //
    146 //            final int read;
    147 //            if (free > chunk)
    148 //            {
    149 //                // try reading more than 'chunk' anyway:
    150 //                read = in.read (m_buf, m_pos, free);
    151 //            }
    152 //            else
    153 //            {
    154 //                // extend the capacity to match 'chunk':
    155 //                {
    156 //                    System.out.println ("reallocation");
    157 //                    final byte [] newbuf = new byte [m_pos + chunk];
    158 //
    159 //                    if (m_pos < NATIVE_COPY_THRESHOLD)
    160 //                        for (int i = 0; i < m_pos; ++ i) newbuf [i] = m_buf [i];
    161 //                    else
    162 //                        System.arraycopy (m_buf, 0, newbuf, 0, m_pos);
    163 //
    164 //                    m_buf = newbuf;
    165 //                }
    166 //
    167 //                read = in.read (m_buf, m_pos, chunk);
    168 //            }
    169 //
    170 //            if (read < 0)
    171 //                break;
    172 //            else
    173 //                m_pos += read;
    174 //        }
    175 //    }
    176 
    177 //    public final void addCapacity (final int extraCapacity)
    178 //    {
    179 //        final int pos = m_pos;
    180 //        final int capacity = pos + extraCapacity;
    181 //        byte [] mbuf = m_buf;
    182 //        final int mbuflen = mbuf.length;
    183 //
    184 //        if (mbuflen < capacity)
    185 //        {
    186 //            final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)];
    187 //
    188 //            if (pos < NATIVE_COPY_THRESHOLD)
    189 //                for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i];
    190 //            else
    191 //                System.arraycopy (mbuf, 0, newbuf, 0, pos);
    192 //
    193 //            m_buf = newbuf;
    194 //        }
    195 //    }
    196 
    197     public final byte [] getByteArray ()
    198     {
    199         return m_buf;
    200     }
    201 
    202     /**
    203      *
    204      * @return [result.length = size()]
    205      */
    206     public final byte [] copyByteArray ()
    207     {
    208         final int pos = m_pos;
    209 
    210         final byte [] result = new byte [pos];
    211         final byte [] mbuf = m_buf;
    212 
    213         if (pos < NATIVE_COPY_THRESHOLD)
    214             for (int i = 0; i < pos; ++ i) result [i] = mbuf [i];
    215         else
    216             System.arraycopy (mbuf, 0, result, 0, pos);
    217 
    218         return result;
    219     }
    220 
    221     public final int size ()
    222     {
    223         return m_pos;
    224     }
    225 
    226     public final int capacity ()
    227     {
    228         return m_buf.length;
    229     }
    230 
    231     /**
    232      * Does not reduce the current capacity.
    233      */
    234     public final void reset ()
    235     {
    236         m_pos = 0;
    237     }
    238 
    239     // OutputStream:
    240 
    241     public final void write (final int b)
    242     {
    243         final int pos = m_pos;
    244         final int capacity = pos + 1;
    245         byte [] mbuf = m_buf;
    246         final int mbuflen = mbuf.length;
    247 
    248         if (mbuflen < capacity)
    249         {
    250             final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)];
    251 
    252             if (pos < NATIVE_COPY_THRESHOLD)
    253                 for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i];
    254             else
    255                 System.arraycopy (mbuf, 0, newbuf, 0, pos);
    256 
    257             m_buf = mbuf = newbuf;
    258         }
    259 
    260         mbuf [pos] = (byte) b;
    261         m_pos = capacity;
    262     }
    263 
    264 
    265     public final void write (final byte [] buf, final int offset, final int length)
    266     {
    267         if ($assert.ENABLED)
    268             $assert.ASSERT ((offset >= 0) && (offset <= buf.length) &&
    269                 (length >= 0) && ((offset + length) <= buf.length),
    270                 "invalid input (" + buf.length + ", " + offset + ", " + length + ")");
    271 
    272         final int pos = m_pos;
    273         final int capacity = pos + length;
    274         byte [] mbuf = m_buf;
    275         final int mbuflen = mbuf.length;
    276 
    277         if (mbuflen < capacity)
    278         {
    279             final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)];
    280 
    281             if (pos < NATIVE_COPY_THRESHOLD)
    282                 for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i];
    283             else
    284                 System.arraycopy (mbuf, 0, newbuf, 0, pos);
    285 
    286             m_buf = mbuf = newbuf;
    287         }
    288 
    289         if (length < NATIVE_COPY_THRESHOLD)
    290             for (int i = 0; i < length; ++ i) mbuf [pos + i] = buf [offset + i];
    291         else
    292             System.arraycopy (buf, offset, mbuf, pos, length);
    293 
    294         m_pos = capacity;
    295     }
    296 
    297 
    298     /**
    299      * Equivalent to {@link #reset()}.
    300      */
    301     public final void close ()
    302     {
    303         reset ();
    304     }
    305 
    306     // protected: .............................................................
    307 
    308     // package: ...............................................................
    309 
    310     // private: ...............................................................
    311 
    312 
    313     private byte [] m_buf;
    314     private int m_pos;
    315 
    316 //    private static final int READ_CHUNK_SIZE        = 16 * 1024;
    317     private static final int NATIVE_COPY_THRESHOLD  = 9;
    318 
    319 } // end of class
    320 // ----------------------------------------------------------------------------