/** * Copyright 2014 National University of Ireland, Galway. * * This file is part of the SIREn project. Project and contact information: * * https://github.com/rdelbru/SIREn * * 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 org.sindice.siren.util; import org.apache.lucene.util.IntsRef; /** * Reusable methods to manage and compare node paths. */ public class NodeUtils { /** * Compares the first node with the second node for order. * Returns a negative integer, zero, or a positive integer if the first node * is less than, equal to, or greater than the second node. */ public static final int compare(final IntsRef n1, final IntsRef n2) { return compare(n1.ints, n1.offset, n1.length, n2.ints, n2.offset, n2.length); } private static final int compare(final int[] n1, final int n1Offset, final int n1Len, final int[] n2, final int n2Offset, final int n2Len) { final int n1Limit = n1Len + n1Offset; final int n2Limit = n2Len + n2Offset; for (int i = n1Offset, j = n2Offset; i < n1Limit && j < n2Limit; i++, j++) { if (n1[i] != n2[j]) { return n1[i] - n2[j]; } } // exception, if node path is equal, check node path length return n1Len - n2Len; } /** * Compares the first node with the second node for order. * Returns: * <ul> * <li> a negative integer if the first node is a predecessor of the second * node, * <li> zero if the first node is an ancestor of the second node, * <li> a positive integer if the first node is equal to or greater than the * second node. * </ul> */ public static final int compareAncestor(final IntsRef n1, final IntsRef n2) { return compareAncestor(n1.ints, n1.length, n2.ints, n2.length); } public static final int compareAncestor(final int[] n1, final int n1Len, final int[] n2, final int n2Len) { for (int i = 0; i < n1Len && i < n2Len; i++) { if (n1[i] != n2[i]) { return n1[i] - n2[i]; } } // exception, if node path is equal, check node path length return n1Len < n2Len ? 0 : 1; } /** * Increase the size of the array and copy the content of the original array * into the new one. */ public static final int[] growAndCopy(final int[] array, final int minSize) { assert minSize >= 0: "size must be positive (got " + minSize + "): likely integer overflow?"; if (array.length < minSize) { final int[] newArray = new int[minSize]; System.arraycopy(array, 0, newArray, 0, array.length); return newArray; } else { return array; } } /** * Check if a node path is satisfying the interval constraints. * <p> * The <code>level</code> parameter allows to force the node to be on a * certain level. * <p> * The <code>levelIndex</code> array contains the level associated with * the interval constraints in <code>constraints</code>. * <p> * Example: <br> * Given the lower bound constraint [1], upper bound constraint [10] at * level 1, then the node paths [1,4], [5,10,9] or [10,5] satisfy * the constraints. However, the node path [0,3] or [11,0,9] does not satisfy * the constraints. */ public static final boolean isConstraintSatisfied(final IntsRef node, final int level, final int[] levelIndex, final int[][] constraints) { // check if node satisfies level if (node.length != level) { return false; } final int offset = node.offset; final int[] ints = node.ints; int[] constraint; int value; for (int i = 0; i < levelIndex.length; i++) { // check if node value at given level satisfies the interval constraint constraint = constraints[i]; value = ints[offset + levelIndex[i] - 1]; if (value < constraint[0] || value > constraint[1]) { return false; } } return true; } /** * Check if a node path is satisfying the interval constraints. * <p> * The <code>levelIndex</code> array contains the level associated with * the interval constraints in <code>constraints</code>. * <p> * Example: <br> * Given the lower bound constraint [1], upper bound constraint [10] at * level 1, then the node paths [1,4], [5,10,9] or [10,5] satisfy * the constraints. However, the node path [0,3] or [11,0,9] does not satisfy * the constraints. */ public static final boolean isConstraintSatisfied(final IntsRef node, final int level, final int[] constraint) { // check if node satisfies level if (level != -1 && node.length != level) { return false; } // retrieve last value of the node path final int value = node.ints[node.offset + node.length - 1]; if (value < constraint[0] || value > constraint[1]) { return false; } return true; } /** * Check if a node path is satisfying the level constraint. * <p> * The <code>level</code> parameter allows to force the node to be on a * certain level. * <br> * Given that the root of the tree (level 0) is the document id, the node * level constraint ranges from 1 to <code>Integer.MAX_VALUE</code>. A node * level constraint of 0 will always return false. * <br> * The sentinel value to ignore the node level constraint is -1. * <p> * Example: <br> * Given the level constraint 2, the node paths [0,1], [3,10] or [2,5] satisfy * the constraints. However, the node path [2,3,4] does not satisfy the * constraints. */ public static final boolean isConstraintSatisfied(final IntsRef node, final int level) { if (level != -1 && node.length != level) { return false; } return true; } }