diff --git a/README.md b/README.md
index 69304e0..8789b46 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@ Maven:
ch.ethz.globis.phtree
phtree
- 2.3.0
+ 2.4.0
```
@@ -33,12 +33,15 @@ A C++ version of the PH-Tree (with slightly different design) is available [here
# News
+### 2019-11-10
+Release 2.4.0
+- Added missing public API for filtered queries: `PhTree.query(min, max, filter)`
+
### 2019-03-19
Release 2.3.0
- Added missing compute functions for `PhTreeF`, `PhTreeSolid` and `PhTreeSolidF`
- Fixed bug in `compute()`/`computeIfPresent()` in V13
-
### 2019-03-15
Release 2.2.0
diff --git a/src/main/java/ch/ethz/globis/phtree/PhTree.java b/src/main/java/ch/ethz/globis/phtree/PhTree.java
index b1d71bd..a6f4e1c 100644
--- a/src/main/java/ch/ethz/globis/phtree/PhTree.java
+++ b/src/main/java/ch/ethz/globis/phtree/PhTree.java
@@ -113,6 +113,18 @@ public interface PhTree {
*/
PhQuery query(long[] min, long[] max);
+ /**
+ * Performs a rectangular window query. The parameters are the min and max keys which
+ * contain the minimum respectively the maximum keys in every dimension.
+ * @param min Minimum values
+ * @param max Maximum values
+ * @param filter A filter function. The iterator will only return results that match the filter.
+ * @return Result iterator.
+ */
+ default PhQuery query(long[] min, long[] max, PhFilter filter) {
+ throw new UnsupportedOperationException("This is only supported in V13, V16 and V16HD.");
+ }
+
/**
*
* @return the number of dimensions of the tree
@@ -278,8 +290,9 @@ interface PhQuery extends PhIterator {
* Reset the query with the new 'min' and 'max' boundaries.
* @param min min values
* @param max max values
+ * @return the query itself
*/
- void reset(long[] min, long[] max);
+ PhQuery reset(long[] min, long[] max);
}
/**
diff --git a/src/main/java/ch/ethz/globis/phtree/v11/PhIteratorNoGC.java b/src/main/java/ch/ethz/globis/phtree/v11/PhIteratorNoGC.java
index 628a444..2f5aad8 100644
--- a/src/main/java/ch/ethz/globis/phtree/v11/PhIteratorNoGC.java
+++ b/src/main/java/ch/ethz/globis/phtree/v11/PhIteratorNoGC.java
@@ -82,7 +82,7 @@ public PhIteratorNoGC(PhTree11 pht, PhFilter checker) {
}
@Override
- public void reset(long[] rangeMin, long[] rangeMax) {
+ public PhIteratorNoGC reset(long[] rangeMin, long[] rangeMax) {
this.rangeMin = rangeMin;
this.rangeMax = rangeMax;
this.stack.size = 0;
@@ -91,11 +91,12 @@ public void reset(long[] rangeMin, long[] rangeMax) {
if (pht.getRoot() == null) {
//empty index
isFinished = true;
- return;
+ return this;
}
stack.prepareAndPush(pht.getRoot());
findNextElement();
+ return this;
}
private void findNextElement() {
diff --git a/src/main/java/ch/ethz/globis/phtree/v13/PhIteratorNoGC.java b/src/main/java/ch/ethz/globis/phtree/v13/PhIteratorNoGC.java
index ba4e307..21258d7 100644
--- a/src/main/java/ch/ethz/globis/phtree/v13/PhIteratorNoGC.java
+++ b/src/main/java/ch/ethz/globis/phtree/v13/PhIteratorNoGC.java
@@ -84,7 +84,7 @@ public PhIteratorNoGC(PhTree13 pht, PhFilter checker) {
}
@Override
- public void reset(long[] rangeMin, long[] rangeMax) {
+ public PhIteratorNoGC reset(long[] rangeMin, long[] rangeMax) {
this.rangeMin = rangeMin;
this.rangeMax = rangeMax;
this.stack.size = 0;
@@ -93,11 +93,12 @@ public void reset(long[] rangeMin, long[] rangeMax) {
if (pht.getRoot() == null) {
//empty index
isFinished = true;
- return;
+ return this;
}
stack.prepareAndPush(pht.getRoot());
findNextElement();
+ return this;
}
private void findNextElement() {
diff --git a/src/main/java/ch/ethz/globis/phtree/v13/PhTree13.java b/src/main/java/ch/ethz/globis/phtree/v13/PhTree13.java
index a654ab7..ec9ee18 100644
--- a/src/main/java/ch/ethz/globis/phtree/v13/PhTree13.java
+++ b/src/main/java/ch/ethz/globis/phtree/v13/PhTree13.java
@@ -556,6 +556,25 @@ public PhQuery query(long[] min, long[] max) {
return q;
}
+ /**
+ * Performs a rectangular window query. The parameters are the min and max keys which
+ * contain the minimum respectively the maximum keys in every dimension.
+ * @param min Minimum values
+ * @param max Maximum values
+ * @param filter A filter function. The iterator will only return results that match the filter.
+ * @return Result iterator.
+ */
+ @Override
+ public PhQuery query(long[] min, long[] max, PhFilter filter) {
+ if (min.length != dims || max.length != dims) {
+ throw new IllegalArgumentException("Invalid number of arguments: " + min.length +
+ " / " + max.length + " DIM=" + dims);
+ }
+ PhQuery q = new PhIteratorNoGC<>(this, filter);
+ q.reset(min, max);
+ return q;
+ }
+
/**
* Performs a rectangular window query. The parameters are the min and max keys which
* contain the minimum respectively the maximum keys in every dimension.
diff --git a/src/main/java/ch/ethz/globis/phtree/v13SynchedPool/PhIteratorNoGC.java b/src/main/java/ch/ethz/globis/phtree/v13SynchedPool/PhIteratorNoGC.java
index 2adaf2b..344de1b 100644
--- a/src/main/java/ch/ethz/globis/phtree/v13SynchedPool/PhIteratorNoGC.java
+++ b/src/main/java/ch/ethz/globis/phtree/v13SynchedPool/PhIteratorNoGC.java
@@ -84,7 +84,7 @@ public PhIteratorNoGC(PhTree13SP pht, PhFilter checker) {
}
@Override
- public void reset(long[] rangeMin, long[] rangeMax) {
+ public PhIteratorNoGC reset(long[] rangeMin, long[] rangeMax) {
this.rangeMin = rangeMin;
this.rangeMax = rangeMax;
this.stack.size = 0;
@@ -93,11 +93,12 @@ public void reset(long[] rangeMin, long[] rangeMax) {
if (pht.getRoot() == null) {
//empty index
isFinished = true;
- return;
+ return this;
}
stack.prepareAndPush(pht.getRoot());
findNextElement();
+ return this;
}
private void findNextElement() {
diff --git a/src/main/java/ch/ethz/globis/phtree/v16/PhIteratorNoGC.java b/src/main/java/ch/ethz/globis/phtree/v16/PhIteratorNoGC.java
index cfe7224..2ea83ac 100644
--- a/src/main/java/ch/ethz/globis/phtree/v16/PhIteratorNoGC.java
+++ b/src/main/java/ch/ethz/globis/phtree/v16/PhIteratorNoGC.java
@@ -94,7 +94,7 @@ public PhIteratorNoGC(PhTree16 pht, PhFilter checker) {
}
@Override
- public void reset(long[] rangeMin, long[] rangeMax) {
+ public PhIteratorNoGC reset(long[] rangeMin, long[] rangeMax) {
this.rangeMin = rangeMin;
this.rangeMax = rangeMax;
this.stack.size = 0;
@@ -103,11 +103,12 @@ public void reset(long[] rangeMin, long[] rangeMax) {
if (pht.getRoot() == null) {
//empty index
isFinished = true;
- return;
+ return this;
}
stack.prepareAndPush(pht.getRoot(), null);
findNextElement();
+ return this;
}
private void findNextElement() {
diff --git a/src/main/java/ch/ethz/globis/phtree/v16/PhTree16.java b/src/main/java/ch/ethz/globis/phtree/v16/PhTree16.java
index ec52a5f..92743ac 100644
--- a/src/main/java/ch/ethz/globis/phtree/v16/PhTree16.java
+++ b/src/main/java/ch/ethz/globis/phtree/v16/PhTree16.java
@@ -607,6 +607,25 @@ public PhQuery query(long[] min, long[] max) {
return q;
}
+ /**
+ * Performs a rectangular window query. The parameters are the min and max keys which
+ * contain the minimum respectively the maximum keys in every dimension.
+ * @param min Minimum values
+ * @param max Maximum values
+ * @param filter A filter function. The iterator will only return results that match the filter.
+ * @return Result iterator.
+ */
+ @Override
+ public PhQuery query(long[] min, long[] max, PhFilter filter) {
+ if (min.length != dims || max.length != dims) {
+ throw new IllegalArgumentException("Invalid number of arguments: " + min.length +
+ " / " + max.length + " DIM=" + dims);
+ }
+ PhQuery q = new PhIteratorNoGC<>(this, filter);
+ q.reset(min, max);
+ return q;
+ }
+
/**
* Performs a rectangular window query. The parameters are the min and max keys which
* contain the minimum respectively the maximum keys in every dimension.
diff --git a/src/main/java/ch/ethz/globis/phtree/v16hd/PhIteratorNoGC.java b/src/main/java/ch/ethz/globis/phtree/v16hd/PhIteratorNoGC.java
index 7dcc26e..2039672 100644
--- a/src/main/java/ch/ethz/globis/phtree/v16hd/PhIteratorNoGC.java
+++ b/src/main/java/ch/ethz/globis/phtree/v16hd/PhIteratorNoGC.java
@@ -93,7 +93,7 @@ public PhIteratorNoGC(PhTree16HD pht, PhFilter checker) {
}
@Override
- public void reset(long[] rangeMin, long[] rangeMax) {
+ public PhIteratorNoGC reset(long[] rangeMin, long[] rangeMax) {
this.rangeMin = rangeMin;
this.rangeMax = rangeMax;
this.stack.size = 0;
@@ -102,11 +102,12 @@ public void reset(long[] rangeMin, long[] rangeMax) {
if (pht.getRoot() == null) {
//empty index
isFinished = true;
- return;
+ return this;
}
stack.prepareAndPush(pht.getRoot(), null);
findNextElement();
+ return this;
}
private void findNextElement() {
diff --git a/src/main/java/ch/ethz/globis/phtree/v16hd/PhTree16HD.java b/src/main/java/ch/ethz/globis/phtree/v16hd/PhTree16HD.java
index a6e3464..54a4a7c 100644
--- a/src/main/java/ch/ethz/globis/phtree/v16hd/PhTree16HD.java
+++ b/src/main/java/ch/ethz/globis/phtree/v16hd/PhTree16HD.java
@@ -455,6 +455,25 @@ public PhQuery query(long[] min, long[] max) {
return q;
}
+ /**
+ * Performs a rectangular window query. The parameters are the min and max keys which
+ * contain the minimum respectively the maximum keys in every dimension.
+ * @param min Minimum values
+ * @param max Maximum values
+ * @param filter A filter function. The iterator will only return results that match the filter.
+ * @return Result iterator.
+ */
+ @Override
+ public PhQuery query(long[] min, long[] max, PhFilter filter) {
+ if (min.length != dims || max.length != dims) {
+ throw new IllegalArgumentException("Invalid number of arguments: " + min.length +
+ " / " + max.length + " DIM=" + dims);
+ }
+ PhQuery q = new PhIteratorNoGC<>(this, filter);
+ q.reset(min, max);
+ return q;
+ }
+
/**
* Performs a rectangular window query. The parameters are the min and max keys which
* contain the minimum respectively the maximum keys in every dimension.
diff --git a/src/main/java/ch/ethz/globis/phtree/v8/PhIteratorNoGC.java b/src/main/java/ch/ethz/globis/phtree/v8/PhIteratorNoGC.java
index a54dce0..f1a81ca 100644
--- a/src/main/java/ch/ethz/globis/phtree/v8/PhIteratorNoGC.java
+++ b/src/main/java/ch/ethz/globis/phtree/v8/PhIteratorNoGC.java
@@ -95,7 +95,7 @@ public PhIteratorNoGC(PhTree8 pht, PhFilter checker) {
}
@Override
- public void reset(long[] rangeMin, long[] rangeMax) {
+ public PhIteratorNoGC reset(long[] rangeMin, long[] rangeMax) {
this.rangeMin = rangeMin;
this.rangeMax = rangeMax;
this.stack.size = 0;
@@ -104,7 +104,7 @@ public void reset(long[] rangeMin, long[] rangeMax) {
if (pht.getRoot() == null) {
//empty index
isFinished = true;
- return;
+ return this;
}
if (stack.prepare(pht.getRoot())) {
@@ -112,6 +112,7 @@ public void reset(long[] rangeMin, long[] rangeMax) {
} else {
isFinished = true;
}
+ return this;
}
private void findNextElement() {
diff --git a/src/test/java/ch/ethz/globis/phtree/test/TestRangeQuery.java b/src/test/java/ch/ethz/globis/phtree/test/TestRangeQuery.java
index 75bd4ba..fef5a8a 100644
--- a/src/test/java/ch/ethz/globis/phtree/test/TestRangeQuery.java
+++ b/src/test/java/ch/ethz/globis/phtree/test/TestRangeQuery.java
@@ -15,14 +15,20 @@
import java.util.Arrays;
import java.util.List;
import java.util.Random;
+import java.util.function.IntFunction;
import org.junit.Test;
+import ch.ethz.globis.phtree.PhDistanceL;
+import ch.ethz.globis.phtree.PhFilter;
import ch.ethz.globis.phtree.PhRangeQuery;
import ch.ethz.globis.phtree.PhTree;
import ch.ethz.globis.phtree.PhTree.PhIterator;
import ch.ethz.globis.phtree.test.util.TestUtil;
import ch.ethz.globis.phtree.util.Bits;
+import ch.ethz.globis.phtree.v13.PhTree13;
+import ch.ethz.globis.phtree.v16.PhTree16;
+import ch.ethz.globis.phtree.v16hd.PhTree16HD;
public class TestRangeQuery {
@@ -112,7 +118,7 @@ public void testQueryND64Random1() {
final int range = MAXV/2;
final Random R = new Random(0);
for (int d = 0; d < LOOP; d++) {
- PhTree