Skip to content

Commit

Permalink
Support for sortable base64 encoding
Browse files Browse the repository at this point in the history
implement #11

Change-Id: I39b8f26d025e095d9d654f655657df6d6dc2543f
  • Loading branch information
javeme committed Dec 25, 2018
1 parent bbbc8e7 commit 242613f
Show file tree
Hide file tree
Showing 10 changed files with 649 additions and 27 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.baidu.hugegraph</groupId>
<artifactId>hugegraph-common</artifactId>
<version>1.5.5</version>
<version>1.5.6</version>

<name>hugegraph-common</name>
<url>https://github.com/hugegraph/hugegraph-common</url>
Expand Down Expand Up @@ -198,7 +198,7 @@
<manifestEntries>
<!-- Must be on one line, otherwise the automatic
upgrade script cannot replace the version number -->
<Implementation-Version>1.5.5.0</Implementation-Version>
<Implementation-Version>1.5.6.0</Implementation-Version>
</manifestEntries>
</archive>
</configuration>
Expand Down
76 changes: 68 additions & 8 deletions src/main/java/com/baidu/hugegraph/util/LongEncoding.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,77 @@
public final class LongEncoding {

private static final String BASE_SYMBOLS =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-~";
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~";

public static long decode(String s) {
return decode(s, BASE_SYMBOLS);
private static final String LENGTH_SYMBOLS = "0123456789ABCDEF";
private static final char NEG = LENGTH_SYMBOLS.charAt(0);

private static final long FULL_LONG = 0x8000000000000000L;

public static String encodeNumber(Object number) {
Number num = NumericUtil.convertToNumber(number);
long value = NumericUtil.numberToSortableLong(num);
return encodeSortable(value);
}

public static Number decodeNumber(String str, Class<?> clazz) {
long value = decodeSortable(str);
Number number = NumericUtil.sortableLongToNumber(value, clazz);
return number;
}

public static String encodeSortable(long num) {
boolean negative = false;
if (num < 0L) {
negative = true;
num += FULL_LONG;
}

String encoded = encode(num, BASE_SYMBOLS);
int length = encoded.length();
E.checkArgument(length <= LENGTH_SYMBOLS.length(),
"Length symbols can't represent encoded number '%s'",
encoded);
StringBuilder sb = new StringBuilder(length + 2);
if (negative) {
sb.append(NEG);
}
char len = LENGTH_SYMBOLS.charAt(length);
sb.append(len);
sb.append(encoded);

return sb.toString();
}

public static long decodeSortable(String str) {
E.checkArgument(str.length() >= 2,
"Length of sortable encoded string must be >=2");
boolean negative = str.charAt(0) == NEG;
int prefix = 1;
if (negative) {
prefix = 2;
}
String encoded = str.substring(prefix);
long value = decode(encoded);
if (negative) {
value -= FULL_LONG;
}
return value;
}

public static String encode(long num) {
return encode(num, BASE_SYMBOLS);
}

public static long decode(String s, String symbols) {
public static long decode(String str) {
return decode(str, BASE_SYMBOLS);
}

public static long decode(String str, String symbols) {
final int B = symbols.length();
E.checkArgument(B > 0, "The symbols parameter can't be empty");
long num = 0;
for (char ch : s.toCharArray()) {
for (char ch : str.toCharArray()) {
num *= B;
int pos = symbols.indexOf(ch);
if (pos < 0)
Expand All @@ -49,13 +106,16 @@ public static long decode(String s, String symbols) {
}

public static String encode(long num, String symbols) {
E.checkArgument(num >= 0, "Expected non-negative number: %s", num);
final int B = symbols.length();
E.checkArgument(num >= 0, "Expected non-negative number: %s", num);
E.checkArgument(B > 0, "The symbols parameter can't be empty");

StringBuilder sb = new StringBuilder();
while (num != 0) {
do {
sb.append(symbols.charAt((int) (num % B)));
num /= B;
}
} while (num != 0);

return sb.reverse().toString();
}
}
66 changes: 59 additions & 7 deletions src/main/java/com/baidu/hugegraph/util/NumericUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,48 @@ public static int sortableFloatBits(int bits) {
return bits ^ (bits >> 31) & 0x7fffffff;
}

public static long numberToSortableLong(Number number) {
if (number instanceof Double) {
return doubleToSortableLong(number.doubleValue());
} else if (number instanceof Float) {
return floatToSortableInt(number.floatValue());
} else if (number instanceof Long || number instanceof Integer ||
number instanceof Short || number instanceof Byte) {
return number.longValue();
} else if (number instanceof BigDecimal) {
BigDecimal bd = (BigDecimal) number;
boolean intNumber = bd.stripTrailingZeros().scale() <= 0;
return intNumber ? bd.longValueExact() :
doubleToSortableLong(bd.doubleValue());
}
// TODO: support other number types
throw new IllegalArgumentException(String.format(
"Unsupported number type: %s(%s)",
number.getClass().getSimpleName(), number));
}

public static Number sortableLongToNumber(long value, Class<?> clazz) {
assert NumericUtil.isNumber(clazz);

if (clazz == Double.class) {
return sortableLongToDouble(value);
} else if (clazz == Float.class) {
return sortableIntToFloat((int) value);
} else if (clazz == Long.class) {
return value;
} else if (clazz == Integer.class) {
return (int) value;
} else if (clazz == Short.class) {
return (short) value;
} else if (clazz == Byte.class) {
return (byte) value;
}

// TODO: support other number types
throw new IllegalArgumentException(String.format(
"Unsupported number type: %s", clazz.getSimpleName()));
}

public static byte[] numberToSortableBytes(Number number) {
if (number instanceof Long) {
return longToBytes(number.longValue());
Expand All @@ -117,7 +159,9 @@ public static byte[] numberToSortableBytes(Number number) {
}

// TODO: support other number types
return null;
throw new IllegalArgumentException(String.format(
"Unsupported number type: %s(%s)",
number.getClass().getSimpleName(), number));
}

public static Number sortableBytesToNumber(byte[] bytes, Class<?> clazz) {
Expand All @@ -138,7 +182,8 @@ public static Number sortableBytesToNumber(byte[] bytes, Class<?> clazz) {
}

// TODO: support other number types
return null;
throw new IllegalArgumentException(String.format(
"Unsupported number type: %s", clazz.getSimpleName()));
}

public static byte[] longToBytes(long value) {
Expand Down Expand Up @@ -174,16 +219,23 @@ public static boolean isNumber(Class<?> clazz) {
return Number.class.isAssignableFrom(clazz);
}

public static Object convertToNumber(Object value) {
if (!isNumber(value) && value != null) {
public static Number convertToNumber(Object value) {
if (value == null) {
return null;
}

Number number;
if (isNumber(value)) {
number = (Number) value;
} else {
if (value instanceof Date) {
value = ((Date) value).getTime();
number = ((Date) value).getTime();
} else {
// TODO: add some more types to convert
value = new BigDecimal(value.toString());
number = new BigDecimal(value.toString());
}
}
return value;
return number;
}

/**
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/com/baidu/hugegraph/util/VersionUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ public static boolean match(Version version, String begin, String end) {
version.compareTo(new Version(end)) < 0;
}

/**
* Compare if a version is greater than the other one (inclusive)
* @param version The version to be compared
* @param begin The lower bound of the range
* @return true if it's greater than the other, otherwise false
*/
public static boolean gte(String version, String other) {
E.checkArgumentNotNull(version, "The version to match is null");
return new Version(version).compareTo(new Version(other)) >= 0;
}

/**
* Check whether a component version is matched expected range,
* throw an exception if it's not matched.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ public class CommonVersion {

// The second parameter of Version.of() is for all-in-one JAR
public static final Version VERSION = Version.of(CommonVersion.class,
"1.5.5");
"1.5.6");
}
6 changes: 5 additions & 1 deletion src/test/java/com/baidu/hugegraph/unit/UnitTestSuite.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,13 @@
import com.baidu.hugegraph.unit.util.CollectionUtilTest;
import com.baidu.hugegraph.unit.util.HashUtilTest;
import com.baidu.hugegraph.unit.util.InsertionOrderUtilTest;
import com.baidu.hugegraph.unit.util.LongEncodingTest;
import com.baidu.hugegraph.unit.util.VersionUtilTest;
import com.baidu.hugegraph.unit.version.VersionTest;

@RunWith(Suite.class)
@Suite.SuiteClasses({
VersionTest.class,
EventHubTest.class,

ExtendableIteratorTest.class,
Expand All @@ -48,7 +51,8 @@
CollectionUtilTest.class,
HashUtilTest.class,
InsertionOrderUtilTest.class,
VersionUtilTest.class
VersionUtilTest.class,
LongEncodingTest.class
})
public class UnitTestSuite {
}
12 changes: 6 additions & 6 deletions src/test/java/com/baidu/hugegraph/unit/event/EventHubTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -461,24 +461,24 @@ public Object event(Event event) {

event.checkArgs(Integer.class);
int i = (int) event.args()[0];
if (i % 100000 == 0) {
if (i % 10000 == 0) {
System.out.println("On event '" + notify + "': " + i);
}
return null;
}
};

Thread listenerUpdateThread = new Thread(() -> {
// This will cost about 10s
for (int i = 0; i < 100; i++) {
// This will cost about 1s
for (int i = 0; i < 10; i++) {
this.eventHub.listen(notify, listener1);
if (!this.eventHub.listeners(notify).contains(listener2)) {
this.eventHub.listen(notify, listener2);
}

this.wait100ms();

if (i % 10 == 0) {
if (i % 2 == 0) {
this.eventHub.unlisten(notify);
} else {
this.eventHub.unlisten(notify, listener1);
Expand All @@ -488,8 +488,8 @@ public Object event(Event event) {
listenerUpdateThread.start();

runWithThreads(THREADS_NUM, () -> {
// This will cost about 10s ~ 20s
for (int i = 0; i < 10000 * 100; i++) {
// This will cost about 1s ~ 2s
for (int i = 0; i < 10000 * 10; i++) {
this.eventHub.notify(notify, i);
Thread.yield();
}
Expand Down
Loading

0 comments on commit 242613f

Please sign in to comment.