Package com.fasterxml.util.membuf.impl

Source Code of com.fasterxml.util.membuf.impl.ByteBufferBytesSegment$Allocator

package com.fasterxml.util.membuf.impl;

import java.nio.ByteBuffer;

import com.fasterxml.util.membuf.*;
import com.fasterxml.util.membuf.base.BytesSegment;
import com.fasterxml.util.membuf.base.SegmentAllocatorBase;

/**
* {@link Segment} implementation that uses {@link ByteBuffer}s for
* storing data.
* Basically a wrapper around (direct) {@link ByteBuffer},
* adding state information and linkage to next segment in chain
* (of used or free segments).
*
* @author Tatu Saloranta
*/
public class ByteBufferBytesSegment extends BytesSegment
{
    /*
    /**********************************************************************
    /* Storage
    /**********************************************************************
     */
   
    /**
     * Underlying low-level buffer in which raw entry data is queued
     */
    protected final ByteBuffer _buffer;

    /**
     * Wrapper buffer used for reading previously written content; wrapper
     * used to allow separate pointers for reading and writing content.
     */
    protected ByteBuffer _readBuffer;

    /*
    /**********************************************************************
    /* Life-cycle
    /**********************************************************************
     */
   
    public ByteBufferBytesSegment(int size, boolean useDirect)
    {
        super();
        if (size < ABSOLUTE_MINIMUM_LENGTH) {
            size = ABSOLUTE_MINIMUM_LENGTH;
        }
        _buffer = useDirect ? ByteBuffer.allocateDirect(size) : ByteBuffer.allocate(size);
    }


    /**
     * Factory method for construction {@link SegmentAllocatorBase} that
     * constructs instances of this segment type
     */
    public static Allocator allocator(int segmentSize, int minSegmentsToRetain, int maxSegments,
            boolean allocateNativeBuffers) {
        return new Allocator(segmentSize, minSegmentsToRetain, maxSegments, allocateNativeBuffers);
    }
   
    /*
    /**********************************************************************
    /* API: state changes
    /**********************************************************************
     */

    //public Segment initForWriting()
    //public Segment finishWriting()
   
    @Override
    public BytesSegment initForReading()
    {
        super.initForReading();
        _readBuffer = _buffer.asReadOnlyBuffer();
        _readBuffer.clear();
        return this;
    }

    @Override
    public BytesSegment finishReading()
    {
        BytesSegment result = super.finishReading();
        // clear write pointer for further reuse
        _buffer.clear();
        // and drop reference to read-wrapper:
        _readBuffer = null;
        return result;
    }

    /**
     * Method that will erase any content segment may have and reset
     * various pointers: will be called when clearing buffer, the last
     * remaining segment needs to be cleared.
     */
    @Override
    public void clear()
    {
        _readBuffer = null; // could/should we just reset it instead?
        _buffer.clear(); // clear the write pointer
        super.clear();
    }

    /*
    /**********************************************************************
    /* Package methods, properties
    /**********************************************************************
     */

    @Override
    public int availableForAppend() {
        return _buffer.remaining();
    }

    @Override
    public int availableForReading() {
        if (_readBuffer == null) { // sanity check...
            throw new IllegalStateException("Method should not be called when _readBuffer is null");
        }
        return _readBuffer.remaining();
    }

    /*
    /**********************************************************************
    /* Package methods, appending data
    /**********************************************************************
     */
   
    @Override
    public void append(byte[] src, int offset, int length) {
        _buffer.put(src, offset, length);
    }

    @Override
    public int tryAppend(byte[] src, int offset, int length)
    {
        int actualLen = Math.min(length, availableForAppend());
        if (actualLen > 0) {
            _buffer.put(src, offset, actualLen);
        }
        return actualLen;
    }

    @Override
    public boolean tryAppend(byte value)
    {
        if (availableForAppend() > 0) {
            _buffer.put(value);
            return true;
        }
        return false;
    }
   
    /*
    /**********************************************************************
    /* Reading data
    /**********************************************************************
     */

    @Override
    public byte read() { // caller must check bounds; otherwise it'll get out-of-bounds
        return _readBuffer.get();
    }
   
    @Override
    public void read(byte[] buffer, int offset, int length) {
        _readBuffer.get(buffer, offset, length);
    }

    @Override
    public int tryRead(byte[] buffer, int offset, int length)
    {
        int actualLen = Math.min(availableForReading(), length);
        if (actualLen > 0) {
            _readBuffer.get(buffer, offset, actualLen);
        }
        return actualLen;
    }
   
    @Override
    public int skip(int length)
    {
        length = Math.min(length, availableForReading());
        _readBuffer.position(_readBuffer.position() + length);
        return length;
    }

    @Override
    public int readLength()
    {
        int available = availableForReading();
        if (available == 0) {
            return -1;
        }
        int length = _readBuffer.get();

        if (length < 0) { // single-byte length, simple
            return (length & 0x7F);
        }
        if (--available == 0) {
            return -(length + 1);
        }

        // second byte:
        int b = _readBuffer.get();
        if (b < 0) { // two-byte completed
            return (length << 7) + (b & 0x7F);
        }
        length = (length << 7) + b;
        if (--available == 0) {
            return -(length + 1);
        }

        // third byte:
        b = _readBuffer.get();
        if (b < 0) {
            return (length << 7) + (b & 0x7F);
        }
        length = (length << 7) + b;
        if (--available == 0) {
            return -(length + 1);
        }

        // fourth byte:
        b = _readBuffer.get();
        if (b < 0) {
            return (length << 7) + (b & 0x7F);
        }
        length = (length << 7) + b;
        if (--available == 0) {
            return -(length + 1);
        }

        // fifth and last byte
        b = _readBuffer.get();
        if (b < 0) {
            return (length << 7) + (b & 0x7F);
        }
        // ... or, corrupt data
        throw new IllegalStateException("Corrupt segment: fifth byte of length was 0x"+Integer.toHexString(b)+" did not have high-bit set");
    }

    /**
     * Method that is called to read length prefix that is split across
     * segment boundary. Due to
     */
    @Override
    public int readSplitLength(int partial)
    {
        while (true) {
            partial = (partial << 7);
            int b = _readBuffer.get();
            if (b < 0) { // complete...
                return partial + (b & 0x7F);
            }
            partial += b;
        }
    }

    /*
    /**********************************************************************
    /* Helper class: Allocator for this segment type
    /**********************************************************************
     */
   
    /**
     * {@link SegmentAllocator} implementation that allocates
     * {@link ByteBufferBytesSegment}s.
     */
    public static class Allocator extends SegmentAllocatorBase<BytesSegment>
    {
        protected final boolean _cfgAllocateNative;
       
        public Allocator(int segmentSize, int minSegmentsToRetain, int maxSegments,
                boolean allocateNativeBuffers)
              
        {
            super(segmentSize, minSegmentsToRetain, maxSegments);
            _cfgAllocateNative = allocateNativeBuffers;
        }

        @Override
        protected BytesSegment _allocateSegment()
        {
            // can reuse a segment returned earlier?
            if (_reusableSegmentCount > 0) {
                BytesSegment segment = _firstReusableSegment;
                _firstReusableSegment = segment.getNext();
                ++_bufferOwnedSegmentCount;
                --_reusableSegmentCount;
                return segment;
            }
            BytesSegment segment = new ByteBufferBytesSegment(_segmentSize, _cfgAllocateNative);
            ++_bufferOwnedSegmentCount;
            return segment;
        }
    }
}
TOP

Related Classes of com.fasterxml.util.membuf.impl.ByteBufferBytesSegment$Allocator

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.