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

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

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

final class BitmapContainerRangeIterator implements SearchRangeIterator {
    private final long[] bitmap;

    private int x; // position in the bitmap array, for our next value.
    private long w; // remaining bits not returned by the iterator yet from the word at position x.
    private int start; // start of the current range.
    private int end; // end of the current range, exclusive.
    private int offset; // bit offset in bitmap[x] where w begins.
    private boolean hasNext;

    public BitmapContainerRangeIterator(final BitmapContainer p) {
        this(p, 0);
    }

    public BitmapContainerRangeIterator(final BitmapContainer p, int initialSkipCount) {
        bitmap = p.bitmap;
        x = 0;
        offset = 0;
        w = bitmap[0];
        int remaining = initialSkipCount;
        while (true) {
            final int bitCount = Long.bitCount(w);
            if (remaining < bitCount) {
                for (int i = 0; i < remaining; ++i) {
                    int shift = lowestBit(w) + 1;
                    offset += shift;
                    w = w >>> shift;
                }
                break;
            }
            remaining -= bitCount;
            if (x >= 1023) {
                w = 0;
                break;
            }
            ++x;
            w = bitmap[x];
        }
        start = end = -1;
        hasNext = eatZeroes();
    }

    // move x and shift w until the first bit set is found, or we run out of bitmap.
    // return whether "hasNext".
    private boolean eatZeroes() {
        if (x >= bitmap.length) {
            return false;
        }
        // Advance x until the word at x has some bit set;
        // set offset to point to that first bit set if there is one.
        // If not, we ran out of ranges.
        if (w == 0) {
            offset = 0;
            while (++x < bitmap.length) {
                w = bitmap[x];
                if (w != 0) {
                    break;
                }
            }
            if (w == 0) {
                return false;
            }
        }
        // w != 0
        int zbits = lowestBit(w);
        offset += zbits;
        w = w >>> zbits;
        return true;
    }

    BitmapContainerRangeIterator(final BitmapContainerRangeIterator other) {
        this.bitmap = other.bitmap;
        this.x = other.x;
        this.w = other.w;
        this.start = other.start;
        this.end = other.end;
        this.offset = other.offset;
        this.hasNext = other.hasNext;
    }

    public BitmapContainerRangeIterator copy() {
        return new BitmapContainerRangeIterator(this);
    }

    @Override
    public boolean hasNext() {
        return hasNext;
    }

    @Override
    public int start() {
        return start;
    }

    @Override
    public int end() {
        return end;
    }

    @Override
    public void next() {
        // given invariants, at this point `(w & 1) != 0`.
        start = 64 * x + offset;
        int oneBits = lowestBit(w ^ ~0L); // oneBits is at least 1.
        offset += oneBits;
        w = w >>> oneBits;
        if (offset == 64) {
            offset = 0;
            do {
                ++x;
                if (x >= bitmap.length) {
                    end = 0xFFFF + 1;
                    hasNext = false;
                    return;
                }
                w = bitmap[x];
            } while (w == ~0L);
            // w has /some/ zero bit.
            oneBits = lowestBit(w ^ ~0L);
            offset += oneBits;
            w = w >>> oneBits;
        }
        end = 64 * x + offset;
        hasNext = eatZeroes();
    }

    @Override
    public boolean advance(final int v) {
        if (start == -1) {
            if (!hasNext()) {
                return false;
            }
            next();
        }
        if (v < end) {
            if (start < v) {
                start = v;
            }
            return true;
        }
        final int p = v >> 6; // v / 64.
        final int poffset = v & 63; // v % 64.
        x = p;
        if (x >= bitmap.length) {
            return false;
        }
        offset = poffset;
        w = bitmap[x] >>> offset;
        hasNext = eatZeroes();
        if (!hasNext()) {
            return false;
        }
        next();
        if (start < v) {
            start = v;
        }
        return true;
    }

