Skip to content

Commit

Permalink
fixes #924 add byte[] compare to Bytes (#934)
Browse files Browse the repository at this point in the history
Squashed commit of the following:

commit dad21ce
Author: Joseph Koshakow <koshy44@gmail.com>
Date:   Tue Oct 3 23:24:14 2017 -0400

    Added the following methods:
      private int compareToUnchecked(byte[] bytes, int offset, int len){...}
      private boolean contentEqualsUnchecked(byte[] bytes, int offset, int len){...}
    Refactored the following methods:
      public final int compareTo(Bytes other){...}
      public int compareTo(byte[] bytes){...}
      public int compareTo(byte[] bytes, int offset, int len){...}
      public final boolean equals(Object other){...}
      public boolean contentEquals(byte[] bytes){...}
      public boolean contentEquals(byte[] bytes, int offset, int len){...}
    Added tests to test offsets greater than 0

commit b3038dd
Author: Joseph Koshakow <koshy44@gmail.com>
Date:   Mon Oct 2 23:44:33 2017 -0400

    Modified precondition for contentEquals(byte[] bytes, int offset, int len){...}

commit ad5f06c
Author: Joseph Koshakow <koshy44@gmail.com>
Date:   Mon Oct 2 23:37:04 2017 -0400

    Added @SInCE 1.2.0 tags to new methods
    Added a Precondition.checkArgument to methods that take offset and len
    Added tests for different length Bytes and byte[] and empty Bytes and byte[]
    Added tests for invalid arguments

commit d0033f5
Author: Joseph Koshakow <koshy44@gmail.com>
Date:   Mon Oct 2 20:17:32 2017 -0400

    Created the following methods and corresponding unit tests for them:
      public boolean contentEquals(byte[] bytes){...}
      public boolean contentEquals(byte[] bytes, int offset, int len){...}
      public int compareTo(byte[] bytes){...}
      public int compareTo(byte[] bytes, int offset, int len){...}
    Refactored the following methods:
      public final int compareTo(Bytes other){...}
      public final boolean equals(Object other){...}
  • Loading branch information
jkosh44 authored and keith-turner committed Oct 4, 2017
1 parent 69df4dd commit 7c16599
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 16 deletions.
108 changes: 92 additions & 16 deletions modules/api/src/main/java/org/apache/fluo/api/data/Bytes.java
Original file line number Diff line number Diff line change
Expand Up @@ -186,32 +186,81 @@ public void writeTo(OutputStream out) throws IOException {
}
}

/**
* Compares this to the passed bytes, byte by byte, returning a negative, zero, or positive result
* if the first sequence is less than, equal to, or greater than the second. The comparison is
* performed starting with the first byte of each sequence, and proceeds until a pair of bytes
* differs, or one sequence runs out of byte (is shorter). A shorter sequence is considered less
* than a longer one.
*
* @return comparison result
*/
@Override
public final int compareTo(Bytes other) {
if (this == other) {
return 0;
} else {
return compareToUnchecked(other.data, other.offset, other.length);
}
}

