]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.datatypes/src/org/simantics/datatypes/literal/GUID.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.datatypes / src / org / simantics / datatypes / literal / GUID.java
1 package org.simantics.datatypes.literal;\r
2 \r
3 import java.util.UUID;\r
4 \r
5 import org.simantics.databoard.Bindings;\r
6 import org.simantics.databoard.binding.Binding;\r
7 import org.simantics.databoard.util.Bean;\r
8 \r
9 \r
10 public class GUID extends Bean {\r
11 \r
12         public static final Binding BINDING = Bindings.getBindingUnchecked(GUID.class);\r
13 \r
14         public long mostSignificant;\r
15         public long leastSignificant;\r
16         \r
17         public GUID(long mostSignificant, long leastSignificant) {\r
18                 super(BINDING);\r
19                 this.mostSignificant = mostSignificant;\r
20                 this.leastSignificant = leastSignificant;\r
21         }\r
22         \r
23         public static GUID invalid() {\r
24                 return new GUID(0, 0);\r
25         }\r
26         \r
27         public static GUID invalid2() {\r
28                 return new GUID(0, 1);\r
29         }\r
30 \r
31         public boolean isInvalid() {\r
32                 return mostSignificant == 0 && leastSignificant == 0;\r
33         }\r
34 \r
35         public static GUID random() {\r
36                 UUID random = UUID.randomUUID();\r
37                 return new GUID(random.getMostSignificantBits(), random.getLeastSignificantBits());\r
38         }\r
39         \r
40         public String indexString() {\r
41                 StringBuilder b = new StringBuilder();\r
42                 b.append(Long.toHexString(mostSignificant));\r
43                 b.append("_");\r
44                 b.append(Long.toHexString(leastSignificant));\r
45                 return b.toString();\r
46         }\r
47         \r
48         public static GUID parseIndexString(String indexString) {\r
49                 String[] parts = indexString.split("_");\r
50                 if(parts.length != 2) throw new IllegalArgumentException();\r
51                 Long mostSignificant = parseUnsignedLong(parts[0].toUpperCase(), 16);\r
52                 Long leastSignificant = parseUnsignedLong(parts[1], 16);\r
53                 return new GUID(mostSignificant, leastSignificant);\r
54         }\r
55 \r
56     /**\r
57      * Parses the string argument as an unsigned {@code long} in the\r
58      * radix specified by the second argument.  An unsigned integer\r
59      * maps the values usually associated with negative numbers to\r
60      * positive numbers larger than {@code MAX_VALUE}.\r
61      *\r
62      * The characters in the string must all be digits of the\r
63      * specified radix (as determined by whether {@link\r
64      * java.lang.Character#digit(char, int)} returns a nonnegative\r
65      * value), except that the first character may be an ASCII plus\r
66      * sign {@code '+'} ({@code '\u005Cu002B'}). The resulting\r
67      * integer value is returned.\r
68      *\r
69      * <p>An exception of type {@code NumberFormatException} is\r
70      * thrown if any of the following situations occurs:\r
71      * <ul>\r
72      * <li>The first argument is {@code null} or is a string of\r
73      * length zero.\r
74      *\r
75      * <li>The radix is either smaller than\r
76      * {@link java.lang.Character#MIN_RADIX} or\r
77      * larger than {@link java.lang.Character#MAX_RADIX}.\r
78      *\r
79      * <li>Any character of the string is not a digit of the specified\r
80      * radix, except that the first character may be a plus sign\r
81      * {@code '+'} ({@code '\u005Cu002B'}) provided that the\r
82      * string is longer than length 1.\r
83      *\r
84      * <li>The value represented by the string is larger than the\r
85      * largest unsigned {@code long}, 2<sup>64</sup>-1.\r
86      *\r
87      * </ul>\r
88      *\r
89      *\r
90      * @param      s   the {@code String} containing the unsigned integer\r
91      *                  representation to be parsed\r
92      * @param      radix   the radix to be used while parsing {@code s}.\r
93      * @return     the unsigned {@code long} represented by the string\r
94      *             argument in the specified radix.\r
95      * @throws     NumberFormatException if the {@code String}\r
96      *             does not contain a parsable {@code long}.\r
97      * @since 1.8\r
98      */\r
99     public static long parseUnsignedLong(String s, int radix)\r
100                 throws NumberFormatException {\r
101         if (s == null)  {\r
102             throw new NumberFormatException("null");\r
103         }\r
104 \r
105         int len = s.length();\r
106         if (len > 0) {\r
107             char firstChar = s.charAt(0);\r
108             if (firstChar == '-') {\r
109                 throw new\r
110                     NumberFormatException(String.format("Illegal leading minus sign " +\r
111                                                        "on unsigned string %s.", s));\r
112             } else {\r
113                 if (len <= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits\r
114                     (radix == 10 && len <= 18) ) { // Long.MAX_VALUE in base 10 is 19 digits\r
115                     return Long.parseLong(s, radix);\r
116                 }\r
117 \r
118                 // No need for range checks on len due to testing above.\r
119                 long first = Long.parseLong(s.substring(0, len - 1), radix);\r
120                 int second = Character.digit(s.charAt(len - 1), radix);\r
121                 if (second < 0) {\r
122                     throw new NumberFormatException("Bad digit at end of " + s);\r
123                 }\r
124                 long result = first * radix + second;\r
125                 if (compareUnsigned(result, first) < 0) {\r
126                     /*\r
127                      * The maximum unsigned value, (2^64)-1, takes at\r
128                      * most one more digit to represent than the\r
129                      * maximum signed value, (2^63)-1.  Therefore,\r
130                      * parsing (len - 1) digits will be appropriately\r
131                      * in-range of the signed parsing.  In other\r
132                      * words, if parsing (len -1) digits overflows\r
133                      * signed parsing, parsing len digits will\r
134                      * certainly overflow unsigned parsing.\r
135                      *\r
136                      * The compareUnsigned check above catches\r
137                      * situations where an unsigned overflow occurs\r
138                      * incorporating the contribution of the final\r
139                      * digit.\r
140                      */\r
141                     throw new NumberFormatException(String.format("String value %s exceeds " +\r
142                                                                   "range of unsigned long.", s));\r
143                 }\r
144                 return result;\r
145             }\r
146         } else {\r
147             throw new NumberFormatException("For input string: \"" + s + "\"");\r
148         }\r
149     }\r
150 \r
151     /**\r
152      * Compares two {@code long} values numerically treating the values\r
153      * as unsigned.\r
154      *\r
155      * @param  x the first {@code long} to compare\r
156      * @param  y the second {@code long} to compare\r
157      * @return the value {@code 0} if {@code x == y}; a value less\r
158      *         than {@code 0} if {@code x < y} as unsigned values; and\r
159      *         a value greater than {@code 0} if {@code x > y} as\r
160      *         unsigned values\r
161      * @since 1.8\r
162      */\r
163     public static int compareUnsigned(long x, long y) {\r
164         return Long.compare(x + Long.MIN_VALUE, y + Long.MIN_VALUE);\r
165     }\r
166     \r
167 }\r