All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fasterxml.storemate.shared.ByteContainer Maven / Gradle / Ivy

There is a newer version: 1.1.4
Show newest version
package com.fasterxml.storemate.shared;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;

import com.fasterxml.storemate.shared.hash.BlockHasher32;
import com.fasterxml.storemate.shared.util.WithBytesCallback;

/**
 * Simple read-only wrapper around basic in-heap byte array, used for buffering.
 */
public abstract class ByteContainer
{
    public final static ByteContainer emptyContainer() {
        return NoBytesContainer.instance;
    }

    public final static ByteContainer simple(byte[] bytes) {
        return new SimpleContainer(bytes, 0, bytes.length);
    }
    
    public final static ByteContainer simple(byte[] bytes, int offset, int len)
    {
        if (len == 0) {
            return emptyContainer();
        }
        // Let's do some sanity checks, saves us debugging
        if (bytes == null) throw new IllegalArgumentException("Null 'bytes'");
        final int arrayLen = bytes.length;
        if (offset < 0 || len < 0 || (offset + len) > arrayLen) {
            throw new IllegalArgumentException("Illegal offset/length ("+offset+"/"+len
                    +"): extend beyond start/end of array of "+arrayLen);
        }
        return new SimpleContainer(bytes, offset, len);
    }
    
    /**
     * Accessor for checking how many bytes are contained.
     */
    public abstract int byteLength();

    /**
     * Simple accessor only to be used by tests (real code should use
     * callbacks or bulk access)
     */
    public abstract byte get(int index);
    
    /**
     * Factory method for creating a view of contents of this container.
     * 
     * @param offset Offset in the original buffer; has to be between
     *    0 and length - 1 (inclusive)
     * @param length Length of the slice to create: must not extend past
     *   end of this instance
     *   
     * @return New container with the view, if necessary; or this instance
     *    if no change
     */
    public abstract ByteContainer view(int offset, int length);
    
    public abstract  T withBytes(WithBytesCallback cb);

    public abstract  T withBytes(WithBytesCallback cb, int offset, int length);
    
    /**
     * @param buffer Buffer into which copy bytes
     * @param offset Offset to copy bytes at
     * 
     * @return Offset after copying the bytes, that is: offset + byteLength()
     */
    public abstract int getBytes(byte[] buffer, int offset);
    
    public abstract byte[] asBytes();

    public abstract int hash(BlockHasher32 hasher, int seed);
    
    public abstract void writeBytes(OutputStream out) throws IOException;

    public abstract void writeBytes(OutputStream out, int offset, int length) throws IOException;
    
    private final static class NoBytesContainer extends ByteContainer
    {
        final static byte[] NO_BYTES = new byte[0];
        
        final static NoBytesContainer instance = new NoBytesContainer();
        
        private NoBytesContainer() { }

        @Override public int byteLength() {
            return 0;
        }

        @Override public byte get(int index) {
            throw new IllegalArgumentException("Bad offset ("+index+"); this length is 0");
        }
        
        @Override public int getBytes(byte[] buffer, int offset) {
            return offset;
        }

        @Override public byte[] asBytes() { return NO_BYTES; }

        @Override public int hash(BlockHasher32 hasher, int seed) {
            return hasher.hash(seed, NO_BYTES);
        }
        
        @Override public void writeBytes(OutputStream out)  { }
        @Override
        public void writeBytes(OutputStream out, int offset, int length) {
        	if (offset != 0 || length != 0) {
                throw new IllegalArgumentException("Bad offset/length ("+offset+"/"+length+"); this length is 0");
        	}
        }

        @Override public  T withBytes(WithBytesCallback cb) {
            return cb.withBytes(NO_BYTES, 0, 0);
        }
        
        @Override public  T withBytes(WithBytesCallback cb, int offset, int length) {
            if (offset == 0 && length == 0) {
                return cb.withBytes(NO_BYTES, 0, 0);
            }
            throw new IllegalArgumentException("Bad offset/length ("+offset+"/"+length+"); this length is 0");
        }
        
        @Override
        public ByteContainer view(int offset, int length) {
            if (offset == 0 && length == 0) {
                return this;
            }
            throw new IllegalArgumentException("Bad offset/length ("+offset+"/"+length+"); this length is 0");
        }        
    }

    private final static class SimpleContainer extends ByteContainer
    {
        private final byte[] _data;
        private final int _offset, _length;
        
        SimpleContainer(byte[] bytes, int offset, int len) {
            _data = bytes;
            _offset = offset;
            _length = len;
        }

        @Override public int byteLength() {
            return _length;
        }

        @Override public byte get(int index) {
            if (index < 0 || index >= _length) {
                throw new IllegalArgumentException("Bad offset ("+index+"); this length is "+_length);
            }
            return _data[_offset + index];
        }
        
        @Override public int getBytes(byte[] buffer, int offset) {
            System.arraycopy(_data, _offset, buffer, offset, _length);
            return (offset + _length);
        }

        @Override
        public byte[] asBytes() {
            if (_offset == 0) {
                return Arrays.copyOf(_data, _length);
            }
            return Arrays.copyOfRange(_data, _offset, _offset + _length);
        }
        
        @Override public int hash(BlockHasher32 hasher, int seed) {
            return hasher.hash(seed, _data, _offset, _length);
        }
        
        @Override public void writeBytes(OutputStream out) throws IOException {
            out.write(_data, _offset, _length);
        }

        @Override
        public void writeBytes(OutputStream out, int offset, int length) throws IOException
        {
        	if (offset < 0 || (offset+length) > _length) {
                throw new IllegalArgumentException("Bad offset/length ("+offset+"/"+length+"); this length is "+_length);
            }
            out.write(_data, _offset + offset, length);
        }
        
        @Override public  T withBytes(WithBytesCallback cb) {
            return cb.withBytes(_data, _offset, _length);
        }

        @Override public  T withBytes(WithBytesCallback cb, int offset, int length) {
            if (offset == 0 && length == _length) {
                return cb.withBytes(_data, _offset, _length);
            }
            if (offset < 0 || (offset+length) > _length) {
                throw new IllegalArgumentException("Bad offset/length ("+offset+"/"+length+"); this length is "+_length);
            }
            return cb.withBytes(_data, _offset + offset, length);
        }
        
        @Override
        public ByteContainer view(int offset, int length) {
            if (offset == 0 && length == _length) {
                return this;
            }
            if (offset < 0 || (offset+length) > _length) {
                throw new IllegalArgumentException("Bad offset/length ("+offset+"/"+length+"); this length is "+_length);
            }
            return new SimpleContainer(_data, _offset + offset, length);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy