![JAR search and dependency download from the Maven repository](/logo.png)
net.yetamine.lang.containers.bytes.ByteContainer Maven / Gradle / Ivy
Show all versions of net.yetamine.lang Show documentation
/*
* Copyright 2016 Yetamine
*
* 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 net.yetamine.lang.containers.bytes;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.stream.IntStream;
/**
* An immutable implementation of {@link ByteSequence}.
*
*
* Because this class represents an immutable sequence, it carries a copy of the
* original data and provides only copies or read-only interface to access them.
*/
public final class ByteContainer implements ByteSequence {
/** Empty instance singleton. */
private static final ByteContainer EMPTY = new ByteContainer(new byte[0]);
/** Data storage. */
private final byte[] array;
/** Cached byte buffer. */
private ByteBuffer buffer;
/** Cached hash code. */
private int hashCode;
/**
* Create a new instance that just wraps the given array.
*
*
* The caller is responsible for passing the ownership of the given array to
* the new instance and it must not change the array after that (preferably,
* the only reference to the array should exist within the new instance).
*
* @param data
* the array to accept. It must not be {@code null}.
*/
private ByteContainer(byte[] data) {
assert (data != null);
array = data;
}
/**
* Returns an empty instance.
*
* @return an empty instance
*/
public static ByteContainer empty() {
return EMPTY;
}
/**
* Returns an instance equal to the given source, but ensuring that the
* result is an instance of this class, hence immutable for sure.
*
* @param source
* the source of the data. It must not be {@code null}.
*
* @return an instance equal to the given source
*/
public static ByteContainer secure(ByteSequence source) {
return (source instanceof ByteContainer) ? (ByteContainer) source : of(source.buffer());
}
/**
* Creates a new instance.
*
* @param data
* the data to view, using just lower 8 bits, ignoring the
* others. It must not be {@code null}.
*
* @return the new instance
*/
public static ByteContainer from(int... data) {
if (data.length == 0) {
return empty();
}
final byte[] result = new byte[data.length];
for (int i = 0; i < data.length; i++) {
result[i] = (byte) data[i];
}
return new ByteContainer(result);
}
/**
* Returns an instance for the given array.
*
* @param data
* the array. It must not be {@code null}.
*
* @return the instance
*/
public static ByteContainer of(byte... data) {
return (data.length == 0) ? empty() : new ByteContainer(data.clone());
}
/**
* Returns an instance for the given array part.
*
* @param data
* the array. It must not be {@code null}.
* @param from
* the start index, inclusive
* @param to
* the end index, exclusive
*
* @return the instance
*
* @throws IndexOutOfBoundsException
* if {@code from} or {@code to} are negative, if {@code to} is
* greater than the length of the array, or if {@code from} is
* greater than {@code to}
*/
public static ByteContainer of(byte[] data, int from, int to) {
final int length = ByteSequences.length(from, to, data.length);
if (length == 0) {
return empty();
}
final byte[] array = new byte[length];
System.arraycopy(data, from, array, 0, length);
return new ByteContainer(array);
}
/**
* Get an new instance from a buffer. The remaining part of the buffer is
* read and its position is advanced accordingly.
*
* @param data
* the buffer. It must not be {@code null}.
*
* @return the instance
*/
public static ByteContainer of(ByteBuffer data) {
final int length = data.remaining();
if (length == 0) {
return empty();
}
final byte[] payload = new byte[length];
data.get(payload);
return new ByteContainer(payload);
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return ByteSequences.toString(this);
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
return ByteSequences.equals(this, obj);
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = ByteSequences.hashCode(this);
hashCode = result;
}
return result;
}
/**
* Computes SHA-1 digest.
*
* @param sequence
* the sequence to process. It must not be {@code null}.
*
* @return the digest
*/
public static ByteContainer sha1(ByteSequence sequence) {
return new ByteContainer(ByteSequences.sha1(sequence));
}
/**
* Computes SHA-1 digest.
*
* @return the digest
*/
public ByteContainer sha1() {
return sha1(this);
}
/**
* @see net.yetamine.lang.containers.bytes.ByteSequence#length()
*/
public int length() {
return array.length;
}
/**
* @see net.yetamine.lang.containers.bytes.ByteSequence#valueAt(int)
*/
public byte valueAt(int index) {
return array[index];
}
/**
* @see net.yetamine.lang.containers.bytes.ByteSequence#copy(int, int)
*/
public ByteContainer copy(int from, int to) {
return ((from == 0) && (to == length())) ? this : of(array, from, to);
}
/**
* @see net.yetamine.lang.containers.bytes.ByteSequence#view(int, int)
*/
public ByteSequence view(int from, int to) {
return ByteArrayView.of(array, from, to);
}
/**
* @see net.yetamine.lang.containers.bytes.ByteSequence#array()
*/
public byte[] array() {
return (array.length == 0) ? array : array.clone();
}
/**
* @see net.yetamine.lang.containers.bytes.ByteSequence#array(int, int)
*/
public byte[] array(int from, int to) {
final int length = ByteSequences.length(from, to, array.length);
if (length == 0) {
return EMPTY.array;
}
final byte[] result = new byte[length];
System.arraycopy(array, 0, result, 0, length);
return result;
}
/**
* @see net.yetamine.lang.containers.bytes.ByteSequence#string(java.nio.charset.Charset)
*/
public String string(Charset encoding) {
return new String(array, encoding);
}
/**
* @see net.yetamine.lang.containers.bytes.ByteSequence#buffer()
*/
public ByteBuffer buffer() {
ByteBuffer result = buffer;
if (result == null) {
result = ByteBuffer.wrap(array);
buffer = result;
}
return result.asReadOnlyBuffer();
}
/**
* @see net.yetamine.lang.containers.bytes.ByteSequence#stream()
*/
public IntStream stream() {
return IntStream.range(0, array.length).map(i -> array[i]);
}
}