Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/EnumDefinition.java')
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/EnumDefinition.java290
1 files changed, 290 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/EnumDefinition.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/EnumDefinition.java
new file mode 100644
index 000000000..1d265328f
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/EnumDefinition.java
@@ -0,0 +1,290 @@
+package org.eclipse.equinox.internal.p2.metadata;
+
+import java.io.Serializable;
+import java.util.*;
+
+class EnumDefinition implements Comparable<EnumDefinition>, Serializable {
+ static class EnumSegment implements Comparable<EnumSegment>, Serializable {
+ private static final long serialVersionUID = 4737907767214436543L;
+
+ private final int ordinal;
+ private final EnumDefinition definition;
+
+ EnumSegment(int ordinal, EnumDefinition definition) {
+ this.ordinal = ordinal;
+ this.definition = definition;
+ }
+
+ public int compareTo(EnumSegment other) {
+ if (other == this)
+ return 0;
+ if (definition == other.definition)
+ // Same definition. Just compare ordinals
+ return ordinal - other.ordinal;
+
+ String thisId = definition.getIdentifier(ordinal);
+ String otherId = other.definition.getIdentifier(other.ordinal);
+ if (thisId.equals(otherId))
+ return 0;
+
+ int thisOrdinalInOther = other.definition.getOrdinal(thisId);
+ int otherOrdinalInThis = definition.getOrdinal(otherId);
+ if (thisOrdinalInOther >= 0) {
+ if (otherOrdinalInThis >= 0) {
+ // Both identifiers exists in both enums. Let's see if both
+ // enums order them the same way
+ int thisOrder = ordinal - otherOrdinalInThis;
+ int otherOrder = thisOrdinalInOther - other.ordinal;
+ if (thisOrder > 0 && otherOrder > 0)
+ return 1;
+ if (thisOrder < 0 && otherOrder < 0)
+ return -1;
+ // Difference in opinion...
+ } else {
+ // Use the order in other since it has both identifiers and
+ // this enum does not
+ return thisOrdinalInOther - other.ordinal;
+ }
+ } else if (otherOrdinalInThis >= 0) {
+ // Use the order in this since it has both identifiers and the
+ // other does not.
+ return ordinal - otherOrdinalInThis;
+ }
+
+ // We can't compare the enums since neither enum contain both identifiers
+ // or both do, but use different order. Fall back to comparing the definitions
+ return definition.compareTo(other.definition);
+ }
+
+ public boolean equals(Object other) {
+ return other == this || other instanceof EnumSegment && compareTo((EnumSegment) other) == 0;
+ }
+
+ public int hashCode() {
+ return (1 + ordinal) * 31 + definition.getIdentifier(ordinal).hashCode();
+ }
+
+ int getOrdinal() {
+ return ordinal;
+ }
+
+ String getIdentifier() {
+ return definition.getIdentifier(ordinal);
+ }
+
+ void toString(StringBuffer sb) {
+ definition.toString(sb, ordinal);
+ }
+
+ // For ligthweight deserialization
+ private Object readResolve() {
+ return definition.getSegment(ordinal);
+ }
+ }
+
+ private static final long serialVersionUID = 7237775466362654473L;
+ private static final Map<EnumDefinition, EnumSegment[]> enumDefinitionCache = new HashMap<EnumDefinition, EnumSegment[]>();
+
+ private static EnumSegment[] getEnumSegments(EnumDefinition ed) {
+ EnumSegment[] values = enumDefinitionCache.get(ed);
+ if (values == null) {
+ int ordinal = ed.identifiers.length;
+ values = new EnumSegment[ordinal];
+ while (--ordinal >= 0)
+ values[ordinal] = new EnumSegment(ordinal, ed);
+ enumDefinitionCache.put(ed, values);
+ }
+ return values;
+ }
+
+ static EnumDefinition getEnumDefinition(List<List<String>> identifiers) {
+ nextEd: for (EnumDefinition ed : enumDefinitionCache.keySet()) {
+ String[][] defs = ed.identifiers;
+ int ordinal = defs.length;
+ if (ordinal != identifiers.size())
+ continue;
+
+ while (--ordinal >= 0) {
+ String[] def = defs[ordinal];
+ List<String> ldef = identifiers.get(ordinal);
+ int idx = def.length;
+ if (ldef.size() != idx)
+ continue nextEd;
+ while (--idx >= 0)
+ if (!def[idx].equals(ldef.get(idx)))
+ continue nextEd;
+ }
+ return ed;
+ }
+ EnumDefinition ed = new EnumDefinition(identifiers);
+ getEnumSegments(ed);
+ return ed;
+ }
+
+ private final String[][] identifiers;
+ private final int longestLength;
+ private final int shortestLength;
+
+ private EnumDefinition(List<List<String>> identifiers) {
+ int ordinal = identifiers.size();
+ String[][] defs = new String[ordinal][];
+ int minLen = Integer.MAX_VALUE;
+ int maxLen = 0;
+ while (--ordinal >= 0) {
+ List<String> idents = identifiers.get(ordinal);
+ int idx = idents.size();
+ String[] def = idents.toArray(new String[idx]);
+ defs[ordinal] = def;
+ while (--idx >= 0) {
+ int idLen = def[idx].length();
+ if (idLen < minLen)
+ minLen = idLen;
+ if (idLen > maxLen)
+ maxLen = idLen;
+ }
+ }
+ this.shortestLength = minLen;
+ this.longestLength = maxLen;
+ this.identifiers = defs;
+ }
+
+ static EnumSegment getSegment(List<List<String>> identifiers, int ordinal) {
+ return new EnumDefinition(identifiers).getSegment(ordinal);
+ }
+
+ EnumSegment getSegment(int ordinal) {
+ return getEnumSegments(this)[ordinal];
+ }
+
+ /**
+ * Returns the ordinal for the given identifier
+ * @param identifier The identifier
+ * @return The ordinal of the identifier or -1 if it didn't exist.
+ */
+ int getOrdinal(String identifier) {
+ if (identifier != null) {
+ int ordinal = identifiers.length;
+ while (--ordinal >= 0) {
+ String[] idents = identifiers[ordinal];
+ int idx = idents.length;
+ while (--idx >= 0)
+ if (idents[idx].equals(identifier))
+ return ordinal;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the canonical identifier for the given ordinal.
+ * @param ordinal The ordinal number of the desired identifier
+ * @return The identifier or <code>null</code> if the ordinal is out of bounds
+ */
+ String getIdentifier(int ordinal) {
+ return ordinal >= 0 && ordinal < identifiers.length ? identifiers[ordinal][0] : null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 1;
+ int ordinal = identifiers.length;
+ while (--ordinal > 0) {
+ String[] idents = identifiers[ordinal];
+ int idx = idents.length;
+ while (--idx >= 0)
+ result = 31 * result + idents[idx].hashCode();
+ }
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this)
+ return true;
+ if (!(o instanceof EnumDefinition))
+ return false;
+ String[][] otherIds = ((EnumDefinition) o).identifiers;
+ int ordinal = identifiers.length;
+ if (ordinal != otherIds.length)
+ return false;
+ while (--ordinal >= 0)
+ if (!Arrays.equals(identifiers[ordinal], otherIds[ordinal]))
+ return false;
+ return true;
+ }
+
+ public int compareTo(EnumDefinition o) {
+ if (o == this)
+ return 0;
+
+ int top = identifiers.length;
+ int cmp = top - o.identifiers.length;
+ if (cmp != 0)
+ return cmp;
+
+ for (int idx = 0; idx < top; ++idx) {
+ cmp = identifiers[idx][0].compareTo(o.identifiers[idx][0]);
+ if (cmp != 0)
+ return cmp;
+ }
+ // this should never happen since we use a lightweight pattern
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer bld = new StringBuffer();
+ toString(bld);
+ return bld.toString();
+ }
+
+ public void toString(StringBuffer bld) {
+ bld.append('{');
+ int top = identifiers.length;
+ for (int ordinal = 0;;) {
+ String[] idents = identifiers[ordinal];
+ int identsTop = idents.length;
+ bld.append(idents[0]);
+ for (int idx = 1; idx < identsTop; ++idx) {
+ bld.append('=');
+ bld.append(idents[idx]);
+ }
+ if (++ordinal == top)
+ break;
+ bld.append(',');
+ }
+ bld.append('}');
+ }
+
+ void toString(StringBuffer bld, int selectedOrdinal) {
+ bld.append('{');
+ int top = identifiers.length;
+ for (int ordinal = 0;;) {
+ if (ordinal == selectedOrdinal)
+ bld.append('^');
+ bld.append(identifiers[ordinal][0]);
+ if (++ordinal == top)
+ break;
+ bld.append(',');
+ }
+ bld.append('}');
+ }
+
+ /**
+ * Returns the length of the longest identifier. This method is
+ * used by the parser
+ * @return The length of the longest identifier
+ */
+ int getLongestLength() {
+ return longestLength;
+ }
+
+ /**
+ * Returns the length of the shortest identifier. This method is
+ * used by the parser
+ * @return The length of the shortest identifier
+ */
+ int getShortestLength() {
+ return shortestLength;
+ }
+} \ No newline at end of file

Back to the top