Skip to content

Commit 1a1be60

Browse files
committed
Refactor readonly & mutable hierarchy
1 parent 78e7f43 commit 1a1be60

File tree

8 files changed

+280
-133
lines changed

8 files changed

+280
-133
lines changed

src/main/java/at/favre/lib/bytes/AbstractBytes.java

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,31 +21,22 @@
2121

2222
package at.favre.lib.bytes;
2323

24-
import java.nio.ByteOrder;
25-
26-
public abstract class AbstractBytes {
27-
28-
private final byte[] byteArray;
29-
private final ByteOrder byteOrder;
24+
/**
25+
* Base interface for bytes
26+
*/
27+
public interface AbstractBytes {
3028

3129
/**
32-
* Creates a new immutable instance
30+
* Checks if instance is mutable
3331
*
34-
* @param byteArray internal byte array
35-
* @param byteOrder the internal byte order - this is used to interpret given array, not to change it
32+
* @return true if mutable, ie. transformers will change internal array
3633
*/
37-
public AbstractBytes(byte[] byteArray, ByteOrder byteOrder) {
38-
this.byteArray = byteArray;
39-
this.byteOrder = byteOrder;
40-
}
41-
42-
abstract BytesFactory getFactory();
34+
boolean isMutable();
4335

44-
public boolean isMutable() {
45-
return false;
46-
}
47-
48-
public boolean isReadOnly() {
49-
return false;
50-
}
36+
/**
37+
* Checks if instance is readonly
38+
*
39+
* @return true if readonly, ie. no direct access to the internal array
40+
*/
41+
boolean isReadOnly();
5142
}

src/main/java/at/favre/lib/bytes/Bytes.java

Lines changed: 52 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
* </pre>
5757
*/
5858
@SuppressWarnings("WeakerAccess")
59-
public class Bytes extends AbstractBytes implements Comparable<Bytes> {
59+
public class Bytes implements Comparable<Bytes>, AbstractBytes {
6060

6161
/* FACTORY ***************************************************************************************************/
6262

@@ -93,7 +93,7 @@ public static Bytes allocate(int length, byte defaultValue) {
9393
* @return new instance
9494
*/
9595
public static Bytes wrap(Bytes bytes) {
96-
return new Bytes(bytes.internalArray(), bytes.byteOrder, bytes.mutable, bytes.readonly);
96+
return new Bytes(bytes.internalArray(), bytes.byteOrder);
9797
}
9898

9999
/**
@@ -381,16 +381,22 @@ public static Bytes random(int length, Random random) {
381381

382382
private final byte[] byteArray;
383383
private final ByteOrder byteOrder;
384+
private final BytesFactory factory;
385+
386+
Bytes(byte[] byteArray, ByteOrder byteOrder) {
387+
this(byteArray, byteOrder, new Factory());
388+
}
384389

385390
/**
386391
* Creates a new immutable instance
387392
*
388393
* @param byteArray internal byte array
389394
* @param byteOrder the internal byte order - this is used to interpret given array, not to change it
390395
*/
391-
public Bytes(byte[] byteArray, ByteOrder byteOrder) {
396+
Bytes(byte[] byteArray, ByteOrder byteOrder, BytesFactory factory) {
392397
this.byteArray = byteArray;
393398
this.byteOrder = byteOrder;
399+
this.factory = factory;
394400
}
395401

396402
/* TRANSFORMER **********************************************************************************************/
@@ -580,7 +586,7 @@ public Bytes rightShift(int shiftCount) {
580586
* @return copied instance
581587
*/
582588
public Bytes copy() {
583-
return new Bytes(Arrays.copyOf(internalArray(), length()), byteOrder, mutable, readonly);
589+
return transform(new BytesTransformer.CopyTransformer(0, length()));
584590
}
585591

586592
/**
@@ -591,9 +597,7 @@ public Bytes copy() {
591597
* @return copied instance
592598
*/
593599
public Bytes copy(int offset, int length) {
594-
byte[] copy = new byte[length];
595-
System.arraycopy(internalArray(), offset, copy, 0, copy.length);
596-
return new Bytes(copy, byteOrder, mutable, readonly);
600+
return transform(new BytesTransformer.CopyTransformer(offset, length));
597601
}
598602

599603
/**
@@ -653,22 +657,6 @@ public Bytes shuffle() {
653657
return transform(new BytesTransformer.ShuffleTransformer(new SecureRandom()));
654658
}
655659

656-
/**
657-
* Generic transformation of this instance.
658-
* <p>
659-
* This transformation might be done in-place (ie. without copying the internal array and overwriting its old state),
660-
* or on a copy of the internal data, depending on the type (e.g. {@link MutableBytes}) and if the operation can be done
661-
* in-place. Therefore the caller has to ensure that certain side-effects, which occur due to the changing of the internal
662-
* data, do not create bugs in his/her code. Usually immutability is prefered, but when handling many or big byte arrays,
663-
* mutability enables drastically better performance.
664-
*
665-
* @param transformer used to transform this instance
666-
* @return the transformed instance (might be the same, or a new one)
667-
*/
668-
public Bytes transform(BytesTransformer transformer) {
669-
return transformer.transform(this, isMutable());
670-
}
671-
672660
/**
673661
* Copies the specified array, truncating or padding with zeros (if necessary)
674662
* so the copy has the specified length. For all indices that are
@@ -683,28 +671,24 @@ public Bytes transform(BytesTransformer transformer) {
683671
* @return a copy with the desired size or "this" instance if newByteLength == current length
684672
*/
685673
public Bytes resize(int newByteLength) {
686-
if (length() == newByteLength) {
687-
return this;
688-
}
689-
690-
if (newByteLength < 0) {
691-
throw new IllegalArgumentException("cannot resize to smaller than 0");
692-
}
693-
694-
if (newByteLength == 0) {
695-
return new Bytes(new byte[0], this);
696-
}
697-
698-
byte[] resizedArray = new byte[newByteLength];
699-
if (newByteLength > length()) {
700-
System.arraycopy(internalArray(), 0, resizedArray, Math.max(0, Math.abs(newByteLength - length())), Math.min(newByteLength, length()));
701-
} else {
702-
System.arraycopy(internalArray(), Math.max(0, Math.abs(newByteLength - length())), resizedArray, Math.min(0, Math.abs(newByteLength - length())), Math.min(newByteLength, length()));
703-
}
704-
705-
return new Bytes(resizedArray, this);
674+
return transform(new BytesTransformer.ResizeTransformer(newByteLength));
706675
}
707676

677+
/**
678+
* Generic transformation of this instance.
679+
* <p>
680+
* This transformation might be done in-place (ie. without copying the internal array and overwriting its old state),
681+
* or on a copy of the internal data, depending on the type (e.g. {@link MutableBytes}) and if the operation can be done
682+
* in-place. Therefore the caller has to ensure that certain side-effects, which occur due to the changing of the internal
683+
* data, do not create bugs in his/her code. Usually immutability is prefered, but when handling many or big byte arrays,
684+
* mutability enables drastically better performance.
685+
*
686+
* @param transformer used to transform this instance
687+
* @return the transformed instance (might be the same, or a new one)
688+
*/
689+
public Bytes transform(BytesTransformer transformer) {
690+
return factory.wrap(transformer.transform(internalArray(), isMutable()), byteOrder);
691+
}
708692

709693
/* ATTRIBUTES ************************************************************************************************/
710694

@@ -745,6 +729,16 @@ public ByteOrder byteOrder() {
745729
return byteOrder;
746730
}
747731

732+
/**
733+
* Checks if instance is mutable
734+
*
735+
* @return true if mutable, ie. transformers will change internal array
736+
*/
737+
@Override
738+
public boolean isMutable() {
739+
return false;
740+
}
741+
748742
/**
749743
* Check if this instance is read only
750744
*
@@ -852,10 +846,9 @@ public double entropy() {
852846
* @return new instance backed by the same data
853847
*/
854848
public Bytes duplicate() {
855-
return wrap(this);
849+
return factory.wrap(internalArray(), byteOrder);
856850
}
857851

858-
859852
/**
860853
* Set the byte order or endianness of this instance. Default in Java is {@link ByteOrder#BIG_ENDIAN}.
861854
* <p>
@@ -867,7 +860,7 @@ public Bytes duplicate() {
867860
*/
868861
public Bytes byteOrder(ByteOrder byteOrder) {
869862
if (byteOrder != this.byteOrder) {
870-
return new Bytes(internalArray(), byteOrder, mutable, readonly);
863+
return wrap(internalArray(), byteOrder);
871864
}
872865
return this;
873866
}
@@ -878,11 +871,11 @@ public Bytes byteOrder(ByteOrder byteOrder) {
878871
*
879872
* @return a new instance if not already readonly, or "this" otherwise
880873
*/
881-
public Bytes readOnly() {
874+
public ReadOnlyBytes readOnly() {
882875
if (isReadOnly()) {
883-
return this;
876+
return (ReadOnlyBytes) this;
884877
} else {
885-
return new Bytes(internalArray(), byteOrder, false, true);
878+
return new ReadOnlyBytes(internalArray(), byteOrder);
886879
}
887880
}
888881

@@ -915,7 +908,7 @@ private ByteBuffer internalBuffer() {
915908
*/
916909
public BigInteger bigInteger() {
917910
if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
918-
return new BigInteger(new BytesTransformer.ReverseTransformer().transform(this, false).array());
911+
return new BigInteger(new BytesTransformer.ReverseTransformer().transform(array(), false));
919912
} else {
920913
return new BigInteger(array());
921914
}
@@ -942,7 +935,7 @@ public MutableBytes mutable() {
942935
* @return new input stream
943936
*/
944937
public InputStream inputStream() {
945-
return new ByteArrayInputStream(internalArray());
938+
return new ByteArrayInputStream(array());
946939
}
947940

948941
/**
@@ -955,10 +948,7 @@ public InputStream inputStream() {
955948
* @throws ReadOnlyBufferException if this is a read-only instance
956949
*/
957950
public byte[] array() {
958-
if (!isReadOnly()) {
959-
return internalArray();
960-
}
961-
throw new ReadOnlyBufferException();
951+
return internalArray();
962952
}
963953

964954
byte[] internalArray() {
@@ -1216,8 +1206,6 @@ public boolean equals(Object o) {
12161206

12171207
Bytes bytes = (Bytes) o;
12181208

1219-
if (mutable != bytes.mutable) return false;
1220-
if (readonly != bytes.readonly) return false;
12211209
if (!Arrays.equals(byteArray, bytes.byteArray)) return false;
12221210
return byteOrder != null ? byteOrder.equals(bytes.byteOrder) : bytes.byteOrder == null;
12231211
}
@@ -1246,8 +1234,6 @@ public boolean equalsContent(byte[] array) {
12461234
public int hashCode() {
12471235
int result = Arrays.hashCode(byteArray);
12481236
result = 31 * result + (byteOrder != null ? byteOrder.hashCode() : 0);
1249-
result = 31 * result + (mutable ? 1 : 0);
1250-
result = 31 * result + (readonly ? 1 : 0);
12511237
return result;
12521238
}
12531239

@@ -1271,4 +1257,11 @@ public String toString() {
12711257
return length() + " bytes " + preview;
12721258
}
12731259

1260+
private static class Factory implements BytesFactory {
1261+
@Override
1262+
public Bytes wrap(byte[] array, ByteOrder byteOrder) {
1263+
return new Bytes(array, byteOrder);
1264+
}
1265+
}
1266+
12741267
}

0 commit comments

Comments
 (0)