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 requireThatSmallRangeIsExpandedInArity2() {
        PredicateRangeTermExpander expander = new PredicateRangeTermExpander(2);
        Iterator<String> expectedLabels = List.of(
                "key=42-43",
                "key=40-43",
                "key=40-47",
                "key=32-47",
                "key=32-63",
                "key=0-63",
                "key=0-127",
                "key=0-255",
                "key=0-511",
                "key=0-1023",
                "key=0-2047",
                "key=0-4095",
                "key=0-8191",
                "key=0-16383",
                "key=0-32767",
                "key=0-65535",
                "key=0-131071",
                "key=0-262143",
                "key=0-524287",
                "key=0-1048575",
                "key=0-2097151",
                "key=0-4194303",
                "key=0-8388607",
                "key=0-16777215",
                "key=0-33554431",
                "key=0-67108863",
                "key=0-134217727",
                "key=0-268435455",
                "key=0-536870911",
                "key=0-1073741823",
                "key=0-2147483647",
                "key=0-4294967295",
                "key=0-8589934591",
                "key=0-17179869183",
                "key=0-34359738367",
                "key=0-68719476735",
                "key=0-137438953471",
                "key=0-274877906943",
                "key=0-549755813887",
                "key=0-1099511627775",
                "key=0-2199023255551",
                "key=0-4398046511103",
                "key=0-8796093022207",
                "key=0-17592186044415",
                "key=0-35184372088831",
                "key=0-70368744177663",
                "key=0-140737488355327",
                "key=0-281474976710655",
                "key=0-562949953421311",
                "key=0-1125899906842623",
                "key=0-2251799813685247",
                "key=0-4503599627370495",
                "key=0-9007199254740991",
                "key=0-18014398509481983",
                "key=0-36028797018963967",
                "key=0-72057594037927935",
                "key=0-144115188075855871",
                "key=0-288230376151711743",
                "key=0-576460752303423487",
                "key=0-1152921504606846975",
                "key=0-2305843009213693951",
                "key=0-4611686018427387903",
                "key=0-9223372036854775807").iterator();
        expander.expand("key", 42, range -> assertEquals(PredicateHash.hash64(expectedLabels.next()), range),
                (edge, value) -> {
                    assertEquals(PredicateHash.hash64("key=42"), edge);
                    assertEquals(0, value);
                });
        assertFalse(expectedLabels.hasNext());
    }