/**************************************************************************** * Sangria * * Copyright (C) 2014 Tavian Barnes * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * ****************************************************************************/ package com.tavianator.sangria.core; import java.util.*; import com.google.common.collect.ComparisonChain; import com.google.common.primitives.Ints; /** * A loosely-coupled, infinitely divisible priority/weight system. * *

* This class implements an extensible priority system based on lexicographical ordering. In its simplest use, {@code * Priority.create(0)} is ordered before {@code Priority.create(1)}, then {@code Priority.create(2)}, etc. *

* *

* To create a priority that is ordered between two existing ones, simply add another parameter: {@code * Priority.create(1, 1)} comes after {@code Priority.create(1)}, but before {@code Priority.create(2)}. In this way, * priorities can always be inserted anywhere in a sequence. *

* *

* The {@link #next()} method creates a priority that is ordered immediately following the current one, and is distinct * from all priorities obtained by any other means. This provides a convenient way to order entire segments of lists. *

* *

* A special priority, obtained by {@code Priority.getDefault()}, sorts before all other priorities. *

* * @author Tavian Barnes (tavianator@tavianator.com) * @version 1.1 * @since 1.1 */ public class Priority implements Comparable { private static final Priority DEFAULT = new Priority(new int[0], 0); private static final Comparator COMPARATOR = Ints.lexicographicalComparator(); private final int[] weights; private final int seq; /** * @return The default priority, which comes before all other priorities. */ public static Priority getDefault() { return DEFAULT; } /** * Create a {@link Priority} with the given sequence. * * @param weight The first value of the weight sequence. * @param weights An integer sequence. These sequences are sorted lexicographically, so {@code Priority.create(1)} * sorts before {@code Priority.create(1, 1)}, which sorts before {@code Priority.create(2)}. * @return A new {@link Priority}. */ public static Priority create(int weight, int... weights) { int[] newWeights = new int[weights.length + 1]; newWeights[0] = weight; System.arraycopy(weights, 0, newWeights, 1, weights.length); return new Priority(newWeights, 0); } private Priority(int[] weights, int seq) { this.weights = weights; this.seq = seq; } /** * @return Whether this priority originated in a call to {@link #getDefault()}. */ public boolean isDefault() { return weights.length == 0; } /** * @return A new {@link Priority} which immediately follows this one, and which is distinct from all other * priorities obtained by {@link #create(int, int...)}. */ public Priority next() { return new Priority(weights, seq + 1); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } else if (!(obj instanceof Priority)) { return false; } Priority other = (Priority)obj; return Arrays.equals(weights, other.weights) && seq == other.seq; } @Override public int hashCode() { return Arrays.hashCode(weights) + seq; } @Override public int compareTo(Priority o) { return ComparisonChain.start() .compare(weights, o.weights, COMPARATOR) .compare(seq, o.seq) .result(); } @Override public String toString() { StringBuilder builder = new StringBuilder(); if (weights.length == 0) { builder.append("default priority"); } else { builder.append("priority ["); for (int i = 0; i < weights.length; ++i) { if (i != 0) { builder.append(", "); } builder.append(weights[i]); } builder.append("]"); } if (seq != 0) { builder.append(" + ") .append(seq); } return builder.toString(); } }