com.rgi.geopackage.features.ByteOutputStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swagd Show documentation
Show all versions of swagd Show documentation
SWAGD: Software to Aggregate Geospatial Data
The newest version!
/* The MIT License (MIT)
*
* Copyright (c) 2015 Reinventing Geospatial, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.rgi.geopackage.features;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.Objects;
/**
* @author Luke Lambert
*/
public final class ByteOutputStream implements AutoCloseable
{
/**
* Constructor
*
* Uses a default initial capacity of 32 bytes
*/
public ByteOutputStream()
{
this(DEFAULT_INITIAL_CAPACITY);
}
/**
* Constructor
*
* @param capacity
* Initial allocation byte size of the backing buffer
*/
public ByteOutputStream(final int capacity)
{
if(capacity < 0)
{
throw new IllegalArgumentException("Capacity must be positive");
}
this.buffer = new byte[capacity];
this.position = 0;
this.setByteOrder(DEFAULT_INITIAL_BYTE_ORDER);
}
/**
* @return a copy of the backing buffer without any trailing unused bytes
*/
public byte[] array()
{
return this.position <= 0 ? EMPTY_ARRAY
: Arrays.copyOfRange(this.buffer, 0, this.position);
}
/**
* Writes a byte to the stream
*
* @param b
* a byte
*/
public void write(final byte b)
{
this.checkCapacity(BYTE_BYTE_SIZE);
this.buffer[this.position] = b;
this.position += BYTE_BYTE_SIZE;
}
/**
* Writes a 2 byte short to the stream using the proscribed byte order
*
* @param s
* a short
*/
public void write(final short s)
{
this.checkCapacity(SHORT_BYTE_SIZE);
this.bytePutter.put(s);
this.position += SHORT_BYTE_SIZE;
}
/**
* Writes a 4 byte int to the stream using the proscribed byte order
*
* @param i
* an int
*/
public void write(final int i)
{
this.checkCapacity(INT_BYTE_SIZE);
this.bytePutter.put(i);
this.position += INT_BYTE_SIZE;
}
/**
* Writes a 4 byte float to the stream using the proscribed byte order
*
* @param f
* a float
*/
public void write(final float f)
{
this.write(Float.floatToRawIntBits(f));
}
/**
* Writes an 8 byte long to the stream using the proscribed byte order
*
* @param l
* a long
*/
public void write(final long l)
{
this.checkCapacity(LONG_BYTE_SIZE);
this.bytePutter.put(l);
this.position += LONG_BYTE_SIZE;
}
/**
* Writes an 8 byte double to the stream using the proscribed byte order
*
* @param d
* a double
*/
public void write(final double d)
{
this.write(Double.doubleToLongBits(d));
}
/**
* Writes a series of bytes to the stream
*
* @param bytes
* a byte array
*/
public void write(final byte[] bytes)
{
if(bytes == null)
{
throw new IllegalArgumentException("Bytes may not be null");
}
this.checkCapacity(bytes.length);
System.arraycopy(bytes, 0, this.buffer, this.position, bytes.length);
this.position += bytes.length;
}
public ByteOrder getByteOrder()
{
return this.bytePutter.getByteOrder();
}
public void setByteOrder(final ByteOrder byteOrder)
{
if(byteOrder == null)
{
throw new IllegalArgumentException("Byte order may not be null");
}
this.bytePutter = Objects.equals(byteOrder, ByteOrder.BIG_ENDIAN) ? this.bigEndianBytePutter
: this.littleEndianBytePutter;
}
private void checkCapacity(final int requestedBytes)
{
if(this.position + requestedBytes > this.buffer.length)
{
this.resize(requestedBytes);
}
}
private void resize(final int requestedBytes)
{
final int minimum = this.buffer.length + requestedBytes;
// Growing by 1.5 seems to be the most common strategy:
// https://groups.google.com/forum/#!msg/comp.lang.c++.moderated/asH_VojWKJw/4jJHJXPzWJ0J
@SuppressWarnings("NumericCastThatLosesPrecision")
final int oneAndAHalf = (int)Math.ceil(this.buffer.length * 1.5);
final int newSize = Math.max(minimum, oneAndAHalf);
final byte[] newBuffer = new byte[newSize];
System.arraycopy(this.buffer, 0, newBuffer, 0, this.buffer.length);
this.buffer = newBuffer;
}
@SuppressWarnings({"MagicNumber", "NumericCastThatLosesPrecision"}) private static byte short1(final short x) { return (byte)(x >> 8); } // x >> (1 * 8)
@SuppressWarnings({"MagicNumber", "NumericCastThatLosesPrecision"}) private static byte short0(final short x) { return (byte)(x ); } // x >> (0 * 8)
@SuppressWarnings({"MagicNumber", "NumericCastThatLosesPrecision"}) private static byte int3(final int x) { return (byte)(x >> 24); } // x >> (3 * 8)
@SuppressWarnings({"MagicNumber", "NumericCastThatLosesPrecision"}) private static byte int2(final int x) { return (byte)(x >> 16); } // x >> (2 * 8)
@SuppressWarnings({"MagicNumber", "NumericCastThatLosesPrecision"}) private static byte int1(final int x) { return (byte)(x >> 8); } // x >> (1 * 8)
@SuppressWarnings({"MagicNumber", "NumericCastThatLosesPrecision"}) private static byte int0(final int x) { return (byte)(x ); } // x >> (0 * 8)
@SuppressWarnings({"MagicNumber", "NumericCastThatLosesPrecision"}) private static byte long7(final long x) { return (byte)(x >> 56); } // x >> (7 * 8)
@SuppressWarnings({"MagicNumber", "NumericCastThatLosesPrecision"}) private static byte long6(final long x) { return (byte)(x >> 48); } // x >> (6 * 8)
@SuppressWarnings({"MagicNumber", "NumericCastThatLosesPrecision"}) private static byte long5(final long x) { return (byte)(x >> 40); } // x >> (5 * 8)
@SuppressWarnings({"MagicNumber", "NumericCastThatLosesPrecision"}) private static byte long4(final long x) { return (byte)(x >> 32); } // x >> (4 * 8)
@SuppressWarnings({"MagicNumber", "NumericCastThatLosesPrecision"}) private static byte long3(final long x) { return (byte)(x >> 24); } // x >> (3 * 8)
@SuppressWarnings({"MagicNumber", "NumericCastThatLosesPrecision"}) private static byte long2(final long x) { return (byte)(x >> 16); } // x >> (2 * 8)
@SuppressWarnings({"MagicNumber", "NumericCastThatLosesPrecision"}) private static byte long1(final long x) { return (byte)(x >> 8); } // x >> (1 * 8)
@SuppressWarnings({"MagicNumber", "NumericCastThatLosesPrecision"}) private static byte long0(final long x) { return (byte)(x ); } // x >> (0 * 8)
private interface BytePutter
{
void put(final short s);
void put(final int i);
void put(final long l);
ByteOrder getByteOrder();
}
private final BytePutter bigEndianBytePutter = new BytePutter()
{
@Override
public void put(final short s)
{
ByteOutputStream.this.buffer[ByteOutputStream.this.position ] = short1(s);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 1] = short0(s);
}
@Override
public void put(final int i)
{
ByteOutputStream.this.buffer[ByteOutputStream.this.position ] = int3(i);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 1] = int2(i);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 2] = int1(i);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 3] = int0(i);
}
@Override
public void put(final long l)
{
ByteOutputStream.this.buffer[ByteOutputStream.this.position ] = long7(l);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 1] = long6(l);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 2] = long5(l);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 3] = long4(l);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 4] = long3(l);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 5] = long2(l);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 6] = long1(l);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 7] = long0(l);
}
@Override
public ByteOrder getByteOrder()
{
return ByteOrder.BIG_ENDIAN;
}
};
private final BytePutter littleEndianBytePutter = new BytePutter()
{
@Override
public void put(final short s)
{
ByteOutputStream.this.buffer[ByteOutputStream.this.position ] = short0(s);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 1] = short1(s);
}
@Override
public void put(final int i)
{
ByteOutputStream.this.buffer[ByteOutputStream.this.position ] = int0(i);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 1] = int1(i);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 2] = int2(i);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 3] = int3(i);
}
@Override
public void put(final long l)
{
ByteOutputStream.this.buffer[ByteOutputStream.this.position ] = long0(l);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 1] = long1(l);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 2] = long2(l);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 3] = long3(l);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 4] = long4(l);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 5] = long5(l);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 6] = long6(l);
ByteOutputStream.this.buffer[ByteOutputStream.this.position + 7] = long7(l);
}
@Override
public ByteOrder getByteOrder()
{
return ByteOrder.LITTLE_ENDIAN;
}
};
private byte[] buffer;
private int position;
private BytePutter bytePutter;
private static final ByteOrder DEFAULT_INITIAL_BYTE_ORDER = ByteOrder.BIG_ENDIAN;
private static final int DEFAULT_INITIAL_CAPACITY = 32;
private static final int BYTE_BYTE_SIZE = 1;
private static final int SHORT_BYTE_SIZE = 2;
private static final int INT_BYTE_SIZE = 4;
private static final int FLOAT_BYTE_SIZE = 4;
private static final int LONG_BYTE_SIZE = 8;
private static final int DOUBLE_BYTE_SIZE = 8;
private static final byte[] EMPTY_ARRAY = {};
@Override
public void close()
{
//noinspection AssignmentToNull
this.buffer = null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy