Skip to content

Add an ImmutableByteArray implementation#139

Merged
markelliot merged 6 commits into
developfrom
me/immutableByteArray
Jan 7, 2019
Merged

Add an ImmutableByteArray implementation#139
markelliot merged 6 commits into
developfrom
me/immutableByteArray

Conversation

@markelliot
Copy link
Copy Markdown
Contributor

Preparation for replacing ByteBuffer in generated classes since ByteBuffer is not
immutable and maintains mutable state.

Preparation for replacing ByteBuffer in generated classes since ByteBuffer is not
immutable and maintains mutable state.
@markelliot markelliot requested a review from a team as a code owner December 20, 2018 14:02
@uschi2000
Copy link
Copy Markdown
Contributor

uschi2000 commented Dec 20, 2018

@j-baker Didn't you have one of those somewhere already?

Copy link
Copy Markdown
Contributor

@carterkozak carterkozak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strongly in favor of this feature, thanks Mark!
I recall @schlosna was interested in this feature as well.

Old PR from @j-baker:<internal-github>/conjure/pull/816

}

/** Copies this byte array into the provided byte array beginning at offset and up to the provided length. */
public void copy(byte[] array, int offset, int length) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would prefer to rename the array parameter something along the lines of destination

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bikeshed: method name copyTo?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, will rename to copyTo

public byte[] getBytes() {
byte[] unsafe = new byte[safe.length];
System.arraycopy(safe, 0, unsafe, 0, safe.length);
return unsafe;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return safe.clone() is simpler.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to know we're doing this using the System copy primitives, and so going to keep this relatively small amount of code, confidently given test coverage.

}

/** Returns a new read-only {@link ByteBuffer} backed by this byte array. */
public ByteBuffer getByteBuffer() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on as or to over get?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess “asNewByteBuffer”?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure new is necessary here, since the byte buffer isn't mutable. It happens to be new, but that makes no difference to api consumers.
Our data could just as easily be backed by a heap ByteBuffer rather than byte[], in which case we wouldn't create new objects.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is a constant time/memory operation unlike getBytes the originalgetByteBuffer is probably best here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, for symmetry this will be called asByteBuffer (no "new").


/** Returns a copy of this byte array. */
@JsonValue
public byte[] getBytes() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be helpful to include some indication in the method name that we're making a copy, which is potentially expensive.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“asNewByteArray”?

import java.util.Arrays;

/** An immutable {@code byte[]} wrapper. */
public final class ImmutableByteArray {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on naming this Binary to couple this with the cojure primitive? Byte array is an implementation detail.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe ImmutableBytes? “binary” translates a few different ways — sometimes as a stream — so would avoid the direct naming here. Also open to “ByteString” or just “Bytes”.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bytes is reasonable, though I prefer Binary. Other types have different java bindings based on context, int, OptionalInt, List<Integer> for example.
Bytes sounds a bit like a utility rather than a data object (see com.google.common.primitives.Bytes).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just ByteArray? why don't prefix other classes with Immutable even if they are, e.g. ResourceIdentifier.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

going to go with "Bytes"

public boolean equals(Object obj) {
return this == obj
|| (obj instanceof ImmutableByteArray && Arrays.equals(safe, ((ImmutableByteArray) obj).safe));
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing toString, though I'm not sure what I'd expect a binary toString to do. Perhaps class name and length?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added toString that includes the size but nothing else

}

/** Returns a copy of this byte array. */
@JsonValue
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we move @JsonValue to getByteBuffer and avoid duplicating contents for serialization? Annotation may apply to the safe field, but I've not tested that type of usage.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, I'll move it to the other method. It's more appropriate to label a method than a private member, so we'll stick with methods.

Copy link
Copy Markdown
Contributor

@schlosna schlosna left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

palantir/atlasdb#2020 was one place where we didn't want to require a 3rd party dependency in public API that this could be useful.

}

/** Copies this byte array into the provided byte array beginning at offset and up to the provided length. */
public void copy(byte[] array, int offset, int length) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bikeshed: method name copyTo?


/** Constructs a new {@link ImmutableByteArray} read from the provided {@link ByteBuffer}. */
public static ImmutableByteArray from(ByteBuffer buffer) {
ByteBuffer local = buffer.duplicate();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a comment saying why this duplicate is necessary?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

assertThat(immutable.getBytes()[0]).isEqualTo((byte) 0);

input[0] = 1;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could cut this line (34) and the one above (30)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a comment on what line 33 is doing, believe the whitespace improves readability


@Test
public void testConstructionCopiesArrayWithRange() {
byte[] input = new byte[]{0, 1, 2};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also test end by doing {0,1,2,3} --> {1,2}?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Copy Markdown
Contributor

@uschi2000 uschi2000 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good modulo the naming discussion and one docs suggestion.

Copy link
Copy Markdown
Contributor

@carterkozak carterkozak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants