package com.github.xbn.number; import java.util.Objects; import com.github.xbn.keyed.Named; import com.github.xbn.lang.Null; import com.github.xbn.text.CrashIfString; import com.github.xbn.lang.CrashIfObject; /** * <p>Minimum or maximum extreme of a range.</p> **/ public abstract class NumberBound<N extends Number> implements Named { private final N num; private final boolean isInclusive; private final String name; /** * @deprecated Use <code><!-- Generic parameters fail in at-links: --><a href="#NumberBound(N, com.github.xbn.number.Inclusive, java.lang.String)">NumberBound</a>(N,i,s)</code> * @since 0.1.5 */ public NumberBound(N num, boolean is_inclusive, String name) { this(num, Inclusive.getForBoolean(is_inclusive), name); } /** * <p>Create a new {@code NumberBound}.</p> * @param num May not be <code>null</code>. Get with {@link #get() get}{@code ()}. * @param incl May not be <code>null</code>. Get with {@link #isInclusive() isInclusive}{@code ()}. * @param name Descriptive name. Get with {@link #getName() getName}{@code ()}. * @since 0.1.5 */ public NumberBound(N num, Inclusive incl, String name) { Objects.requireNonNull(num, "num"); this.num = num; isInclusive = incl.isYes(); CrashIfString.empty(Null.OK, name, "name", null); this.name = name; } /** * <p>Create a new {@code NumberBound} as a duplicate of another.</p> * * <p>This<ol> * <li>YYY</li> * </ol></p> * @param to_copy May not be {@code null}. */ public NumberBound(NumberBound<N> to_copy) { try { num = to_copy.get(); } catch(RuntimeException rx) { throw CrashIfObject.nullOrReturnCause(to_copy, "to_copy", null, rx); } isInclusive = to_copy.isInclusive(); name = to_copy.getName(); } /** * The descriptive name of this bound. * @return A name suitable for diagnostics. * @see <code><!-- Generic parameters fail in at-links: --><a href="#NumberBound(N, com.github.xbn.number.Inclusive, java.lang.String)">NumberBound</a>(N,i,s)</code> */ public String getName() { return name; } /** * <p>Get the bound number.</p> * @see <code><!-- Generic parameters fail in at-links: --><a href="#NumberBound(N, com.github.xbn.number.Inclusive, java.lang.String)">NumberBound</a>(N,i,s)</code> * @see #getGivenIncl(com.github.xbn.number.BoundSide) */ public final N get() { return num; } /** * Get the absolute bound-value, given its inclusivity. * @param min_orMax May not be <code>null</code>. * @return Integer example: If {@linkplain #isInclusive() inclusive}is <ul> * <li>{@code true}: {@link #get() get}{@code ()}</li> * <li>{@code false}: If <code>min_orMax.{@link BoundSide#isMin() isMin}()</code> is <ul> * <li>{@code true}: {@code (get() + 1)}</li> * <li>{@code false}: {@code (get() - 1)}</li> * </ul></li> * </ul> * @see #get() */ public abstract N getGivenIncl(BoundSide min_orMax); /** * Compare the <i>inclusive</i> bound-value against a number. * @param min_orMax May not be <code>null</code>. * @param num May not be <code>null</code>. * @return Integer example: * <br/>     <code>{@link #getGivenIncl(BoundSide) getGivenIncl}(min_orMax).intValue() - num.intValue();</code> * @exception NullPointerException If {@code num} is {@code null}. */ public abstract N getInclComparedTo(BoundSide min_orMax, N num); /** * <p>Is this bound considered inclusive?.</p> * @return <ul> * <li>{@code true} This bound is inclusive (meaning--if a minimum--a number must be greater-than-or-equal-to it).</li> * <li>{@code false}: Exclusive (a number must be greater than it).</li> * </ul> * @see <code><!-- Generic parameters fail in at-links: --><a href="#NumberBound(N, com.github.xbn.number.Inclusive, java.lang.String)">NumberBound</a>(N,i,s)</code> */ public final boolean isInclusive() { return isInclusive; } public String toString() { return ((getName() == null) ? "" : getName() + "=") + get() + " (" + (isInclusive() ? "in" : "ex") + "clusive)"; } /** * @param to_compareTo May not be {@code null}. */ @Override public boolean equals(Object to_compareTo) { //Check for object equality first, since it's faster than instanceof. if(this == to_compareTo) { return true; } if(!(to_compareTo instanceof NumberBound)) { //to_compareTo is either null or not an NumberBound. //java.lang.Object.object(o): "For any non-null reference value x, //x.equals(null) should return false." return false; } //Safe to cast @SuppressWarnings("unchecked") NumberBound<N> o = (NumberBound<N>)to_compareTo; //Finish with field-by-field comparison. return areFieldsEqual(o); } /** * <p>Are all relevant fields equal?.</p> * @param to_compareTo May not be {@code null}. */ public boolean areFieldsEqual(NumberBound<?> to_compareTo) { return (get().equals(to_compareTo.get()) && isInclusive() == to_compareTo.isInclusive()); } @Override public int hashCode() { return 27 * get().hashCode() + (isInclusive() ? 1 : 0); } public static final <N extends Number> StringBuilder appendExclusiveOrES(StringBuilder sd_toAppendTo, String prefixfixForEx, NumberBound<N> bound, String postfixfixForEx) { try { if(bound.isInclusive()) { //Nothing to append return sd_toAppendTo; } } catch(RuntimeException rx) { throw CrashIfObject.nullOrReturnCause(bound, "bound", null, rx); } return sd_toAppendTo.append(prefixfixForEx).append("exclusive").append(postfixfixForEx); } public String getKey() { return getName(); } }