All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.almworks.jira.structure.api.util.ComparableTuple Maven / Gradle / Ivy

The newest version!
package com.almworks.jira.structure.api.util;

import org.jetbrains.annotations.NotNull;

import java.util.*;

/**
 * 

Comparable tuple is a tuple consisting of numbers and strings, which is compared on per-component order, starting * with the first element (most significant), down to the last one. It works similar to the string comparison by * character.

* *

Each pair of elements are compared based on their types. Elements of the same types are compared using their * standard comparison method. If elements have different types, the numbers come before the strings.

*/ public final class ComparableTuple implements Comparable { public static final ComparableTuple NIL = new ComparableTuple(new Object[] {}); @NotNull private final Object[] myValue; private ComparableTuple(@NotNull Object[] value) { myValue = value; } public static ComparableTuple of(long number) { return new ComparableTuple(new Object[] { number }); } public static ComparableTuple of(double number) { return new ComparableTuple(new Object[] { number }); } public static ComparableTuple of(String string) { if (string == null) { throw new IllegalArgumentException(); } return new ComparableTuple(new Object[] { string }); } public static ComparableTuple of(String a, String b) { if (a == null || b == null) { throw new IllegalArgumentException(); } return new ComparableTuple(new Object[] { a, b }); } public static ComparableTuple of(long a, long b) { return new ComparableTuple(new Object[] { a, b }); } public static ComparableTuple of(String[] strings) { if (strings == null) { throw new IllegalArgumentException(); } return new ComparableTuple(Arrays.copyOf(strings, strings.length)); } public static ComparableTuple of(Long[] longs) { if (longs == null) { throw new IllegalArgumentException(); } return new ComparableTuple(Arrays.copyOf(longs, longs.length)); } public static ComparableTuple of(String a, long b) { if (a == null) { throw new IllegalArgumentException(); } return new ComparableTuple(new Object[] {a, b}); } public static ComparableTuple of(String a, long b, String c) { if (a == null || c == null) { throw new IllegalArgumentException(); } return new ComparableTuple(new Object[] {a, b, c}); } public static ComparableTuple of(List values) { if (values == null) { throw new IllegalArgumentException(); } List list = new ArrayList<>(values.size()); for (Object v : values) { if (v == null) { throw new IllegalArgumentException(); } else if (v instanceof String || v instanceof Number) { list.add(v); } else if (v instanceof ComparableTuple) { list.addAll(Arrays.asList(((ComparableTuple) v).myValue)); } else { throw new IllegalArgumentException(); } } return new ComparableTuple(list.toArray(new Object[list.size()])); } // todo other factory methods - support only java.lang types (support for BigInteger / BigDecimal could be added on demand) public int compareTo(@NotNull ComparableTuple other) { int len1 = myValue.length; int len2 = other.myValue.length; int len = Math.min(len1, len2); for (int i = 0; i < len; i++) { int r = compareElement(myValue[i], other.myValue[i]); if (r != 0) { return r; } } return len1 == len2 ? 0 : (len1 < len2 ? -1 : 1); } private int compareElement(Object a, Object b) { if (a instanceof String) { if (b instanceof String) { return ((String)a).compareTo((String)b); } else { return 1; } } else { if (b instanceof String) { return -1; } else { return compareNumbers((Number) a, (Number) b); } } } private int compareNumbers(Number a, Number b) { // does not support BigInteger / BigDecimal // first check for integral types (long's resolution exceeds double's integral part, so we can't check just double values) long v1 = a.longValue(); long v2 = b.longValue(); if (v1 != v2) { return v1 < v2 ? -1 : 1; } // in case these are floating point numbers double d1 = a.doubleValue(); double d2 = b.doubleValue(); if (d1 != d2) { return d1 < d2 ? -1 : 1; } return 0; } public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ComparableTuple that = (ComparableTuple) o; return compareTo(that) == 0; } public int hashCode() { int r = 0; for (Object v : myValue) { if (v instanceof String) { r = r * 31 + v.hashCode(); } else { r = r * 31 + new Double(((Number)v).doubleValue()).hashCode(); } } return r; } public String toString() { StringBuilder r = new StringBuilder("("); String prefix = ""; for (Object v : myValue) { r.append(prefix); if (v instanceof String) { r.append('\'').append(v).append('\''); } else { r.append(v); } prefix = ","; } r.append(')'); return r.toString(); } }