Package com.intellij.util.io

Source Code of com.intellij.util.io.CachedFile

/*
* Copyright 2000-2007 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.util.io;

import com.intellij.util.containers.IntObjectCache;
import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;

import java.io.*;
import java.util.Arrays;

public abstract class CachedFile implements DataOutput, DataInput, Flushable, Closeable {
  @NonNls private static final String UTF_8_CHARSET_NAME = "UTF-8";
  private byte[] myTypedIOBuffer = new byte[8];

  protected long myLength;
  protected long myPosition;
  protected CachingStrategy myStrategy;

  abstract void loadPage(long offset, byte[] page, int size) throws IOException;

  abstract void savePage(long offset, byte[] page, int size) throws IOException;

  final void markPageDirty(CachedFilePage page, boolean dirty) {
    myStrategy.markPageDirty(page, dirty);
  }

  public final long getFilePointer() {
    return myPosition;
  }

  public final long length() {
    return myLength;
  }

  public final void seek(long pos) throws IOException {
    if (pos < 0 || pos > myLength) {
      throw new IOException("Invalid position: " + pos + ", length = " + myLength);
    }
    myPosition = pos;
  }

  public final int usedMemory() {
    return myStrategy.usedMemory();
  }

  public final double cacheHitRate() {
    return myStrategy.cacheHitRate();
  }

  public void write(int b) throws IOException {
    myStrategy.getPage(this, myPosition).setByte((int)(myPosition % myStrategy.getPageSize()), (byte)b);
    if (++myPosition > myLength) {
      myLength = myPosition;
    }
  }

  public void write(byte[] b) throws IOException {
    write(b, 0, b.length);
  }

  public void write(byte[] b, int off, int len) throws IOException {
    while (len > 0) {
      CachedFilePage page = myStrategy.getPage(this, myPosition);
      int pageIndex = (int)(myPosition % myStrategy.getPageSize());
      int pageBytes = myStrategy.getPageSize() - pageIndex;
      if (pageBytes > len) {
        pageBytes = len;
      }
      page.write(b, off, pageIndex, pageBytes);
      len -= pageBytes;
      off += pageBytes;
      myPosition += pageBytes;
      if (myPosition > myLength) {
        myLength = myPosition;
      }
    }
  }

  public final void writeBoolean(boolean v) throws IOException {
    write(v ? 1 : 0);
  }

  public final void writeByte(int v) throws IOException {
    write(v);
  }

  public final void writeShort(int v) throws IOException {
    byte[] buffer = myTypedIOBuffer;
    buffer[0] = (byte)((v >>> 8) & 0xFF);
    buffer[1] = (byte)(v & 0xFF);
    write(buffer, 0, 2);
  }

  public final void writeChar(int v) throws IOException {
    writeShort(v);
  }

  public final void writeInt(int v) throws IOException {
    byte[] buffer = myTypedIOBuffer;
    buffer[0] = (byte)((v >>> 24) & 0xFF);
    buffer[1] = (byte)((v >>> 16) & 0xFF);
    buffer[2] = (byte)((v >>> 8) & 0xFF);
    buffer[3] = (byte)(v & 0xFF);
    write(buffer, 0, 4);
  }

  public final void writeLong(long v) throws IOException {
    byte[] buffer = myTypedIOBuffer;
    buffer[0] = (byte)((v >>> 56) & 0xFF);
    buffer[1] = (byte)((v >>> 48) & 0xFF);
    buffer[2] = (byte)((v >>> 40) & 0xFF);
    buffer[3] = (byte)((v >>> 32) & 0xFF);
    buffer[4] = (byte)((v >>> 24) & 0xFF);
    buffer[5] = (byte)((v >>> 16) & 0xFF);
    buffer[6] = (byte)((v >>> 8) & 0xFF);
    buffer[7] = (byte)(v & 0xFF);
    write(buffer, 0, 8);
  }

  public final void writeFloat(float v) throws IOException {
    writeInt(Float.floatToIntBits(v));
  }

  public final void writeDouble(double v) throws IOException {
    writeLong(Double.doubleToLongBits(v));
  }

  public final void writeBytes(String s) throws IOException {
    write(s.getBytes());
  }

  public final void writeChars(String s) throws IOException {
    int clen = s.length();
    int blen = 2 * clen;
    byte[] b = new byte[blen];
    char[] c = new char[clen];
    s.getChars(0, clen, c, 0);
    for (int i = 0, j = 0; i < clen; i++) {
      b[j++] = (byte)(c[i] >>> 8);
      b[j++] = (byte)c[i];
    }
    write(b);
  }

  public final void writeUTF(String str) throws IOException {
    final byte[] bytes = str.getBytes(UTF_8_CHARSET_NAME);
    writeInt(bytes.length);
    write(bytes);
  }

  public int read() throws IOException, EOFException {
    if (myPosition >= myLength) {
      throw new EOFException();
    }
    final byte result = myStrategy.getPage(this, myPosition).getByte((int)(myPosition % myStrategy.getPageSize()));
    ++myPosition;
    return result & 0xff;
  }

  public int read(byte[] b) throws IOException {
    return read(b, 0, b.length);
  }

  public int read(byte[] b, int off, int len) throws IOException {
    int savedOffset = off;
    while (len > 0 && myPosition < myLength) {
      CachedFilePage page = myStrategy.getPage(this, myPosition);
      int pageIndex = (int)(myPosition % myStrategy.getPageSize());
      int readBytes = page.read(pageIndex, b, off, len);
      myPosition += readBytes;
      off += readBytes;
      len -= readBytes;
    }
    return off - savedOffset;
  }

  public final void readFully(byte[] b) throws IOException {
    readFully(b, 0, b.length);
  }

  public final void readFully(byte[] b, int off, int len) throws IOException {
    int n = 0;
    while (len > n) {
      if (myPosition >= myLength) {
        throw new EOFException("Position " + myPosition + " is out of file length " + myLength + ". Bytes to read: " + (len - n));
      }
      n += read(b, off + n, len - n);
    }
  }

  public int skipBytes(int n) throws IOException {
    long pos;
    long len;
    long newpos;
    if (n <= 0) {
      return 0;
    }
    pos = getFilePointer();
    len = length();
    newpos = pos + n;
    if (newpos > len) {
      newpos = len;
    }
    seek(newpos);
    return (int)(newpos - pos);
  }

  public final boolean readBoolean() throws IOException {
    int ch = read();
    return (ch != 0);
  }

  public final byte readByte() throws IOException {
    int ch = read();
    return (byte)ch;
  }

  public final int readUnsignedByte() throws IOException {
    return read();
  }

  public final short readShort() throws IOException {
    byte[] buffer = myTypedIOBuffer;
    if (read(buffer, 0, 2) < 2) {
      throw new EOFException();
    }
    int ch1 = buffer[0] & 0xff;
    int ch2 = buffer[1] & 0xff;
    return (short)((ch1 << 8) + ch2);
  }

  public final int readUnsignedShort() throws IOException {
    byte[] buffer = myTypedIOBuffer;
    if (read(buffer, 0, 2) < 2) {
      throw new EOFException();
    }
    int ch1 = buffer[0] & 0xff;
    int ch2 = buffer[1] & 0xff;
    return (ch1 << 8) + ch2;
  }

  public final char readChar() throws IOException {
    return (char)readUnsignedShort();
  }

  public final int readInt() throws IOException {
    byte[] buffer = myTypedIOBuffer;
    if (read(buffer, 0, 4) < 4) {
      throw new EOFException();
    }
    int ch1 = buffer[0] & 0xff;
    int ch2 = buffer[1] & 0xff;
    int ch3 = buffer[2] & 0xff;
    int ch4 = buffer[3] & 0xff;
    return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4);
  }

  public final long readLong() throws IOException {
    byte[] buffer = myTypedIOBuffer;
    if (read(buffer, 0, 8) < 8) {
      throw new EOFException();
    }
    long ch1 = buffer[0] & 0xff;
    long ch2 = buffer[1] & 0xff;
    long ch3 = buffer[2] & 0xff;
    long ch4 = buffer[3] & 0xff;
    long ch5 = buffer[4] & 0xff;
    long ch6 = buffer[5] & 0xff;
    long ch7 = buffer[6] & 0xff;
    long ch8 = buffer[7] & 0xff;
    return ((ch1 << 56) + (ch2 << 48) + (ch3 << 40) + (ch4 << 32) + (ch5 << 24) + (ch6 << 16) + (ch7 << 8) + ch8);
  }

  public final float readFloat() throws IOException {
    return Float.intBitsToFloat(readInt());
  }

  public final double readDouble() throws IOException {
    return Double.longBitsToDouble(readLong());
  }

  @Nullable
  public final String readLine() throws IOException {
    StringBuffer input = new StringBuffer();
    int c = -1;
    boolean eol = false;
    while (!eol) {
      switch (c = read()) {
        case -1:
        case '\n':
          eol = true;
          break;
        case '\r':
          eol = true;
          long cur = getFilePointer();
          if ((read()) != '\n') {
            seek(cur);
          }
          break;
        default:
          input.append((char)c);
          break;
      }
    }
    if ((c == -1) && (input.length() == 0)) {
      return null;
    }
    return input.toString();
  }

  public final String readUTF() throws IOException {
    int len = readInt();
    byte[] bytes = new byte[ len ];
    readFully(bytes);
    return new String(bytes, UTF_8_CHARSET_NAME);
  }

  public void flush() throws IOException {
    myStrategy.flush(this);
  }

  public void close() throws IOException {
    myStrategy.close(this);
  }

  public void dispose() throws IOException {
    close();
  }

  protected void init(final CachingStrategy strategy, final long length, final long position) throws IOException {
    myLength = length;
    myPosition = position;
    myStrategy = strategy;
  }

  protected static class SingleFileCachingStrategy implements CachingStrategy {

    final private int myPageSize;
    final private IntObjectCache<CachedFilePage> myCache;
    final private TIntHashSet myDirtyPages;
    private CachedFilePage myLastAccessedPage;
    private CachedFilePage myFreePage;

    SingleFileCachingStrategy(int pageSize, int pagesCount) {
      myPageSize = pageSize;
      myCache = new IntObjectCache<CachedFilePage>(pagesCount);
      myDirtyPages = new TIntHashSet();
      myCache.addDeletedPairsListener(new IntObjectCache.DeletedPairsListener() {
        public void objectRemoved(final int key, final Object value) {
          myFreePage = (CachedFilePage)value;
        }
      });
    }

    public CachedFilePage getPage(CachedFile owner, long offset) throws IOException {
      offset -= (offset % myPageSize);
      if (myLastAccessedPage != null && offset == myLastAccessedPage.getOffset()) {
        return myLastAccessedPage;
      }
      int pageOffset = (int)(offset / (long)myPageSize);
      CachedFilePage result = myCache.tryKey(pageOffset);
      if (result == null) {
        if (myFreePage == null) {
          result = new CachedFilePage(owner, offset, myPageSize);
        }
        else {
          result = myFreePage;
          result.setOffset(offset);
          myFreePage = null;
        }
        long bytes2End = owner.length() - offset;
        if (bytes2End < 0) {
          bytes2End = 0;
        }
        result.setSize((bytes2End >= myPageSize) ? myPageSize : (int)bytes2End);
        result.load();
        myCache.cacheObject(pageOffset, result);
        if (myFreePage != null) {
          myFreePage.save();
        }
      }
      return (myLastAccessedPage = result);
    }

    public void markPageDirty(CachedFilePage page, boolean dirty) {
      int offset = (int)(page.getOffset() / myPageSize);
      if (dirty) {
        myDirtyPages.add(offset);
      }
      else {
        myDirtyPages.remove(offset);
      }
    }

    public void flush(CachedFile owner) throws IOException {
      flush();
    }

    public void flush() throws IOException {
      if (myDirtyPages.size() > 0) {
        final int[] ints = myDirtyPages.toArray();
        if (ints.length > 1) {
          Arrays.sort(ints);
        }
        for (int offset : ints) {
          final CachedFilePage page = myCache.tryKey(offset);
          if (page != null) {
            page.save();
          }
        }
      }
    }

    public void close(CachedFile owner) throws IOException {
      flush();
    }

    public int getCacheSize() {
      return myCache.size();
    }

    public int getPageSize() {
      return myPageSize;
    }

    public int usedMemory() {
      return myCache.count() * myPageSize;
    }

    public double cacheHitRate() {
      return myCache.hitRate();
    }
  }
}
TOP

Related Classes of com.intellij.util.io.CachedFile

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.