mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
460 lines
11 KiB
Java
460 lines
11 KiB
Java
/* ###
|
|
* IP: GHIDRA
|
|
*
|
|
* 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 generic;
|
|
|
|
import java.util.Comparator;
|
|
import java.util.function.Function;
|
|
|
|
import generic.Span.Domain;
|
|
|
|
/**
|
|
* An endpoint for spans for specifying open endpoints
|
|
*
|
|
* <p>
|
|
* This is achieved by considering a value +/- an optional epsilon, where epsilon is "the smallest
|
|
* non-zero value". Closed endpoints do not have an epsilon. Open endpoint have an epsilon added or
|
|
* subtracted, depending on whether it is a lower or upper endpoint, respectively. For example, the
|
|
* interval (2, +inf) has the lower endpoint {@code 2 + epsilon} so that 2 is excluded, but any
|
|
* number greater than 2 is included. There are some wrinkles, since the domain for values
|
|
* necessitating open intervals is no longer discreet, but we can abuse {@link #dec()} and
|
|
* {@link #inc()} to compute endpoints of connected intervals. We cannot allow negative epsilon to
|
|
* be used on lower bounds and vice versa, though. This is a natural restriction, because such
|
|
* intervals wouldn't make sense, but it also overcomes the situation where {@link #dec()} or
|
|
* {@link #inc()} would need to change the value. Instead, they need only adjust the use of epsilon.
|
|
*
|
|
* @param <T> the type of values
|
|
*/
|
|
public interface End<T> {
|
|
/**
|
|
* Get the endpoint representing no lower bound
|
|
*
|
|
* <p>
|
|
* This always returns the same instance of negative infinity. Clients can rely on identity when
|
|
* checking for equality.
|
|
*
|
|
* @param <T> the type of values
|
|
* @return negative "infinity"
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
static <T> End<T> negativeInfinity() {
|
|
return (End<T>) Unbound.NEG_INF;
|
|
}
|
|
|
|
/**
|
|
* Get the endpoint representing no upper bound
|
|
*
|
|
* <p>
|
|
* This always returns the same instance of positive infinity. Clients can rely on identity when
|
|
* checking for equality.
|
|
*
|
|
* @param <T> the type of values
|
|
* @return positive "infinity"
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
static <T> End<T> positiveInfinity() {
|
|
return (End<T>) Unbound.POS_INF;
|
|
}
|
|
|
|
/**
|
|
* Construct a lower endpoint
|
|
*
|
|
* @param <T> the type of value
|
|
* @param value the value
|
|
* @param inclusive whether the endpoint includes the given value
|
|
* @return the endpoint
|
|
*/
|
|
static <T> End<T> lower(T value, boolean inclusive) {
|
|
return new Point<>(value, inclusive ? Epsilon.ZERO : Epsilon.POSITIVE);
|
|
}
|
|
|
|
/**
|
|
* Construct an upper endpoint
|
|
*
|
|
* @param <T> the type of value
|
|
* @param value the value
|
|
* @param inclusive whether the endpoint includes the given value
|
|
* @return the endpoint
|
|
*/
|
|
static <T> End<T> upper(T value, boolean inclusive) {
|
|
return new Point<>(value, inclusive ? Epsilon.ZERO : Epsilon.NEGATIVE);
|
|
}
|
|
|
|
/**
|
|
* An enum for the two values of infinity
|
|
*/
|
|
enum Unbound implements End<Void> {
|
|
NEG_INF {
|
|
@Override
|
|
public int compareTo(End<Void> that, Comparator<Void> comparator) {
|
|
return that == NEG_INF ? 0 : -1;
|
|
}
|
|
|
|
@Override
|
|
public End<Void> dec() {
|
|
return NEG_INF;
|
|
}
|
|
|
|
@Override
|
|
public String toMinString(Function<? super End<Void>, String> nToString) {
|
|
return "(-inf";
|
|
}
|
|
|
|
@Override
|
|
public String toMaxString(Function<? super End<Void>, String> nToString) {
|
|
return "#ERROR-inf)";
|
|
}
|
|
|
|
@Override
|
|
public boolean isValidMin() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean isValidMax() {
|
|
return false;
|
|
}
|
|
},
|
|
POS_INF {
|
|
@Override
|
|
public int compareTo(End<Void> that, Comparator<Void> comparator) {
|
|
return that == POS_INF ? 0 : 1;
|
|
}
|
|
|
|
@Override
|
|
public End<Void> inc() {
|
|
return POS_INF;
|
|
}
|
|
|
|
@Override
|
|
public String toMinString(Function<? super End<Void>, String> nToString) {
|
|
return "(#ERROR+inf";
|
|
}
|
|
|
|
@Override
|
|
public String toMaxString(Function<? super End<Void>, String> nToString) {
|
|
return "+inf)";
|
|
}
|
|
|
|
@Override
|
|
public boolean isValidMin() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean isValidMax() {
|
|
return true;
|
|
}
|
|
};
|
|
|
|
@Override
|
|
public End<Void> inc() {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
@Override
|
|
public End<Void> dec() {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
@Override
|
|
public boolean isInclusive() {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An enum for the three allowed coefficients of epsilon
|
|
*/
|
|
enum Epsilon {
|
|
/** {@code value - 1*epsilon}, -1 for open upper endpoints */
|
|
NEGATIVE {
|
|
@Override
|
|
Epsilon inc() {
|
|
return ZERO;
|
|
}
|
|
|
|
@Override
|
|
Epsilon dec() {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
},
|
|
/** {@code value + 0*epsilon}, 0 for closed enpoints */
|
|
ZERO {
|
|
@Override
|
|
Epsilon inc() {
|
|
return POSITIVE;
|
|
}
|
|
|
|
@Override
|
|
Epsilon dec() {
|
|
return NEGATIVE;
|
|
}
|
|
},
|
|
/** {@code value + epsilon}, 1 for open lower endpoints */
|
|
POSITIVE {
|
|
@Override
|
|
Epsilon inc() {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
@Override
|
|
Epsilon dec() {
|
|
return ZERO;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Compute the epsilon for an incremented endpoint
|
|
*
|
|
* @return the new "incremented" epsilon
|
|
* @throws UnsupportedOperationException if this is already {@link #POSITIVE}
|
|
*/
|
|
abstract Epsilon inc();
|
|
|
|
/**
|
|
* Compute the epsilon for a decremented endpoint
|
|
*
|
|
* @return the new "decremented" epsilon
|
|
* @throws UnsupportedOperationException if this is already {@link #NEGATIVE}
|
|
*/
|
|
abstract Epsilon dec();
|
|
}
|
|
|
|
/**
|
|
* An endpoint representing a bound
|
|
*
|
|
* @param val the value of the endpoint
|
|
* @param epsilon determines whether the endpoint is included
|
|
* @param <T> the type of values
|
|
*/
|
|
record Point<T>(T val, Epsilon epsilon) implements End<T> {
|
|
@Override
|
|
public String toMinString(Function<? super End<T>, String> nToString) {
|
|
switch (epsilon) {
|
|
case NEGATIVE:
|
|
return "(#ERROR" + nToString.apply(this);
|
|
case ZERO:
|
|
return "[" + nToString.apply(this);
|
|
case POSITIVE:
|
|
return "(" + nToString.apply(this);
|
|
}
|
|
throw new AssertionError();
|
|
}
|
|
|
|
@Override
|
|
public String toMaxString(Function<? super End<T>, String> nToString) {
|
|
switch (epsilon) {
|
|
case NEGATIVE:
|
|
return nToString.apply(this) + ")";
|
|
case ZERO:
|
|
return nToString.apply(this) + "]";
|
|
case POSITIVE:
|
|
return "#ERROR" + nToString.apply(this) + ")";
|
|
}
|
|
throw new AssertionError();
|
|
}
|
|
|
|
@Override
|
|
public End<T> inc() {
|
|
return new Point<>(val, epsilon.inc());
|
|
}
|
|
|
|
@Override
|
|
public End<T> dec() {
|
|
return new Point<>(val, epsilon.dec());
|
|
}
|
|
|
|
@Override
|
|
public boolean isValidMin() {
|
|
return epsilon != Epsilon.NEGATIVE;
|
|
}
|
|
|
|
@Override
|
|
public boolean isValidMax() {
|
|
return epsilon != Epsilon.POSITIVE;
|
|
}
|
|
|
|
@Override
|
|
public boolean isInclusive() {
|
|
return epsilon == Epsilon.ZERO;
|
|
}
|
|
|
|
@Override
|
|
public int compareTo(End<T> that, Comparator<T> comparator) {
|
|
if (that == Unbound.NEG_INF) {
|
|
return 1;
|
|
}
|
|
if (that == Unbound.POS_INF) {
|
|
return -1;
|
|
}
|
|
if (that instanceof Point<T> point) {
|
|
int result = comparator.compare(this.val, point.val);
|
|
if (result != 0) {
|
|
return result;
|
|
}
|
|
result = this.epsilon.compareTo(point.epsilon);
|
|
if (result != 0) {
|
|
return result;
|
|
}
|
|
return 0;
|
|
}
|
|
throw new AssertionError();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An interface of intervals with open, closed, or unbounded endpoints
|
|
*
|
|
* @param <N> the type of values
|
|
* @param <S> the type of spans
|
|
*/
|
|
public interface EndSpan<N, S extends EndSpan<N, S>> extends Span<End<N>, S> {
|
|
/**
|
|
* Check if this interval contains the given value
|
|
*
|
|
* <p>
|
|
* This is equivalent to, and a shortcut for, {@link #contains(Object)}, passing
|
|
* {@code value + 0*epsilon}.
|
|
*
|
|
* @param n the value
|
|
* @return true if contained
|
|
*/
|
|
default boolean containsPoint(N n) {
|
|
return contains(new Point<>(n, Epsilon.ZERO));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The domain for spans of {@link End}
|
|
*
|
|
* <p>
|
|
* Because the domain is no longer necessarily discreet, only comparison is necessary to
|
|
* implement it. {@link #dec(End)} and {@link #inc(End)} are instead applied to the coefficient
|
|
* on epsilon to find connected intervals.
|
|
*
|
|
* @param <N> the type of values
|
|
* @param <S> the type of spans
|
|
*/
|
|
public abstract class EndDomain<N, S extends EndSpan<N, S>> implements Span.Domain<End<N>, S> {
|
|
private final Comparator<N> comparator;
|
|
|
|
/**
|
|
* Construct a domain using the given comparator
|
|
*
|
|
* @param comparator the comparator for values
|
|
*/
|
|
public EndDomain(Comparator<N> comparator) {
|
|
this.comparator = comparator;
|
|
}
|
|
|
|
@Override
|
|
public String toMinString(End<N> min, Function<? super End<N>, String> nToString) {
|
|
return min.toMinString(nToString);
|
|
}
|
|
|
|
@Override
|
|
public String toMaxString(End<N> max, Function<? super End<N>, String> nToString) {
|
|
return max.toMaxString(nToString);
|
|
}
|
|
|
|
@Override
|
|
public int compare(End<N> n1, End<N> n2) {
|
|
return n1.compareTo(n2, comparator);
|
|
}
|
|
|
|
@Override
|
|
public End<N> min() {
|
|
return negativeInfinity();
|
|
}
|
|
|
|
@Override
|
|
public End<N> max() {
|
|
return positiveInfinity();
|
|
}
|
|
|
|
@Override
|
|
public End<N> inc(End<N> n) {
|
|
return n.inc();
|
|
}
|
|
|
|
@Override
|
|
public End<N> dec(End<N> n) {
|
|
return n.dec();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @see Domain#toMinString(Object, Function)
|
|
* @param nToString the endpoint-to-string function
|
|
* @return the string
|
|
*/
|
|
String toMinString(Function<? super End<T>, String> nToString);
|
|
|
|
/**
|
|
* @see Domain#toMaxString(Object, Function)
|
|
* @param nToString the endpoint-to-string function
|
|
* @return the string
|
|
*/
|
|
String toMaxString(Function<? super End<T>, String> nToString);
|
|
|
|
/**
|
|
* Increment this endpoint, only by changing the coefficient of epsilon
|
|
*
|
|
* @return the resulting endpoint
|
|
*/
|
|
End<T> inc();
|
|
|
|
/**
|
|
* Decrement this endpoint, only by changing the coefficient of epsilon
|
|
*
|
|
* @return the resulting endpoint
|
|
*/
|
|
End<T> dec();
|
|
|
|
/**
|
|
* Compare two endpoints
|
|
*
|
|
* <p>
|
|
* First, the values of infinity are considered. Then, the values of the endpoints are
|
|
* considered. Finally, the coefficients of epsilon are considered.
|
|
*
|
|
* @param that the other endpoint
|
|
* @param comparator the value comparator
|
|
* @return the result as in {@link Comparator#compare(Object, Object)}
|
|
*/
|
|
int compareTo(End<T> that, Comparator<T> comparator);
|
|
|
|
/**
|
|
* Check if this endpoint is allowed as a lower endpoint
|
|
*
|
|
* @return true if allowed
|
|
*/
|
|
boolean isValidMin();
|
|
|
|
/**
|
|
* Check if this endpoint is allowed as an upper endpoint
|
|
*
|
|
* @return true if allowed
|
|
*/
|
|
boolean isValidMax();
|
|
|
|
/**
|
|
* Check if this endpoint includes its value
|
|
*
|
|
* @return true if included
|
|
*/
|
|
boolean isInclusive();
|
|
}
|