1 package org.simantics.datatypes.literal;
5 import org.simantics.databoard.Bindings;
6 import org.simantics.databoard.binding.Binding;
7 import org.simantics.databoard.util.Bean;
10 public class GUID extends Bean {
12 public static final Binding BINDING = Bindings.getBindingUnchecked(GUID.class);
14 public long mostSignificant;
15 public long leastSignificant;
17 public GUID(long mostSignificant, long leastSignificant) {
19 this.mostSignificant = mostSignificant;
20 this.leastSignificant = leastSignificant;
23 public static GUID invalid() {
24 return new GUID(0, 0);
27 public static GUID invalid2() {
28 return new GUID(0, 1);
31 public boolean isInvalid() {
32 return mostSignificant == 0 && leastSignificant == 0;
35 public static GUID random() {
36 UUID random = UUID.randomUUID();
37 return new GUID(random.getMostSignificantBits(), random.getLeastSignificantBits());
40 public String indexString() {
41 StringBuilder b = new StringBuilder();
42 b.append(Long.toHexString(mostSignificant));
44 b.append(Long.toHexString(leastSignificant));
48 public static GUID parseIndexString(String indexString) {
49 String[] parts = indexString.split("_");
50 if(parts.length != 2) throw new IllegalArgumentException();
51 Long mostSignificant = parseUnsignedLong(parts[0].toUpperCase(), 16);
52 Long leastSignificant = parseUnsignedLong(parts[1], 16);
53 return new GUID(mostSignificant, leastSignificant);
57 * Parses the string argument as an unsigned {@code long} in the
58 * radix specified by the second argument. An unsigned integer
59 * maps the values usually associated with negative numbers to
60 * positive numbers larger than {@code MAX_VALUE}.
62 * The characters in the string must all be digits of the
63 * specified radix (as determined by whether {@link
64 * java.lang.Character#digit(char, int)} returns a nonnegative
65 * value), except that the first character may be an ASCII plus
66 * sign {@code '+'} ({@code '\u005Cu002B'}). The resulting
67 * integer value is returned.
69 * <p>An exception of type {@code NumberFormatException} is
70 * thrown if any of the following situations occurs:
72 * <li>The first argument is {@code null} or is a string of
75 * <li>The radix is either smaller than
76 * {@link java.lang.Character#MIN_RADIX} or
77 * larger than {@link java.lang.Character#MAX_RADIX}.
79 * <li>Any character of the string is not a digit of the specified
80 * radix, except that the first character may be a plus sign
81 * {@code '+'} ({@code '\u005Cu002B'}) provided that the
82 * string is longer than length 1.
84 * <li>The value represented by the string is larger than the
85 * largest unsigned {@code long}, 2<sup>64</sup>-1.
90 * @param s the {@code String} containing the unsigned integer
91 * representation to be parsed
92 * @param radix the radix to be used while parsing {@code s}.
93 * @return the unsigned {@code long} represented by the string
94 * argument in the specified radix.
95 * @throws NumberFormatException if the {@code String}
96 * does not contain a parsable {@code long}.
99 public static long parseUnsignedLong(String s, int radix)
100 throws NumberFormatException {
102 throw new NumberFormatException("null");
105 int len = s.length();
107 char firstChar = s.charAt(0);
108 if (firstChar == '-') {
110 NumberFormatException(String.format("Illegal leading minus sign " +
111 "on unsigned string %s.", s));
113 if (len <= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits
114 (radix == 10 && len <= 18) ) { // Long.MAX_VALUE in base 10 is 19 digits
115 return Long.parseLong(s, radix);
118 // No need for range checks on len due to testing above.
119 long first = Long.parseLong(s.substring(0, len - 1), radix);
120 int second = Character.digit(s.charAt(len - 1), radix);
122 throw new NumberFormatException("Bad digit at end of " + s);
124 long result = first * radix + second;
125 if (compareUnsigned(result, first) < 0) {
127 * The maximum unsigned value, (2^64)-1, takes at
128 * most one more digit to represent than the
129 * maximum signed value, (2^63)-1. Therefore,
130 * parsing (len - 1) digits will be appropriately
131 * in-range of the signed parsing. In other
132 * words, if parsing (len -1) digits overflows
133 * signed parsing, parsing len digits will
134 * certainly overflow unsigned parsing.
136 * The compareUnsigned check above catches
137 * situations where an unsigned overflow occurs
138 * incorporating the contribution of the final
141 throw new NumberFormatException(String.format("String value %s exceeds " +
142 "range of unsigned long.", s));
147 throw new NumberFormatException("For input string: \"" + s + "\"");
152 * Compares two {@code long} values numerically treating the values
155 * @param x the first {@code long} to compare
156 * @param y the second {@code long} to compare
157 * @return the value {@code 0} if {@code x == y}; a value less
158 * than {@code 0} if {@code x < y} as unsigned values; and
159 * a value greater than {@code 0} if {@code x > y} as
163 public static int compareUnsigned(long x, long y) {
164 return Long.compare(x + Long.MIN_VALUE, y + Long.MIN_VALUE);