Mercurial > hg > Members > sugi > MessagePack-java
diff src/main/java/org/msgpack/io/LinkedBufferInput.java @ 0:cb825acd883a
first commit
author | sugi |
---|---|
date | Sat, 18 Oct 2014 15:06:15 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/org/msgpack/io/LinkedBufferInput.java Sat Oct 18 15:06:15 2014 +0900 @@ -0,0 +1,399 @@ +// +// MessagePack for Java +// +// Copyright (C) 2009 - 2013 FURUHASHI Sadayuki +// +// 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 org.msgpack.io; + +import java.io.IOException; +import java.io.EOFException; +import java.util.LinkedList; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.nio.ByteBuffer; + +public class LinkedBufferInput extends AbstractInput { + LinkedList<ByteBuffer> link; + + int writable; + + private int nextAdvance; + + private byte[] tmpBuffer; + + private ByteBuffer tmpByteBuffer; + + private final int bufferSize; + + public LinkedBufferInput(int bufferSize) { + this.link = new LinkedList<ByteBuffer>(); + this.writable = -1; + this.tmpBuffer = new byte[8]; + this.tmpByteBuffer = ByteBuffer.wrap(tmpBuffer); + this.bufferSize = bufferSize; + } + + public int read(byte[] b, int off, int len) throws EOFException { + if (link.isEmpty()) { + return 0; + } + int olen = len; + while (true) { + ByteBuffer bb = link.getFirst(); + if (len < bb.remaining()) { + bb.get(b, off, len); + incrReadByteCount(len); + return olen; + } + int rem = bb.remaining(); + bb.get(b, off, rem); + incrReadByteCount(rem); + len -= rem; + off += rem; + if (!removeFirstLink(bb)) { + break; + } + } + return olen - len; + } + + public boolean tryRefer(BufferReferer ref, int len) throws IOException { + ByteBuffer bb = null; + try { + bb = link.getFirst(); + } catch(NoSuchElementException e) {} + if (bb == null) { + throw new EndOfBufferException(); + } else if (bb.remaining() < len) { + return false; + } + boolean success = false; + int pos = bb.position(); + int lim = bb.limit(); + try { + bb.limit(pos + len); + ref.refer(bb, true); + incrReadByteCount(len); + success = true; + } finally { + bb.limit(lim); + if (success) { + bb.position(pos + len); + } else { + bb.position(pos); + } + if (bb.remaining() == 0) { + removeFirstLink(bb); + } + } + return true; + } + + public byte readByte() throws EOFException { + ByteBuffer bb = null; + try { + bb = link.getFirst(); + } catch(NoSuchElementException e) {} + if (bb == null || bb.remaining() == 0) { + throw new EndOfBufferException(); + } + byte result = bb.get(); + incrReadOneByteCount(); + if (bb.remaining() == 0) { + removeFirstLink(bb); + } + return result; + } + + public void advance() { + if (link.isEmpty()) { + return; + } + int len = nextAdvance; + ByteBuffer bb; + while (true) { + bb = link.getFirst(); + if (len < bb.remaining()) { + bb.position(bb.position() + len); + break; + } + len -= bb.remaining(); + bb.position(bb.position() + bb.remaining()); + if (!removeFirstLink(bb)) { + break; + } + } + incrReadByteCount(nextAdvance); + nextAdvance = 0; + } + + private boolean removeFirstLink(ByteBuffer first) { + if (link.size() == 1) { + if (writable >= 0) { + first.position(0); + first.limit(0); + writable = first.capacity(); + return false; + } else { + link.removeFirst(); + return false; + } + } else { + link.removeFirst(); + return true; + } + } + + private void requireMore(int n) throws EOFException { + int off = 0; + for (ByteBuffer bb : link) { + if (n <= bb.remaining()) { + int pos = bb.position(); + bb.get(tmpBuffer, off, n); + bb.position(pos); + return; + } + int rem = bb.remaining(); + int pos = bb.position(); + bb.get(tmpBuffer, off, rem); + bb.position(pos); + n -= rem; + off += rem; + } + throw new EndOfBufferException(); + } + + private ByteBuffer require(int n) throws EOFException { + ByteBuffer bb = null; + try { + bb = link.getFirst(); + } catch(NoSuchElementException e) {} + if (bb == null) { + throw new EndOfBufferException(); + } + if (n <= bb.remaining()) { + nextAdvance = n; + return bb; + } else { + requireMore(n); + nextAdvance = n; + return tmpByteBuffer; + } + } + + public byte getByte() throws EOFException { + ByteBuffer bb = require(1); + return bb.get(bb.position()); + } + + public short getShort() throws EOFException { + ByteBuffer bb = require(2); + return bb.getShort(bb.position()); + } + + public int getInt() throws EOFException { + ByteBuffer bb = require(4); + return bb.getInt(bb.position()); + } + + public long getLong() throws EOFException { + ByteBuffer bb = require(8); + return bb.getLong(bb.position()); + } + + public float getFloat() throws EOFException { + ByteBuffer bb = require(4); + return bb.getFloat(bb.position()); + } + + public double getDouble() throws EOFException { + ByteBuffer bb = require(8); + return bb.getDouble(bb.position()); + } + + public void feed(byte[] b) { + feed(b, 0, b.length, false); + } + + public void feed(byte[] b, boolean reference) { + feed(b, 0, b.length, reference); + } + + public void feed(byte[] b, int off, int len) { + feed(b, off, len, false); + } + + public void feed(byte[] b, int off, int len, boolean reference) { + if (reference) { + if (writable > 0 && link.getLast().remaining() == 0) { + link.add(link.size()-1, ByteBuffer.wrap(b, off, len)); + return; + } + link.addLast(ByteBuffer.wrap(b, off, len)); + writable = -1; + return; + } + + ByteBuffer bb = null; + try { + bb = link.getLast(); + } catch(NoSuchElementException e) {} + if (len <= writable) { + int pos = bb.position(); + bb.position(bb.limit()); + bb.limit(bb.limit() + len); + bb.put(b, off, len); + bb.position(pos); + writable = bb.capacity() - bb.limit(); + return; + } + + if (writable > 0) { + int pos = bb.position(); + bb.position(bb.limit()); + bb.limit(bb.limit() + writable); + bb.put(b, off, writable); + bb.position(pos); + off += writable; + len -= writable; + writable = 0; + } + + int sz = Math.max(len, bufferSize); + ByteBuffer nb = ByteBuffer.allocate(sz); + nb.put(b, off, len); + nb.limit(len); + nb.position(0); + link.addLast(nb); + writable = sz - len; + } + + public void feed(ByteBuffer b) { + feed(b, false); + } + + public void feed(ByteBuffer buf, boolean reference) { + if (reference) { + if (writable > 0 && link.getLast().remaining() == 0) { + link.add(link.size()-1, buf); + return; + } + link.addLast(buf); + writable = -1; + return; + } + + int rem = buf.remaining(); + + ByteBuffer bb = null; + try { + bb = link.getLast(); + } catch(NoSuchElementException e) {} + if (rem <= writable) { + int pos = bb.position(); + bb.position(bb.limit()); + bb.limit(bb.limit() + rem); + bb.put(buf); + bb.position(pos); + writable = bb.capacity() - bb.limit(); + return; + } + + if (writable > 0) { + int pos = bb.position(); + bb.position(bb.limit()); + bb.limit(bb.limit() + writable); + buf.limit(writable); + bb.put(buf); + bb.position(pos); + rem -= writable; + buf.limit(buf.limit() + rem); + writable = 0; + } + + int sz = Math.max(rem, bufferSize); + ByteBuffer nb = ByteBuffer.allocate(sz); + nb.put(buf); + nb.limit(rem); + nb.position(0); + link.addLast(nb); + writable = sz - rem; + } + + public void clear() { + if (writable >= 0) { + ByteBuffer bb = link.getLast(); + link.clear(); + bb.position(0); + bb.limit(0); + link.addLast(bb); + writable = bb.capacity(); + } else { + link.clear(); + writable = -1; + } + } + + public void copyReferencedBuffer() { + if (link.isEmpty()) { + return; + } + + int size = 0; + for(ByteBuffer bb : link) { + size += bb.remaining(); + } + if (size == 0) { + return; + } + + if (writable >= 0) { + ByteBuffer last = link.removeLast(); + byte[] copy = new byte[size - last.remaining()]; + int off = 0; + for(ByteBuffer bb : link) { + int len = bb.remaining(); + bb.get(copy, off, len); + off += len; + } + link.clear(); + link.add(ByteBuffer.wrap(copy)); + link.add(last); + + } else { + byte[] copy = new byte[size]; + int off = 0; + for(ByteBuffer bb : link) { + int len = bb.remaining(); + bb.get(copy, off, len); + off += len; + } + link.clear(); + link.add(ByteBuffer.wrap(copy)); + writable = 0; + } + } + + public int getSize() { + int size = 0; + for(ByteBuffer bb : link) { + size += bb.remaining(); + } + return size; + } + + public void close() { + } +}