Changeset 11970


Ignore:
Timestamp:
05/31/09 17:01:08 (12 years ago)
Author:
ehuelsmann
Message:

Performance improvement by removing fcn.size() calls;
also lots of reindenting (for some reason I'm seeing lots
of bad indentation in NetBeans?; my config?).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/abcl/src/org/armedbear/lisp/util/RandomAccessCharacterFile.java

    r11511 r11970  
    6060        }
    6161       
    62   private byte[] read_buf = new byte[1];
    63 
    64         @Override
    65   public int read() throws IOException {
    66       int len = read(read_buf);
    67       if (len == 1) {
    68     // byte is signed, char is unsigned, int is signed.
    69     // buf can hold 0xff, we want it as 0xff in int, not -1.
    70     return 0xff & (int) read_buf[0];
    71       } else {
    72     return -1;
    73       }
    74   }
     62        private byte[] read_buf = new byte[1];
     63
     64        @Override
     65        public int read() throws IOException {
     66            int len = read(read_buf);
     67            if (len == 1) {
     68                // byte is signed, char is unsigned, int is signed.
     69                // buf can hold 0xff, we want it as 0xff in int, not -1.
     70                return 0xff & (int) read_buf[0];
     71            } else {
     72                return -1;
     73            }
     74        }
    7575               
    76   @Override
     76        @Override
    7777        public int read(byte[] b, int off, int len) throws IOException {
    78       return RandomAccessCharacterFile.this.read(b, off, len);
    79   }
     78            return RandomAccessCharacterFile.this.read(b, off, len);
     79        }
    8080
    8181        @Override
     
    126126        }
    127127
    128   @Override
    129   public void close() throws IOException {
    130       RandomAccessCharacterFile.this.close();
    131   }
     128        @Override
     129        public void close() throws IOException {
     130            RandomAccessCharacterFile.this.close();
     131        }
    132132    }
    133133
    134134    private class RandomAccessOutputStream extends OutputStream {
    135135
    136   private RandomAccessOutputStream() {
    137   }
    138 
    139   private byte[] buf = new byte[1];
    140   public void write(int b) throws IOException {
    141       buf[0] = (byte)b;
    142       write(buf);
    143   }
    144 
    145   @Override
    146       public void write(byte[] b, int off, int len) throws IOException {
    147       RandomAccessCharacterFile.this.write(b, off, len);
    148   }
    149 
    150   @Override
    151   public void flush() throws IOException {
    152       RandomAccessCharacterFile.this.flush();
    153   }
    154 
    155   @Override
    156   public void close() throws IOException {
    157       RandomAccessCharacterFile.this.close();
    158   }
     136        private RandomAccessOutputStream() {
     137        }
     138
     139        private byte[] buf = new byte[1];
     140        public void write(int b) throws IOException {
     141            buf[0] = (byte)b;
     142            write(buf);
     143        }
     144
     145        @Override
     146            public void write(byte[] b, int off, int len) throws IOException {
     147            RandomAccessCharacterFile.this.write(b, off, len);
     148        }
     149
     150        @Override
     151        public void flush() throws IOException {
     152            RandomAccessCharacterFile.this.flush();
     153        }
     154
     155        @Override
     156        public void close() throws IOException {
     157            RandomAccessCharacterFile.this.close();
     158        }
    159159    }
    160160   
     
    165165    private class RandomAccessReader extends PushbackReader {
    166166
    167   private RandomAccessReader() {
    168             // because we override all methods of Pushbackreader,
    169             // staticReader will never be referenced
    170             super(staticReader);
    171   }
    172 
    173         @Override
    174   public void close() throws IOException {
    175       RandomAccessCharacterFile.this.close();
    176   }
     167        private RandomAccessReader() {
     168                // because we override all methods of Pushbackreader,
     169                // staticReader will never be referenced
     170                super(staticReader);
     171        }
     172
     173            @Override
     174        public void close() throws IOException {
     175            RandomAccessCharacterFile.this.close();
     176        }
    177177       
    178178        private char[] read_buf = new char[1];
     
    215215        }
    216216       
    217 
    218        
    219   @Override
    220   public int read(char[] cb, int off, int len) throws IOException {
    221       return RandomAccessCharacterFile.this.read(cb, off, len);
    222   }
     217        @Override
     218        public int read(char[] cb, int off, int len) throws IOException {
     219            return RandomAccessCharacterFile.this.read(cb, off, len);
     220        }
    223221    }
    224222
    225223    private class RandomAccessWriter extends Writer {
    226224
    227   private RandomAccessWriter() {
    228   }
    229 
    230   public void close() throws IOException {
    231       RandomAccessCharacterFile.this.close();
    232   }
    233 
    234   public void flush() throws IOException {
    235       RandomAccessCharacterFile.this.flush();
    236   }
    237 
    238   @Override
    239       public void write(char[] cb, int off, int len) throws IOException {
    240       RandomAccessCharacterFile.this.write(cb, off, len);
    241   }
     225        private RandomAccessWriter() {
     226        }
     227
     228        public void close() throws IOException {
     229            RandomAccessCharacterFile.this.close();
     230        }
     231
     232        public void flush() throws IOException {
     233            RandomAccessCharacterFile.this.flush();
     234        }
     235
     236        @Override
     237            public void write(char[] cb, int off, int len) throws IOException {
     238            RandomAccessCharacterFile.this.write(cb, off, len);
     239        }
    242240
    243241    }
     
    272270    public RandomAccessCharacterFile(RandomAccessFile raf, String encoding) throws IOException {
    273271
    274   fcn = raf.getChannel();
    275   fcnpos = fcn.position();
    276   fcnsize = fcn.size();
    277  
    278   cset = (encoding == null) ? Charset.defaultCharset() : Charset.forName(encoding);
    279   cdec = cset.newDecoder();
    280   cdec.onMalformedInput(CodingErrorAction.REPLACE);
    281   cdec.onUnmappableCharacter(CodingErrorAction.REPLACE);
    282   cenc = cset.newEncoder();
    283    
    284   bbuf = ByteBuffer.allocate(BUFSIZ);
    285    
    286   // there is no readable data available in the buffers.
    287   bbuf.flip();
    288    
    289   // there is no write pending data in the buffers.
    290   bbufIsDirty = false;
    291    
    292   bbufpos = fcn.position();
    293 
    294   reader = new RandomAccessReader();
    295   writer = new RandomAccessWriter();
    296   inputStream = new RandomAccessInputStream();
    297   outputStream = new RandomAccessOutputStream();
     272        fcn = raf.getChannel();
     273        fcnpos = fcn.position();
     274        fcnsize = fcn.size();
     275
     276        cset = (encoding == null) ? Charset.defaultCharset() : Charset.forName(encoding);
     277        cdec = cset.newDecoder();
     278        cdec.onMalformedInput(CodingErrorAction.REPLACE);
     279        cdec.onUnmappableCharacter(CodingErrorAction.REPLACE);
     280        cenc = cset.newEncoder();
     281
     282        bbuf = ByteBuffer.allocate(BUFSIZ);
     283
     284        // there is no readable data available in the buffers.
     285        bbuf.flip();
     286
     287        // there is no write pending data in the buffers.
     288        bbufIsDirty = false;
     289
     290        bbufpos = fcn.position();
     291
     292        reader = new RandomAccessReader();
     293        writer = new RandomAccessWriter();
     294        inputStream = new RandomAccessInputStream();
     295        outputStream = new RandomAccessOutputStream();
    298296    }
    299297 
    300298    public Writer getWriter() {
    301   return writer;
     299        return writer;
    302300    }
    303301 
    304302    public PushbackReader getReader() {
    305   return reader;
     303        return reader;
    306304    }
    307305 
    308306    public PushbackInputStream getInputStream() {
    309   return inputStream;
     307        return inputStream;
    310308    }
    311309 
    312310    public OutputStream getOutputStream() {
    313   return outputStream;
     311        return outputStream;
    314312    }
    315313 
    316314    public void close() throws IOException {
    317   internalFlush(true);
    318   fcn.close();
     315        internalFlush(true);
     316        fcn.close();
    319317    }
    320318 
    321319    public void flush() throws IOException {
    322   internalFlush(false);
     320        internalFlush(false);
    323321    }
    324322
    325323    private int read(char[] cb, int off, int len) throws IOException {
    326   CharBuffer cbuf = CharBuffer.wrap(cb, off, len);
    327   boolean decodeWasUnderflow = false;
    328   boolean atEof = false;
    329   while ((cbuf.remaining() > 0) && dataIsAvailableForRead()
    330          && ! atEof) {
    331       if ((bbuf.remaining() == 0) || decodeWasUnderflow) {
    332     // need to read from the file.
    333     flushBbuf(); // in case bbuf is dirty.
    334     // update bbufpos.
    335     bbufpos += bbuf.position();
    336     int partialBytes = bbuf.remaining(); // partialBytes > 0 happens when decodeWasUnderflow
    337     // if reads and writes are mixed, we may need to seek first.
    338     if (bbufpos + partialBytes != fcnpos) {
    339         fcn.position(bbufpos + partialBytes);
    340     }
    341     // need to read data from file.
    342     bbuf.compact();
    343     //###FIXME: we're ignoring end-of-stream here!!!
    344     atEof = (fcn.read(bbuf) == -1);
    345     bbuf.flip();
    346     fcnpos = bbufpos + bbuf.remaining();
    347       }
    348       CoderResult r = cdec.decode(bbuf, cbuf, pointingAtEOF() );
    349       decodeWasUnderflow = (CoderResult.UNDERFLOW == r);
    350   }
    351   if (cbuf.remaining() == len) {
    352       return -1;
    353   } else {
    354       return len - cbuf.remaining();
    355   }
     324        CharBuffer cbuf = CharBuffer.wrap(cb, off, len);
     325        boolean decodeWasUnderflow = false;
     326        boolean atEof = false;
     327        while ((cbuf.remaining() > 0) && dataIsAvailableForRead()
     328               && ! atEof) {
     329            if ((bbuf.remaining() == 0) || decodeWasUnderflow) {
     330            // need to read from the file.
     331            flushBbuf(); // in case bbuf is dirty.
     332            // update bbufpos.
     333            bbufpos += bbuf.position();
     334            int partialBytes = bbuf.remaining(); // partialBytes > 0 happens when decodeWasUnderflow
     335            // if reads and writes are mixed, we may need to seek first.
     336            if (bbufpos + partialBytes != fcnpos) {
     337                fcn.position(bbufpos + partialBytes);
     338            }
     339            // need to read data from file.
     340            bbuf.compact();
     341            //###FIXME: we're ignoring end-of-stream here!!!
     342            atEof = (fcn.read(bbuf) == -1);
     343            bbuf.flip();
     344            fcnpos = bbufpos + bbuf.remaining();
     345            }
     346            CoderResult r = cdec.decode(bbuf, cbuf, pointingAtEOF() );
     347            decodeWasUnderflow = (CoderResult.UNDERFLOW == r);
     348        }
     349        if (cbuf.remaining() == len) {
     350            return -1;
     351        } else {
     352            return len - cbuf.remaining();
     353        }
    356354    }
    357355
    358356    private boolean dataIsAvailableForRead() throws IOException {
    359   return ((bbuf.remaining() > 0) || (fcn.position() < fcn.size()));
     357        return ((bbuf.remaining() > 0) || (fcn.position() < fcn.size()));
    360358    }
    361359 
    362360    private boolean pointingAtEOF() {
    363   return (bbuf.remaining() == 0) && (fcnpos == fcnsize);
     361        return (bbuf.remaining() == 0) && (fcnpos == fcnsize);
    364362    }
    365363
    366364    private void write(char[] cb, int off, int len) throws IOException {
    367   CharBuffer cbuf = CharBuffer.wrap(cb, off, len);
    368   encodeAndWrite(cbuf, false, false);
     365        CharBuffer cbuf = CharBuffer.wrap(cb, off, len);
     366        encodeAndWrite(cbuf, false, false);
    369367    }
    370368
    371369    private void internalFlush(boolean endOfFile) throws IOException {
    372   if (endOfFile) {
    373       CharBuffer cbuf = CharBuffer.allocate(0);
    374       encodeAndWrite(cbuf, true, endOfFile);
    375   } else {
    376       flushBbuf();
    377   }
     370        if (endOfFile) {
     371            CharBuffer cbuf = CharBuffer.allocate(0);
     372            encodeAndWrite(cbuf, true, endOfFile);
     373        } else {
     374            flushBbuf();
     375        }
    378376    }
    379377
    380378    private void encodeAndWrite(CharBuffer cbuf, boolean flush, boolean endOfFile) throws IOException {
    381   if (bbufpos == fcnsize) {
    382       bbuf.clear();
    383   }
    384   while (cbuf.remaining() > 0) {
    385       CoderResult r = cenc.encode(cbuf, bbuf, endOfFile);
    386       bbufIsDirty = true;
    387       long curpos = bbufpos + bbuf.position();
    388       if (curpos > fcnsize) {
    389     // the file is extended.
    390     fcnsize = curpos;
    391       }
    392       if (CoderResult.OVERFLOW == r || bbuf.remaining() == 0) {
    393     flushBbuf();
    394     bbufpos += bbuf.limit();
    395     bbuf.clear();
    396     if (fcnpos < fcnsize) {
    397         fcn.read(bbuf);
    398         bbuf.flip();
    399         fcnpos += bbuf.remaining();
    400     }
    401     // if we are at the end of file, bbuf is simply cleared.
    402     // in that case, bbufpos + bbuf.position points to the EOF, not fcnpos.
    403       }
    404   }
    405   if (bbuf.position() > 0 && bbufIsDirty && flush) {
    406       flushBbuf();
    407   }
     379        if (bbufpos == fcnsize) {
     380            bbuf.clear();
     381        }
     382        while (cbuf.remaining() > 0) {
     383            CoderResult r = cenc.encode(cbuf, bbuf, endOfFile);
     384            bbufIsDirty = true;
     385            long curpos = bbufpos + bbuf.position();
     386            if (curpos > fcnsize) {
     387                // the file is extended.
     388                fcnsize = curpos;
     389            }
     390            if (CoderResult.OVERFLOW == r || bbuf.remaining() == 0) {
     391                flushBbuf();
     392                bbufpos += bbuf.limit();
     393                bbuf.clear();
     394                if (fcnpos < fcnsize) {
     395                    fcn.read(bbuf);
     396                    bbuf.flip();
     397                    fcnpos += bbuf.remaining();
     398                }
     399            // if we are at the end of file, bbuf is simply cleared.
     400            // in that case, bbufpos + bbuf.position points to the EOF, not fcnpos.
     401            }
     402        }
     403        if (bbuf.position() > 0 && bbufIsDirty && flush) {
     404            flushBbuf();
     405        }
    408406    }
    409407
    410408    public void position(long newPosition) throws IOException {
    411   flushBbuf();
    412   long bbufend = bbufpos + bbuf.limit();
    413   if (newPosition >= bbufpos && newPosition < bbufend) {
    414       // near seek. within existing data of bbuf.
    415       bbuf.position((int)(newPosition - bbufpos));
    416   } else {
    417       // far seek. discard the buffer.
    418       flushBbuf();
    419       fcn.position(newPosition);
    420       fcnpos = newPosition;
    421       bbuf.clear();
    422       bbuf.flip(); // "there is no useful data on this buffer yet."
    423       bbufpos = fcnpos;
    424   }
     409        flushBbuf();
     410        long bbufend = bbufpos + bbuf.limit();
     411        if (newPosition >= bbufpos && newPosition < bbufend) {
     412            // near seek. within existing data of bbuf.
     413            bbuf.position((int)(newPosition - bbufpos));
     414        } else {
     415            // far seek. discard the buffer.
     416            flushBbuf();
     417            fcn.position(newPosition);
     418            fcnpos = newPosition;
     419            bbuf.clear();
     420            bbuf.flip(); // "there is no useful data on this buffer yet."
     421            bbufpos = fcnpos;
     422        }
    425423    }
    426424 
    427425    public long position() throws IOException {
    428   flushBbuf();
    429   return bbufpos + bbuf.position(); // the logical position within the file.
     426        flushBbuf();
     427        return bbufpos + bbuf.position(); // the logical position within the file.
    430428    }
    431429
    432430    public long length() throws IOException {
    433   flushBbuf();
    434   return fcn.size();
    435     }
    436        
     431        flushBbuf();
     432        return fcn.size();
     433    }
     434
    437435    private void flushBbuf() throws IOException {
    438   if (bbufIsDirty) {
    439       if (fcnpos != bbufpos) {
    440     fcn.position(bbufpos);
    441       }
    442       bbuf.position(0);
    443       if (bbufpos + bbuf.limit() > fcnsize) {
    444     // the buffer is at the end of the file.
    445     // area beyond fcnsize does not have data.
    446     bbuf.limit((int)(fcnsize - bbufpos));
    447       }
    448       fcn.write(bbuf);
    449       fcnpos = bbufpos + bbuf.limit();
    450       bbufIsDirty = false;
    451   }
     436        if (! bbufIsDirty)
     437            return;
     438
     439        if (fcnpos != bbufpos)
     440            fcn.position(bbufpos);
     441
     442        bbuf.position(0);
     443        if (bbufpos + bbuf.limit() > fcnsize) {
     444            // the buffer is at the end of the file.
     445            // area beyond fcnsize does not have data.
     446            bbuf.limit((int)(fcnsize - bbufpos));
     447        }
     448        fcn.write(bbuf);
     449        fcnpos = bbufpos + bbuf.limit();
     450        bbufIsDirty = false;
    452451    }
    453452
    454453    public int read(byte[] b, int off, int len) throws IOException {
    455   int pos = off;
    456   boolean atEof = false;
    457   while (pos - off < len && dataIsAvailableForRead()
    458          && ! atEof) {
    459       if (bbuf.remaining() == 0) {
    460     // need to read from the file.
    461     flushBbuf(); // in case bbuf is dirty.
    462     // update bbufpos.
    463     bbufpos += bbuf.limit();
    464     // if reads and writes are mixed, we may need to seek first.
    465     if (bbufpos != fcnpos) {
    466         fcn.position(bbufpos);
    467     }
    468     // need to read data from file.
    469     bbuf.clear();
    470     atEof = (fcn.read(bbuf) == -1);
    471     bbuf.flip();
    472     fcnpos = bbufpos + bbuf.remaining();
    473       }
    474       int want = len - pos;
    475       if (want > bbuf.remaining()) {
    476     want = bbuf.remaining();
    477       }
    478       bbuf.get(b, pos, want);
    479       pos += want;
    480   }
    481   return pos - off;
     454        int pos = off;
     455        boolean atEof = false;
     456        while (pos - off < len && dataIsAvailableForRead()
     457               && ! atEof) {
     458            if (bbuf.remaining() == 0) {
     459                // need to read from the file.
     460                flushBbuf(); // in case bbuf is dirty.
     461                // update bbufpos.
     462                bbufpos += bbuf.limit();
     463                // if reads and writes are mixed, we may need to seek first.
     464                if (bbufpos != fcnpos) {
     465                    fcn.position(bbufpos);
     466                }
     467                // need to read data from file.
     468                bbuf.clear();
     469                atEof = (fcn.read(bbuf) == -1);
     470                bbuf.flip();
     471                fcnpos = bbufpos + bbuf.remaining();
     472            }
     473            int want = len - pos;
     474            if (want > bbuf.remaining()) {
     475                want = bbuf.remaining();
     476            }
     477            bbuf.get(b, pos, want);
     478            pos += want;
     479        }
     480        return pos - off;
    482481    }
    483482       
     
    491490    private ByteBuffer shortByteBuf;
    492491    public void unreadChar(char c) throws IOException {
    493   // algorithm :
    494   //  1. encode c into bytes, to find out how many bytes it corresponds to
    495   //  2. move the position backwards that many bytes.
    496   //  ** we stop here.  Don't bother to write the bytes to the buffer,
    497   //     assuming that it is the same as the original data.
    498   //     If we allow to write back different characters, the buffer must get 'dirty'
    499   //     but that would require read/write permissions on files you use unreadChar,
    500   //     even if you are just reading for some tokenizer.
    501   //
    502   //  So we don't do the following.
    503   //  3. write the bytes.
    504   //  4. move the position back again.
    505   if (singleCharBuf == null) {
    506       singleCharBuf = CharBuffer.allocate(1);
    507       shortByteBuf = ByteBuffer.allocate((int)cenc.maxBytesPerChar());
    508   }
    509   singleCharBuf.clear();
    510   singleCharBuf.append(c);
    511   singleCharBuf.flip();
    512   shortByteBuf.clear();
    513   cenc.encode(singleCharBuf, shortByteBuf, false);
    514   int n = shortByteBuf.position();
    515   long pos = position() - n;
    516   position(pos);
     492        // algorithm :
     493        //  1. encode c into bytes, to find out how many bytes it corresponds to
     494        //  2. move the position backwards that many bytes.
     495        //  ** we stop here.  Don't bother to write the bytes to the buffer,
     496        //     assuming that it is the same as the original data.
     497        //     If we allow to write back different characters, the buffer must get 'dirty'
     498        //     but that would require read/write permissions on files you use unreadChar,
     499        //     even if you are just reading for some tokenizer.
     500        //
     501        //  So we don't do the following.
     502        //  3. write the bytes.
     503        //  4. move the position back again.
     504        if (singleCharBuf == null) {
     505            singleCharBuf = CharBuffer.allocate(1);
     506            shortByteBuf = ByteBuffer.allocate((int)cenc.maxBytesPerChar());
     507        }
     508        singleCharBuf.clear();
     509        singleCharBuf.append(c);
     510        singleCharBuf.flip();
     511        shortByteBuf.clear();
     512        cenc.encode(singleCharBuf, shortByteBuf, false);
     513        int n = shortByteBuf.position();
     514        long pos = position() - n;
     515        position(pos);
    517516    }
    518517 
    519518    public void unreadByte(byte b) throws IOException {
    520   long pos = position() - 1;
    521   position(pos);
     519        long pos = position() - 1;
     520        position(pos);
    522521    }
    523522
    524523    private void write(byte[] b, int off, int len) throws IOException {
    525   int pos = off;
    526   while (pos < off + len) {
    527       int want = len;
    528       if (want > bbuf.remaining()) {
    529     want = bbuf.remaining();
    530       }
    531       bbuf.put(b, pos, want);
    532       pos += want;
    533       bbufIsDirty = true;
    534       long curpos = bbufpos + bbuf.position();
    535       if (curpos > fcn.size()) {
    536     // the file is extended.
    537     fcnsize = curpos;
    538       }
    539       if (bbuf.remaining() == 0) {
    540     flushBbuf();
    541     bbufpos += bbuf.limit();
    542     bbuf.clear();
    543     if (fcn.position() < fcn.size()) {
    544         bbufpos = fcn.position();
    545         fcn.read(bbuf);
    546         bbuf.flip();
    547         fcnpos += bbuf.remaining();
    548     }
    549     // if we are at the end of file, bbuf is simply cleared.
    550     // in that case, bbufpos + bbuf.position points to the EOF, not fcnpos.
    551       }
    552   }
     524        int pos = off;
     525        if (len > bbuf.limit()) {
     526            if (bbufIsDirty)
     527                flushBbuf();
     528            fcn.write(ByteBuffer.wrap(b, off, len));
     529            fcnpos = fcn.position();
     530            if (fcnpos > fcnsize)
     531                fcnsize = fcnpos;
     532        }
     533        while (pos < off + len) {
     534            int want = len;
     535            if (want > bbuf.remaining()) {
     536                want = bbuf.remaining();
     537            }
     538            bbuf.put(b, pos, want);
     539            pos += want;
     540            bbufIsDirty = true;
     541            long curpos = bbufpos + bbuf.position();
     542            if (curpos > fcnsize) {
     543                // the file is extended.
     544                fcnsize = curpos;
     545            }
     546            if (bbuf.remaining() == 0) {
     547                flushBbuf();
     548                bbufpos += bbuf.limit();
     549                bbuf.clear();
     550                if (fcn.position() < fcnsize) {
     551                    bbufpos = fcn.position();
     552                    fcn.read(bbuf);
     553                    bbuf.flip();
     554                    fcnpos += bbuf.remaining();
     555                }
     556                // if we are at the end of file, bbuf is simply cleared.
     557                // in that case, bbufpos + bbuf.position points to the EOF, not fcnpos.
     558            }
     559        }
    553560    }
    554561}
Note: See TracChangeset for help on using the changeset viewer.