/**
* Compares this to the passed bytes, byte by byte, returning a negative, zero, or positive result
* if the first sequence is less than, equal to, or greater than the second. The comparison is
* performed starting with the first byte of each sequence, and proceeds until a pair of bytes
* differs, or one sequence runs out of byte (is shorter). A shorter sequence is considered less
* than a longer one.
*
* @since 1.2.0
* @return comparison result
*/
@Override
public final int compareTo(Bytes other) {
if (this == other) {
return 0;
} else if (this.length == this.data.length && other.length == other.data.length) {
return UnsignedBytes.lexicographicalComparator().compare(this.data, other.data);
public int compareTo(byte[] bytes) {
return compareToUnchecked(bytes, 0, bytes.length);
}

/**
* Compares this to the passed bytes, byte by byte, returning a negative, zero, or positive result
* if the first sequence is less than, equal to, or greater than the second. The comparison is
* performed starting with the first byte of each sequence, and proceeds until a pair of bytes
* differs, or one sequence runs out of byte (is shorter). A shorter sequence is considered less
* than a longer one.
*
* This method checks the arguments passed to it.
*
* @since 1.2.0
* @return comparison result
*/
public int compareTo(byte[] bytes, int offset, int len) {
Preconditions.checkArgument(offset >= 0 && len >= 0 && offset + len <= bytes.length);
return compareToUnchecked(bytes, offset, len);
}

/**
* Compares this to the passed bytes, byte by byte, returning a negative, zero, or positive result
* if the first sequence is less than, equal to, or greater than the second. The comparison is
* performed starting with the first byte of each sequence, and proceeds until a pair of bytes
* differs, or one sequence runs out of byte (is shorter). A shorter sequence is considered less
* than a longer one.
*
* This method does not check the arguments passed to it.
*
* @since 1.2.0
* @return comparison result
*/
private int compareToUnchecked(byte[] bytes, int offset, int len) {
if (this.length == this.data.length && len == bytes.length) {
int res = UnsignedBytes.lexicographicalComparator().compare(this.data, bytes);
return UnsignedBytes.lexicographicalComparator().compare(this.data, bytes);
} else {
int minLen = Math.min(this.length, other.length);
for (int i = this.offset, j = other.offset; i < minLen; i++, j++) {
int minLen = Math.min(this.length, len);
for (int i = this.offset, j = offset; i < minLen; i++, j++) {
int a = (this.data[i] & 0xff);
int b = (other.data[j] & 0xff);

int b = (bytes[j] & 0xff);
if (a != b) {
return a - b;
}
}
return this.length - other.length;
return this.length - len;
}
}

Expand All @@ -228,15 +277,42 @@ public final boolean equals(Object other) {
if (other instanceof Bytes) {
Bytes ob = (Bytes) other;

if (length != ob.length) {
return false;
}

return compareTo(ob) == 0;
return contentEqualsUnchecked(ob.data, ob.offset, ob.length);
}
return false;
}

/**
* Returns true if this Bytes object equals another.
* @since 1.2.0
*/
public boolean contentEquals(byte[] bytes) {
return contentEqualsUnchecked(bytes, 0, bytes.length);
}

/**
* Returns true if this Bytes object equals another.
* This method checks it's arguments.
* @since 1.2.0
*/
public boolean contentEquals(byte[] bytes, int offset, int len) {
Preconditions.checkArgument(len >= 0 && offset >= 0 && offset + len <= bytes.length);
return contentEqualsUnchecked(bytes, offset, len);
}

/**
* Returns true if this Bytes object equals another.
* This method doesn't check it's arguments.
* @since 1.2.0
*/
private boolean contentEqualsUnchecked(byte[] bytes, int offset, int len) {
if (length != len) {
return false;
}

return compareToUnchecked(bytes, offset, len) == 0;
}

@Override
public final int hashCode() {
if (hashCode == 0) {
Expand Down
73 changes: 73 additions & 0 deletions modules/api/src/test/java/org/apache/fluo/api/data/BytesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.IllegalArgumentException;
import java.nio.ByteBuffer;
import java.nio.ReadOnlyBufferException;
import java.nio.charset.StandardCharsets;
Expand Down Expand Up @@ -108,6 +109,30 @@ public void testPrefixSuffix() {
Assert.assertFalse(b1.subSequence(0, 2).endsWith(b1));
}

@Test
public void testContentEquals() {
Bytes b1 = Bytes.of("a");
byte[] b2 = b1.toArray();
byte[] b3 = Bytes.of("b").toArray();
Bytes b5 = Bytes.of("qwerty");
byte[] b6 = b5.toArray();
Bytes b7 = Bytes.of("");
byte[] b8 = b7.toArray();


Assert.assertTrue(b1.contentEquals(b2));
Assert.assertTrue(b5.contentEquals(b6));
Assert.assertTrue(b7.contentEquals(b8));

Assert.assertFalse(b1.contentEquals(b3));
Assert.assertFalse(b1.contentEquals(b6));
Assert.assertFalse(b5.contentEquals(b2));
Assert.assertFalse(b1.contentEquals(b8));
Assert.assertFalse(b5.contentEquals(b8));
Assert.assertFalse(b7.contentEquals(b2));
Assert.assertFalse(b7.contentEquals(b6));
}

@Test
public void testCompare() {
Bytes b1 = Bytes.of("a");
Expand All @@ -118,6 +143,54 @@ public void testCompare() {
Assert.assertEquals(0, b1.compareTo(b3));
Assert.assertEquals(0, b1.compareTo(b1));
Assert.assertEquals(1, b1.compareTo(Bytes.EMPTY));

byte[] b1Arr = b1.toArray();
byte[] b2Arr = b2.toArray();
byte[] b3Arr = b3.toArray();
Assert.assertEquals(-1, b1.compareTo(b2Arr));
Assert.assertEquals(1, b2.compareTo(b1Arr));
Assert.assertEquals(0, b1.compareTo(b3Arr));
Assert.assertEquals(0, b1.compareTo(b1Arr));
Assert.assertEquals(1, b1.compareTo(Bytes.EMPTY));

Bytes b4 = Bytes.of("abc");
byte[] b4Arr = b4.toArray();
Bytes b5 = Bytes.of("baz");
byte[] b5Arr = b5.toArray();
Bytes b6 = Bytes.of("ab");
byte[] b7Arr = Bytes.of("dabc").toArray();

Assert.assertEquals(0, b4.compareTo(b4Arr, 0, 3));
Assert.assertTrue(b4.compareTo(b4Arr, 1, 2) < 0);
Assert.assertTrue(b5.compareTo(b4Arr, 1, 2) < 0);
Assert.assertTrue(b5.compareTo(b5Arr, 1, 2) > 0);
Assert.assertTrue(b4.compareTo(b4Arr, 0, 2) > 0);
Assert.assertTrue(b6.compareTo(b7Arr, 1, 3) < 0);
Assert.assertTrue(b6.compareTo(b1Arr) > 0);
}

@Test(expected = IllegalArgumentException.class)
public void testCompareNegOffset() {
Bytes b1 = Bytes.of("abc");
byte[] b2 = b1.toArray();

b1.compareTo(b2, -4, 1);
}

@Test(expected = IllegalArgumentException.class)
public void testCompareNegLen() {
Bytes b1 = Bytes.of("abc");
byte[] b2 = b1.toArray();

b1.compareTo(b2, 0, -1);
}

@Test(expected = IllegalArgumentException.class)
public void testCompareBadArgs() {
Bytes b1 = Bytes.of("abc");
byte[] b2 = b1.toArray();

b1.compareTo(b2, 2, 2);
}

@Test
Expand Down

0 comments on commit 7c16599

Please sign in to comment.