modules/io/src/main/java/net/multiphasicapps/io/ByteDeque.java
// -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
// ---------------------------------------------------------------------------
// SquirrelJME
// Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
// ---------------------------------------------------------------------------
// SquirrelJME is under the Mozilla Public License Version 2.0.
// See license.mkd for licensing and copyright information.
// ---------------------------------------------------------------------------
package net.multiphasicapps.io;
import cc.squirreljme.jvm.mle.RuntimeShelf;
import cc.squirreljme.jvm.mle.constants.MemoryProfileType;
import cc.squirreljme.runtime.cldc.debug.Debugging;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.NoSuchElementException;
/**
* This is a byte buffer which provides bytes for input and output as a
* double ended queue.
*
* If the queue reaches full capacity then it is increased in size.
*
* This class is not thread safe.
*
* @since 2016/03/11
*/
public class ByteDeque
{
/**
* {@squirreljme.property net.multiphasicapps.util.datadeque.blocksize=n
* The block size of individual arrays that make up the {@link ByteDeque}
* class. The value must be a power of two.}
*/
private static final int _BLOCK_SIZE =
Math.max(8, Integer.getInteger(
"net.multiphasicapps.util.datadeque.blocksize",
ByteDeque.__dequeSliceSize()));
/** The block size mask. */
private static final int _BLOCK_MASK =
ByteDeque._BLOCK_SIZE - 1;
/** The shift to convert block based values. */
private static final int _BLOCK_SHIFT =
Integer.numberOfTrailingZeros(ByteDeque._BLOCK_SIZE);
/** The maximum permitted capacity. */
protected final int capacity;
/** Blocks which make up the queue. */
private final LinkedList<byte[]> _blocks =
new LinkedList<>();
/** Single byte (since it is synchronized). */
private final byte[] _solo =
new byte[1];
/** The number of bytes in the queue. */
private volatile int _total;
/** The relative position of the head in relation to the first block. */
private volatile int _head;
/** The relative position of the tail in relation to the last block. */
private volatile int _tail;
/**
* Sets the default block size.
*
* @since 2016/05/01
*/
static
{
/* {@squirreljme.error BD21 The block size of the data deque is not
a power of two. (The specified block size)} */
if (Integer.bitCount(ByteDeque._BLOCK_SIZE) != 1)
throw new RuntimeException(String.format("BD21 %d",
ByteDeque._BLOCK_SIZE));
}
/**
* Initializes a byte deque with a 2GiB buffer size limit.
*
* @since 2016/03/11
*/
public ByteDeque()
{
this(Integer.MAX_VALUE);
}
/**
* Initializes a byte deque with the given capacity.
*
* @param __cap The maximum deque capacity.
* @throws IllegalArgumentException If the capacity is negative.
* @since 2016/05/01
*/
public ByteDeque(int __cap)
throws IllegalArgumentException
{
/* {@squirreljme.error BD22 Negative deque capacity specified.} */
if (__cap < 0)
throw new IllegalArgumentException("BD22");
// Set
this.capacity = __cap;
}
/**
* Attempts to add a single byte to the start of the queue, if the capacity
* would be violated then an exception is thrown.
*
* @param __b The byte to add.
* @throws IllegalStateException If the capacity is violated.
* @since 2016/05/01
*/
public final void addFirst(byte __b)
throws IllegalStateException
{
byte[] solo = this._solo;
solo[0] = __b;
this.addFirst(solo, 0, 1);
}
/**
* Attempts to add multiple bytes to the start of the queue, if the
* capacity would be violated then an exception is thrown.
*
* @param __b The array to source bytes from.
* @throws IllegalStateException If the capacity is violated.
* @throws NullPointerException On null arguments.
* @since 2016/05/01
*/
public final void addFirst(byte[] __b)
throws IllegalStateException, NullPointerException
{
this.addFirst(__b, 0, __b.length);
}
/**
* Attempts to add multiple bytes to the start of the queue, if the
* capacity would be violated then an exception is thrown.
*
* @param __b The array to source bytes from.
* @param __o The offset to start reading from.
* @param __l The number of bytes to write.
* @throws IllegalStateException If the capacity is violated.
* @throws IndexOutOfBoundsException If the offset or length are negative
* or they exceed the array bounds.
* @throws NullPointerException On null arguments.
* @since 2016/05/01
*/
public final void addFirst(byte[] __b, int __o, int __l)
throws IllegalStateException, IndexOutOfBoundsException,
NullPointerException
{
// Check
if (__b == null)
throw new NullPointerException("NARG");
if (__o < 0 || __l < 0 || (__o + __l) < 0 || (__o + __l) > __b.length)
throw new IndexOutOfBoundsException("BAOB");
// No bytes to add, do nothing
if (__l == 0)
return;
/* {@squirreljme.error BD23 Adding bytes to the start would exceed
the capacity of the queue.} */
int total = this._total;
int newtotal = total + __l;
if (newtotal < 0 || newtotal > this.capacity)
throw new IllegalStateException("BD23");
// Get some things
LinkedList<byte[]> blocks = this._blocks;
int nb = blocks.size();
int head = this._head, tail = this._tail;
throw Debugging.todo();
}
/**
* Attempts to add a single byte to the end of the queue, if the capacity
* would be violated then an exception is thrown.
*
* @param __b The byte to add.
* @throws IllegalStateException If the capacity is violated.
* @since 2016/05/01
*/
public final void addLast(byte __b)
throws IllegalStateException
{
byte[] solo = this._solo;
solo[0] = __b;
this.addLast(solo, 0, 1);
}
/**
* Attempts to add multiple bytes to the end of the queue, if the capacity
* would be violated then an exception is thrown.
*
* @param __b The array to source bytes from.
* @throws IllegalStateException If the capacity is violated.
* @throws NullPointerException On null arguments.
* @since 2016/05/01
*/
public final void addLast(byte[] __b)
throws IllegalStateException, NullPointerException
{
this.addLast(__b, 0, __b.length);
}
/**
* Attempts to add multiple bytes to the end of the queue, if the capacity
* would be violated then an exception is thrown.
*
* @param __b The array to source bytes from.
* @param __o The offset to start reading from.
* @param __l The number of bytes to write.
* @throws IllegalStateException If the capacity is violated.
* @throws IndexOutOfBoundsException If the offset or length are negative
* or they exceed the array bounds.
* @throws NullPointerException On null arguments.
* @since 2016/05/01
*/
public final void addLast(byte[] __b, int __o, int __l)
throws IllegalStateException, IndexOutOfBoundsException,
NullPointerException
{
// Check
if (__b == null)
throw new NullPointerException("NARG");
if (__o < 0 || __l < 0 || (__o + __l) < 0 || (__o + __l) > __b.length)
throw new IndexOutOfBoundsException("BAOB");
// No bytes to add, do nothing
if (__l == 0)
return;
/* {@squirreljme.error BD24 Adding bytes to the end would exceed
the capacity of the queue.} */
int total = this._total;
int newtotal = total + __l;
if (newtotal < 0 || newtotal > this.capacity)
throw new IllegalStateException("BD24");
// Get some things
LinkedList<byte[]> blocks = this._blocks;
int nb = blocks.size();
int head = this._head, tail = this._tail;
// Keep adding in data
int bs = ByteDeque._BLOCK_SIZE;
int bm = ByteDeque._BLOCK_MASK;
int left = __l;
int at = __o;
while (left > 0)
{
// If the tail is at the start of the block then a new one
// must be created
byte[] bl;
if (tail == 0)
{
bl = new byte[bs];
blocks.addLast(bl);
}
// Otherwise get the last one
else
bl = blocks.getLast();
// Only can fit a single block
int limit = bs - tail;
if (left < limit)
limit = left;
// Write data
System.arraycopy(__b, at,
bl, tail, limit);
tail += limit;
at += limit;
/*for (int i = 0; i < limit; i++)
bl[tail++] = __b[at++];*/
// Masking is only needed after the write
tail &= bm;
// Consumed bytes
left -= limit;
}
// Set new details
this._total = newtotal;
this._tail = tail;
}
/**
* Returns the number of available bytes inside of the queue.
*
* @return The number of bytes in the queue.
* @since 2016/05/01
*/
public final int available()
{
return this._total;
}
/**
* Clears the queue and every associated byte.
*
* @since 2016/08/02
*/
public final void clear()
{
// Reset variables
this._total = 0;
this._head = 0;
this._tail = 0;
// Zero out all blocks (for security and better compression)
LinkedList<byte[]> blocks = this._blocks;
for (byte[] bl : blocks)
Arrays.fill(bl, (byte)0);
blocks.clear();
}
/**
* Deletes the specified number of bytes at the start of the deque.
*
* @param __l The number of bytes to delete.
* @return The number of deleted bytes.
* @throws IndexOutOfBoundsException If the number of bytes is negative.
* @since 2016/08/04
*/
public final int deleteFirst(int __l)
throws IndexOutOfBoundsException
{
/* {@squirreljme.error BD25 Attempt to delete starting from a negative
address.} */
if (__l < 0)
throw new IndexOutOfBoundsException("BD25");
// Do nothing
if (__l == 0)
return 0;
// If the queue is empty do nothing
int total = this._total;
if (total == 0)
return 0;
// Do not remove more bytes than there are available
int limit = (Math.min(__l, total));
int newtotal = total - limit;
// Get some things
LinkedList<byte[]> blocks = this._blocks;
int nb = blocks.size();
int head = this._head, tail = this._tail;
// Write bytes into the target
int left = limit;
int bs = ByteDeque._BLOCK_SIZE;
int bm = ByteDeque._BLOCK_MASK;
while (left > 0)
{
// Get the first block
byte[] bl = blocks.getFirst();
boolean lastbl = (nb == 1);
// Determine the max number of bytes to delete
int rc = (lastbl ? (tail == 0 ? bs : tail) - head : bs - head);
if (left < rc)
rc = left;
// Should never occur, because that means the end is lower
// than the start
if (rc < 0)
throw Debugging.oops();
// Erase data
for (int i = 0; i < rc; i++)
bl[head++] = 0;
// Mask the head to detect overflow
head &= bm;
// If cycled, remove the first block
if (head == 0 || (lastbl && head == tail))
{
blocks.removeFirst();
nb--;
}
// Bytes were removed
left -= rc;
}
// Emptied? Clear head/tail pointers
if (newtotal == 0)
head = tail = 0;
// Set details
this._total = newtotal;
this._head = head;
this._tail = tail;
// Return the erase count
return limit;
}
/**
* Gets a single byte offset from the start of the deque as if it were an
* array.
*
* @param __a The index to get the byte value of.
* @return The byte at the given position.
* @throws IndexOutOfBoundsException If the address is not within bounds.
* @since 2016/08/03
*/
public final byte get(int __a)
throws IndexOutOfBoundsException
{
/* {@squirreljme.error BD26 Request get at a negative index.} */
if (__a < 0)
throw new IndexOutOfBoundsException("BD26");
byte[] solo = this._solo;
int rv = this.get(__a, solo, 0, 1);
if (rv == 1)
return solo[0];
/* {@squirreljme.error BD27 Could not get the byte at the
given position because it exceeds the deque bounds. (The index)} */
throw new IndexOutOfBoundsException(String.format("BD27 %d", __a));
}
/**
* Gets multiple bytes offset from the start of the deque as if it were
* and array.
*
* @param __a The index to start reading values from.
* @param __b The destination array for values.
* @return The number of bytes read.
* @throws IndexOutOfBoundsException If the address is not within the
* bounds of the deque.
* @throws NullPointerException On null arguments.
* @since 2016/08/03
*/
public final int get(int __a, byte[] __b)
throws IndexOutOfBoundsException, NullPointerException
{
return this.get(__a, __b, 0, __b.length);
}
/**
* Gets multiple bytes offset from the start of the deque as if it were
* and array.
*
* @param __a The index to start reading values from.
* @param __b The destination array for values.
* @param __o Where to start writing destination values.
* @param __l The number of bytes to read.
* @return The number of bytes read.
* @throws IndexOutOfBoundsException If the address is not within the
* bounds of the deque, the offset and/or length are negative, or the
* offset and length exceed the array bounds.
* @throws NullPointerException On null arguments.
* @since 2016/08/03
*/
public final int get(int __a, byte[] __b, int __o, int __l)
throws IndexOutOfBoundsException, NullPointerException
{
/* {@squirreljme.error BD28 Request get at a negative index.} */
if (__a < 0)
throw new IndexOutOfBoundsException("BD28");
// Check
if (__b == null)
throw new NullPointerException("NARG");
if (__o < 0 || __l < 0 || (__o + __l) < 0 || (__o + __l) > __b.length)
throw new IndexOutOfBoundsException("BAOB");
// If there are no bytes, all reads do nothing
int total = this._total;
if (total <= 0)
return 0;
/* {@squirreljme.error BD29 The requested address is outside of
the bounds of the queue. (The requested address; The number of
bytes in the queue)} */
if (__a >= total)
throw new IndexOutOfBoundsException(String.format("BD29 %d %d",
__a, total));
// If the address is within the starting half then seek from the
// start, otherwise start from the trailing end
return this.__getOrSetVia((__a < (total >> 1)),
__a, __b, __o, __l, false);
}
/**
* Obtains but does not remove the first byte.
*
* @return The value of the first byte.
* @throws NoSuchElementException If the deque is empty.
* @since 2016/05/01
*/
public final byte getFirst()
throws NoSuchElementException
{
byte[] solo = this._solo;
int rv = this.getFirst(solo, 0, 1);
if (rv == 1)
return solo[0];
/* {@squirreljme.error BD2a Could not get the first byte
because the deque is empty.} */
throw new NoSuchElementException("BD2a");
}
/**
* Obtains but does not remove the first set of bytes.
*
* @param __b The destination array to obtain the first bytes for.
* @return The number of read bytes.
* @throws NullPointerException On null arguments.
* @since 2016/05/01
*/
public final int getFirst(byte[] __b)
throws NullPointerException
{
return this.getFirst(__b, 0, __b.length);
}
/**
* Obtains but does not remove the first set of bytes.
*
* @param __b The destination array to obtain the first bytes for.
* @param __o The offset in the destination array to start reading bytes
* into.
* @param __l The number of bytes to read.
* @return The number of read bytes.
* @throws IndexOutOfBoundsException If the offset or length are negative
* or they exceed the bounds of the array.
* @throws NullPointerException On null arguments.
* @since 2016/05/01
*/
public final int getFirst(byte[] __b, int __o, int __l)
throws IndexOutOfBoundsException, NullPointerException
{
// This is the same of an any position get at the start
return this.get(0, __b, __o, __l);
}
/**
* Obtains but does not remove the last byte.
*
* @return The value of the last byte.
* @throws NoSuchElementException If the deque is empty.
* @since 2016/05/01
*/
public final byte getLast()
throws NoSuchElementException
{
byte[] solo = this._solo;
int rv = this.getLast(solo, 0, 1);
if (rv == 0)
return solo[0];
/* {@squirreljme.error BD2b Could not remove the last byte because
the deque is empty.} */
throw new NoSuchElementException("BD2b");
}
/**
* Obtains but does not remove the last set of bytes.
*
* @param __b The destination array to obtain the last bytes for.
* @return The number of read bytes.
* @throws NullPointerException On null arguments.
* @since 2016/05/01
*/
public final int getLast(byte[] __b)
throws NullPointerException
{
return this.getLast(__b, 0, __b.length);
}
/**
* Obtains but does not remove the last set of bytes.
*
* @param __b The destination array to obtain the last bytes for.
* @param __o The offset in the destination array to start reading bytes
* into.
* @param __l The number of bytes to read.
* @return The number of read bytes.
* @throws IndexOutOfBoundsException If the offset or length are negative
* or they exceed the bounds of the array.
* @throws NullPointerException On null arguments.
* @since 2016/05/01
*/
public final int getLast(byte[] __b, int __o, int __l)
throws IndexOutOfBoundsException, NullPointerException
{
// Check, the length is used so make sure it is positive
if (__l < 0)
throw new IndexOutOfBoundsException("BAOB");
// This is the same of an any position get from the end
int total = this._total;
return this.get(Math.max(0, total - __l), __b, __o, __l);
}
/**
* Returns whether or not this deque is empty.
*
* @return Whether it is empty or not.
* @since 2017/08/22
*/
public final boolean isEmpty()
{
return this.available() == 0;
}
/**
* Offers a single byte to the start of the deque and returns {@code true}
* if it was added to the deque.
*
* @param __b The byte to add to the start.
* @return {@code true} if the capacity was not violated and the bytes were
* added.
* @since 2016/05/01
*/
public final boolean offerFirst(byte __b)
{
// May violate the capacity
try
{
this.addFirst(__b);
return true;
}
// Violates capacity
catch (IllegalStateException ise)
{
return false;
}
}
/**
* Offers multiple bytes to the start of the deque and returns {@code true}
* if they were added to the deque.
*
* @param __b The array to source bytes from.
* @return {@code true} if the capacity was not violated and the bytes were
* added.
* @throws NullPointerException On null arguments.
* @since 2016/05/01
*/
public final boolean offerFirst(byte[] __b)
throws NullPointerException
{
return this.offerFirst(__b, 0, __b.length);
}
/**
* Offers multiple bytes to the start of the deque and returns {@code true}
* if they were added to the deque.
*
* @param __b The array to source bytes from.
* @param __o The offset to start reading from.
* @param __l The number of bytes to write.
* @return {@code this}.
* @throws IndexOutOfBoundsException If the offset or length are negative
* or they exceed the array bounds.
* @throws NullPointerException On null arguments.
* @since 2016/05/01
*/
public final boolean offerFirst(byte[] __b, int __o, int __l)
throws IndexOutOfBoundsException
{
// May violate the capacity
try
{
this.addFirst(__b, __o, __l);
return true;
}
// Violates capacity
catch (IllegalStateException ise)
{
return false;
}
}
/**
* Offers a single byte to the end of the deque and returns {@code true} if
* it was added to the deque.
*
* @param __b The byte to add to the end.
* @return {@code true} if the capacity was not violated and the bytes were
* added.
* @since 2016/05/01
*/
public final boolean offerLast(byte __b)
{
// May violate the capacity
try
{
this.addLast(__b);
return true;
}
// Violates capacity
catch (IllegalStateException ise)
{
return false;
}
}
/**
* Offers multiple bytes to the end of the deque and returns {@code true}
* if they were added to the deque.
*
* @param __b The array to source bytes from.
* @return {@code true} if the capacity was not violated and the bytes were
* added.
* @throws NullPointerException On null arguments.
* @since 2016/05/01
*/
public final boolean offerLast(byte[] __b)
throws NullPointerException
{
return this.offerLast(__b, 0, __b.length);
}
/**
* Offers multiple bytes to the end of the deque and returns {@code true}
* if they were added to the deque.
*
* @param __b The array to source bytes from.
* @param __o The offset to start reading from.
* @param __l The number of bytes to write.
* @return {@code this}.
* @throws IndexOutOfBoundsException If the offset or length are negative
* or they exceed the array bounds.
* @throws NullPointerException On null arguments.
* @since 2016/05/01
*/
public final boolean offerLast(byte[] __b, int __o, int __l)
throws IndexOutOfBoundsException
{
// May violate the capacity
try
{
this.addLast(__b, __o, __l);
return true;
}
// Violates capacity
catch (IllegalStateException ise)
{
return false;
}
}
/**
* Obtains but does not remove the first byte, returning a special value
* if the deque is empty.
*
* @return The value of the first byte or a negative value if the deque is
* empty.
* @since 2016/05/01
*/
public final int peekFirst()
throws NoSuchElementException
{
// The deque could be empty
try
{
return ((int)this.getFirst()) & 0xFF;
}
// Does not exist.
catch (NoSuchElementException e)
{
return -1;
}
}
/**
* Obtains but does not remove the last byte, returning a special value
* if the deque is empty.
*
* @return The value of the last byte or a negative value if the deque is
* empty.
* @since 2016/05/01
*/
public final int peekLast()
throws NoSuchElementException
{
// The deque could be empty
try
{
return ((int)this.getLast()) & 0xFF;
}
// Does not exist.
catch (NoSuchElementException e)
{
return -1;
}
}
/**
* Removes a single byte from the from of the deque.
*
* @return The next input byte.
* @throws NoSuchElementException If not a single byte is available.
* @since 2016/05/01
*/
public final byte removeFirst()
throws NoSuchElementException
{
byte[] solo = this._solo;
int rv = this.removeFirst(solo, 0, 1);
if (rv == 1)
return solo[0];
/* {@squirreljme.error BD2c Could not remove the first byte
because the deque is empty.} */
throw new NoSuchElementException("BD2c");
}
/**
* Removes multiple bytes from the front of the deque.
*
* @param __b The array to read bytes into.
* @return The number of removed bytes, may be {@code 0}.
* @throws NullPointerException On null arguments.
* @since 2016/05/01
*/
public final int removeFirst(byte[] __b)
throws NullPointerException
{
return this.removeFirst(__b, 0, __b.length);
}
/**
* Removes multiple bytes from the front of the deque.
*
* @param __b The array to read bytes into.
* @param __o The offset to start writing into.
* @param __l The number of bytes to remove.
* @return The number of removed bytes, may be {@code 0}.
* @throws IndexOutOfBoundsException If the offset or length are negative
* or exceed the array bounds.
* @throws NullPointerException On null arguments.
* @since 2016/05/01
*/
public final int removeFirst(byte[] __b, int __o, int __l)
throws IndexOutOfBoundsException, NullPointerException
{
// Check
if (__b == null)
throw new NullPointerException("NARG");
if (__o < 0 || __l < 0 || (__o + __l) < 0 || (__o + __l) > __b.length)
throw new IndexOutOfBoundsException("BAOB");
// If nothing to remove, do nothing
if (__l == 0)
return 0;
// If the queue is empty do nothing
int total = this._total;
if (total == 0)
return 0;
// A remove is a get followed by a delete
int rva = this.get(0, __b, __o, __l);
int rvb = this.deleteFirst(__l);
// If this occurs then the number of bytes deleted was not the
// same as the number of bytes which were read.
if (rva != rvb)
throw Debugging.oops();
// Return the read count
return rva;
}
/**
* Removes a single byte from the from of the deque.
*
* @return The next input byte.
* @throws NoSuchElementException If not a single byte is available.
* @since 2016/05/01
*/
public final byte removeLast()
throws NoSuchElementException
{
byte[] solo = this._solo;
int rv = this.removeLast(solo, 0, 1);
if (rv == 1)
return solo[0];
/* {@squirreljme.error BD2d Could not remove the last byte because
the deque is empty.} */
throw new NoSuchElementException("BD2d");
}
/**
* Removes multiple bytes from the end of the deque.
*
* @param __b The array to read bytes into.
* @return The number of removed bytes, may be {@code 0}.
* @throws NullPointerException On null arguments.
* @since 2016/05/01
*/
public final int removeLast(byte[] __b)
throws NullPointerException
{
return this.removeLast(__b, 0, __b.length);
}
/**
* Removes multiple bytes from the end of the deque.
*
* @param __b The array to read bytes into.
* @param __o The offset to start writing into.
* @param __l The number of bytes to remove.
* @return The number of removed bytes, may be {@code 0}.
* @throws IndexOutOfBoundsException If the offset or length are negative
* or exceed the array bounds.
* @throws NullPointerException On null arguments.
* @since 2016/05/01
*/
public final int removeLast(byte[] __b, int __o, int __l)
throws IndexOutOfBoundsException, NullPointerException
{
// Check
if (__b == null)
throw new NullPointerException("NARG");
if (__o < 0 || __l < 0 || (__o + __l) < 0 || (__o + __l) > __b.length)
throw new IndexOutOfBoundsException("BAOB");
throw Debugging.todo();
}
/**
* Sets a single byte offset to the start of the deque as if it were an
* array.
*
* @param __a The index to set the byte value of.
* @return The byte at the given position.
* @throws IndexOutOfBoundsException If the address is not within bounds.
* @since 2017/02/04
*/
public final byte set(int __a)
throws IndexOutOfBoundsException
{
/* {@squirreljme.error BD2e Request set at a negative index.} */
if (__a < 0)
throw new IndexOutOfBoundsException("BD2e");
byte[] solo = this._solo;
int rv = this.set(__a, solo, 0, 1);
if (rv == 1)
return solo[0];
/* {@squirreljme.error BD2f Could not set the byte at the
given position because it exceeds the deque bounds. (The index)} */
throw new IndexOutOfBoundsException(String.format("BD2f %d", __a));
}
/**
* Sets multiple bytes offset to the start of the deque as if it were
* and array.
*
* @param __a The index to start writing values to.
* @param __b The source array for values.
* @return The number of bytes write.
* @throws IndexOutOfBoundsException If the address is not within the
* bounds of the deque.
* @throws NullPointerException On null arguments.
* @since 2017/02/04
*/
public final int set(int __a, byte[] __b)
throws IndexOutOfBoundsException, NullPointerException
{
return this.set(__a, __b, 0, __b.length);
}
/**
* Sets multiple bytes offset to the start of the deque as if it were
* and array.
*
* @param __a The index to start writing values to.
* @param __b The source array for values.
* @param __o Where to start writing source values.
* @param __l The number of bytes to write.
* @return The number of bytes write.
* @throws IndexOutOfBoundsException If the address is not within the
* bounds of the deque, the offset and/or length are negative, or the
* offset and length exceed the array bounds.
* @throws NullPointerException On null arguments.
* @since 2017/02/04
*/
public final int set(int __a, byte[] __b, int __o, int __l)
throws IndexOutOfBoundsException, NullPointerException
{
/* {@squirreljme.error BD2g Request set at a negative index.} */
if (__a < 0)
throw new IndexOutOfBoundsException("BD2g");
// Check
if (__b == null)
throw new NullPointerException("NARG");
if (__o < 0 || __l < 0 || (__o + __l) < 0 || (__o + __l) > __b.length)
throw new IndexOutOfBoundsException("BAOB");
/* {@squirreljme.error BD2h The requested address is outside of
the bounds of the queue. (The requested address; The number of
bytes in the queue)} */
int total = this._total;
if (__a < 0 || __a >= total)
throw new IndexOutOfBoundsException(String.format("BD2h %d %d",
__a, total));
// If there are no bytes, all writes do nothing
if (total <= 0)
return 0;
// If the address is within the starting half then seek to the
// start, otherwise start to the trailing end
return this.__getOrSetVia((__a < (total >> 1)), __a, __b, __o, __l, true);
}
/**
* Returns the number of bytes which are in this deque.
*
* @return The total number of bytes in this deque.
* @since 2017/08/14
*/
public final int size()
{
return this._total;
}
/**
* Returns all of the data in this deque as a single byte array.
*
* @return The data contained within this deque.
* @since 2017/02/04
*/
public final byte[] toByteArray()
{
int sz = this.available();
byte[] rv = new byte[sz];
this.get(0, rv, 0, sz);
return rv;
}
/**
* Writes the entire deque into the specified output stream.
*
* @param __os The stream to write to.
* @throws IOException On write errors.
* @throws NullPointerException On null arguments.
* @since 2016/07/25
*/
public final void writeTo(OutputStream __os)
throws IOException, NullPointerException
{
// Check
if (__os == null)
throw new NullPointerException("NARG");
throw Debugging.todo();
}
/**
* Obtains or reads bytes starting from the head or tail side.
*
* @param __last If {@code true} then initial block traversal is done
* from the tail end rather than the head end.
* @param __a The address to read.
* @param __b The destination or source array.
* @param __o The output offset into the array.
* @param __l The number of bytes to read or write.
* @param __set If {@code true} then bytes will be read from the input
* array for writing.
* @return The number of bytes read.
* @since 2016/08/04
*/
private int __getOrSetVia(boolean __last, int __a, byte[] __b,
int __o, int __l, boolean __set)
{
// Get some things
int total = this._total;
LinkedList<byte[]> blocks = this._blocks;
int nb = blocks.size();
int head = this._head, tail = this._tail;
int bs = ByteDeque._BLOCK_SIZE;
int bm = ByteDeque._BLOCK_MASK;
// The number of bytes to read
int limit = total - __a;
if (__l < limit)
limit = __l;
// Skip through the starting set of blocks since they are not
// needed at all
Iterator<byte[]> it;
int blskip = (head + __a) >> ByteDeque._BLOCK_SHIFT;
if (__last && nb > 1)
{
// Start from the back and then go to the index where we are
// supposed to be at
ListIterator<byte[]> lit = blocks.listIterator(nb);
it = lit;
int backskip = nb - blskip;
for (int i = 0; i < backskip; i++)
lit.previous();
}
// Start from the head size (the front)
else
{
it = blocks.iterator();
for (int i = 0; i < blskip; i++)
it.next();
}
// The initial read head starts where the actual data starts
// logically in the buffer (if the head is 2 then address 42 is
// 44 within the buffer).
int rhead = (head + __a) & bm;
// Read these bytes
int left = limit;
int at = __o;
while (left > 0)
{
// Get the block data
byte[] bl = it.next();
// Is this the last block?
boolean lastbl = !it.hasNext();
// Determine the number of bytes to read
int rc = (lastbl && tail != 0 ? tail : bs) - rhead;
if (left < rc)
rc = left;
// Write the data
if (__set)
{
System.arraycopy(__b, at,
bl, rhead, rc);
/*for (int i = 0; i < rc; i++)
bl[rhead++] = __b[at++];*/
}
// Read the data
else
{
System.arraycopy(bl, rhead,
__b, at, rc);
/*for (int i = 0; i < rc; i++)
__b[at++] = bl[rhead++];*/
}
// Move up pointers
at += rc;
rhead += rc;
// Reset head to zero for the next block read
rhead = 0;
// Read this many bytes
left -= rc;
}
// Return the number of bytes read
return limit;
}
/**
* Determines the slice size to use for deques.
*
* @return The slice size.
* @since 2021/12/05
*/
private static int __dequeSliceSize()
{
/*switch (RuntimeShelf.memoryProfile())
{
case MemoryProfileType.MINIMAL:
return 128;
case MemoryProfileType.NORMAL:
default:
return 512;
}*/
return 512;
}
}