提交 b4ae071e authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Add StringUtils.parseUInt31()

上级 1a8cbc76
...@@ -17,6 +17,7 @@ import java.util.HashMap; ...@@ -17,6 +17,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.util.StringUtils;
/** /**
* Utility methods * Utility methods
...@@ -931,9 +932,8 @@ public final class DataUtils { ...@@ -931,9 +932,8 @@ public final class DataUtils {
if (m != null && m.endsWith("]")) { if (m != null && m.endsWith("]")) {
int dash = m.lastIndexOf('/'); int dash = m.lastIndexOf('/');
if (dash >= 0) { if (dash >= 0) {
String s = m.substring(dash + 1, m.length() - 1);
try { try {
return Integer.parseInt(s); return StringUtils.parseUInt31(m, dash + 1, m.length() - 1);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
// no error code // no error code
} }
......
...@@ -33,6 +33,7 @@ import org.h2.store.InDoubtTransaction; ...@@ -33,6 +33,7 @@ import org.h2.store.InDoubtTransaction;
import org.h2.store.fs.FileChannelInputStream; import org.h2.store.fs.FileChannelInputStream;
import org.h2.store.fs.FileUtils; import org.h2.store.fs.FileUtils;
import org.h2.table.TableBase; import org.h2.table.TableBase;
import org.h2.util.StringUtils;
import org.h2.util.Utils; import org.h2.util.Utils;
/** /**
...@@ -267,7 +268,7 @@ public class MVTableEngine implements TableEngine { ...@@ -267,7 +268,7 @@ public class MVTableEngine implements TableEngine {
if (mapName.startsWith("temp.")) { if (mapName.startsWith("temp.")) {
mvStore.removeMap(mapName); mvStore.removeMap(mapName);
} else if (mapName.startsWith("table.") || mapName.startsWith("index.")) { } else if (mapName.startsWith("table.") || mapName.startsWith("index.")) {
int id = Integer.parseInt(mapName.substring(1 + mapName.indexOf('.'))); int id = StringUtils.parseUInt31(mapName, mapName.indexOf('.') + 1, mapName.length());
if (!objectIds.get(id)) { if (!objectIds.get(id)) {
mvStore.removeMap(mapName); mvStore.removeMap(mapName);
} }
......
...@@ -19,6 +19,7 @@ import org.h2.mvstore.MVStore; ...@@ -19,6 +19,7 @@ import org.h2.mvstore.MVStore;
import org.h2.mvstore.WriteBuffer; import org.h2.mvstore.WriteBuffer;
import org.h2.mvstore.type.DataType; import org.h2.mvstore.type.DataType;
import org.h2.mvstore.type.ObjectDataType; import org.h2.mvstore.type.ObjectDataType;
import org.h2.util.StringUtils;
/** /**
* A store that supports concurrent MVCC read-committed transactions. * A store that supports concurrent MVCC read-committed transactions.
...@@ -153,7 +154,8 @@ public class TransactionStore { ...@@ -153,7 +154,8 @@ public class TransactionStore {
if (mapName.length() > UNDO_LOG_NAME_PREFIX.length()) { if (mapName.length() > UNDO_LOG_NAME_PREFIX.length()) {
boolean committed = mapName.charAt(UNDO_LOG_NAME_PREFIX.length()) == UNDO_LOG_COMMITTED; boolean committed = mapName.charAt(UNDO_LOG_NAME_PREFIX.length()) == UNDO_LOG_COMMITTED;
if (store.hasData(mapName) || committed) { if (store.hasData(mapName) || committed) {
int transactionId = Integer.parseInt(mapName.substring(UNDO_LOG_NAME_PREFIX.length() + 1)); int transactionId = StringUtils.parseUInt31(mapName, UNDO_LOG_NAME_PREFIX.length() + 1,
mapName.length());
VersionedBitSet openTxBitSet = openTransactions.get(); VersionedBitSet openTxBitSet = openTransactions.get();
if (!openTxBitSet.get(transactionId)) { if (!openTxBitSet.get(transactionId)) {
Object[] data = preparedTransactions.get(transactionId); Object[] data = preparedTransactions.get(transactionId);
......
...@@ -370,8 +370,8 @@ public class DateTimeUtils { ...@@ -370,8 +370,8 @@ public class DateTimeUtils {
} }
} }
int year = Integer.parseInt(s.substring(start, yEnd)); int year = Integer.parseInt(s.substring(start, yEnd));
int month = Integer.parseInt(s.substring(mStart, mEnd)); int month = StringUtils.parseUInt31(s, mStart, mEnd);
int day = Integer.parseInt(s.substring(dStart, end)); int day = StringUtils.parseUInt31(s, dStart, end);
if (!isValidDate(year, month, day)) { if (!isValidDate(year, month, day)) {
throw new IllegalArgumentException(year + "-" + month + "-" + day); throw new IllegalArgumentException(year + "-" + month + "-" + day);
} }
...@@ -439,23 +439,23 @@ public class DateTimeUtils { ...@@ -439,23 +439,23 @@ public class DateTimeUtils {
sEnd = s.indexOf('.', sStart); sEnd = s.indexOf('.', sStart);
} }
} }
hour = Integer.parseInt(s.substring(start, hEnd)); hour = StringUtils.parseUInt31(s, start, hEnd);
if (hour < 0 || hour == 0 && s.charAt(start) == '-' || hour >= 24) { if (hour >= 24) {
throw new IllegalArgumentException(s); throw new IllegalArgumentException(s);
} }
minute = Integer.parseInt(s.substring(mStart, mEnd)); minute = StringUtils.parseUInt31(s, mStart, mEnd);
if (sStart > 0) { if (sStart > 0) {
if (sEnd < 0) { if (sEnd < 0) {
second = Integer.parseInt(s.substring(sStart, end)); second = StringUtils.parseUInt31(s, sStart, end);
nanos = 0; nanos = 0;
} else { } else {
second = Integer.parseInt(s.substring(sStart, sEnd)); second = StringUtils.parseUInt31(s, sStart, sEnd);
nanos = parseNanos(s, sEnd + 1, end); nanos = parseNanos(s, sEnd + 1, end);
} }
} else { } else {
second = nanos = 0; second = nanos = 0;
} }
if (minute < 0 || minute >= 60 || second < 0 || second >= 60) { if (minute >= 60 || second >= 60) {
throw new IllegalArgumentException(s); throw new IllegalArgumentException(s);
} }
return ((((hour * 60L) + minute) * 60) + second) * NANOS_PER_SECOND + nanos; return ((((hour * 60L) + minute) * 60) + second) * NANOS_PER_SECOND + nanos;
...@@ -1856,8 +1856,8 @@ public class DateTimeUtils { ...@@ -1856,8 +1856,8 @@ public class DateTimeUtils {
} }
private static long parseIntervalRemaining(String s, int start, int end, int max) { private static long parseIntervalRemaining(String s, int start, int end, int max) {
long v = Integer.parseInt(s.substring(start, end)); int v = StringUtils.parseUInt31(s, start, end);
if (v < 0 || v > max) { if (v > max) {
throw new IllegalArgumentException(s); throw new IllegalArgumentException(s);
} }
return v; return v;
...@@ -1867,13 +1867,13 @@ public class DateTimeUtils { ...@@ -1867,13 +1867,13 @@ public class DateTimeUtils {
int seconds, nanos; int seconds, nanos;
int dot = s.indexOf('.', start + 1); int dot = s.indexOf('.', start + 1);
if (dot < 0) { if (dot < 0) {
seconds = Integer.parseInt(s.substring(start)); seconds = StringUtils.parseUInt31(s, start, s.length());
nanos = 0; nanos = 0;
} else { } else {
seconds = Integer.parseInt(s.substring(start, dot)); seconds = StringUtils.parseUInt31(s, start, dot);
nanos = parseNanos(s, dot + 1, s.length()); nanos = parseNanos(s, dot + 1, s.length());
} }
if (seconds < 0 || seconds > 59) { if (seconds > 59) {
throw new IllegalArgumentException(s); throw new IllegalArgumentException(s);
} }
return seconds * NANOS_PER_SECOND + nanos; return seconds * NANOS_PER_SECOND + nanos;
......
...@@ -921,6 +921,38 @@ public class StringUtils { ...@@ -921,6 +921,38 @@ public class StringUtils {
softCache = null; softCache = null;
} }
/**
* Parses an unsigned 31-bit integer. Neither - nor + signs are allowed.
*
* @param s string to parse
* @param start the beginning index, inclusive
* @param end the ending index, exclusive
* @return the unsigned {@code int} not greater than {@link Integer#MAX_VALUE}.
*/
public static int parseUInt31(String s, int start, int end) {
if (end > s.length() || start < 0 || start > end) {
throw new IndexOutOfBoundsException();
}
if (start == end) {
throw new NumberFormatException("");
}
int result = 0;
for (int i = start; i < end; i++) {
char ch = s.charAt(i);
// Ensure that character is valid and that multiplication by 10 will
// be performed without overflow
if (ch < '0' || ch > '9' || result > 214_748_364) {
throw new NumberFormatException(s.substring(start, end));
}
result = result * 10 + ch - '0';
if (result < 0) {
// Overflow
throw new NumberFormatException(s.substring(start, end));
}
}
return result;
}
/** /**
* Convert a hex encoded string to a byte array. * Convert a hex encoded string to a byte array.
* *
......
...@@ -32,6 +32,7 @@ public class TestStringUtils extends TestBase { ...@@ -32,6 +32,7 @@ public class TestStringUtils extends TestBase {
@Override @Override
public void test() throws Exception { public void test() throws Exception {
testParseUInt31();
testHex(); testHex();
testXML(); testXML();
testSplit(); testSplit();
...@@ -43,6 +44,32 @@ public class TestStringUtils extends TestBase { ...@@ -43,6 +44,32 @@ public class TestStringUtils extends TestBase {
testTrimSubstring(); testTrimSubstring();
} }
private void testParseUInt31() {
assertEquals(0, StringUtils.parseUInt31("101", 1, 2));
assertEquals(11, StringUtils.parseUInt31("11", 0, 2));
assertEquals(0, StringUtils.parseUInt31("000", 0, 3));
assertEquals(1, StringUtils.parseUInt31("01", 0, 2));
assertEquals(999999999, StringUtils.parseUInt31("X999999999", 1, 10));
assertEquals(2147483647, StringUtils.parseUInt31("2147483647", 0, 10));
testParseUInt31Bad(null, 0, 1);
testParseUInt31Bad("1", -1, 1);
testParseUInt31Bad("1", 0, 0);
testParseUInt31Bad("12", 1, 0);
testParseUInt31Bad("-0", 0, 2);
testParseUInt31Bad("+0", 0, 2);
testParseUInt31Bad("2147483648", 0, 10);
testParseUInt31Bad("21474836470", 0, 11);
}
private void testParseUInt31Bad(String s, int start, int end) {
try {
StringUtils.parseUInt31(s, start, end);
} catch (NullPointerException | IndexOutOfBoundsException | NumberFormatException e) {
return;
}
fail();
}
private void testHex() { private void testHex() {
assertEquals("face", assertEquals("face",
StringUtils.convertBytesToHex(new byte[] StringUtils.convertBytesToHex(new byte[]
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论