Skip to content

Commit 67450f7

Browse files
committed
Code tidying
1 parent eef0f8d commit 67450f7

File tree

2 files changed

+95
-73
lines changed

2 files changed

+95
-73
lines changed

convex-core/src/main/java/convex/core/data/Blob.java

Lines changed: 83 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,25 @@
1212
/**
1313
* General purpose immutable wrapper for byte array data.
1414
*
15-
* Can be encoded fully as a single Cell if 4096 bytes or less, otherwise needs to be
16-
* structures as a BlobTree.
15+
* Can be encoded fully as a single Cell if 4096 bytes or less, otherwise needs
16+
* to be structures as a BlobTree.
1717
*
18-
* Encoding format is:
19-
* - Tag.BLOB tag byte
20-
* - VLC encoded Blob length in bytes (one or two bytes describing a length in range 0..4096)
21-
* - Byte data of the given length
18+
* Encoding format is: - Tag.BLOB tag byte - VLC encoded Blob length in bytes
19+
* (one or two bytes describing a length in range 0..4096) - Byte data of the
20+
* given length
2221
*/
2322
public class Blob extends AArrayBlob {
2423
public static final Blob EMPTY = Cells.intern(wrap(Utils.EMPTY_BYTES));
25-
public static final Blob SINGLE_ZERO = Cells.intern(wrap(new byte[] {0}));
26-
public static final Blob SINGLE_ONE = Cells.intern(wrap(new byte[] {1}));
27-
public static final Blob SINGLE_A =wrap(new byte[] {0x41});
24+
public static final Blob SINGLE_ZERO = Cells.intern(wrap(new byte[] { 0 }));
25+
public static final Blob SINGLE_ONE = Cells.intern(wrap(new byte[] { 1 }));
26+
public static final Blob SINGLE_A = wrap(new byte[] { 0x41 });
27+
28+
public static final Blob NULL_ENCODING = Blob.wrap(new byte[] { Tag.NULL });
2829

29-
public static final Blob NULL_ENCODING = Blob.wrap(new byte[] {Tag.NULL});
30-
3130
public static final int CHUNK_LENGTH = 4096;
32-
33-
private static final byte[] EMPTY_CHUNK_BYTES=new byte[CHUNK_LENGTH];
34-
31+
32+
private static final byte[] EMPTY_CHUNK_BYTES = new byte[CHUNK_LENGTH];
33+
3534
public static final Blob EMPTY_CHUNK = Cells.intern(wrap(EMPTY_CHUNK_BYTES));
3635

3736
private Blob(byte[] bytes, int offset, int length) {
@@ -41,14 +40,15 @@ private Blob(byte[] bytes, int offset, int length) {
4140
/**
4241
* Creates a new Blob using a copy of the specified byte range
4342
*
44-
* @param data Byte array
43+
* @param data Byte array
4544
* @param offset Start offset in the byte array
4645
* @param length Number of bytes to take from data array
4746
* @return The new Data object
4847
*/
4948
public static Blob create(byte[] data, int offset, int length) {
5049
if (length <= 0) {
51-
if (length == 0) return EMPTY;
50+
if (length == 0)
51+
return EMPTY;
5252
throw new IllegalArgumentException(ErrorMessages.negativeLength(length));
5353
}
5454
byte[] store = Arrays.copyOfRange(data, offset, offset + length);
@@ -64,16 +64,17 @@ public static Blob create(byte[] data, int offset, int length) {
6464
public static Blob create(byte[] data) {
6565
return create(data, 0, data.length);
6666
}
67-
67+
6868
/**
6969
* Parses String input as a Blob. Converts from hex.
7070
*
7171
* @param data Byte array
7272
* @return Blob with the same byte contents as the given array
7373
*/
7474
public static Blob parse(String data) {
75-
ABlob b=Blobs.parse(data);
76-
if (b==null) return null;
75+
ABlob b = Blobs.parse(data);
76+
if (b == null)
77+
return null;
7778
return b.toFlatBlob();
7879
}
7980

@@ -94,21 +95,23 @@ public static Blob wrap(byte[] data) {
9495
* directly. Use only if no other references to the byte array are kept which
9596
* might be mutated.
9697
*
97-
* @param data Byte array
98+
* @param data Byte array
9899
* @param offset Offset into byte array
99100
* @param length Length of byte array to wrap
100101
* @return Blob wrapping the given byte array segment
101102
*/
102103
public static Blob wrap(byte[] data, int offset, int length) {
103-
if (length < 0) throw new IllegalArgumentException(ErrorMessages.negativeLength(length));
104+
if (length < 0)
105+
throw new IllegalArgumentException(ErrorMessages.negativeLength(length));
104106
if ((offset < 0) || (offset + length > data.length))
105-
throw new IndexOutOfBoundsException(ErrorMessages.badRange(offset, offset+length));
106-
if (length==0) return Blob.EMPTY;
107-
Blob b= new Blob(data, offset, length);
108-
107+
throw new IndexOutOfBoundsException(ErrorMessages.badRange(offset, offset + length));
108+
if (length == 0)
109+
return Blob.EMPTY;
110+
Blob b = new Blob(data, offset, length);
111+
109112
// optimisation to re-use Blob encoding if present
110-
if ((offset>=2)&&(length<128)&&(data[offset-1]==(byte)length)&&(data[offset-2]==Tag.BLOB)) {
111-
b.attachEncoding(Blob.wrap(data,offset-2,length+2));
113+
if ((offset >= 2) && (length < 128) && (data[offset - 1] == (byte) length) && (data[offset - 2] == Tag.BLOB)) {
114+
b.attachEncoding(Blob.wrap(data, offset - 2, length + 2));
112115
}
113116
return b;
114117
}
@@ -120,55 +123,61 @@ public Blob toFlatBlob() {
120123

121124
@Override
122125
public Blob slice(long start, long end) {
123-
if (start < 0) return null;
126+
if (start < 0) return null;
124127
if (end > this.count) return null;
125-
long length=end-start;
126-
int size=(int)length;
127-
if (size!=length) return null; // int overflow, too big for valid Blob slice!
128+
long length = end - start;
129+
int size = (int) length;
130+
if (size != length) return null; // int overflow, i.e. too big for valid Blob slice!
128131
if (length < 0) return null;
129132
if (length == 0) return EMPTY;
130-
if (length==this.count) return this;
133+
if (length == this.count) return this;
131134
return Blob.wrap(store, Utils.checkedInt(start + offset), size);
132135
}
133-
136+
134137
@Override
135138
public Blob slice(long start) {
136139
return slice(start, count());
137140
}
138141

139142
@Override
140143
public boolean equals(ABlob a) {
141-
if (a==this) return true;
142-
if (a instanceof AArrayBlob) return equals((AArrayBlob) a);
143-
long n=count();
144-
if (a.count()!=n) return false;
145-
if (!(a.getType()==Types.BLOB)) return false;
146-
if (n<=CHUNK_LENGTH) {
144+
if (a == this)
145+
return true;
146+
if (a instanceof AArrayBlob)
147+
return equals((AArrayBlob) a);
148+
long n = count();
149+
if (a.count() != n)
150+
return false;
151+
if (!(a.getType() == Types.BLOB))
152+
return false;
153+
if (n <= CHUNK_LENGTH) {
154+
// Fast byte comparison, this is the normal fast path
147155
return a.equalsBytes(this.store, this.offset);
148156
} else {
149-
// this must be a non-canonical Blob
157+
// this must be a non-canonical Blob, i.e. bigger than CHUNK_LENGTH
150158
// we coerce encoding, since might have hash, and probably needed anyway
159+
// Expensive encoding might happen, but at least this gets cached
151160
return getEncoding().equals(a.getEncoding());
152161
}
153162
}
154163

155-
156-
157164
/**
158165
* Constructs a Blob object from a hex string
159166
*
160167
* @param hexString Hex String to read
161168
* @return Blob with the provided hex value, or null if not a valid blob
162169
*/
163170
public static Blob fromHex(String hexString) {
164-
byte[] bs=Utils.hexToBytes(hexString);
165-
if (bs==null) return null;
166-
if (bs.length==0) return EMPTY;
171+
byte[] bs = Utils.hexToBytes(hexString);
172+
if (bs == null)
173+
return null;
174+
if (bs.length == 0)
175+
return EMPTY;
167176
return wrap(bs);
168177
}
169-
178+
170179
public static Blob forByte(byte b) {
171-
return wrap(new byte[] {b});
180+
return wrap(new byte[] { b });
172181
}
173182

174183
/**
@@ -184,34 +193,35 @@ public static Blob fromByteBuffer(ByteBuffer bb) {
184193
return Blob.wrap(bs);
185194
}
186195

187-
188-
189196
/**
190-
* Fast read of a Blob from its encoding inside another Blob object.
191-
* Assumes count is correct at start of encoding (pos+1)
197+
* Fast read of a Blob from its encoding inside another Blob object. Assumes
198+
* count is correct at start of encoding (pos+1)
192199
*
193200
* @param source Source Blob object.
194-
* @param pos Position in source to start reading from (location of tag byte)
195-
* @param count Length in bytes to take from the source Blob
201+
* @param pos Position in source to start reading from (location of tag byte)
202+
* @param count Length in bytes to take from the source Blob
196203
* @return Blob read from the source
197204
* @throws BadFormatException If encoding is invalid
198205
*/
199206
public static Blob read(Blob source, int pos, long count) throws BadFormatException {
200-
if (count==0) return EMPTY; // important! Don't want to allocate new empty Blobs or mess with EMPTY encoding
201-
if (count>CHUNK_LENGTH) throw new BadFormatException("Trying to read flat blob with count = " +count);
202-
207+
if (count == 0)
208+
return EMPTY; // important! Don't want to allocate new empty Blobs or mess with EMPTY encoding
209+
if (count > CHUNK_LENGTH)
210+
throw new BadFormatException("Trying to read flat blob with count = " + count);
211+
203212
// compute data length, excluding tag and encoded length
204213
int headerLength = (1 + Format.getVLQCountLength(count));
205-
long start = pos+ headerLength;
206-
if (start+count>source.count()) {
214+
long start = pos + headerLength;
215+
if (start + count > source.count()) {
207216
throw new BadFormatException("Insufficient bytes to read Blob required count =" + count);
208217
}
209218

210-
Blob result= source.slice(start , start+count);
211-
if (result==null) throw new IllegalArgumentException("Failed to slice Blob source");
212-
if (source.byteAtUnchecked(pos)==Tag.BLOB) {
219+
Blob result = source.slice(start, start + count);
220+
if (result == null)
221+
throw new IllegalArgumentException("Failed to slice Blob source");
222+
if (source.byteAtUnchecked(pos) == Tag.BLOB) {
213223
// Only attach encoding if we were reading a genuine Blob
214-
result.attachEncoding(source.slice(pos,pos+(headerLength+count)));
224+
result.attachEncoding(source.slice(pos, pos + (headerLength + count)));
215225
}
216226
return result;
217227
}
@@ -222,22 +232,21 @@ public int encodeRaw(byte[] bs, int pos) {
222232
// We aren't canonical, so need to encode canonical representation
223233
return getCanonical().encodeRaw(bs, pos);
224234
} else {
225-
pos=super.encodeRaw(bs,pos);
235+
pos = super.encodeRaw(bs, pos);
226236
return pos;
227237
}
228238
}
229-
239+
230240
@Override
231241
public int estimatedEncodingSize() {
232242
// space for tag, generous VLC length, plus raw data
233243
return 1 + Format.MAX_VLQ_LONG_LENGTH + size();
234244
}
235-
245+
236246
/**
237247
* Maximum encoding size for a regular Blob
238248
*/
239-
public static final int MAX_ENCODING_LENGTH=1+Format.getVLQCountLength(CHUNK_LENGTH)+CHUNK_LENGTH;
240-
249+
public static final int MAX_ENCODING_LENGTH = 1 + Format.getVLQCountLength(CHUNK_LENGTH) + CHUNK_LENGTH;
241250

242251
@Override
243252
public boolean isCanonical() {
@@ -259,21 +268,22 @@ public static Blob createRandom(Random random, long length) {
259268

260269
@Override
261270
public Blob getChunk(long i) {
262-
if ((i == 0) && (count <= CHUNK_LENGTH)) return this;
271+
if ((i == 0) && (count <= CHUNK_LENGTH))
272+
return this;
263273
long start = i * CHUNK_LENGTH;
264-
long take=Math.min(CHUNK_LENGTH, count - start);
265-
return slice(start, start+take);
274+
long take = Math.min(CHUNK_LENGTH, count - start);
275+
return slice(start, start + take);
266276
}
267277

268278
public void attachContentHash(Hash hash) {
269-
if (contentHash==null) contentHash = hash;
279+
if (contentHash == null) contentHash = hash;
270280
}
271281

272282
@Override
273283
public ABlob toCanonical() {
274-
if (isCanonical()) return this;
284+
if (isCanonical())
285+
return this;
275286
return Blobs.toCanonical(this);
276287
}
277-
278288

279289
}

convex-core/src/main/java/convex/core/data/util/BlobBuilder.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,18 @@ public BlobBuilder append(byte b) {
213213
return this;
214214
}
215215

216+
public BlobBuilder appendRepeatedByte(byte b, long count) {
217+
int spare=spare();
218+
if (spare<1) throw new Panic("BlobBuilder should always have spare bytes but was: "+spare);
219+
ensureArray(arrayPos()+1);
220+
tail[Blob.CHUNK_LENGTH-spare]=b;
221+
count+=1;
222+
if (spare==1) {
223+
completeChunk();
224+
}
225+
return this;
226+
}
227+
216228
public void append(byte[] bs) {
217229
append(bs,0,bs.length);
218230
}

0 commit comments

Comments
 (0)