All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.deephaven.engine.table.impl.rangejoin.RangeSearchKernelObject Maven / Gradle / Ivy

There is a newer version: 0.37.1
Show newest version
/*
 * ---------------------------------------------------------------------------------------------------------------------
 * AUTO-GENERATED CLASS - DO NOT EDIT MANUALLY - for any changes edit RangeSearchKernelChar and regenerate
 * ---------------------------------------------------------------------------------------------------------------------
 */
package io.deephaven.engine.table.impl.rangejoin;

import io.deephaven.api.RangeEndRule;
import io.deephaven.api.RangeStartRule;
import io.deephaven.base.verify.Assert;
import io.deephaven.chunk.*;
import io.deephaven.chunk.attributes.ChunkPositions;
import io.deephaven.chunk.attributes.Values;
import org.jetbrains.annotations.NotNull;

import static io.deephaven.util.QueryConstants.NULL_INT;

/**
 * {@link RangeSearchKernel} for values of type Object.
 */
enum RangeSearchKernelObject implements RangeSearchKernel {

    LT_GT {
        @Override
        void processAllRangesForEmptyRight(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            populateAllRangesForEmptyRightDisallowEqual(lsv, lev, ospi, oepe);
        }

        @Override
        void processInvalidRanges(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableBooleanChunk validity,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            processInvalidRangesDisallowEqual(lsv, lev, validity, ospi, oepe);
        }

        @Override
        void processRangeStarts(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk ospi) {
            processRangeStartsLessThan(lv, lp, rv, rso, rse, ospi);
        }

        @Override
        void processRangeEnds(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk oepe) {
            processRangeEndsGreaterThan(lv, lp, rv, rso, rse, oepe);
        }
    },

    LEQ_GT {
        @Override
        void processAllRangesForEmptyRight(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            populateAllRangesForEmptyRightDisallowEqual(lsv, lev, ospi, oepe);
        }

        @Override
        void processInvalidRanges(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableBooleanChunk validity,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            processInvalidRangesDisallowEqual(lsv, lev, validity, ospi, oepe);
        }

        @Override
        void processRangeStarts(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk ospi) {
            processRangeStartsLessThanEqual(lv, lp, rv, rso, rse, ospi);
        }

        @Override
        void processRangeEnds(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk oepe) {
            processRangeEndsGreaterThan(lv, lp, rv, rso, rse, oepe);
        }
    },

    LEQAP_GT {
        @Override
        void processAllRangesForEmptyRight(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            populateAllRangesForEmptyRightDisallowEqual(lsv, lev, ospi, oepe);
        }

        @Override
        void processInvalidRanges(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableBooleanChunk validity,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            processInvalidRangesDisallowEqual(lsv, lev, validity, ospi, oepe);
        }

        @Override
        void processRangeStarts(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk ospi) {
            processRangeStartsLessThanEqualAllowPreceding(lv, lp, rv, rso, rse, ospi);
        }

        @Override
        void processRangeEnds(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk oepe) {
            processRangeEndsGreaterThan(lv, lp, rv, rso, rse, oepe);
        }
    },

    LT_GEQ {
        @Override
        void processAllRangesForEmptyRight(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            populateAllRangesForEmptyRightDisallowEqual(lsv, lev, ospi, oepe);
        }

        @Override
        void processInvalidRanges(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableBooleanChunk validity,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            processInvalidRangesDisallowEqual(lsv, lev, validity, ospi, oepe);
        }

        @Override
        void processRangeStarts(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk ospi) {
            processRangeStartsLessThan(lv, lp, rv, rso, rse, ospi);
        }

        @Override
        void processRangeEnds(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk oepe) {
            processRangeEndsGreaterThanEqual(lv, lp, rv, rso, rse, oepe);
        }
    },

    LEQ_GEQ {
        @Override
        void processAllRangesForEmptyRight(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            populateAllRangesForEmptyRightAllowEqual(lsv, lev, ospi, oepe);
        }

        @Override
        void processInvalidRanges(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableBooleanChunk validity,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            processInvalidRangesAllowEqual(lsv, lev, validity, ospi, oepe);
        }

        @Override
        void processRangeStarts(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk ospi) {
            processRangeStartsLessThanEqual(lv, lp, rv, rso, rse, ospi);
        }

        @Override
        void processRangeEnds(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk oepe) {
            processRangeEndsGreaterThanEqual(lv, lp, rv, rso, rse, oepe);
        }
    },

    LEQAP_GEQ {
        @Override
        void processAllRangesForEmptyRight(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            populateAllRangesForEmptyRightAllowEqual(lsv, lev, ospi, oepe);
        }

        @Override
        void processInvalidRanges(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableBooleanChunk validity,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            processInvalidRangesAllowEqual(lsv, lev, validity, ospi, oepe);
        }

        @Override
        void processRangeStarts(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk ospi) {
            processRangeStartsLessThanEqualAllowPreceding(lv, lp, rv, rso, rse, ospi);
        }

        @Override
        void processRangeEnds(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk oepe) {
            processRangeEndsGreaterThanEqual(lv, lp, rv, rso, rse, oepe);
        }
    },

    LT_GEQAF {
        @Override
        void processAllRangesForEmptyRight(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            populateAllRangesForEmptyRightDisallowEqual(lsv, lev, ospi, oepe);
        }

        @Override
        void processInvalidRanges(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableBooleanChunk validity,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            processInvalidRangesDisallowEqual(lsv, lev, validity, ospi, oepe);
        }

        @Override
        void processRangeStarts(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk ospi) {
            processRangeStartsLessThan(lv, lp, rv, rso, rse, ospi);
        }

        @Override
        void processRangeEnds(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk oepe) {
            processRangeEndsGreaterThanEqualAllowFollowing(lv, lp, rv, rso, rse, oepe);
        }
    },

    LEQ_GEQAF {
        @Override
        void processAllRangesForEmptyRight(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            populateAllRangesForEmptyRightAllowEqual(lsv, lev, ospi, oepe);
        }

        @Override
        void processInvalidRanges(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableBooleanChunk validity,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            processInvalidRangesAllowEqual(lsv, lev, validity, ospi, oepe);
        }

        @Override
        void processRangeStarts(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk ospi) {
            processRangeStartsLessThanEqual(lv, lp, rv, rso, rse, ospi);
        }

        @Override
        void processRangeEnds(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk oepe) {
            processRangeEndsGreaterThanEqualAllowFollowing(lv, lp, rv, rso, rse, oepe);
        }
    },

    LEQAP_GEQAF {
        @Override
        void processAllRangesForEmptyRight(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            populateAllRangesForEmptyRightAllowEqual(lsv, lev, ospi, oepe);
        }

        @Override
        void processInvalidRanges(
                @NotNull final ObjectChunk lsv,
                @NotNull final ObjectChunk lev,
                @NotNull final WritableBooleanChunk validity,
                @NotNull final WritableIntChunk ospi,
                @NotNull final WritableIntChunk oepe) {
            processInvalidRangesAllowEqual(lsv, lev, validity, ospi, oepe);
        }

        @Override
        void processRangeStarts(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk ospi) {
            processRangeStartsLessThanEqualAllowPreceding(lv, lp, rv, rso, rse, ospi);
        }

        @Override
        void processRangeEnds(
                @NotNull final ObjectChunk lv,
                @NotNull final IntChunk lp,
                @NotNull final ObjectChunk rv,
                @NotNull final IntChunk rso,
                int rse,
                @NotNull final WritableIntChunk oepe) {
            processRangeEndsGreaterThanEqualAllowFollowing(lv, lp, rv, rso, rse, oepe);
        }
    };

    static RangeSearchKernelObject forRules(
            @NotNull final RangeStartRule startRule,
            @NotNull final RangeEndRule endRule) {
        switch (startRule) {
            case LESS_THAN:
                switch (endRule) {
                    case GREATER_THAN:
                        return LT_GT;
                    case GREATER_THAN_OR_EQUAL:
                        return LT_GEQ;
                    case GREATER_THAN_OR_EQUAL_ALLOW_FOLLOWING:
                        return LT_GEQAF;
                }
                break;
            case LESS_THAN_OR_EQUAL:
                switch (endRule) {
                    case GREATER_THAN:
                        return LEQ_GT;
                    case GREATER_THAN_OR_EQUAL:
                        return LEQ_GEQ;
                    case GREATER_THAN_OR_EQUAL_ALLOW_FOLLOWING:
                        return LEQ_GEQAF;
                }
                break;
            case LESS_THAN_OR_EQUAL_ALLOW_PRECEDING:
                switch (endRule) {
                    case GREATER_THAN:
                        return LEQAP_GT;
                    case GREATER_THAN_OR_EQUAL:
                        return LEQAP_GEQ;
                    case GREATER_THAN_OR_EQUAL_ALLOW_FOLLOWING:
                        return LEQAP_GEQAF;
                }
                break;
        }
        throw new UnsupportedOperationException(String.format(
                "Unrecognized range rule pair {%s, %s}", startRule, endRule));
    }

    @Override
    public final void processAllRangesForEmptyRight(
            @NotNull final Chunk leftStartValues,
            @NotNull final Chunk leftEndValues,
            @NotNull final WritableIntChunk outputStartPositionsInclusive,
            @NotNull final WritableIntChunk outputEndPositionsExclusive) {
        processAllRangesForEmptyRight(
                leftStartValues.asObjectChunk(),
                leftEndValues.asObjectChunk(),
                outputStartPositionsInclusive,
                outputEndPositionsExclusive);
    }

    abstract void processAllRangesForEmptyRight(
            @NotNull ObjectChunk leftStartValues,
            @NotNull ObjectChunk leftEndValues,
            @NotNull WritableIntChunk outputStartPositionsInclusive,
            @NotNull WritableIntChunk outputEndPositionsExclusive);

    @Override
    public final void processInvalidRanges(
            @NotNull final Chunk leftStartValues,
            @NotNull final Chunk leftEndValues,
            @NotNull final WritableBooleanChunk validity,
            @NotNull final WritableIntChunk outputStartPositionsInclusive,
            @NotNull final WritableIntChunk outputEndPositionsExclusive) {
        processInvalidRanges(
                leftStartValues.asObjectChunk(),
                leftEndValues.asObjectChunk(),
                validity,
                outputStartPositionsInclusive,
                outputEndPositionsExclusive);
    }

    abstract void processInvalidRanges(
            @NotNull ObjectChunk leftStartValues,
            @NotNull ObjectChunk leftEndValues,
            @NotNull WritableBooleanChunk validity,
            @NotNull WritableIntChunk outputStartPositionsInclusive,
            @NotNull WritableIntChunk outputEndPositionsExclusive);

    @Override
    public final void processRangeStarts(
            @NotNull final Chunk leftValues,
            @NotNull final IntChunk leftPositions,
            @NotNull final Chunk rightValues,
            @NotNull final IntChunk rightStartOffsets,
            final int rightSizeExpanded,
            @NotNull final WritableIntChunk outputStartPositionsInclusive) {
        processRangeStarts(
                leftValues.asObjectChunk(),
                leftPositions,
                rightValues.asObjectChunk(),
                rightStartOffsets,
                rightSizeExpanded,
                outputStartPositionsInclusive);
    }

    abstract void processRangeStarts(
            @NotNull ObjectChunk leftValues,
            @NotNull IntChunk leftPositions,
            @NotNull ObjectChunk rightValues,
            @NotNull IntChunk rightStartOffsets,
            int rightSizeExpanded,
            @NotNull WritableIntChunk outputStartPositionsInclusive);

    @Override
    public final void processRangeEnds(
            @NotNull final Chunk leftValues,
            @NotNull final IntChunk leftPositions,
            @NotNull final Chunk rightValues,
            @NotNull final IntChunk rightStartOffsets,
            final int rightSizeExpanded,
            @NotNull final WritableIntChunk outputEndPositionsExclusive) {
        processRangeEnds(
                leftValues.asObjectChunk(),
                leftPositions,
                rightValues.asObjectChunk(),
                rightStartOffsets,
                rightSizeExpanded,
                outputEndPositionsExclusive);
    }

    abstract void processRangeEnds(
            @NotNull ObjectChunk leftValues,
            @NotNull IntChunk leftPositions,
            @NotNull ObjectChunk rightValues,
            @NotNull IntChunk rightStartOffsets,
            int rightSizeExpanded,
            @NotNull WritableIntChunk outputEndPositionsExclusive);

    private static void populateAllRangesForEmptyRightAllowEqual(
            @NotNull final ObjectChunk leftStartValues,
            @NotNull final ObjectChunk leftEndValues,
            @NotNull final WritableIntChunk outputStartPositionsInclusive,
            @NotNull final WritableIntChunk outputEndPositionsExclusive) {
        final int size = leftStartValues.size();
        Assert.eq(size, "leftStartValues.size()", leftEndValues.size(), "leftEndValues.size()");

        for (int li = 0; li < size; ++li) {
            if (isValidPairAllowEqual(leftStartValues.get(li), leftEndValues.get(li))) {
                outputStartPositionsInclusive.set(li, 0);
                outputEndPositionsExclusive.set((li), 0);
            } else {
                outputStartPositionsInclusive.set(li, NULL_INT);
                outputEndPositionsExclusive.set(li, NULL_INT);
            }
        }
        outputStartPositionsInclusive.setSize(size);
        outputEndPositionsExclusive.setSize(size);
    }

    private static void populateAllRangesForEmptyRightDisallowEqual(
            @NotNull final ObjectChunk leftStartValues,
            @NotNull final ObjectChunk leftEndValues,
            @NotNull final WritableIntChunk outputStartPositionsInclusive,
            @NotNull final WritableIntChunk outputEndPositionsExclusive) {
        final int size = leftStartValues.size();
        Assert.eq(size, "leftStartValues.size()", leftEndValues.size(), "leftEndValues.size()");

        for (int li = 0; li < size; ++li) {
            if (isValidPairDisallowEqual(leftStartValues.get(li), leftEndValues.get(li))) {
                outputStartPositionsInclusive.set(li, 0);
                outputEndPositionsExclusive.set(li, 0);
            } else {
                outputStartPositionsInclusive.set(li, NULL_INT);
                outputEndPositionsExclusive.set(li, NULL_INT);
            }
        }
        outputStartPositionsInclusive.setSize(size);
        outputEndPositionsExclusive.setSize(size);
    }

    private static void processInvalidRangesAllowEqual(
            @NotNull final ObjectChunk leftStartValues,
            @NotNull final ObjectChunk leftEndValues,
            @NotNull final WritableBooleanChunk validity,
            @NotNull final WritableIntChunk outputStartPositionsInclusive,
            @NotNull final WritableIntChunk outputEndPositionsExclusive) {
        final int size = leftStartValues.size();
        Assert.eq(size, "leftStartValues.size()", leftEndValues.size(), "leftEndValues.size()");

        for (int li = 0; li < size; ++li) {
            if (isValidPairAllowEqual(leftStartValues.get(li), leftEndValues.get(li))) {
                validity.set(li, true);
            } else {
                validity.set(li, false);
                outputStartPositionsInclusive.set(li, NULL_INT);
                outputEndPositionsExclusive.set(li, NULL_INT);
            }
        }
        validity.setSize(size);
        outputStartPositionsInclusive.setSize(size);
        outputEndPositionsExclusive.setSize(size);
    }

    private static void processInvalidRangesDisallowEqual(
            @NotNull final ObjectChunk leftStartValues,
            @NotNull final ObjectChunk leftEndValues,
            @NotNull final WritableBooleanChunk validity,
            @NotNull final WritableIntChunk outputStartPositionsInclusive,
            @NotNull final WritableIntChunk outputEndPositionsExclusive) {
        final int size = leftStartValues.size();
        Assert.eq(size, "leftStartValues.size()", leftEndValues.size(), "leftEndValues.size()");

        for (int li = 0; li < size; ++li) {
            if (isValidPairDisallowEqual(leftStartValues.get(li), leftEndValues.get(li))) {
                validity.set(li, true);
            } else {
                validity.set(li, false);
                outputStartPositionsInclusive.set(li, NULL_INT);
                outputEndPositionsExclusive.set(li, NULL_INT);
            }
        }
        validity.setSize(size);
        outputStartPositionsInclusive.setSize(size);
        outputEndPositionsExclusive.setSize(size);
    }

    private static boolean isValidPairAllowEqual(final Object start, final Object end) {
        return !isNaN(start) && !isNaN(end) && (isNull(start) || isNull(end) || leq(start, end));
    }

    private static boolean isValidPairDisallowEqual(final Object start, final Object end) {
        return !isNaN(start) && !isNaN(end) && (isNull(start) || isNull(end) || lt(start, end));
    }

    private static void processRangeStartsLessThan(
            @NotNull final ObjectChunk leftValues,
            @NotNull final IntChunk leftPositions,
            @NotNull final ObjectChunk rightValues,
            @NotNull final IntChunk rightStartOffsets,
            final int rightSizeExpanded,
            @NotNull final WritableIntChunk outputStartPositionsInclusive) {
        // Note that invalid and undefined ranges have already been eliminated
        final int leftSize = leftValues.size();
        final int rightSize = rightValues.size();

        // Empty rights are handled via a different method
        Assert.gtZero(rightSize, "rightSize");

        // null left start values imply that the responsive right range starts at position 0
        int leftIndex = 0;
        while (leftIndex < leftSize && isNull(leftValues.get(leftIndex))) {
            outputStartPositionsInclusive.set(leftPositions.get(leftIndex++), 0);
        }
        if (leftIndex == leftSize) {
            return;
        }

        // Find the range starts for non-null left values
        int rightLowIndexInclusive = 0;
        Object leftValue = leftValues.get(leftIndex);
        do {
            final int searchResult = eq(leftValue, rightValues.get(rightLowIndexInclusive))
                    ? rightLowIndexInclusive
                    : rightValues.binarySearch(rightLowIndexInclusive, rightSize, leftValue);
            // rightIndex should be the index of the first right value whose first position we want to include, so
            // take the insertion point (when not found) or one past the insertion point (when found)
            final int rightIndex = searchResult < 0 ? ~searchResult : searchResult + 1;
            if (rightIndex == rightSize) {
                break;
            }
            final int rightPosition = rightStartOffsets.get(rightIndex);
            final Object rightValue = rightValues.get(rightIndex);
            outputStartPositionsInclusive.set(leftPositions.get(leftIndex++), rightPosition);
            // Proceed linearly until we have a reason to binary search again. We can re-use rightPosition until
            // we reach rightValue.
            while (leftIndex < leftSize && lt(leftValue = leftValues.get(leftIndex), rightValue)) {
                outputStartPositionsInclusive.set(leftPositions.get(leftIndex++), rightPosition);
            }
            // We've processed all left values that care about rightValue, so begin searching after rightIndex
            rightLowIndexInclusive = rightIndex + 1;
        } while (leftIndex < leftSize && rightLowIndexInclusive < rightSize);

        // All remaining ranges start after last right (and are thus empty)
        while (leftIndex < leftSize) {
            outputStartPositionsInclusive.set(leftPositions.get(leftIndex++), rightSizeExpanded);
        }
    }

    private static void processRangeStartsLessThanEqual(
            @NotNull final ObjectChunk leftValues,
            @NotNull final IntChunk leftPositions,
            @NotNull final ObjectChunk rightValues,
            @NotNull final IntChunk rightStartOffsets,
            final int rightSizeExpanded,
            @NotNull final WritableIntChunk outputStartPositionsInclusive) {
        // Note that invalid and undefined ranges have already been eliminated
        final int leftSize = leftValues.size();
        final int rightSize = rightValues.size();

        // Empty rights are handled via a different method
        Assert.gtZero(rightSize, "rightSize");

        // null left start values imply that the responsive right range starts at position 0
        int leftIndex = 0;
        while (leftIndex < leftSize && isNull(leftValues.get(leftIndex))) {
            outputStartPositionsInclusive.set(leftPositions.get(leftIndex++), 0);
        }
        if (leftIndex == leftSize) {
            return;
        }

        // Find the range starts for non-null left values
        int rightLowIndexInclusive = 0;
        Object leftValue = leftValues.get(leftIndex);
        do {
            final int searchResult = eq(leftValue, rightValues.get(rightLowIndexInclusive))
                    ? rightLowIndexInclusive
                    : rightValues.binarySearch(rightLowIndexInclusive, rightSize, leftValue);
            // rightIndex should be the index of the first right value whose first position we want to include, so
            // take the insertion point whether found or not
            final int rightIndex = searchResult < 0 ? ~searchResult : searchResult;
            if (rightIndex == rightSize) {
                break;
            }
            final int rightPosition = rightStartOffsets.get(rightIndex);
            final Object rightValue = rightValues.get(rightIndex);
            outputStartPositionsInclusive.set(leftPositions.get(leftIndex++), rightPosition);
            // Proceed linearly until we have a reason to binary search again. We can re-use rightPosition until
            // we pass rightValue.
            while (leftIndex < leftSize && leq(leftValue = leftValues.get(leftIndex), rightValue)) {
                outputStartPositionsInclusive.set(leftPositions.get(leftIndex++), rightPosition);
            }
            // We've processed all left values that care about rightValue, so begin searching after rightIndex
            rightLowIndexInclusive = rightIndex + 1;
        } while (leftIndex < leftSize && rightLowIndexInclusive < rightSize);

        // All remaining ranges start after last right (and are thus empty)
        while (leftIndex < leftSize) {
            outputStartPositionsInclusive.set(leftPositions.get(leftIndex++), rightSizeExpanded);
        }
    }

    private static void processRangeStartsLessThanEqualAllowPreceding(
            @NotNull final ObjectChunk leftValues,
            @NotNull final IntChunk leftPositions,
            @NotNull final ObjectChunk rightValues,
            @NotNull final IntChunk rightStartOffsets,
            final int rightSizeExpanded,
            @NotNull final WritableIntChunk outputStartPositionsInclusive) {
        // Note that invalid and undefined ranges have already been eliminated
        final int leftSize = leftValues.size();
        final int rightSize = rightValues.size();

        // Empty rights are handled via a different method
        Assert.gtZero(rightSize, "rightSize");

        // null left start values imply that the responsive right range starts at position 0
        int leftIndex = 0;
        while (leftIndex < leftSize && isNull(leftValues.get(leftIndex))) {
            outputStartPositionsInclusive.set(leftPositions.get(leftIndex++), 0);
        }
        if (leftIndex == leftSize) {
            return;
        }

        // Find the range starts for non-null left values
        int rightLowIndexInclusive = 0;
        Object leftValue = leftValues.get(leftIndex);
        do {
            final int searchResult = eq(leftValue, rightValues.get(rightLowIndexInclusive))
                    ? rightLowIndexInclusive
                    : rightValues.binarySearch(rightLowIndexInclusive, rightSize, leftValue);
            // rightIndex should be the index of the first right value whose first position we want to include, so
            // take the insertion point whether found or not
            final int rightIndex = searchResult < 0 ? ~searchResult : searchResult;
            if (rightIndex == rightSize) {
                break;
            }
            final int rightPosition = rightStartOffsets.get(rightIndex);
            final Object rightValue = rightValues.get(rightIndex);
            // Proceed linearly until we have a reason to binary search again
            if (searchResult < 0 && rightIndex != 0) {
                // If we had an inexact match that isn't at the beginning of the right values, look behind
                final int precedingRightPosition = rightPosition - 1;
                outputStartPositionsInclusive.set(leftPositions.get(leftIndex++), precedingRightPosition);
                // We can re-use precedingRightPosition until we reach rightValue
                while (leftIndex < leftSize && lt(leftValue = leftValues.get(leftIndex), rightValue)) {
                    outputStartPositionsInclusive.set(leftPositions.get(leftIndex++), precedingRightPosition);
                }
            } else {
                outputStartPositionsInclusive.set(leftPositions.get(leftIndex++), rightPosition);
            }
            // We can re-use rightPosition until we pass rightValue
            while (leftIndex < leftSize && leq(leftValue = leftValues.get(leftIndex), rightValue)) {
                outputStartPositionsInclusive.set(leftPositions.get(leftIndex++), rightPosition);
            }
            // We've processed all left values that care about rightValue, so begin searching after rightIndex
            rightLowIndexInclusive = rightIndex + 1;
        } while (leftIndex < leftSize && rightLowIndexInclusive < rightSize);

        // All remaining left start values are after last right value. Last right position is in range by "allow
        // preceding" logic.
        final int lastRightPosition = rightSizeExpanded - 1;
        while (leftIndex < leftSize) {
            outputStartPositionsInclusive.set(leftPositions.get(leftIndex++), lastRightPosition);
        }
    }

    private static void processRangeEndsGreaterThan(
            @NotNull final ObjectChunk leftValues,
            @NotNull final IntChunk leftPositions,
            @NotNull final ObjectChunk rightValues,
            @NotNull final IntChunk rightStartOffsets,
            final int rightSizeExpanded,
            @NotNull final WritableIntChunk outputEndPositionsExclusive) {
        // Note that invalid and undefined ranges have already been eliminated
        final int leftSize = leftValues.size();
        final int rightSize = rightValues.size();

        // Empty rights are handled via a different method
        Assert.gtZero(rightSize, "rightSize");

        // null left end values imply that the responsive right range ends at rightSizeExpanded (exclusive)
        int leftIndex = 0;
        while (leftIndex < leftSize && isNull(leftValues.get(leftIndex))) {
            outputEndPositionsExclusive.set(leftPositions.get(leftIndex++), rightSizeExpanded);
        }
        if (leftIndex == leftSize) {
            return;
        }

        // Find the range ends for non-null left values
        int rightLowIndexInclusive = 0;
        Object leftValue = leftValues.get(leftIndex);
        do {
            final int searchResult = eq(leftValue, rightValues.get(rightLowIndexInclusive))
                    ? rightLowIndexInclusive
                    : rightValues.binarySearch(rightLowIndexInclusive, rightSize, leftValue);
            // rightIndex should be the index of the first right value whose first position we want to exclude, so
            // take the insertion point whether found or not
            final int rightIndex = searchResult < 0 ? ~searchResult : searchResult;
            if (rightIndex == rightSize) {
                break;
            }
            final int rightPosition = rightStartOffsets.get(rightIndex);
            final Object rightValue = rightValues.get(rightIndex);
            outputEndPositionsExclusive.set(leftPositions.get(leftIndex++), rightPosition);
            // Proceed linearly until we have a reason to binary search again. We can re-use rightPosition until
            // we pass rightValue.
            while (leftIndex < leftSize && leq(leftValue = leftValues.get(leftIndex), rightValue)) {
                outputEndPositionsExclusive.set(leftPositions.get(leftIndex++), rightPosition);
            }
            // We've processed all left values that care about rightValue, so begin searching after rightIndex
            rightLowIndexInclusive = rightIndex + 1;
        } while (leftIndex < leftSize && rightLowIndexInclusive < rightSize);

        // All remaining ranges end at last right
        while (leftIndex < leftSize) {
            outputEndPositionsExclusive.set(leftPositions.get(leftIndex++), rightSizeExpanded);
        }
    }

    private static void processRangeEndsGreaterThanEqual(
            @NotNull final ObjectChunk leftValues,
            @NotNull final IntChunk leftPositions,
            @NotNull final ObjectChunk rightValues,
            @NotNull final IntChunk rightStartOffsets,
            final int rightSizeExpanded,
            @NotNull final WritableIntChunk outputEndPositionsExclusive) {
        // Note that invalid and undefined ranges have already been eliminated
        final int leftSize = leftValues.size();
        final int rightSize = rightValues.size();

        // Empty rights are handled via a different method
        Assert.gtZero(rightSize, "rightSize");

        // null left end values imply that the responsive right range ends at rightSizeExpanded (exclusive)
        int leftIndex = 0;
        while (leftIndex < leftSize && isNull(leftValues.get(leftIndex))) {
            outputEndPositionsExclusive.set(leftPositions.get(leftIndex++), rightSizeExpanded);
        }
        if (leftIndex == leftSize) {
            return;
        }

        // Find the range ends for non-null left values
        int rightLowIndexInclusive = 0;
        Object leftValue = leftValues.get(leftIndex);
        do {
            final int searchResult = eq(leftValue, rightValues.get(rightLowIndexInclusive))
                    ? rightLowIndexInclusive
                    : rightValues.binarySearch(rightLowIndexInclusive, rightSize, leftValue);
            // rightIndex should be the index of the first right value whose first position we want to exclude, so
            // take the insertion point (when not found) or one past the insertion point (when found)
            final int rightIndex = searchResult < 0 ? ~searchResult : searchResult + 1;
            if (rightIndex == rightSize) {
                break;
            }
            final int rightPosition = rightStartOffsets.get(rightIndex);
            final Object rightValue = rightValues.get(rightIndex);
            outputEndPositionsExclusive.set(leftPositions.get(leftIndex++), rightPosition);
            // Proceed linearly until we have a reason to binary search again. We can re-use rightPosition until
            // we reach rightValue.
            while (leftIndex < leftSize && lt(leftValue = leftValues.get(leftIndex), rightValue)) {
                outputEndPositionsExclusive.set(leftPositions.get(leftIndex++), rightPosition);
            }
            // We've processed all left values that can exclude rightValue, so begin searching at rightIndex
            rightLowIndexInclusive = rightIndex;
        } while (leftIndex < leftSize && rightLowIndexInclusive < rightSize);

        // All remaining ranges end at last right
        while (leftIndex < leftSize) {
            outputEndPositionsExclusive.set(leftPositions.get(leftIndex++), rightSizeExpanded);
        }
    }

    private static void processRangeEndsGreaterThanEqualAllowFollowing(
            @NotNull final ObjectChunk leftValues,
            @NotNull final IntChunk leftPositions,
            @NotNull final ObjectChunk rightValues,
            @NotNull final IntChunk rightStartOffsets,
            final int rightSizeExpanded,
            @NotNull final WritableIntChunk outputEndPositionsExclusive) {
        // Note that invalid and undefined ranges have already been eliminated
        final int leftSize = leftValues.size();
        final int rightSize = rightValues.size();

        // Empty rights are handled via a different method
        Assert.gtZero(rightSize, "rightSize");

        // null left end values imply that the responsive right range ends at rightSizeExpanded (exclusive)
        int leftIndex = 0;
        while (leftIndex < leftSize && isNull(leftValues.get(leftIndex))) {
            outputEndPositionsExclusive.set(leftPositions.get(leftIndex++), rightSizeExpanded);
        }
        if (leftIndex == leftSize) {
            return;
        }

        // Find the range ends for non-null left values
        int rightLowIndexInclusive = 0;
        Object leftValue = leftValues.get(leftIndex);
        do {
            final int searchResult = eq(leftValue, rightValues.get(rightLowIndexInclusive))
                    ? rightLowIndexInclusive
                    : rightValues.binarySearch(rightLowIndexInclusive, rightSize, leftValue);
            // rightIndex should be the index of the first right value whose first position we want to exclude, so
            // take the insertion point (when not found) or one past the insertion point (when found)
            final int rightIndex = searchResult < 0 ? ~searchResult : searchResult + 1;
            if (rightIndex == rightSize) {
                // This left value and all remaining left values are at or after last right value. All right positions
                // are within this bound.
                break;
            }
            final int rightPosition = rightStartOffsets.get(rightIndex);
            final Object rightValue = rightValues.get(rightIndex);
            // Proceed linearly until we have a reason to binary search again
            if (searchResult < 0) {
                // If we had an inexact match that isn't at the end of the right values, look ahead
                final int followingRightPosition = rightPosition + 1;
                if (followingRightPosition == rightSizeExpanded) {
                    // We're going to fill the remainder with rightSizeExpanded, and we don't need any value comparisons
                    // to figure that out
                    break;
                }
                outputEndPositionsExclusive.set(leftPositions.get(leftIndex++), followingRightPosition);
                // We can re-use followingRightPosition until we reach rightValue
                while (leftIndex < leftSize && lt(leftValue = leftValues.get(leftIndex), rightValue)) {
                    outputEndPositionsExclusive.set(leftPositions.get(leftIndex++), followingRightPosition);
                }
            } else {
                outputEndPositionsExclusive.set(leftPositions.get(leftIndex++), rightPosition);
                // We can re-use rightPosition until we reach rightValue
                while (leftIndex < leftSize && lt(leftValue = leftValues.get(leftIndex), rightValue)) {
                    outputEndPositionsExclusive.set(leftPositions.get(leftIndex++), rightPosition);
                }
            }
            // We've processed all left values that can exclude rightValue, so begin searching at rightIndex
            rightLowIndexInclusive = rightIndex;
        } while (leftIndex < leftSize && rightLowIndexInclusive < rightSize);

        // All remaining ranges end at last right
        while (leftIndex < leftSize) {
            outputEndPositionsExclusive.set(leftPositions.get(leftIndex++), rightSizeExpanded);
        }
    }

    @SuppressWarnings("BooleanMethodIsAlwaysInverted")
    // region isNaN
    private static boolean isNaN(@SuppressWarnings("unused") final Object v) {
        return false;
    }
    // endregion isNaN

    // region isNull
    private static boolean isNull(final Object v) {
        // We need not deal with NaN values here
        return v == null;
    }
    // endregion isNull

    // region eq
    private static boolean eq(final Object a, final Object b) {
        // We need not deal with null or NaN values here
        return a.equals(b);
    }
    // endregion eq

    // region lt
    private static boolean lt(final Object a, final Object b) {
        // We need not deal with null or NaN values here
        //noinspection unchecked,rawtypes
        return ((Comparable)a).compareTo(b) < 0;
    }
    // endregion lt

    // region leq
    private static boolean leq(final Object a, final Object b) {
        // We need not deal with null or NaN values here
        //noinspection unchecked,rawtypes
        return ((Comparable)a).compareTo(b) <= 0;
    }
    // endregion leq
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy