@Nonnull
    public static List<IndexIterationPointer> normalizePointers(@Nonnull List<IndexIterationPointer> result, boolean descending) {
        if (result.size() <= 1) {
            // single pointer, nothing to do
            return result;
        }

        // without the same ordering of pointers order of results would be unspecified
        assert result.stream().allMatch(r -> r.isDescending() == descending)
                : "All iteration pointers must have the same direction";

        // order of ranges is critical for preserving ordering of the results
        Collections.sort(result, descending ? POINTER_COMPARATOR_REVERSED : POINTER_COMPARATOR);

        // loop until we processed the last remaining pair
        //
        // do the normalization in place without extra shifts in the array
        // we write normalized pointers from the beginning
        int writeIdx = 0;
        IndexIterationPointer currentMerged = result.get(0);
        for (int nextPointerIdx = 1; nextPointerIdx < result.size(); nextPointerIdx++) {
            // compare current pointer with next one and merge if they overlap
            // otherwise go to next pointer
            // pointers might be ordered in descending way but util methods expect ascending order of arguments
            IndexIterationPointer next = result.get(nextPointerIdx);
            if (!descending && overlapsOrdered(currentMerged, next, OrderedIndexStore.SPECIAL_AWARE_COMPARATOR)) {
                // merge overlapping ranges
                currentMerged = union(currentMerged, next, OrderedIndexStore.SPECIAL_AWARE_COMPARATOR);
            } else if (descending && overlapsOrdered(next, currentMerged, OrderedIndexStore.SPECIAL_AWARE_COMPARATOR)) {
                // merge overlapping ranges
                currentMerged = union(next, currentMerged, OrderedIndexStore.SPECIAL_AWARE_COMPARATOR);
            } else {
                // write current pointer and advance
                result.set(writeIdx++, currentMerged);
                currentMerged = next;
            }
        }
        // write last remaining pointer
        result.set(writeIdx++, currentMerged);

        return result.subList(0, writeIdx);
    }
@Test
    void normalizePointersMergeIsNullWithLessThan() {
        // due to NULL ordering NULL and < X pointers can be merged

        assertThat(normalizePointers(arrayListOf(
                pointer(lessThan(6)), IS_NULL), false))
                .as("IS NULL should be merged with less than")
                .containsExactly(pointer(closedOpen(NULL, 6)));

        assertThat(normalizePointers(arrayListOf(
                pointer(greaterThan(6)), IS_NULL), false))
                .as("IS NULL should not be merged with greater than")
                .containsExactly(IS_NULL, pointer(greaterThan(6)));
    }