LUCENE-7234: Add InetAddressPoint.nextUp/nextDown

This commit is contained in:
Adrien Grand 2016-04-20 15:45:38 +02:00
parent 2724b99b5c
commit 91fd163112
3 changed files with 99 additions and 0 deletions

View File

@ -19,6 +19,9 @@ New Features
* LUCENE-7069: Add LatLonPoint.nearest, to find nearest N points to a
provided query point (Mike McCandless)
* LUCENE-7234: Added InetAddressPoint.nextDown/nextUp to easily generate range
queries with excluded bounds. (Adrien Grand)
API Changes
* LUCENE-7184: Refactor LatLonPoint encoding methods to new GeoEncodingUtils

View File

@ -26,6 +26,7 @@ import org.apache.lucene.search.PointInSetQuery;
import org.apache.lucene.search.PointRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.NumericUtils;
import org.apache.lucene.util.StringHelper;
/**
@ -65,6 +66,53 @@ public class InetAddressPoint extends Field {
TYPE.freeze();
}
/** The minimum value that an ip address can hold. */
public static final InetAddress MIN_VALUE;
/** The maximum value that an ip address can hold. */
public static final InetAddress MAX_VALUE;
static {
MIN_VALUE = decode(new byte[BYTES]);
byte[] maxValueBytes = new byte[BYTES];
Arrays.fill(maxValueBytes, (byte) 0xFF);
MAX_VALUE = decode(maxValueBytes);
}
/**
* Return the {@link InetAddress} that compares immediately greater than
* {@code address}.
* @throws ArithmeticException if the provided address is the
* {@link #MAX_VALUE maximum ip address}
*/
public static InetAddress nextUp(InetAddress address) {
if (address.equals(MAX_VALUE)) {
throw new ArithmeticException("Overflow: there is no greater InetAddress than "
+ address.getHostAddress());
}
byte[] delta = new byte[BYTES];
delta[BYTES-1] = 1;
byte[] nextUpBytes = new byte[InetAddressPoint.BYTES];
NumericUtils.add(InetAddressPoint.BYTES, 0, encode(address), delta, nextUpBytes);
return decode(nextUpBytes);
}
/**
* Return the {@link InetAddress} that compares immediately less than
* {@code address}.
* @throws ArithmeticException if the provided address is the
* {@link #MIN_VALUE minimum ip address}
*/
public static InetAddress nextDown(InetAddress address) {
if (address.equals(MIN_VALUE)) {
throw new ArithmeticException("Underflow: there is no smaller InetAddress than "
+ address.getHostAddress());
}
byte[] delta = new byte[BYTES];
delta[BYTES-1] = 1;
byte[] nextDownBytes = new byte[InetAddressPoint.BYTES];
NumericUtils.subtract(InetAddressPoint.BYTES, 0, encode(address), delta, nextDownBytes);
return decode(nextDownBytes);
}
/** Change the values of this field */
public void setInetAddressValue(InetAddress value) {
if (value == null) {
@ -187,6 +235,12 @@ public class InetAddressPoint extends Field {
/**
* Create a range query for network addresses.
* <p>
* You can have half-open ranges (which are in fact &lt;/&le; or &gt;/&ge; queries)
* by setting {@code lowerValue = InetAddressPoint.MIN_VALUE} or
* {@code upperValue = InetAddressPoint.MAX_VALUE}.
* <p> Ranges are inclusive. For exclusive ranges, pass {@code InetAddressPoint#nextUp(lowerValue)}
* or {@code InetAddressPoint#nexDown(upperValue)}.
*
* @param field field name. must not be {@code null}.
* @param lowerValue lower portion of the range (inclusive). must not be null.

View File

@ -131,4 +131,46 @@ public class TestInetAddressPoint extends LuceneTestCase {
InetAddressPoint.newRangeQuery("a", InetAddress.getByName("2001::a000:0"), InetAddress.getByName("2001::afff:ffff")),
InetAddressPoint.newPrefixQuery("a", InetAddress.getByName("2001::a6bd:fc80"), 100));
}
public void testNextUp() throws Exception {
assertEquals(InetAddress.getByName("::1"),
InetAddressPoint.nextUp(InetAddress.getByName("::")));
assertEquals(InetAddress.getByName("::1:0"),
InetAddressPoint.nextUp(InetAddress.getByName("::ffff")));
assertEquals(InetAddress.getByName("1.2.4.0"),
InetAddressPoint.nextUp(InetAddress.getByName("1.2.3.255")));
assertEquals(InetAddress.getByName("0.0.0.0"),
InetAddressPoint.nextUp(InetAddress.getByName("::fffe:ffff:ffff")));
assertEquals(InetAddress.getByName("::1:0:0:0"),
InetAddressPoint.nextUp(InetAddress.getByName("255.255.255.255")));
ArithmeticException e = expectThrows(ArithmeticException.class,
() -> InetAddressPoint.nextUp(InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")));
assertEquals("Overflow: there is no greater InetAddress than ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", e.getMessage());
}
public void testNextDown() throws Exception {
assertEquals(InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe"),
InetAddressPoint.nextDown(InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")));
assertEquals(InetAddress.getByName("::ffff"),
InetAddressPoint.nextDown(InetAddress.getByName("::1:0")));
assertEquals(InetAddress.getByName("1.2.3.255"),
InetAddressPoint.nextDown(InetAddress.getByName("1.2.4.0")));
assertEquals(InetAddress.getByName("::fffe:ffff:ffff"),
InetAddressPoint.nextDown(InetAddress.getByName("0.0.0.0")));
assertEquals(InetAddress.getByName("255.255.255.255"),
InetAddressPoint.nextDown(InetAddress.getByName("::1:0:0:0")));
ArithmeticException e = expectThrows(ArithmeticException.class,
() -> InetAddressPoint.nextDown(InetAddress.getByName("::")));
assertEquals("Underflow: there is no smaller InetAddress than 0:0:0:0:0:0:0:0", e.getMessage());
}
}