public void expand(String key, long value, RangeHandler rangeHandler, EdgeHandler edgeHandler) {
        if (value < lowerBound || value > upperBound) {
            // Value outside bounds -> expand to nothing.
            return;
        }
        int maxLevels = value > 0 ? maxPositiveLevels : maxNegativeLevels;
        int sign = value > 0 ? 1 : -1;
        // Append key to feature string builder
        StringBuilder builder = new StringBuilder(128);
        builder.append(key).append('=');

        long levelSize = arity;
        long edgeInterval = (value / arity) * arity;
        edgeHandler.handleEdge(createEdgeFeatureHash(builder, edgeInterval), (int) Math.abs(value - edgeInterval));
        for (int i = 0; i < maxLevels; ++i) {
            long start = (value / levelSize) * levelSize;
            if (Math.abs(start) + levelSize - 1 < 0) {  // overflow
                break;
            }
            rangeHandler.handleRange(createRangeFeatureHash(builder, start, start + sign * (levelSize - 1)));
            levelSize *= arity;
            if (levelSize <= 0 && levelSize != Long.MIN_VALUE) {  //overflow
                break;
            }
        }
    }
@Test
    void requireThatMaxRangeIsExpanded() {
        PredicateRangeTermExpander expander = new PredicateRangeTermExpander(10);
        expander.expand("key", 9223372036854775807L, range -> fail(),
                (edge, value) -> {
                    assertEquals(PredicateHash.hash64("key=9223372036854775800"), edge);
                    assertEquals(7, value);
                });
    }