diff options
author | Thomas Wolf <thomas.wolf@paranor.ch> | 2021-10-30 19:37:44 +0200 |
---|---|---|
committer | Thomas Wolf <thomas.wolf@paranor.ch> | 2021-10-30 23:05:22 +0200 |
commit | 3444a3be8c8a567f944fd7b81838e615852d787a (patch) | |
tree | 3c5565b2966fff8a8225fbfb3d2c95e9c0dbc254 /org.eclipse.jgit/src/org/eclipse/jgit/util | |
parent | c2204bb6835e4e6dc666bb34eaea910fb1484092 (diff) | |
download | jgit-3444a3be8c8a567f944fd7b81838e615852d787a.tar.gz jgit-3444a3be8c8a567f944fd7b81838e615852d787a.zip |
Factor out parsing git-style size numbers to StringUtils
Move the code to parse numbers with an optional 'k', 'm', or 'g' suffix
from the config file handling to StringUtils. This enables me to re-use
it in EGit, which has duplicate code in StorageSizeFieldEditor.
As this is generally useful functionality, providing it in the library
makes sense.
Change-Id: I86e4f5f62e14f99b35726b198ba3bbf1669418d9
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
Diffstat (limited to 'org.eclipse.jgit/src/org/eclipse/jgit/util')
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java index 61de65cac1..b77fb920ed 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java @@ -13,12 +13,20 @@ package org.eclipse.jgit.util; import java.text.MessageFormat; import java.util.Collection; +import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.internal.JGitText; /** * Miscellaneous string comparison utility methods. */ public final class StringUtils { + + private static final long KiB = 1024; + + private static final long MiB = 1024 * KiB; + + private static final long GiB = 1024 * MiB; + private static final char[] LC; static { @@ -307,4 +315,130 @@ public final class StringUtils { } return new String(buf, 0, o); } + + /** + * Parses a number with optional case-insensitive suffix 'k', 'm', or 'g' + * indicating KiB, MiB, and GiB, respectively. The suffix may follow the + * number with optional separation by one or more blanks. + * + * @param value + * {@link String} to parse; with leading and trailing whitespace + * ignored + * @param positiveOnly + * {@code true} to only accept positive numbers, {@code false} to + * allow negative numbers, too + * @return the value parsed + * @throws NumberFormatException + * if the {@value} is not parseable, or beyond the range of + * {@link Long} + * @throws StringIndexOutOfBoundsException + * if the string is empty or contains only whitespace, or + * contains only the letter 'k', 'm', or 'g' + * @since 6.0 + */ + public static long parseLongWithSuffix(@NonNull String value, + boolean positiveOnly) + throws NumberFormatException, StringIndexOutOfBoundsException { + String n = value.strip(); + if (n.isEmpty()) { + throw new StringIndexOutOfBoundsException(); + } + long mul = 1; + switch (n.charAt(n.length() - 1)) { + case 'g': + case 'G': + mul = GiB; + break; + case 'm': + case 'M': + mul = MiB; + break; + case 'k': + case 'K': + mul = KiB; + break; + default: + break; + } + if (mul > 1) { + n = n.substring(0, n.length() - 1).trim(); + } + if (n.isEmpty()) { + throw new StringIndexOutOfBoundsException(); + } + long number; + if (positiveOnly) { + number = Long.parseUnsignedLong(n); + if (number < 0) { + throw new NumberFormatException( + MessageFormat.format(JGitText.get().valueExceedsRange, + value, Long.class.getSimpleName())); + } + } else { + number = Long.parseLong(n); + } + if (mul == 1) { + return number; + } + try { + return Math.multiplyExact(mul, number); + } catch (ArithmeticException e) { + throw new NumberFormatException(e.getLocalizedMessage()); + } + } + + /** + * Parses a number with optional case-insensitive suffix 'k', 'm', or 'g' + * indicating KiB, MiB, and GiB, respectively. The suffix may follow the + * number with optional separation by blanks. + * + * @param value + * {@link String} to parse; with leading and trailing whitespace + * ignored + * @param positiveOnly + * {@code true} to only accept positive numbers, {@code false} to + * allow negative numbers, too + * @return the value parsed + * @throws NumberFormatException + * if the {@value} is not parseable or beyond the range of + * {@link Integer} + * @throws StringIndexOutOfBoundsException + * if the string is empty or contains only whitespace, or + * contains only the letter 'k', 'm', or 'g' + * @since 6.0 + */ + public static int parseIntWithSuffix(@NonNull String value, + boolean positiveOnly) + throws NumberFormatException, StringIndexOutOfBoundsException { + try { + return Math.toIntExact(parseLongWithSuffix(value, positiveOnly)); + } catch (ArithmeticException e) { + throw new NumberFormatException( + MessageFormat.format(JGitText.get().valueExceedsRange, + value, Integer.class.getSimpleName())); + } + } + + /** + * Formats an integral value as a decimal number with 'k', 'm', or 'g' + * suffix if it is an exact multiple of 1024, otherwise returns the value + * representation as a decimal number without suffix. + * + * @param value + * Value to format + * @return the value's String representation + * @since 6.0 + */ + public static String formatWithSuffix(long value) { + if (value >= GiB && (value % GiB) == 0) { + return String.valueOf(value / GiB) + 'g'; + } + if (value >= MiB && (value % MiB) == 0) { + return String.valueOf(value / MiB) + 'm'; + } + if (value >= KiB && (value % KiB) == 0) { + return String.valueOf(value / KiB) + 'k'; + } + return String.valueOf(value); + } } |