    private void setTo(final int i, final int ioffset) {
        x = i;
        w = bitmap[x];
        offset = ioffset;
        w = w >>> offset;
        next();
    }

    private static int lowestBit(final long v) {
        return Long.numberOfTrailingZeros(v);
    }

    private static int highestBit(final long v) {
        return 63 - Long.numberOfLeadingZeros(v);
    }

    private static long maskForAllBitsSetFromOffsetToHigher(final int offset) {
        return ~0L << offset;
    }

    @Override
    public boolean search(final ContainerUtil.TargetComparator comp) {
        if (start == -1) {
            if (!hasNext()) {
                return false;
            }
            next();
        }
        int c = comp.directionFrom(start);
        if (c <= 0) {
            return (c == 0);
        }
        int j = bitmap.length - 1;
        while (j > 0 && bitmap[j] == 0) {
            --j; // seek backward
        }
        // (j,joffset) will be our cursor to the higher words with invariant directionToTarget < 0.
        int joffset = highestBit(bitmap[j]);
        int jv = 64 * j + joffset;
        if (comp.directionFrom(jv) >= 0) {
            x = bitmap.length;
            start = jv;
            end = start + 1;
            hasNext = false;
            return true;
        }
        // (i,ioffset) will be our cursor to the lower words with invariant directionToTarget >= 0.
        int i = start >>> 6; // v / 64.
        int ioffset = start & 63; // v % 64.
        int iv = start;
        while (true) {
            int mv = (iv + jv) / 2;
            int m = mv >>> 6; // mv / 64.
            int moffset = mv & 63; // mv % 64.
            boolean tryLowerBits = false;
            final long mask = maskForAllBitsSetFromOffsetToHigher(moffset);
            long masked = bitmap[m] & mask;
            if (masked == 0) {
                // We will try towards the higher words first. Don't clobber m as we may realize we need to go towards
                // lower words from m instead.
                int m2 = m;
                do {
                    ++m2;
                    // by construction, bitmap[j] != 0 on entry, and m <= j, so this loop will end before
                    // mm > bitmap.length - 1.
                } while (bitmap[m2] == 0);
                // since we are moving towards higher words, the lowest bit is the one closer to the original
                // (m,moffset) target.
                int m2offset = lowestBit(bitmap[m2]);
                if (m2 == j && m2offset == joffset) {
                    // Going towards higher words we ended up in the same place we started, and there are no more lower
                    // bits.
                    // Try indexes from m towards the lower words instead.
                    tryLowerBits = true;
                } else {
                    m = m2;
                    moffset = m2offset;
                    mv = 64 * m + moffset;
                }
            } else {
                moffset = lowestBit(masked);
                if (m == j && moffset == joffset) {
                    tryLowerBits = true;
                } else {
                    mv = 64 * m + moffset;
                }
            }
            if (tryLowerBits) {
                masked = bitmap[m] & ~mask;
                if (masked != 0) {
                    moffset = highestBit(masked);
                    mv = 64 * m + moffset;
                    // We already found (j,joffset) to the highest words. If this happens to be (i,ioffset)
                    // we are done. That check will happen a bit later.
                } else {
                    do {
                        --m;
                        // by construction, bitmap[i] != 0 on entry, and i <= m, so this loop will end before m < 0.
                    } while (bitmap[m] == 0);
                    moffset = highestBit(bitmap[m]);
                    mv = 64 * m + moffset;
                    // We already found (j,joffset) to the highest words. If this happens to be (i,ioffset)
                    // we are done. That check will happen a bit later.
                }
            }
            if (mv <= iv || mv >= jv) {
                setTo(i, ioffset);
                return true;
            }
            c = comp.directionFrom(mv);
            if (c < 0) {
                jv = mv;
                j = m;
                joffset = moffset;
                continue;
            }
            if (c > 0) {
                iv = mv;
                i = m;
                ioffset = moffset;
                continue;
            }
            // c == 0.
            setTo(m, moffset);
            return true;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy