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

io.deephaven.engine.rowset.impl.rsp.container.Container Maven / Gradle / Ivy

/*
 * (c) the authors Licensed under the Apache License, Version 2.0.
 *
 * The code in this file is a heavily modified version of the original in the RoaringBitmap library; please see
 * https://roaringbitmap.org/
 *
 */

package io.deephaven.engine.rowset.impl.rsp.container;

import java.util.NoSuchElementException;

/**
 * Base container class.
 */
public abstract class Container {

    public static final boolean DEBUG =
            Boolean.getBoolean("io.deephaven.engine.rowset.impl.rsp.container.Container.DEBUG");

    /**
     * The maximum possible cardinality of a container, as an int. Also the maximum possible exclusive end for a range
     * that can be stored in a container.
     */
    public static final int MAX_RANGE = (1 << 16);

    /**
     * The maxumum possible value that can be stored in a container, as an int.
     */
    public static final int MAX_VALUE = MAX_RANGE - 1;

    // Sizing of a short array object in a 64 bit JVM (Hotspot) uses
    // 12 bytes of object overhead (including array.length), plus
    // the space for the short elements payload, plus padding to round
    // objects to 8 bytes boundaries.
    // So an array of 4 elements uses: 12 + 2*4 + 4 padding = 24 bytes = 3*8 bytes.
    // The 4 bytes of padding are wasted and can be used for another 2 short elements.
    static int shortArraySizeRounding(final int sizeToRound) {
        final int sz = 12 + 2 * sizeToRound;
        final int szMod8 = sz & 7;
        final int padding = szMod8 > 0 ? 8 - szMod8 : 0;
        return sizeToRound + padding / 2;
    }

    static int runsShortArraySizeRounding(final int nruns) {
        return 2 * runsSizeRounding(nruns);
    }

    static int runsSizeRounding(final int nruns) {
        final int sz = 12 + 4 * nruns;
        final int szMod8 = sz & 7;
        final int padding = szMod8 > 0 ? 8 - szMod8 : 0;
        return nruns + padding / 4;
    }

    protected static final ThreadLocal threadLocalBuf = ThreadLocal.withInitial(() -> new short[256 - 12]);

    public final void ifDebugValidate() {
        if (DEBUG) {
            validate();
        }
    }

    public Container check() {
        validate();
        return this;
    }

    public abstract void validate();

    private static boolean smallContainersDisabled() {
        return !ImmutableContainer.ENABLED;
    }

    public static Container singleton(final short v) {
        if (smallContainersDisabled()) {
            final short[] vs = new short[shortArraySizeRounding(1)];
            vs[0] = v;
            return new ArrayContainer(vs, 1);
        }
        return new SingletonContainer(v);
    }

    public static Container singleRange(final int start, final int end) {
        if (DEBUG) {
            if (end <= start || start < 0 || end > MAX_RANGE) {
                throw new IllegalArgumentException("start=" + start + ", end=" + end);
            }
        }
        return rangeOfOnes(start, end);
    }

    public static Container full() {
        if (smallContainersDisabled()) {
            return new RunContainer(0, MAX_RANGE);
        }
        return new SingleRangeContainer(0, MAX_RANGE);
    }

    /**
     * Create a container initialized with a range of consecutive values
     *
     * @param start first index
     * @param end last index (range is exclusive)
     * @return a new container initialized with the specified values
     */
    public static Container rangeOfOnes(final int start, final int end) {
        if (DEBUG && (start < 0 || end > MAX_RANGE)) {
            throw new IllegalArgumentException("start=" + start + ", end=" + end);
        }
        if (end <= start) {
            return Container.empty();
        }
        if (end - start == 1) {
            return Container.singleton(ContainerUtil.lowbits(start));
        }
        if (smallContainersDisabled()) {
            return new RunContainer(start, end);
        }
        return new SingleRangeContainer(start, end);
    }

    public static Container twoValues(final short v1, final short v2) {
        final int iv1 = ContainerUtil.toIntUnsigned(v1);
        final int iv2 = ContainerUtil.toIntUnsigned(v2);
        if (DEBUG) {
            if (iv2 <= iv1) {
                throw new IllegalStateException("iv1=" + iv1 + " && iv2=" + iv2);
            }
        }
        if (smallContainersDisabled()) {
            final short[] vs = new short[shortArraySizeRounding(2)];
            vs[0] = v1;
            vs[1] = v2;
            return new ArrayContainer(vs, 2);
        }
        if (iv2 - 1 == iv1) {
            return Container.singleRange(iv1, iv2 + 1);
        }
        return new TwoValuesContainer(v1, v2);
    }

    /**
     * Returns a new Container containing the two provided ranges. The ranges provided should be nonempty, disjoint and
     * provided in appearance order, ie, start2 > start1.
     *
     * @param start1 start of first range, inclusive.
     * @param end1 end of first range, exclusive.
     * @param start2 start of second range, inclusive.
     * @param end2 end of second range, exclusive.
     * @return A new Container containing the provided ranges.
     */
    public static Container twoRanges(final int start1, final int end1, final int start2, final int end2) {
        if (DEBUG) {
            if (end1 <= start1 || end2 <= start2 ||
                    start1 < 0 || start2 < 0 ||
                    end1 > MAX_RANGE || end2 > MAX_RANGE ||
                    start2 <= end1) {
                throw new IllegalArgumentException(
                        "start1=" + start1 + ", end1=" + end1 + ", start2=" + start2 + ", end2=" + end2);
            }
        }
        if (smallContainersDisabled()) {
            return new RunContainer(start1, end1, start2, end2);
        }
        if (end1 - start1 == 1 && end2 - start2 == 1) {
            return new TwoValuesContainer(ContainerUtil.lowbits(start1), ContainerUtil.lowbits(start2));
        }
        return new RunContainer(start1, end1, start2, end2);
    }

    static Container makeSingletonContainer(final short v) {
        if (smallContainersDisabled()) {
            return new ArrayContainer(v);
        }
        return new SingletonContainer(v);
    }

    static Container makeTwoValuesContainer(final short v1, final short v2) {
        if (smallContainersDisabled()) {
            return new ArrayContainer(v1, v2);
        }
        return new TwoValuesContainer(v1, v2);
    }

    static Container makeSingleRangeContainer(final int start, final int end) {
        if (smallContainersDisabled()) {
            return new RunContainer(start, end);
        }
        return new SingleRangeContainer(start, end);
    }

    /**
     * @return An empty container.
     */
    public static Container empty() {
        if (smallContainersDisabled()) {
            return new ArrayContainer();
        }
        return EmptyContainer.instance;
    }

    /**
     * Return a new container with all shorts in [begin,end) added using an unsigned interpretation.
     *
     * @param begin start of range (inclusive)
     * @param end end of range (exclusive)
     * @return the new container
     */
    public abstract Container add(int begin, int end);

    /**
     * Insert a short to the container. May generate a new container.
     *
     * @param x short to be added
     * @return the resulting container
     */
    public abstract Container iset(short x);

    /**
     * Return a new container with the short given as parameter added.
     *
     * @param x a short to be added
     * @return a new container with x added
     */
    public abstract Container set(final short x);

    private String myType() {
        return getClass().getSimpleName();
    }

    /**
     * Computes the bitwise AND of this container with another (intersection). This container as well as the provided
     * container are left unaffected.
     *
     * @param x Another container
     * @return aggregated container
     */
    public abstract Container and(ArrayContainer x);

    /**
     * Computes the bitwise AND of this container with another (intersection). This container as well as the provided
     * container are left unaffected.
     *
     * @param x Another container
     * @return aggregated container
     */
    public abstract Container and(BitmapContainer x);

    /**
     * Computes the bitwise AND of this container with another (intersection). This container as well as the provided
     * container are left unaffected.
     *
     * @param x Another container
     * @return aggregated container
     */
    public abstract Container and(RunContainer x);

    private Container and(final SingletonContainer sc) {
        return contains(sc.value) ? sc : Container.empty();
    }

    private Container and(final SingleRangeContainer sr) {
        return andRange(sr.first(), sr.last() + 1);
    }

    private Container and(final TwoValuesContainer tv) {
        final boolean has1 = contains(tv.v1);
        final boolean has2 = contains(tv.v2);
        if (has1) {
            if (has2) {
                return tv.cowRef();
            }
            return Container.singleton(tv.v1);
        }
        if (has2) {
            return Container.singleton(tv.v2);
        }
        return Container.empty();
    }

    /**
     * Computes the bitwise AND of this container with another (intersection). This container as well as the provided
     * container are left unaffected.
     *
     * @param x Another container
     * @return aggregated container
     */
    public Container and(final Container x) {
        if (isEmpty() || x.isEmpty()) {
            return Container.empty();
        }
        if (x instanceof SingletonContainer) {
            return and((SingletonContainer) x);
        }
        if (x instanceof SingleRangeContainer) {
            return and((SingleRangeContainer) x);
        }
        if (x instanceof TwoValuesContainer) {
            return and((TwoValuesContainer) x);
        }
        if (x instanceof ArrayContainer) {
            return and((ArrayContainer) x);
        }
        if (x instanceof BitmapContainer) {
            return and((BitmapContainer) x);
        }
        if (x instanceof RunContainer) {
            return and((RunContainer) x);
        }
        throw new IllegalStateException(x.myType());
    }


    /**
     * Calculate the intersection of this container and a range, in a new container. The existing container is not
     * modified.
     *
     * @param start start of range
     * @param end end of range, exclusive.
     * @return a new Container containing the intersction of this container and the given range.
     */
    public abstract Container andRange(int start, int end);

    /**
     * Calculate the intersection of this container and a range; may overwrite the existing container or return a new
     * one.
     *
     * @param start start of range
     * @param end end of range, exclusive.
     * @return a Container containing the intersction of this container and the given range.
     */
    public abstract Container iandRange(int start, int end);

    /**
     * Computes the bitwise ANDNOT of this container with another (difference). This container as well as the provided
     * container are left unaffected.
     *
     * @param x Another container
     * @return aggregated container
     */
    public abstract Container andNot(ArrayContainer x);

    /**
     * Computes the bitwise ANDNOT of this container with another (difference). This container as well as the provided
     * container are left unaffected.
     *
     * @param x Another container
     * @return aggregated container
     */
    public abstract Container andNot(BitmapContainer x);

    /**
     * Computes the bitwise ANDNOT of this container with another (difference). This container as well as the provided
     * container are left unaffected.
     *
     * @param x Another container
     * @return aggregated container
     */
    public abstract Container andNot(RunContainer x);

    private Container andNot(final SingletonContainer sc) {
        return unset(sc.value);
    }

    private Container andNot(final SingleRangeContainer sr) {
        return remove(sr.first(), sr.last() + 1);
    }

    private Container andNot(final TwoValuesContainer tv) {
        final PositionHint hint = new PositionHint();
        return unset(tv.v1, hint).iunset(tv.v2, hint);
    }

    /**
     * Computes the bitwise ANDNOT of this container with another (difference). This container as well as the provided
     * container are left unaffected.
     *
     * @param x Another container
     * @return aggregated container
     */
    public Container andNot(final Container x) {
        if (isEmpty()) {
            return Container.empty();
        }
        if (x.isEmpty()) {
            return cowRef();
        }
        if (x instanceof SingletonContainer) {
            return andNot((SingletonContainer) x);
        }
        if (x instanceof SingleRangeContainer) {
            return andNot((SingleRangeContainer) x);
        }
        if (x instanceof TwoValuesContainer) {
            return andNot((TwoValuesContainer) x);
        }
        if (x instanceof ArrayContainer) {
            return andNot((ArrayContainer) x);
        }
        if (x instanceof BitmapContainer) {
            return andNot((BitmapContainer) x);
        }
        if (x instanceof RunContainer) {
            return andNot((RunContainer) x);
        }
        throw new IllegalStateException(x.myType());
    }

    /**
     * Get a full deep copy of the container in a new container object.
     *
     * @return A copy of the container as a new object.
     */
    public abstract Container deepCopy();

    /**
     * Get a shared, copy-on-write copy of an existing container. Mutations on the returned container will always return
     * a copy and leave the original container unchanged.
     * 

* This operation allows for cheap read-only references to the same values, at the cost of an additional copy for * any first mutation. * * @return A copy-on-write reference to the container. */ public abstract Container cowRef(); /** * Checks whether the container is empty or not. * * @return true if the container is empty. */ public abstract boolean isEmpty(); /** * Checks whether the container spans the full 2^16 range (ie, contains every short value) This is an O(1) operation * in all container types (some do not cache cardinality). * * @return true if the container does not miss any single short value. */ public abstract boolean isAllOnes(); /** * Checks whether the container has exactly one element (meaningful since cardinality may not be cached in some * Container types, eg, Run). * * @return true if the container contains exactly one element, false otherwise. */ public boolean isSingleElement() { return getCardinality() == 1; } /** * Checks whether the container spans the full 2^16 range (ie, contains every short value) This is an O(1) operation * in all container types (some do not cache cardinality). * * @return true if the container does not miss any single short value. This method is deprecated, prefer isAllOnes * instead. */ @Deprecated public final boolean isFull() { return isAllOnes(); } /** * Checks whether the contain contains the provided value * * @param x value to check * @return whether the value is in the container */ public abstract boolean contains(short x); /** * Checks whether the container contains the entire range * * @param rangeStart the inclusive lower bound of the range * @param rangeEnd the exclusive upper bound of the range * @return true if the container contains the range */ public abstract boolean contains(int rangeStart, int rangeEnd); protected abstract boolean contains(ArrayContainer arrayContainer); protected abstract boolean contains(BitmapContainer bitmapContainer); protected abstract boolean contains(RunContainer runContainer); /** * Checks whether the container is a subset of this container or not * * @param subset the container to be tested * @return true if the parameter is a subset of this container */ public boolean contains(final Container subset) { if (subset.isEmpty()) { return true; } if (isEmpty()) { return false; } if (subset instanceof SingletonContainer) { final SingletonContainer sc = (SingletonContainer) subset; return contains(sc.value); } if (subset instanceof SingleRangeContainer) { final SingleRangeContainer sr = (SingleRangeContainer) subset; return contains(sr.first(), sr.last() + 1); } if (subset instanceof TwoValuesContainer) { final TwoValuesContainer tv = (TwoValuesContainer) subset; return contains(tv.v1) && contains(tv.v2); } if (subset instanceof ArrayContainer) { return contains((ArrayContainer) subset); } if (subset instanceof BitmapContainer) { return contains((BitmapContainer) subset); } if (subset instanceof RunContainer) { return contains((RunContainer) subset); } throw new IllegalStateException(subset.myType()); } /** * Add a short to the container if it is not present, otherwise remove it. May generate a new container. * * @param x short to be added * @return the new container */ public abstract Container iflip(short x); /** * Computes the distinct number of short values in the container. Can be expected to run in constant time. * * @return the cardinality */ public abstract int getCardinality(); /** * Get the name of this container. * * @return name of the container */ public String getContainerName() { if (this instanceof EmptyContainer) { return ContainerNames[0]; } if (this instanceof SingletonContainer) { return ContainerNames[1]; } if (this instanceof SingleRangeContainer) { return ContainerNames[2]; } if (this instanceof TwoValuesContainer) { return ContainerNames[3]; } if (this instanceof ArrayContainer) { return ContainerNames[4]; } if (this instanceof BitmapContainer) { return ContainerNames[5]; } if (this instanceof RunContainer) { return ContainerNames[6]; } throw new IllegalStateException(myType()); } /** * Name of the various possible containers */ public static final String[] ContainerNames = { "empty", "singleton", "singlerange", "twovalues", "array", "bitmap", "run"}; /** * Iterate through the values of this container in order and pass them along to the ShortConsumer. * * @param sc a shortConsumer * @return false if the consumer returned false at some point, true otherwise. */ public abstract boolean forEach(ShortConsumer sc); /** * Like forEach, but skipping the first rankOffset elements. * * @param rankOffset the position (rank) offset of the element where to start * @param sc a ShortConsumer * @return false if the consumer returned false at some point, true otherwise. */ public abstract boolean forEach(int rankOffset, ShortConsumer sc); public abstract boolean forEachRange(int rankOffset, ShortRangeConsumer sc); /** * Iterator to visit the short values in the container in descending order. * * @return iterator */ public abstract ShortAdvanceIterator getReverseShortIterator(); /** * Iterator to visit the short values in the container in ascending order. * * @return iterator */ public abstract ShortIterator getShortIterator(); /** * Gets an iterator to visit the contents of the container in batches of short values * * @param skipFromStartCount number of elements to skip from the start of the container. * @return iterator */ public abstract ContainerShortBatchIterator getShortBatchIterator(int skipFromStartCount); /** * Iterator to visit the short values in container in [start, end) ranges, in increasing order of start values. * * @return iterator */ public abstract SearchRangeIterator getShortRangeIterator(int skipFromStartCount); /** * Add all shorts in [begin,end) using an unsigned interpretation. May generate a new container. * * @param begin start of range (inclusive) * @param end end of range (exclusive) * @return the new container */ public abstract Container iadd(int begin, int end); /** * Add all shorts in [begin,end) using an unsigned interpretation. May generate a new container. The beginning of * the range should be strictly greater than the last value already present in the container, if there is one. * * @param begin start of range (inclusive) * @param end end of range (exclusive) * @return the new container */ public abstract Container iappend(int begin, int end); /** * Computes the in-place bitwise AND of this container with another (intersection). The current container is * generally modified, whereas the provided container (x) is unaffected. May generate a new container. * * @param x Another container * @return aggregated container */ public abstract Container iand(ArrayContainer x); /** * Computes the in-place bitwise AND of this container with another (intersection). The current container is * generally modified, whereas the provided container (x) is unaffected. May generate a new container. * * @param x Another container * @return aggregated container */ public abstract Container iand(BitmapContainer x); /** * Computes the in-place bitwise AND of this container with another (intersection). The current container is * generally modified, whereas the provided container (x) is unaffected. May generate a new container. * * @param x Another container * @return aggregated container */ public abstract Container iand(RunContainer x); private Container iand(final SingleRangeContainer sr) { return iandRange(sr.first(), sr.last() + 1); } /** * Computes the in-place bitwise AND of this container with another (intersection). The current container is * generally modified, whereas the provided container (x) is unaffected. May generate a new container. * * @param x Another container * @return aggregated container */ public Container iand(final Container x) { if (isEmpty() || x.isEmpty()) { return Container.empty(); } if (x instanceof SingletonContainer) { return and((SingletonContainer) x); } if (x instanceof SingleRangeContainer) { return iand((SingleRangeContainer) x); } if (x instanceof TwoValuesContainer) { return and((TwoValuesContainer) x); } if (x instanceof ArrayContainer) { return iand((ArrayContainer) x); } if (x instanceof BitmapContainer) { return iand((BitmapContainer) x); } if (x instanceof RunContainer) { return iand((RunContainer) x); } throw new IllegalStateException(x.myType()); } /** * Computes the in-place bitwise ANDNOT of this container with another (difference). The current container is * generally modified, whereas the provided container (x) is unaffected. May generate a new container. * * @param x Another container * @return aggregated container */ public abstract Container iandNot(ArrayContainer x); /** * Computes the in-place bitwise ANDNOT of this container with another (difference). The current container is * generally modified, whereas the provided container (x) is unaffected. May generate a new container. * * @param x Another container * @return aggregated container */ public abstract Container iandNot(BitmapContainer x); /** * Computes the in-place bitwise ANDNOT of this container with another (difference). The current container is * generally modified, whereas the provided container (x) is unaffected. May generate a new container. * * @param x Another container * @return aggregated container */ public abstract Container iandNot(RunContainer x); private Container iandNot(final SingletonContainer sc) { return iunset(sc.value); } private Container iandNot(final SingleRangeContainer sr) { return iremove(sr.first(), sr.last() + 1); } private Container iandNot(final TwoValuesContainer tv) { final PositionHint hint = new PositionHint(); return iunset(tv.v1, hint).iunset(tv.v2, hint); } /** * Computes the in-place bitwise ANDNOT of this container with another (difference). The current container is * generally modified, whereas the provided container (x) is unaffected. May generate a new container. * * @param x Another container * @return aggregated container */ public Container iandNot(final Container x) { if (isEmpty()) { return Container.empty(); } if (x.isEmpty()) { return this; } if (x instanceof SingletonContainer) { return iandNot((SingletonContainer) x); } if (x instanceof SingleRangeContainer) { return iandNot((SingleRangeContainer) x); } if (x instanceof TwoValuesContainer) { return iandNot((TwoValuesContainer) x); } if (x instanceof ArrayContainer) { return iandNot((ArrayContainer) x); } if (x instanceof BitmapContainer) { return iandNot((BitmapContainer) x); } if (x instanceof RunContainer) { return iandNot((RunContainer) x); } throw new IllegalStateException(x.myType()); } /** * Computes the in-place bitwise NOT of this container (complement). Only those bits within the range are affected. * The current container is generally modified. May generate a new container. * * @param rangeStart beginning of range (inclusive); 0 is beginning of this container. * @param rangeEnd ending of range (exclusive) * @return (partially) complemented container */ public abstract Container inot(int rangeStart, int rangeEnd); /** * Computes the in-place bitwise OR of this container with another (union). The current container is generally * modified, whereas the provided container (x) is unaffected. May generate a new container. * * @param x Another container * @return aggregated container */ public abstract Container ior(ArrayContainer x); /** * Computes the in-place bitwise OR of this container with another (union). The current container is generally * modified, whereas the provided container (x) is unaffected. May generate a new container. * * @param x Another container * @return aggregated container */ public abstract Container ior(BitmapContainer x); /** * Computes the in-place bitwise OR of this container with another (union). The current container is generally * modified, whereas the provided container (x) is unaffected. May generate a new container. * * @param x Another container * @return aggregated container */ public abstract Container ior(RunContainer x); private Container ior(final SingletonContainer sc) { return iset(sc.value); } private Container ior(final SingleRangeContainer sr) { return iadd(sr.first(), sr.last() + 1); } private Container ior(final TwoValuesContainer tv) { final PositionHint hint = new PositionHint(); final Container ans = iset(tv.v1, hint); return ans.iset(tv.v2, hint); } /** * Computes the in-place bitwise OR of this container with another (union). The current container is generally * modified, whereas the provided container (x) is unaffected. May generate a new container. * * @param x Another container * @return aggregated container */ public Container ior(final Container x) { if (isEmpty()) { if (x.isEmpty()) { return Container.empty(); } return x.cowRef(); } if (x.isEmpty()) { return this; } if (x instanceof SingletonContainer) { return ior((SingletonContainer) x); } if (x instanceof SingleRangeContainer) { return ior((SingleRangeContainer) x); } if (x instanceof TwoValuesContainer) { return ior((TwoValuesContainer) x); } if (x instanceof ArrayContainer) { return ior((ArrayContainer) x); } if (x instanceof BitmapContainer) { return ior((BitmapContainer) x); } if (x instanceof RunContainer) { return ior((RunContainer) x); } throw new IllegalStateException(x.myType()); } /** * Remove shorts in [begin,end) using an unsigned interpretation. May generate a new container. * * @param begin start of range (inclusive) * @param end end of range (exclusive) * @return the new container */ public abstract Container iremove(int begin, int end); /** * Computes the in-place bitwise XOR of this container with another (symmetric difference). The current container is * generally modified, whereas the provided container (x) is unaffected. May generate a new container. * * @param x Another container * @return aggregated container */ public abstract Container ixor(ArrayContainer x); /** * Computes the in-place bitwise XOR of this container with another (symmetric difference). The current container is * generally modified, whereas the provided container (x) is unaffected. May generate a new container. * * @param x Another container * @return aggregated container */ public abstract Container ixor(BitmapContainer x); /** * Computes the in-place bitwise XOR of this container with another (symmetric difference). The current container is * generally modified, whereas the provided container (x) is unaffected. May generate a new container. * * @param x Another container * @return aggregated container */ public abstract Container ixor(RunContainer x); private Container ixor(final SingletonContainer sc) { return iflip(sc.value); } private Container ixor(final SingleRangeContainer sr) { return inot(sr.first(), sr.last() + 1); } private Container ixor(final TwoValuesContainer tv) { return iflip(tv.v1).iflip(tv.v2); } /** * Computes the in-place bitwise XOR of this container with another. The current container is generally modified, * whereas the provided container (x) is unaffected. May generate a new container. * * @param x Another container * @return xor result as a new container reference */ public Container ixor(final Container x) { if (isEmpty()) { return x.cowRef(); } if (x.isEmpty()) { return this; } if (x instanceof SingletonContainer) { return ixor((SingletonContainer) x); } if (x instanceof SingleRangeContainer) { return ixor((SingleRangeContainer) x); } if (x instanceof TwoValuesContainer) { return ixor((TwoValuesContainer) x); } if (x instanceof ArrayContainer) { return ixor((ArrayContainer) x); } if (x instanceof BitmapContainer) { return ixor((BitmapContainer) x); } if (x instanceof RunContainer) { return ixor((RunContainer) x); } throw new IllegalStateException(x.myType()); } /** * Computes the bitwise NOT of this container (complement). Only those bits within the range are affected. This is * equivalent to an xor with a range of ones for the given range. The current container is left unaffected. * * @param rangeStart beginning of range (inclusive); 0 is beginning of this container. * @param rangeEnd ending of range (exclusive) * @return (partially) complemented container */ public abstract Container not(int rangeStart, int rangeEnd); abstract int numberOfRuns(); // exact /** * Computes the number of ranges that a RangeIterator would provide on this container. * * @return The number of ranges that a RangeIterator would provide on this container. */ @SuppressWarnings("unused") public int numberOfRanges() { return numberOfRuns(); } /** * Computes the bitwise OR of this container with another (union). This container as well as the provided container * are left unaffected. * * @param x Another container * @return aggregated container */ public abstract Container or(ArrayContainer x); /** * Computes the bitwise OR of this container with another (union). This container as well as the provided container * are left unaffected. * * @param x Another container * @return aggregated container */ public abstract Container or(BitmapContainer x); /** * Computes the bitwise OR of this container with another (union). This container as well as the provided container * are left unaffected. * * @param x Another container * @return aggregated container */ public abstract Container or(RunContainer x); private Container or(final SingletonContainer sc) { return set(sc.value); } private Container or(final SingleRangeContainer sr) { return add(sr.first(), sr.last() + 1); } private Container or(final TwoValuesContainer tv) { final PositionHint hint = new PositionHint(); final Container ans = set(tv.v1, hint); return ans.iset(tv.v2, hint); } /** * Computes the bitwise OR of this container with another (union). This container as well as the provided container * are left unaffected. * * @param x Another container * @return aggregated container */ public Container or(final Container x) { if (isEmpty()) { if (x.isEmpty()) { return Container.empty(); } return x.deepCopy(); } if (x.isEmpty()) { return deepCopy(); } if (x instanceof SingletonContainer) { return or((SingletonContainer) x); } if (x instanceof SingleRangeContainer) { return or((SingleRangeContainer) x); } if (x instanceof TwoValuesContainer) { return or((TwoValuesContainer) x); } if (x instanceof ArrayContainer) { return or((ArrayContainer) x); } if (x instanceof BitmapContainer) { return or((BitmapContainer) x); } if (x instanceof RunContainer) { return or((RunContainer) x); } throw new IllegalStateException(x.myType()); } /** * Rank returns the number of integers that are smaller or equal to x (Rank(infinity) would be GetCardinality()). * * @param lowbits upper limit * @return the rank */ public abstract int rank(short lowbits); /** * Return a new container with all shorts in [begin,end) remove using an unsigned interpretation. * * @param begin start of range (inclusive) * @param end end of range (exclusive) * @return the new container */ public abstract Container remove(int begin, int end); /** * Remove the short from this container. May create a new container. Note this legacy method does not respect the * naming convention of an i prefix for inplace operations; prefer iunset. * * @param x to be removed * @return resulting container. */ @Deprecated public final Container remove(short x) { return iunset(x); } /** * Remove the short from this container. May create a new container. * * @param x to be removed * @return resulting container. */ public abstract Container unset(short x); /** * Create a new container with the short removed. * * @param x to be removed * @return New container without x. */ public abstract Container iunset(short x); /** * Convert to RunContainers, when the result is smaller. Overridden by RunContainer to possibility switch from * RunContainer to a smaller alternative. Overridden by BitmapContainer with a more efficient approach. * * @return the new container */ public abstract Container runOptimize(); /** * Return the jth value * * @param j index of the value * @return the value */ public abstract short select(int j); /** * Returns a new container with all values between ranks startPos and endPos. * * @param startRank rank for the start of the range * @param endRank rank for the end of the range, exclusive * @return a new Container with all the values between ranks [startPos, endPos) */ public abstract Container select(int startRank, int endRank); /** * Searches for the specified short value * * @param x value to search for * @return Relative position of the value in the sorted set of elements in this container, in the range [0 .. * cardinality - 1]. If not present, (-(insertion point) - 1) similar to Array.binarySearch. *

* For values of x that {@link io.deephaven.engine.rowset.impl.rsp.container.Container#contains} returns * true, this method returns the same value as * {@link io.deephaven.engine.rowset.impl.rsp.container.Container#rank}. */ public abstract int find(short x); /** * As select but for all the positions in a range. * * @param outValues accept is called in this consumer for each resulting range. * @param inPositions input iterator that provides the position ranges. */ public abstract void selectRanges(RangeConsumer outValues, RangeIterator inPositions); /** * As find but for all the values in a range. * * @param outPositions accept is called in this consumer for each resulting position range. * @param inValues input iterator that provides the key ranges; these must each exist in the container. * @param maxPos maximum position to add to outPositions; values of position > maxPos are not added. * @return true if maxPos was reached, false otherwise. */ public abstract boolean findRanges(RangeConsumer outPositions, RangeIterator inValues, int maxPos); /** * If possible, recover wasted memory. */ public abstract void trim(); /** * Computes the bitwise XOR of this container with another (symmetric difference). This container as well as the * provided container are left unaffected. * * @param x Another container * @return aggregated container */ public abstract Container xor(ArrayContainer x); /** * Computes the bitwise XOR of this container with another (symmetric difference). This container as well as the * provided container are left unaffected. * * @param x Another container * @return aggregated container */ public abstract Container xor(BitmapContainer x); /** * Computes the bitwise XOR of this container with another (symmetric difference). This container as well as the * provided container are left unaffected. * * @param x Another container * @return aggregated container */ public abstract Container xor(RunContainer x); private Container xor(final SingletonContainer sc) { return cowRef().iflip(sc.value); } private Container xor(final SingleRangeContainer sr) { return not(sr.first(), sr.last() + 1); } private Container xor(final TwoValuesContainer tv) { return cowRef().iflip(tv.v1).iflip(tv.v2); } /** * Computes the bitwise OR of this container with another (symmetric difference). This container as well as the * provided container are left unaffected. * * @param x other parameter * @return aggregated container */ public Container xor(final Container x) { if (isEmpty()) { if (x.isEmpty()) { return Container.empty(); } return x.cowRef(); } if (x.isEmpty()) { return cowRef(); } if (x instanceof SingletonContainer) { return xor((SingletonContainer) x); } if (x instanceof SingleRangeContainer) { return xor((SingleRangeContainer) x); } if (x instanceof TwoValuesContainer) { return xor((TwoValuesContainer) x); } if (x instanceof ArrayContainer) { return xor((ArrayContainer) x); } if (x instanceof BitmapContainer) { return xor((BitmapContainer) x); } if (x instanceof RunContainer) { return xor((RunContainer) x); } throw new IllegalStateException(x.myType()); } /** * Convert the current container to a BitmapContainer, if a conversion is needed. If the container is already a * bitmap, the container is returned unchanged. *

* When multiple container "merge" operations are done it might be more efficient to convert to bitmap first, and * then at the end convert to the efficient container type, to avoid multiple container type conversions, since * bitmap can always stay a bitmap. * * @return a bitmap container */ public abstract BitmapContainer toBitmapContainer(); // For tests. abstract Container toLargeContainer(); /** * Gets the first value greater than or equal to the lower bound, or -1 if no such value exists. * * @param fromValue the lower bound (inclusive) * @return the next value */ public abstract int nextValue(short fromValue); /** * Get the first integer held in the container * * @return the first integer in the container * @throws NoSuchElementException if empty */ public abstract int first(); /** * Get the last integer held in the container * * @return the last integer in the container * @throws NoSuchElementException if empty */ public abstract int last(); /** * @param x Another container * @return true if every key in this container is also a key in x. */ public abstract boolean subsetOf(ArrayContainer x); /** * @param x Another container * @return true if every key in this container is also a key in x. */ public abstract boolean subsetOf(BitmapContainer x); /** * @param x Another container * @return true if every key in this container is also a key in x. */ public abstract boolean subsetOf(RunContainer x); private boolean subsetOf(final SingletonContainer sc) { return getCardinality() == 1 && first() == sc.intValue(); } private boolean subsetOf(final SingleRangeContainer sr) { return sr.first() <= first() && last() <= sr.last(); } private boolean subsetOf(final TwoValuesContainer tv) { final int card = getCardinality(); if (card > 2) { return false; } if (card == 2) { return first() == tv.first() && last() == tv.last(); } final int v = first(); return v == tv.v1AsInt() || v == tv.v2AsInt(); } /** * @param x Another container * @return true if every key in this container is also a key in x. */ public boolean subsetOf(final Container x) { if (isEmpty()) { return true; } if (x.isEmpty()) { return false; } if (x instanceof SingletonContainer) { return subsetOf((SingletonContainer) x); } if (x instanceof SingleRangeContainer) { return subsetOf((SingleRangeContainer) x); } if (x instanceof TwoValuesContainer) { return subsetOf((TwoValuesContainer) x); } if (x instanceof ArrayContainer) { return subsetOf((ArrayContainer) x); } if (x instanceof BitmapContainer) { return subsetOf((BitmapContainer) x); } if (x instanceof RunContainer) { return subsetOf((RunContainer) x); } throw new IllegalStateException(x.myType()); } /** * @param x Another container * @return true if some key in this container is also a key in x. */ public final boolean intersects(final Container x) { return overlaps(x); } /** * @param start the beginning of the range, as an int. * @param end the end of the range (exclusive), as an int. * @return true if there is any element in this container in the range provided. */ public final boolean intersects(final int start, final int end) { return overlapsRange(start, end); } /** * @param x Another container * @return true if at least one key in this container is also a key in x. */ public abstract boolean overlaps(ArrayContainer x); /** * @param x Another container * @return true if at least one key in this container is also a key in x. */ public abstract boolean overlaps(BitmapContainer x); /** * @param x Another container * @return true if at least one key in this container is also a key in x. */ public abstract boolean overlaps(RunContainer x); /** * @param start the beginning of the range, as an int. * @param end the end of the range (exclusive), as an int. * @return true if there is any element in this container in the range provided. */ public abstract boolean overlapsRange(int start, int end); private boolean overlaps(final SingletonContainer sc) { return contains(sc.value); } private boolean overlaps(final SingleRangeContainer sr) { return overlapsRange(sr.first(), sr.last() + 1); } private boolean overlaps(final TwoValuesContainer tv) { return contains(tv.v1) || contains(tv.v2); } /** * @param x Another container * @return true if some key in this container is also a key in x. */ public boolean overlaps(final Container x) { if (isEmpty() || x.isEmpty()) { return false; } if (x instanceof SingletonContainer) { return overlaps((SingletonContainer) x); } if (x instanceof SingleRangeContainer) { return overlaps((SingleRangeContainer) x); } if (x instanceof TwoValuesContainer) { return overlaps((TwoValuesContainer) x); } if (x instanceof ArrayContainer) { return overlaps((ArrayContainer) x); } if (x instanceof BitmapContainer) { return overlaps((BitmapContainer) x); } if (x instanceof RunContainer) { return overlaps((RunContainer) x); } throw new IllegalStateException(x.myType()); } /* * Instruct this container to never modify itself with mutation operations, and instead always return a new * container. */ public abstract void setCopyOnWrite(); /** * @return The allocated size in bytes of the underlying array backing store used by this container. */ public abstract int bytesAllocated(); /** * @return The size in bytes of the used portion out of the total allocated bytes for the underlying array backing * store used by this container. */ @SuppressWarnings("unused") public abstract int bytesUsed(); /** * Insert a value in the current container. May modify the existing container or return a new one. If positionHint * is greater or equal than zero, it is taken to be a container-specific position hint to help speed up the * insertion; this can be obtained from previous calls to any method taking a hint to help speedup a sequence of * operations done in increasing value order. Before returning, the method stores in positionHint a valid value for * a subsequent calls to methods taking a hint, which can be used on the returned container for a value greater than * the one provided in this call. * * @param x the value to insert * @param positionHint a position hint to speed up insertion specific to a container, returned from a previous call * to a hint taking method, or -1 if none available. Updated to a valid hint for a subsequent call to a hint * taking method on the returned container; if that subsequent call uses the hint it should be for an * argument bigger than x provided in this call. * @return A container with the value to be inserted added; this container may or may not be a modification on the * object on which the call was performed; the value in positionHint after return would be valid on the * returned container. */ abstract Container iset(short x, PositionHint positionHint); /** * Return a new container container everything in the existing container plus the provided value; does not modify * the existing container. If positionHint is greater or equal than zero, it is taken to be a container-specific * position hint to help speed up the insertion; this can be obtained from previous calls to any method taking a * hint to help speedup a sequence of operations done in increasing value order. Before returning, the method stores * in positionHint a valid value for a subsequent calls to methods taking a hint, which can be used on the returned * container for a value greater than the one provided in this call. * * @param x the value to insert * @param positionHint a position hint to speed up insertion specific to a container, returned from a previous call * to a hint taking method, or -1 if none available. Updated to a valid hint for a subsequent call to a hint * taking method on the returned container; if that subsequent call uses the hint it should be for an * argument bigger than x provided in this call. * @return A new container with the value to be inserted added; the value in positionHint after return would be * valid on the returned container. */ abstract Container set(short x, PositionHint positionHint); /** * Remove a value in the current container. May modify the existing container or return a new one. If positionHint * is greater or equal than zero, it is taken to be a container-specific position hint to help speed up the removal; * this can be obtained from previous calls to any method taking a hint to help speedup a sequence of operations * done in increasing value order. Before returning, the method stores in positionHint a valid value for a * subsequent calls to methods taking a hint, which can be used on the returned container for a value greater than * the one provided in this call. * * @param x the value to remove * @param positionHint a position hint to speed up removal specific to a container, returned from a previous call to * a hint taking method, or -1 if none available. Updated to a valid hint for a subsequent call to a hint * taking method on the returned container; if that subsequent call uses the hint it should be for an * argument bigger than x provided in this call. * @return A container with the value removed; this container may or may not be a modification on the object on * which the call was performed; the value in positionHint after return would be valid on the returned * container. */ abstract Container iunset(short x, PositionHint positionHint); /** * Return a new container with every value in the existing container except for the provided argument; the existing * container is not modified. If positionHint is greater or equal than zero, it is taken to be a container-specific * position hint to help speed up the removal; this can be obtained from previous calls to any method taking a hint * to help speedup a sequence of operations done in increasing value order. Before returning, the method stores in * positionHint a valid value for a subsequent calls to methods taking a hint, which can be used on the returned * container for a value greater than the one provided in this call. * * @param x the value to remove * @param positionHint a position hint to speed up removal specific to a container, returned from a previous call to * a hint taking method, or -1 if none available. Updated to a valid hint for a subsequent call to a hint * taking method on the returned container; if that subsequent call uses the hint it should be for an * argument bigger than x provided in this call. * @return A new container with the value removed; this container may or may not be a modification on the object on * which the call was performed; the value in positionHint after return would be valid on the returned * container. */ abstract Container unset(short x, PositionHint positionHint); @Override public String toString() { StringBuilder sb = new StringBuilder(); final RangeIterator rit = this.getShortRangeIterator(0); final int maxRanges = 99; int range = 0; sb.append("{ "); while (rit.hasNext() && range < maxRanges) { rit.next(); final int first = rit.start(); final int last = rit.end() - 1; if (range > 0) { sb.append(","); } sb.append(first); if (last != first) { sb.append("-").append(last); } ++range; } if (rit.hasNext()) { int prevStart = -1; int prevLast = -1; int prevRange = range; while (rit.hasNext()) { rit.next(); prevStart = rit.start(); prevLast = rit.end() - 1; ++prevRange; } if (prevRange > range + 1) { sb.append(", ... "); } sb.append(","); sb.append(prevStart); if (prevLast != prevStart) { sb.append("-").append(prevLast); } } sb.append(" }"); return sb.toString(); } public abstract boolean isShared(); // @VisibleForTesting final boolean sameContents(final Container other) { if (other.getCardinality() != getCardinality()) { return false; // should be a frequent branch if they differ } return subsetOf(other); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy