package com.googlecode.javaewah;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.PriorityQueue;

/*
 * Copyright 2009-2016, Daniel Lemire, Cliff Moon, David McIntosh, Robert Becho, Google Inc., Veronika Zenz, Owen Kaser, Gregory Ssi-Yan-Kai, Rory Graves
 * Licensed under the Apache License, Version 2.0.
 */

/**
 * Fast algorithms to aggregate many bitmaps. These algorithms are just given as
 * reference. They may not be faster than the corresponding methods in the
 * EWAHCompressedBitmap class.
 *
 * @author Daniel Lemire
 */
public final class FastAggregation {

    /** Private constructor to prevent instantiation */
    private FastAggregation() {}

    /**
     * Compute the and aggregate using a temporary uncompressed bitmap.
     *
     * This function does not seek to match the "sizeinbits" attributes
     * of the input bitmaps.
     *
     * @param bitmaps the source bitmaps
     * @param bufSize buffer size used during the computation in 64-bit
     *                words (per input bitmap)
     * @return the or aggregate.
     */
    public static EWAHCompressedBitmap bufferedand(final int bufSize,
                                                   final EWAHCompressedBitmap... bitmaps) {
        EWAHCompressedBitmap answer = new EWAHCompressedBitmap();
        bufferedandWithContainer(answer, bufSize, bitmaps);
        return answer;
    }

    /**
     * Compute the and aggregate using a temporary uncompressed bitmap.
     *
     * This function does not seek to match the "sizeinbits" attributes
     * of the input bitmaps.
     *
     * @param container where the aggregate is written
     * @param bufSize   buffer size used during the computation in 64-bit
     *                  words (per input bitmap)
     * @param bitmaps   the source bitmaps
     */
    public static void bufferedandWithContainer(
            final BitmapStorage container, final int bufSize,
            final EWAHCompressedBitmap... bitmaps) {

        java.util.LinkedList<IteratingBufferedRunningLengthWord> al = new java.util.LinkedList<IteratingBufferedRunningLengthWord>();
        for (EWAHCompressedBitmap bitmap : bitmaps) {
            al.add(new IteratingBufferedRunningLengthWord(bitmap));
        }

        long[] hardbitmap = new long[bufSize * bitmaps.length];

        for (IteratingRLW i : al)
            if (i.size() == 0) {
                al.clear();
                break;
            }

        while (!al.isEmpty()) {
            Arrays.fill(hardbitmap, ~0l);
            long effective = Integer.MAX_VALUE;
            for (IteratingRLW i : al) {
                int eff = IteratorAggregation.inplaceand(
                        hardbitmap, i);
                if (eff < effective)
                    effective = eff;
            }
            for (int k = 0; k < effective; ++k)
                container.addWord(hardbitmap[k]);
            for (IteratingRLW i : al)
                if (i.size() == 0) {
                    al.clear();
                    break;
                }
        }
    }

    /**
     * Compute the or aggregate using a temporary uncompressed bitmap.
     *
     * @param bitmaps the source bitmaps
     * @param bufSize buffer size used during the computation in 64-bit
     *                words
     * @return the or aggregate.
     */
    public static EWAHCompressedBitmap bufferedor(final int bufSize,
                                                  final EWAHCompressedBitmap... bitmaps) {
        EWAHCompressedBitmap answer = new EWAHCompressedBitmap();
        bufferedorWithContainer(answer, bufSize, bitmaps);
        return answer;
    }

    /**
     * Compute the or aggregate using a temporary uncompressed bitmap.
     *
     * @param container where the aggregate is written
     * @param bufSize   buffer size used during the computation in 64-bit
     *                  words
     * @param bitmaps   the source bitmaps
     */
    public static void bufferedorWithContainer(
            final BitmapStorage container, final int bufSize,
            final EWAHCompressedBitmap... bitmaps) {
        int range = 0;
        EWAHCompressedBitmap[] sbitmaps = bitmaps.clone();
        Arrays.sort(sbitmaps, new Comparator<EWAHCompressedBitmap>() {
            @Override
            public int compare(EWAHCompressedBitmap a,
                               EWAHCompressedBitmap b) {
                return b.sizeInBits() - a.sizeInBits();
            }
        });

        java.util.ArrayList<IteratingBufferedRunningLengthWord> al = new java.util.ArrayList<IteratingBufferedRunningLengthWord>();
        for (EWAHCompressedBitmap bitmap : sbitmaps) {
            if (bitmap.sizeInBits() > range)
                range = bitmap.sizeInBits();
            al.add(new IteratingBufferedRunningLengthWord(bitmap));
        }
        long[] hardbitmap = new long[bufSize];
        int maxr = al.size();
        while (maxr > 0) {
            long effective = 0;
            for (int k = 0; k < maxr; ++k) {
                if (al.get(k).size() > 0) {
                    int eff = IteratorAggregation
                            .inplaceor(hardbitmap,
                                    al.get(k));
                    if (eff > effective)
                        effective = eff;
                } else
                    maxr = k;
            }
            for (int k = 0; k < effective; ++k)
                container.addWord(hardbitmap[k]);
            Arrays.fill(hardbitmap, 0);

        }
        container.setSizeInBitsWithinLastWord(range);
    }

    /**
     * Compute the xor aggregate using a temporary uncompressed bitmap.
     *
     * @param bitmaps the source bitmaps
     * @param bufSize buffer size used during the computation in 64-bit
     *                words
     * @return the xor aggregate.
     */
    public static EWAHCompressedBitmap bufferedxor(final int bufSize,
                                                   final EWAHCompressedBitmap... bitmaps) {
        EWAHCompressedBitmap answer = new EWAHCompressedBitmap();
        bufferedxorWithContainer(answer, bufSize, bitmaps);
        return answer;
    }

    /**
     * Compute the xor aggregate using a temporary uncompressed bitmap.
     *
     *
     * @param container where the aggregate is written
     * @param bufSize   buffer size used during the computation in 64-bit
     *                  words
     * @param bitmaps   the source bitmaps
     */
    public static void bufferedxorWithContainer(
            final BitmapStorage container, final int bufSize,
            final EWAHCompressedBitmap... bitmaps) {
        int range = 0;
        EWAHCompressedBitmap[] sbitmaps = bitmaps.clone();
        Arrays.sort(sbitmaps, new Comparator<EWAHCompressedBitmap>() {
            @Override
            public int compare(EWAHCompressedBitmap a,
                               EWAHCompressedBitmap b) {
                return b.sizeInBits() - a.sizeInBits();
            }
        });

        java.util.ArrayList<IteratingBufferedRunningLengthWord> al = new java.util.ArrayList<IteratingBufferedRunningLengthWord>();
        for (EWAHCompressedBitmap bitmap : sbitmaps) {
            if (bitmap.sizeInBits() > range)
                range = bitmap.sizeInBits();
            al.add(new IteratingBufferedRunningLengthWord(bitmap));
        }
        long[] hardbitmap = new long[bufSize];
        int maxr = al.size();
        while (maxr > 0) {
            long effective = 0;
            for (int k = 0; k < maxr; ++k) {
                if (al.get(k).size() > 0) {
                    int eff = IteratorAggregation.inplacexor(hardbitmap, al.get(k));
                    if (eff > effective)
                        effective = eff;
                } else
                    maxr = k;
            }
            for (int k = 0; k < effective; ++k)
                container.addWord(hardbitmap[k]);
            Arrays.fill(hardbitmap, 0);
        }
        container.setSizeInBitsWithinLastWord(range);
    }

    /**
     * Uses a priority queue to compute the or aggregate.
     *
     * This algorithm runs in linearithmic time (O(n log n)) with respect to the number of bitmaps.
     *
     * @param <T>     a class extending LogicalElement (like a compressed
     *                bitmap)
     * @param bitmaps bitmaps to be aggregated
     * @return the or aggregate
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    public static <T extends LogicalElement> T or(T... bitmaps) {
        PriorityQueue<T> pq = new PriorityQueue<T>(bitmaps.length,
                new Comparator<T>() {
                    @Override
                    public int compare(T a, T b) {
                        return a.sizeInBytes()
                                - b.sizeInBytes();
                    }
                }
        );
        Collections.addAll(pq, bitmaps);
        while (pq.size() > 1) {
            T x1 = pq.poll();
            T x2 = pq.poll();
            pq.add((T) x1.or(x2));
        }
        return pq.poll();
    }

    /**
     * Uses a priority queue to compute the or aggregate.
     *
     * The content of the container is overwritten.
     *
     * This algorithm runs in linearithmic time (O(n log n)) with respect to the number of bitmaps.
     *
     * @param container where we write the result
     * @param bitmaps   to be aggregated
     */
    public static void orToContainer(final BitmapStorage container,
                                     final EWAHCompressedBitmap... bitmaps) {
        if (bitmaps.length < 2)
            throw new IllegalArgumentException(
                    "We need at least two bitmaps");
        PriorityQueue<EWAHCompressedBitmap> pq = new PriorityQueue<EWAHCompressedBitmap>(
                bitmaps.length, new Comparator<EWAHCompressedBitmap>() {
            @Override
            public int compare(EWAHCompressedBitmap a,
                               EWAHCompressedBitmap b) {
                return a.sizeInBytes()
                        - b.sizeInBytes();
            }
        }
        );
        Collections.addAll(pq, bitmaps);
        while (pq.size() > 2) {
            EWAHCompressedBitmap x1 = pq.poll();
            EWAHCompressedBitmap x2 = pq.poll();
            pq.add(x1.or(x2));
        }
        pq.poll().orToContainer(pq.poll(), container);
    }

    /**
     * Simple algorithm that computes the OR aggregate.
     *
     * @param bitmaps input bitmaps
     * @return new bitmap containing the aggregate
     */
    public static EWAHCompressedBitmap or(final EWAHCompressedBitmap... bitmaps) {
        PriorityQueue<EWAHCompressedBitmap> pq = new PriorityQueue<EWAHCompressedBitmap>(bitmaps.length,
                new Comparator<EWAHCompressedBitmap>() {
                    @Override
                    public int compare(EWAHCompressedBitmap a, EWAHCompressedBitmap b) {
                        return a.sizeInBytes()
                                - b.sizeInBytes();
                    }
                }
        );
        Collections.addAll(pq, bitmaps);
        if(pq.isEmpty()) return new EWAHCompressedBitmap();
        while (pq.size() > 1) {
            EWAHCompressedBitmap x1 = pq.poll();
            EWAHCompressedBitmap x2 = pq.poll();
            pq.add(x1.or(x2));
        }
        return pq.poll();
    }

    /**
     * Simple algorithm that computes the XOR aggregate.
     *
     * @param bitmaps input bitmaps
     * @return new bitmap containing the aggregate
     */
    public static EWAHCompressedBitmap xor(final EWAHCompressedBitmap... bitmaps) {
        PriorityQueue<EWAHCompressedBitmap> pq = new PriorityQueue<EWAHCompressedBitmap>(bitmaps.length,
                new Comparator<EWAHCompressedBitmap>() {
                    @Override
                    public int compare(EWAHCompressedBitmap a, EWAHCompressedBitmap b) {
                        return a.sizeInBytes()
                                - b.sizeInBytes();
                    }
                }
        );
        Collections.addAll(pq, bitmaps);
        if(pq.isEmpty()) return new EWAHCompressedBitmap();
        while (pq.size() > 1) {
            EWAHCompressedBitmap x1 = pq.poll();
            EWAHCompressedBitmap x2 = pq.poll();
            pq.add(x1.xor(x2));
        }
        return pq.poll();
    }

    /**
     * Simple algorithm that computes the OR aggregate.
     *
     * @param bitmaps input bitmaps
     * @return new bitmap containing the aggregate
     */
    public static EWAHCompressedBitmap or(final Iterator<EWAHCompressedBitmap> bitmaps) {
        PriorityQueue<EWAHCompressedBitmap> pq = new PriorityQueue<EWAHCompressedBitmap>(32,
                new Comparator<EWAHCompressedBitmap>() {
                    @Override
                    public int compare(EWAHCompressedBitmap a, EWAHCompressedBitmap b) {
                        return a.sizeInBytes()
                                - b.sizeInBytes();
                    }
                }
        );
        while(bitmaps.hasNext())
            pq.add(bitmaps.next());
        if(pq.isEmpty()) return new EWAHCompressedBitmap();
        while (pq.size() > 1) {
            EWAHCompressedBitmap x1 = pq.poll();
            EWAHCompressedBitmap x2 = pq.poll();
            pq.add(x1.or(x2));
        }
        return pq.poll();
    }

    /**
     * Simple algorithm that computes the XOR aggregate.
     *
     * @param bitmaps input bitmaps
     * @return new bitmap containing the aggregate
     */
    public static EWAHCompressedBitmap xor(final Iterator<EWAHCompressedBitmap> bitmaps) {
        PriorityQueue<EWAHCompressedBitmap> pq = new PriorityQueue<EWAHCompressedBitmap>(32,
                new Comparator<EWAHCompressedBitmap>() {
                    @Override
                    public int compare(EWAHCompressedBitmap a, EWAHCompressedBitmap b) {
                        return a.sizeInBytes()
                                - b.sizeInBytes();
                    }
                }
        );
        while(bitmaps.hasNext())
            pq.add(bitmaps.next());
        if(pq.isEmpty()) return new EWAHCompressedBitmap();
        while (pq.size() > 1) {
            EWAHCompressedBitmap x1 = pq.poll();
            EWAHCompressedBitmap x2 = pq.poll();
            pq.add(x1.xor(x2));
        }
        return pq.poll();
    }

    /**
     * Uses a priority queue to compute the xor aggregate.
     *
     * This algorithm runs in linearithmic time (O(n log n)) with respect to the number of bitmaps.
     *
     * @param <T>     a class extending LogicalElement (like a compressed
     *                bitmap)
     * @param bitmaps bitmaps to be aggregated
     * @return the xor aggregate
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    public static <T extends LogicalElement> T xor(T... bitmaps) {
        PriorityQueue<T> pq = new PriorityQueue<T>(bitmaps.length,
                new Comparator<T>() {

                    @Override
                    public int compare(T a, T b) {
                        return a.sizeInBytes()
                                - b.sizeInBytes();
                    }
                }
        );
        Collections.addAll(pq, bitmaps);
        while (pq.size() > 1) {
            T x1 = pq.poll();
            T x2 = pq.poll();
            pq.add((T) x1.xor(x2));
        }
        return pq.poll();
    }

    /**
     * Uses a priority queue to compute the xor aggregate.
     *
     * The content of the container is overwritten.
     *
     * This algorithm runs in linearithmic time (O(n log n)) with respect to the number of bitmaps.
     *
     * @param container where we write the result
     * @param bitmaps   to be aggregated
     */
    public static void xorToContainer(final BitmapStorage container,
                                      final EWAHCompressedBitmap... bitmaps) {
        if (bitmaps.length < 2)
            throw new IllegalArgumentException(
                    "We need at least two bitmaps");
        PriorityQueue<EWAHCompressedBitmap> pq = new PriorityQueue<EWAHCompressedBitmap>(
                bitmaps.length, new Comparator<EWAHCompressedBitmap>() {
            @Override
            public int compare(EWAHCompressedBitmap a,
                               EWAHCompressedBitmap b) {
                return a.sizeInBytes()
                        - b.sizeInBytes();
            }
        }
        );
        Collections.addAll(pq, bitmaps);
        while (pq.size() > 2) {
            EWAHCompressedBitmap x1 = pq.poll();
            EWAHCompressedBitmap x2 = pq.poll();
            pq.add(x1.xor(x2));
        }
        pq.poll().xorToContainer(pq.poll(), container);
    }

}


package com.googlecode.javaewah;

import java.util.Iterator;

/*
 * Copyright 2009-2016, Daniel Lemire, Cliff Moon, David McIntosh, Robert Becho, Google Inc., Veronika Zenz, Owen Kaser, Gregory Ssi-Yan-Kai, Rory Graves
 * Licensed under the Apache License, Version 2.0.
 */

/**
 * Convenience functions for working over iterators
 */
public final class IteratorUtil {

    /** Private constructor to prevent instantiation */
    private IteratorUtil() {}

    /**
     * @param i iterator we wish to iterate over
     * @return an iterator over the set bits corresponding to the iterator
     */
    public static IntIterator toSetBitsIntIterator(final IteratingRLW i) {
        return new IntIteratorOverIteratingRLW(i);
    }

    /**
     * @param i iterator we wish to iterate over
     * @return an iterator over the set bits corresponding to the iterator
     */
    public static Iterator<Integer> toSetBitsIterator(final IteratingRLW i) {
        return new Iterator<Integer>() {
            @Override
            public boolean hasNext() {
                return this.under.hasNext();
            }

            @Override
            public Integer next() {
                return this.under.next();
            }

            @Override
            public void remove() {
            }

            private final IntIterator under = toSetBitsIntIterator(i);
        };

    }

    /**
     * Generate a bitmap from an iterator.
     *
     *
     *
     * @param i iterator we wish to materialize
     * @param c where we write
     */
    public static void materialize(final IteratingRLW i,
                                   final BitmapStorage c) {
        while (true) {
            if (i.getRunningLength() > 0) {
                c.addStreamOfEmptyWords(i.getRunningBit(), i.getRunningLength());
            }
            int il = i.getNumberOfLiteralWords();
            for (int k = 0; k < il ; ++k)
                c.addWord(i.getLiteralWordAt(k));
            if (!i.next())
                break;
        }
    }

    /**
     * @param i iterator we wish to iterate over
     * @return the cardinality (number of set bits) corresponding to the
     * iterator
     */
    public static int cardinality(final IteratingRLW i) {
        int answer = 0;
        while (true) {
            if (i.getRunningBit())
                answer += i.getRunningLength() * EWAHCompressedBitmap.WORD_IN_BITS;
            int lw = i.getNumberOfLiteralWords();
            for (int k = 0; k < lw ; ++k)
                answer += Long.bitCount(i.getLiteralWordAt(k));
            if (!i.next())
                break;
        }
        return answer;
    }

    /**
     * @param x set of bitmaps
     * @return an array of iterators corresponding to the array of bitmaps
     */
    public static IteratingRLW[] toIterators(
            final EWAHCompressedBitmap... x) {
        IteratingRLW[] X = new IteratingRLW[x.length];
        for (int k = 0; k < X.length; ++k) {
            X[k] = new IteratingBufferedRunningLengthWord(x[k]);
        }
        return X;
    }

    /**
     * Turn an iterator into a bitmap.
     *
     * @param i   iterator we wish to materialize
     * @param c   where we write
     * @param max maximum number of words we wish to materialize
     * @return how many words were actually materialized
     */
    public static long materialize(final IteratingRLW i,
                                   final BitmapStorage c, long max) {
        final long origMax = max;
        while (true) {
            if (i.getRunningLength() > 0) {
                long L = i.getRunningLength();
                if (L > max)
                    L = max;
                c.addStreamOfEmptyWords(i.getRunningBit(), L);
                max -= L;
            }
            long L = i.getNumberOfLiteralWords();
            for (int k = 0; k < L; ++k)
                c.addWord(i.getLiteralWordAt(k));
            if (max > 0) {
                if (!i.next())
                    break;
            } else
                break;
        }
        return origMax - max;
    }

    /**
     * Turn an iterator into a bitmap.
     *
     * This can be used to effectively clone a bitmap in the following
     * manner:
     *
     *  <code>
     *  EWAHCompressedBitmap n = IteratorUtil.materialize(bitmap.getIteratingRLW()));
     *  n.setSizeInBitsWithinLastWord(bitmap.sizeInBits());
     *  </code>
     *
     * @param i iterator we wish to materialize
     * @return materialized version of the iterator
     */
    public static EWAHCompressedBitmap materialize(final IteratingRLW i) {
        EWAHCompressedBitmap ewah = new EWAHCompressedBitmap();
        materialize(i, ewah);
        return ewah;
    }
}


package com.googlecode.javaewah.datastructure;

import java.util.Comparator;

/**
 * Special-purpose priority queue. Does limited error checking and supports
 * toss, buildHeap, poll, peek, percolateDown. It is faster than the equivalent
 * class from java.util.
 *
 * @param <T> object type
 * @author Owen Kaser
 * @since 0.8.0
 */
public final class PriorityQ<T> {
    final T[] a;
    int lastIndex;
    final Comparator<T> comp;

    /**
     * Construct a priority queue with a given capacity
     *
     * @param maxSize capacity
     * @param c       comparator
     */
    @SuppressWarnings("unchecked")
    public PriorityQ(final int maxSize, final Comparator<T> c) {
        this.a = (T[]) new Object[maxSize + 1];
        this.lastIndex = 0;
        this.comp = c;
    }

    /**
     * @return the size of the queue
     */
    public int size() {
        return this.lastIndex;
    }

    private int compare(T a, T b) {
        return this.comp.compare(a, b);
    }

    /**
     * Add an element at the end of the queue
     *
     * @param t element to be added
     */
    public void toss(final T t) {
        this.a[++this.lastIndex] = t;
    }

    /**
     * Look at the top of the heap
     *
     * @return the element on top
     */
    public T peek() {
        return this.a[1];
    }

    /**
     * build the heap...
     */
    public void buildHeap() {
        for (int i = this.lastIndex / 2; i > 0; --i) {
            percolateDown(i);
        }
    }

    /**
     * Signals that the element on top of the heap has been updated
     */
    public void percolateDown() {
        percolateDown(1);
    }

    private void percolateDown(int i) {
        T ai = this.a[i];
        while (true) {
            int l = 2 * i;
            int r = l + 1;
            int smallest = i;

            if (r <= this.lastIndex) { // then l also okay
                if (compare(this.a[l], ai) < 0) { // l beats i
                    smallest = l;
                    if (compare(this.a[r], this.a[smallest]) < 0)
                        smallest = r;
                } else if (compare(this.a[r], ai) < 0)
                    smallest = r;
            } else {// may have a l, don't have a r
                if ((l <= this.lastIndex)
                        && (compare(this.a[l], ai) < 0))
                    smallest = l;
            }
            if (i != smallest) {
                // conceptually, swap a[i]& a[smallest]
                // but as an opt., we use ai and just save at
                // end
                // temp = a[i];
                this.a[i] = this.a[smallest]; // move smallest
                // one up into
                // place of i
                i = smallest;
            } else {
                this.a[smallest] = ai;
                return;
            }
        }
    }

    /**
     * Remove the element on top of the heap
     *
     * @return the element being removed
     */
    public T poll() {
        T ans = this.a[1];
        this.a[1] = this.a[this.lastIndex--];
        percolateDown(1);
        return ans;
    }

    /**
     * Check whether the heap is empty.
     *
     * @return true if empty
     */
    public boolean isEmpty() {
        return this.lastIndex == 0;
    }
}


package com.googlecode.javaewah.symmetric;

import com.googlecode.javaewah.BitmapStorage;
import com.googlecode.javaewah.datastructure.BitSet;

import java.util.Iterator;
import java.util.List;

/**
 * This is a Java specification for an "updatable" Boolean function meant to run
 * over EWAH bitmaps.
 *
 * Reference:
 *
 * Daniel Lemire, Owen Kaser, Kamel Aouiche, Sorting improves word-aligned
 * bitmap indexes. Data & Knowledge Engineering 69 (1), pages 3-28, 2010.
 *
 * @author Daniel Lemire
 * @since 0.8.0
 */
public abstract class UpdateableBitmapFunction {
    EWAHPointer[] rw = new EWAHPointer[0];
    int hammingWeight = 0;
    int litWeight = 0;
    boolean[] b = new boolean[0];
    final BitSet litwlist = new BitSet(0);

    UpdateableBitmapFunction() {
    }

    /**
     * @return the current number of literal words
     */
    public final int getNumberOfLiterals() {
        return this.litwlist.cardinality();
    }

    /**
     * Goes through the literals.
     *
     * @return an iterator
     */
    public final Iterable<EWAHPointer> getLiterals() {
        return new Iterable<EWAHPointer>() {

            @Override
            public Iterator<EWAHPointer> iterator() {
                return new Iterator<EWAHPointer>() {
                    int k = UpdateableBitmapFunction.this.litwlist.nextSetBit(0);

                    @Override
                    public boolean hasNext() {
                        return this.k >= 0;
                    }

                    @Override
                    public EWAHPointer next() {
                        EWAHPointer answer = UpdateableBitmapFunction.this.rw[this.k];
                        this.k = UpdateableBitmapFunction.this.litwlist.nextSetBit(this.k + 1);
                        return answer;
                    }

                    @Override
                    public void remove() {
                        throw new RuntimeException("N/A");
                    }
                };
            }
        };
    }

    /**
     * append to the list the literal words as EWAHPointer
     *
     * @param container where we write
     */
    public final void fillWithLiterals(final List<EWAHPointer> container) {
        for (int k = this.litwlist.nextSetBit(0); k >= 0; k = this.litwlist.nextSetBit(k + 1)) {
            container.add(this.rw[k]);
        }
    }

    /**
     * @param newsize the number of inputs
     */
    public final void resize(final int newsize) {
        this.rw = java.util.Arrays.copyOf(this.rw, newsize);
        this.litwlist.resize(newsize);
        this.b = java.util.Arrays.copyOf(this.b, newsize);
    }

    /**
     * @param pos position of a literal
     */
    public void setLiteral(final int pos) {
        if (!this.litwlist.get(pos)) {
            this.litwlist.set(pos);
            this.litWeight++;
            if (this.b[pos]) {
                this.b[pos] = false;
                --this.hammingWeight;
            }
        }
    }

    /**
     * @param pos position where a literal was removed
     */
    public void clearLiteral(final int pos) {
        if (this.litwlist.get(pos)) {
            // litwlist.unset(pos);
            this.litwlist.set(pos, false);
            this.litWeight--;
        }
    }

    /**
     * @param pos position where a zero word was added
     */
    public final void setZero(final int pos) {
        if (this.b[pos]) {
            this.b[pos] = false;
            --this.hammingWeight;
        } else {
            clearLiteral(pos);
        }
    }

    /**
     * @param pos position were a 11...1 word was added
     */
    public final void setOne(final int pos) {
        if (!this.b[pos]) {
            clearLiteral(pos);
            this.b[pos] = true;
            ++this.hammingWeight;
        }
    }

    /**
     * Writes out the answer.
     *
     * @param out      output buffer
     * @param runBegin beginning of the run
     * @param runEnd   end of the run
     */
    public abstract void dispatch(BitmapStorage out, int runBegin, int runEnd);
}


package com.googlecode.javaewah;

import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;

/*
 * Copyright 2009-2016, Daniel Lemire, Cliff Moon, David McIntosh, Robert Becho, Google Inc., Veronika Zenz, Owen Kaser, Gregory Ssi-Yan-Kai, Rory Graves
 * Licensed under the Apache License, Version 2.0.
 */

/**
 * Set of helper functions to aggregate bitmaps.
 */
public final class IteratorAggregation {

    /** Private constructor to prevent instantiation */
    private IteratorAggregation() {}

    /**
     * @param x iterator to negate
     * @return negated version of the iterator
     */
    public static IteratingRLW not(final IteratingRLW x) {
        return new IteratingRLW() {

            @Override
            public boolean next() {
                return x.next();
            }

            @Override
            public long getLiteralWordAt(int index) {
                return ~x.getLiteralWordAt(index);
            }

            @Override
            public int getNumberOfLiteralWords() {
                return x.getNumberOfLiteralWords();
            }

            @Override
            public boolean getRunningBit() {
                return !x.getRunningBit();
            }

            @Override
            public long size() {
                return x.size();
            }

            @Override
            public long getRunningLength() {
                return x.getRunningLength();
            }

            @Override
            public void discardFirstWords(long y) {
                x.discardFirstWords(y);
            }

            @Override
            public void discardRunningWords() {
                x.discardRunningWords();
            }

            @Override
            public IteratingRLW clone()
                    throws CloneNotSupportedException {
                throw new CloneNotSupportedException();
            }

			@Override
			public void discardLiteralWords(long y) {
				x.discardLiteralWords(y);
			}
        };
    }

    /**
     * Aggregate the iterators using a bitmap buffer.
     *
     * @param al set of iterators to aggregate
     * @return and aggregate
     */
    public static IteratingRLW bufferedand(final IteratingRLW... al) {
        return bufferedand(DEFAULT_MAX_BUF_SIZE, al);
    }

    /**
     * Aggregate the iterators using a bitmap buffer.
     *
     * @param al      set of iterators to aggregate
     * @param bufSize size of the internal buffer used by the iterator in
     *                64-bit words (per input iterator)
     * @return and aggregate
     */
    public static IteratingRLW bufferedand(final int bufSize, final IteratingRLW... al) {
        if (al.length == 0)
            throw new IllegalArgumentException("Need at least one iterator");
        if (al.length == 1)
            return al[0];
        final LinkedList<IteratingRLW> basell = new LinkedList<IteratingRLW>();
        Collections.addAll(basell, al);
        return new BufferedIterator(new BufferedAndIterator(basell,
                bufSize));
    }

    /**
     * Aggregate the iterators using a bitmap buffer.
     *
     * @param al set of iterators to aggregate
     * @return or aggregate
     */
    public static IteratingRLW bufferedor(final IteratingRLW... al) {
        return bufferedor(DEFAULT_MAX_BUF_SIZE, al);
    }

    /**
     * Aggregate the iterators using a bitmap buffer.
     *
     * @param al      iterators to aggregate
     * @param bufSize size of the internal buffer used by the iterator in
     *                64-bit words
     * @return or aggregate
     */
    public static IteratingRLW bufferedor(final int bufSize,
                                          final IteratingRLW... al) {
        if (al.length == 0)
            throw new IllegalArgumentException("Need at least one iterator");
        if (al.length == 1)
            return al[0];

        final LinkedList<IteratingRLW> basell = new LinkedList<IteratingRLW>();
        Collections.addAll(basell, al);
        return new BufferedIterator(new BufferedORIterator(basell, bufSize));
    }

    /**
     * Aggregate the iterators using a bitmap buffer.
     *
     * @param al set of iterators to aggregate
     * @return xor aggregate
     */
    public static IteratingRLW bufferedxor(final IteratingRLW... al) {
        return bufferedxor(DEFAULT_MAX_BUF_SIZE, al);
    }

    /**
     * Aggregate the iterators using a bitmap buffer.
     *
     * @param al      iterators to aggregate
     * @param bufSize size of the internal buffer used by the iterator in 64-bit words
     * @return xor aggregate
     */
    public static IteratingRLW bufferedxor(final int bufSize, final IteratingRLW... al) {
        if (al.length == 0)
            throw new IllegalArgumentException("Need at least one iterator");
        if (al.length == 1)
            return al[0];

        final LinkedList<IteratingRLW> basell = new LinkedList<IteratingRLW>();
        Collections.addAll(basell, al);

        return new BufferedIterator(new BufferedXORIterator(basell, bufSize));
    }

    /**
     * Write out the content of the iterator, but as if it were all zeros.
     *
     * @param container where we write
     * @param i         the iterator
     */
    protected static void dischargeAsEmpty(final BitmapStorage container,
                                           final IteratingRLW i) {
        while (i.size() > 0) {
            container.addStreamOfEmptyWords(false, i.size());
            i.next();
        }
    }

    /**
     * Write out up to max words, returns how many were written
     *
     * @param container target for writes
     * @param i         source of data
     * @param max       maximal number of writes
     * @return how many written
     */

    protected static long discharge(final BitmapStorage container, IteratingRLW i, long max) {
        long counter = 0;
        while (i.size() > 0 && counter < max) {
            long l1 = i.getRunningLength();
            if (l1 > 0) {
                if (l1 + counter > max)
                    l1 = max - counter;
                container.addStreamOfEmptyWords(i.getRunningBit(), l1);
                counter += l1;
            }
            long l = i.getNumberOfLiteralWords();
            if (l + counter > max)
                l = max - counter;
            for (int k = 0; k < l; ++k) {
                container.addWord(i.getLiteralWordAt(k));
            }
            counter += l;
            i.discardFirstWords(l + l1);
        }
        return counter;
    }

    /**
     * Write out up to max negated words, returns how many were written
     *
     * @param container target for writes
     * @param i         source of data
     * @param max       maximal number of writes
     * @return how many written
     */
    protected static long dischargeNegated(final BitmapStorage container, IteratingRLW i, long max) {
        long counter = 0;
        while (i.size() > 0 && counter < max) {
            long l1 = i.getRunningLength();
            if (l1 > 0) {
                if (l1 + counter > max)
                    l1 = max - counter;
                container.addStreamOfEmptyWords(!i.getRunningBit(), l1);
                counter += l1;
            }
            long l = i.getNumberOfLiteralWords();
            if (l + counter > max)
                l = max - counter;
            for (int k = 0; k < l; ++k) {
                container.addWord(~i.getLiteralWordAt(k));
            }
            counter += l;
            i.discardFirstWords(l + l1);
        }
        return counter;
    }

    static void andToContainer(final BitmapStorage container,
                               int desiredrlwcount, final IteratingRLW rlwi, IteratingRLW rlwj) {
        while ((rlwi.size() > 0) && (rlwj.size() > 0)
                && (desiredrlwcount-- > 0)) {
            while ((rlwi.getRunningLength() > 0) || (rlwj.getRunningLength() > 0)) {
                final boolean i_is_prey = rlwi.getRunningLength() < rlwj.getRunningLength();
                final IteratingRLW prey = i_is_prey ? rlwi : rlwj;
                final IteratingRLW predator = i_is_prey ? rlwj : rlwi;
                if (!predator.getRunningBit()) {
                    container.addStreamOfEmptyWords(false, predator.getRunningLength());
                    prey.discardFirstWords(predator.getRunningLength());
                    predator.discardFirstWords(predator.getRunningLength());
                } else {
                    final long index = discharge(container, prey, predator.getRunningLength());
                    container.addStreamOfEmptyWords(false, predator.getRunningLength() - index);
                    predator.discardFirstWords(predator.getRunningLength());
                }
            }
            final int nbre_literal = Math.min(rlwi.getNumberOfLiteralWords(), rlwj.getNumberOfLiteralWords());
            if (nbre_literal > 0) {
                desiredrlwcount -= nbre_literal;
                for (int k = 0; k < nbre_literal; ++k)
                    container.addWord(rlwi.getLiteralWordAt(k) & rlwj.getLiteralWordAt(k));
                rlwi.discardFirstWords(nbre_literal);
                rlwj.discardFirstWords(nbre_literal);
            }
        }
    }

    static void andToContainer(final BitmapStorage container,
                               final IteratingRLW rlwi, IteratingRLW rlwj) {
        while ((rlwi.size() > 0) && (rlwj.size() > 0)) {
            while ((rlwi.getRunningLength() > 0) || (rlwj.getRunningLength() > 0)) {
                final boolean i_is_prey = rlwi.getRunningLength() < rlwj.getRunningLength();
                final IteratingRLW prey = i_is_prey ? rlwi : rlwj;
                final IteratingRLW predator = i_is_prey ? rlwj : rlwi;
                if (!predator.getRunningBit()) {
                    container.addStreamOfEmptyWords(false, predator.getRunningLength());
                    prey.discardFirstWords(predator.getRunningLength());
                    predator.discardFirstWords(predator.getRunningLength());
                } else {
                    final long index = discharge(container, prey, predator.getRunningLength());
                    container.addStreamOfEmptyWords(false, predator.getRunningLength() - index);
                    predator.discardFirstWords(predator.getRunningLength());
                }
            }
            final int nbre_literal = Math.min(rlwi.getNumberOfLiteralWords(), rlwj.getNumberOfLiteralWords());
            if (nbre_literal > 0) {
                for (int k = 0; k < nbre_literal; ++k)
                    container.addWord(rlwi.getLiteralWordAt(k) & rlwj.getLiteralWordAt(k));
                rlwi.discardFirstWords(nbre_literal);
                rlwj.discardFirstWords(nbre_literal);
            }
        }
    }

    /**
     * Compute the first few words of the XOR aggregate between two
     * iterators.
     *
     * @param container       where to write
     * @param desiredrlwcount number of words to be written (max)
     * @param rlwi            first iterator to aggregate
     * @param rlwj            second iterator to aggregate
     */
    public static void xorToContainer(final BitmapStorage container,
                                      int desiredrlwcount, final IteratingRLW rlwi,
                                      final IteratingRLW rlwj) {
        while ((rlwi.size() > 0) && (rlwj.size() > 0)
                && (desiredrlwcount-- > 0)) {
            while ((rlwi.getRunningLength() > 0) || (rlwj.getRunningLength() > 0)) {
                final boolean i_is_prey = rlwi.getRunningLength() < rlwj.getRunningLength();
                final IteratingRLW prey = i_is_prey ? rlwi : rlwj;
                final IteratingRLW predator = i_is_prey ? rlwj : rlwi;
                if (!predator.getRunningBit()) {
                    long index = discharge(container, prey, predator.getRunningLength());
                    container.addStreamOfEmptyWords(false, predator.getRunningLength() - index);
                    predator.discardFirstWords(predator.getRunningLength());
                } else {
                    long index = dischargeNegated(container, prey, predator.getRunningLength());
                    container.addStreamOfEmptyWords(true, predator.getRunningLength() - index);
                    predator.discardFirstWords(predator.getRunningLength());
                }
            }
            final int nbre_literal = Math.min(rlwi.getNumberOfLiteralWords(), rlwj.getNumberOfLiteralWords());
            if (nbre_literal > 0) {
                desiredrlwcount -= nbre_literal;
                for (int k = 0; k < nbre_literal; ++k)
                    container.addWord(rlwi.getLiteralWordAt(k) ^ rlwj.getLiteralWordAt(k));
                rlwi.discardFirstWords(nbre_literal);
                rlwj.discardFirstWords(nbre_literal);
            }
        }
    }

    protected static int inplaceor(long[] bitmap, IteratingRLW i) {

        int pos = 0;
        long s;
        while ((s = i.size()) > 0) {
            if (pos + s < bitmap.length) {
                final int L = (int) i.getRunningLength();
                if (i.getRunningBit())
                    java.util.Arrays.fill(bitmap, pos, pos + L, ~0l);
                pos += L;
                final int LR = i.getNumberOfLiteralWords();

                for (int k = 0; k < LR; ++k)
                    bitmap[pos++] |= i.getLiteralWordAt(k);
                if (!i.next()) {
                    return pos;
                }
            } else {
                int howmany = bitmap.length - pos;
                int l = (int) i.getRunningLength();

                if (pos + l > bitmap.length) {
                    if (i.getRunningBit()) {
                        java.util.Arrays.fill(bitmap, pos, bitmap.length, ~0l);
                    }
                    i.discardFirstWords(howmany);
                    return bitmap.length;
                }
                if (i.getRunningBit())
                    java.util.Arrays.fill(bitmap, pos, pos + l, ~0l);
                pos += l;
                for (int k = 0; pos < bitmap.length; ++k)
                    bitmap[pos++] |= i.getLiteralWordAt(k);
                i.discardFirstWords(howmany);
                return pos;
            }
        }
        return pos;
    }

    protected static int inplacexor(long[] bitmap, IteratingRLW i) {
        int pos = 0;
        long s;
        while ((s = i.size()) > 0) {
            if (pos + s < bitmap.length) {
                final int L = (int) i.getRunningLength();
                if (i.getRunningBit()) {
                    for (int k = pos; k < pos + L; ++k)
                        bitmap[k] = ~bitmap[k];
                }
                pos += L;
                final int LR = i.getNumberOfLiteralWords();
                for (int k = 0; k < LR; ++k)
                    bitmap[pos++] ^= i.getLiteralWordAt(k);
                if (!i.next()) {
                    return pos;
                }
            } else {
                int howMany = bitmap.length - pos;
                int l = (int) i.getRunningLength();
                if (pos + l > bitmap.length) {
                    if (i.getRunningBit()) {
                        for (int k = pos; k < bitmap.length; ++k)
                            bitmap[k] = ~bitmap[k];
                    }
                    i.discardFirstWords(howMany);
                    return bitmap.length;
                }
                if (i.getRunningBit())
                    for (int k = pos; k < pos + l; ++k)
                        bitmap[k] = ~bitmap[k];
                pos += l;
                for (int k = 0; pos < bitmap.length; ++k)
                    bitmap[pos++] ^= i.getLiteralWordAt(k);
                i.discardFirstWords(howMany);
                return pos;
            }
        }
        return pos;
    }

    protected static int inplaceand(long[] bitmap, IteratingRLW i) {
        int pos = 0;
        long s;
        while ((s = i.size()) > 0) {
            if (pos + s < bitmap.length) {
                final int L = (int) i.getRunningLength();
                if (!i.getRunningBit()) {
                    for (int k = pos; k < pos + L; ++k)
                        bitmap[k] = 0;
                }
                pos += L;
                final int LR = i.getNumberOfLiteralWords();
                for (int k = 0; k < LR; ++k)
                    bitmap[pos++] &= i.getLiteralWordAt(k);
                if (!i.next()) {
                    return pos;
                }
            } else {
                int howmany = bitmap.length - pos;
                int l = (int) i.getRunningLength();
                if (pos + l > bitmap.length) {
                    if (!i.getRunningBit()) {
                        for (int k = pos; k < bitmap.length; ++k)
                            bitmap[k] = 0;
                    }
                    i.discardFirstWords(howmany);
                    return bitmap.length;
                }
                if (!i.getRunningBit())
                    for (int k = pos; k < pos + l; ++k)
                        bitmap[k] = 0;
                pos += l;
                for (int k = 0; pos < bitmap.length; ++k)
                    bitmap[pos++] &= i.getLiteralWordAt(k);
                i.discardFirstWords(howmany);
                return pos;
            }
        }
        return pos;
    }

    /**
     * An optimization option. Larger values may improve speed, but at the
     * expense of memory.
     */
    public static final int DEFAULT_MAX_BUF_SIZE = 65536;
}

class BufferedORIterator implements CloneableIterator<EWAHIterator> {
    final EWAHCompressedBitmap buffer = new EWAHCompressedBitmap();
    final long[] hardBitmap;
    final LinkedList<IteratingRLW> ll;

    BufferedORIterator(LinkedList<IteratingRLW> basell, int bufSize) {
        this.ll = basell;
        this.hardBitmap = new long[bufSize];
    }

    @Override
    public BufferedXORIterator clone() throws CloneNotSupportedException {
        BufferedXORIterator answer = (BufferedXORIterator) super
                .clone();
        answer.buffer = this.buffer.clone();
        answer.hardbitmap = this.hardBitmap.clone();
        answer.ll = (LinkedList<IteratingRLW>) this.ll.clone();
        return answer;
    }

    @Override
    public boolean hasNext() {
        return !this.ll.isEmpty();
    }

    @Override
    public EWAHIterator next() {
        this.buffer.clear();
        long effective = 0;
        Iterator<IteratingRLW> i = this.ll.iterator();
        while (i.hasNext()) {
            IteratingRLW rlw = i.next();
            if (rlw.size() > 0) {
                int eff = IteratorAggregation.inplaceor(this.hardBitmap, rlw);
                if (eff > effective)
                    effective = eff;
            } else
                i.remove();
        }
        for (int k = 0; k < effective; ++k) {
            this.buffer.addWord(this.hardBitmap[k]);
        }

        Arrays.fill(this.hardBitmap, 0);
        return this.buffer.getEWAHIterator();
    }
}

class BufferedXORIterator implements CloneableIterator<EWAHIterator> {
    EWAHCompressedBitmap buffer = new EWAHCompressedBitmap();
    long[] hardbitmap;
    LinkedList<IteratingRLW> ll;

    BufferedXORIterator(LinkedList<IteratingRLW> basell, int bufSize) {
        this.ll = basell;
        this.hardbitmap = new long[bufSize];
    }

    @Override
    public BufferedXORIterator clone() throws CloneNotSupportedException {
        BufferedXORIterator answer = (BufferedXORIterator) super.clone();
        answer.buffer = this.buffer.clone();
        answer.hardbitmap = this.hardbitmap.clone();
        answer.ll = (LinkedList<IteratingRLW>) this.ll.clone();
        return answer;
    }

    @Override
    public boolean hasNext() {
        return !this.ll.isEmpty();
    }

    @Override
    public EWAHIterator next() {
        this.buffer.clear();
        long effective = 0;
        Iterator<IteratingRLW> i = this.ll.iterator();
        while (i.hasNext()) {
            IteratingRLW rlw = i.next();
            if (rlw.size() > 0) {
                int eff = IteratorAggregation.inplacexor(this.hardbitmap, rlw);
                if (eff > effective)
                    effective = eff;
            } else
                i.remove();
        }
        for (int k = 0; k < effective; ++k)
            this.buffer.addWord(this.hardbitmap[k]);
        Arrays.fill(this.hardbitmap, 0);
        return this.buffer.getEWAHIterator();
    }
}

class BufferedAndIterator implements CloneableIterator<EWAHIterator> {
    EWAHCompressedBitmap buffer = new EWAHCompressedBitmap();
    LinkedList<IteratingRLW> ll;
    final int bufferSize;

    public BufferedAndIterator(LinkedList<IteratingRLW> basell, int bufSize) {
        this.ll = basell;
        this.bufferSize = bufSize;
    }

    @Override
    public boolean hasNext() {
        return !this.ll.isEmpty();
    }

    @Override
    public BufferedAndIterator clone() throws CloneNotSupportedException {
        BufferedAndIterator answer = (BufferedAndIterator) super.clone();
        answer.buffer = this.buffer.clone();
        answer.ll = (LinkedList<IteratingRLW>) this.ll.clone();
        return answer;
    }

    @Override
    public EWAHIterator next() {
        this.buffer.clear();
        IteratorAggregation.andToContainer(this.buffer, this.bufferSize * this.ll.size(),
                this.ll.get(0), this.ll.get(1));
        if (this.ll.size() > 2) {
            Iterator<IteratingRLW> i = this.ll.iterator();
            i.next();
            i.next();
            EWAHCompressedBitmap tmpbuffer = new EWAHCompressedBitmap();
            while (i.hasNext() && this.buffer.sizeInBytes() > 0) {
                IteratorAggregation.andToContainer(tmpbuffer, this.buffer.getIteratingRLW(), i.next());
                this.buffer.swap(tmpbuffer);
                tmpbuffer.clear();
            }
        }
        for (IteratingRLW aLl : this.ll) {
            if (aLl.size() == 0) {
                this.ll.clear();
                break;
            }
        }
        return this.buffer.getEWAHIterator();
    }
}


package com.googlecode.javaewah;

/*
 * Copyright 2009-2016, Daniel Lemire, Cliff Moon, David McIntosh, Robert Becho, Google Inc., Veronika Zenz, Owen Kaser, Gregory Ssi-Yan-Kai, Rory Graves
 * Licensed under the Apache License, Version 2.0.
 */

import java.util.Arrays;

/**
 * Long array wrapper.
 * Users should not be concerned by this class.
 *
 * @author Gregory Ssi-Yan-Kai
 */
final class LongArray implements Buffer, Cloneable {

    /**
     * Creates a buffer with default size
     */
    public LongArray() {
        this(DEFAULT_BUFFER_SIZE);
    }

    /**
     * Creates a buffer with explicit size
     * @param bufferSize
     */
    public LongArray(int bufferSize) {
        if(bufferSize < 1) {
            bufferSize = 1;
        }
        this.buffer = new long[bufferSize];
    }

    @Override
    public int sizeInWords() {
        return this.actualSizeInWords;
    }

    @Override
    public void ensureCapacity(int capacity) {
        resizeBuffer(capacity - this.actualSizeInWords);
    }

    @Override
    public long getWord(int position) {
        return this.buffer[position];
    }

    @Override
    public long getLastWord() {
        return getWord(this.actualSizeInWords - 1);
    }

    @Override
    public void clear() {
        this.actualSizeInWords = 1;
        this.buffer[0] = 0;
    }

    @Override
    public void trim() {
        this.buffer = Arrays.copyOf(this.buffer, this.actualSizeInWords);
    }

    @Override
    public void setWord(int position, long word) {
        this.buffer[position] = word;
    }

    @Override
    public void setLastWord(long word) {
        setWord(this.actualSizeInWords - 1, word);
    }

    @Override
    public void push_back(long word) {
        resizeBuffer(1);
        this.buffer[this.actualSizeInWords++] = word;
    }

    @Override
    public void push_back(Buffer buffer, int start, int number) {
        resizeBuffer(number);
        if(buffer instanceof LongArray) {
            long[] data = ((LongArray)buffer).buffer;
            System.arraycopy(data, start, this.buffer, this.actualSizeInWords, number);
        } else {
            for(int i = 0; i < number; ++i) {
                this.buffer[this.actualSizeInWords + i] = buffer.getWord(start + i);
            }
        }
        this.actualSizeInWords += number;
    }

    @Override
    public void negative_push_back(Buffer buffer, int start, int number) {
        resizeBuffer(number);
        for (int i = 0; i < number; ++i) {
            this.buffer[this.actualSizeInWords + i] = ~buffer.getWord(start + i);
        }
        this.actualSizeInWords += number;
    }

    @Override
    public void removeLastWord() {
        setWord(--this.actualSizeInWords, 0l);
    }

    @Override
    public void negateWord(int position) {
        this.buffer[position] = ~this.buffer[position];
    }

    @Override
    public void andWord(int position, long mask) {
        this.buffer[position] &= mask;
    }

    @Override
    public void orWord(int position, long mask) {
        this.buffer[position] |= mask;
    }

    @Override
    public void andLastWord(long mask) {
        andWord(this.actualSizeInWords - 1, mask);
    }

    @Override
    public void orLastWord(long mask) {
        orWord(this.actualSizeInWords - 1, mask);
    }

    @Override
    public void expand(int position, int length) {
        resizeBuffer(length);
        System.arraycopy(this.buffer, position, this.buffer, position + length, this.actualSizeInWords - position);
        this.actualSizeInWords += length;
    }

    @Override
    public void collapse(int position, int length) {
        System.arraycopy(this.buffer, position + length, this.buffer, position, this.actualSizeInWords - position - length);
        for(int i = 0; i < length; ++i) {
            removeLastWord();
        }
    }

    @Override
    public LongArray clone() {
        LongArray clone = null;
        try {
            clone = (LongArray) super.clone();
            clone.buffer = this.buffer.clone();
            clone.actualSizeInWords = this.actualSizeInWords;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace(); // cannot happen
        }
        return clone;
    }

    @Override
    public void swap(final Buffer other) {
        if(other instanceof LongArray) {
            long[] tmp = this.buffer;
            this.buffer = ((LongArray)other).buffer;
            ((LongArray)other).buffer = tmp;

            int tmp2 = this.actualSizeInWords;
            this.actualSizeInWords = ((LongArray)other).actualSizeInWords;
            ((LongArray)other).actualSizeInWords = tmp2;
        } else {
            long[] tmp = new long[other.sizeInWords()];
            for(int i = 0; i < other.sizeInWords(); ++i) {
                tmp[i] = other.getWord(i);
            }
            int tmp2 = other.sizeInWords();

            other.clear();
            other.removeLastWord();
            other.push_back(this, 0, this.sizeInWords());

            this.buffer = tmp;
            this.actualSizeInWords = tmp2;
        }
    }

    /**
     * Resizes the buffer if the number of words to add exceeds the buffer capacity.
     * @param number the number of words to add
     */
    private void resizeBuffer(int number) {
        int size = newSizeInWords(number);
        if (size >= this.buffer.length) {
            long oldBuffer[] = this.buffer;
            this.buffer = new long[size];
            System.arraycopy(oldBuffer, 0, this.buffer, 0, oldBuffer.length);
        }
	}

    /**
     * Returns the resulting buffer size in words given the number of words to add.
     * @param number the number of words to add
     */
    private int newSizeInWords(int number) {
        int size = this.actualSizeInWords + number;
        if (size >= this.buffer.length) {
            if (size < 32768)
                size = size * 2;
            else if (size * 3 / 2 < size) // overflow
                size = Integer.MAX_VALUE;
            else
                size = size * 3 / 2;
        }
        return size;
    }

    /**
     * The actual size in words.
     */
    private int actualSizeInWords = 1;

    /**
     * The buffer (array of 64-bit words)
     */
    private long buffer[] = null;

    /**
     * The Constant DEFAULT_BUFFER_SIZE: default memory allocation when the
     * object is constructed.
     */
    private static final int DEFAULT_BUFFER_SIZE = 4;

}


package com.googlecode.javaewah32;

import com.googlecode.javaewah.IntIterator;

import java.util.Iterator;

/*
 * Copyright 2009-2016, Daniel Lemire, Cliff Moon, David McIntosh, Robert Becho, Google Inc., Veronika Zenz, Owen Kaser, Gregory Ssi-Yan-Kai, Rory Graves
 * Licensed under the Apache License, Version 2.0.
 */

/**
 * Convenience functions for working over iterators
 */
public final class IteratorUtil32 {

    /** Private constructor to prevent instantiation */
    private IteratorUtil32() {}

    /**
     * @param i iterator we wish to iterate over
     * @return an iterator over the set bits corresponding to the iterator
     */
    public static IntIterator toSetBitsIntIterator(final IteratingRLW32 i) {
        return new IntIteratorOverIteratingRLW32(i);
    }

    /**
     * @param i iterator we wish to iterate over
     * @return an iterator over the set bits corresponding to the iterator
     */
    public static Iterator<Integer> toSetBitsIterator(final IteratingRLW32 i) {
        return new Iterator<Integer>() {
            @Override
            public boolean hasNext() {
                return this.under.hasNext();
            }

            @Override
            public Integer next() {
                return this.under.next();
            }

            @Override
            public void remove() {
            }

            private final IntIterator under = toSetBitsIntIterator(i);
        };

    }

    /**
     * Turn an iterator into a bitmap
     *
     * @param i iterator we wish to materialize
     * @param c where we write
     */
    public static void materialize(final IteratingRLW32 i,
                                   final BitmapStorage32 c) {
        while (true) {
            if (i.getRunningLength() > 0) {
                c.addStreamOfEmptyWords(i.getRunningBit(),
                        i.getRunningLength());
            }
            int il = i.getNumberOfLiteralWords();
            for (int k = 0; k < il ; ++k)
                c.addWord(i.getLiteralWordAt(k));
            if (!i.next())
                break;
        }
    }

    /**
     * @param i iterator we wish to iterate over
     * @return the cardinality (number of set bits) corresponding to the
     * iterator
     */
    public static int cardinality(final IteratingRLW32 i) {
        int answer = 0;
        while (true) {
            if (i.getRunningBit())
                answer += i.getRunningLength()
                        * EWAHCompressedBitmap32.WORD_IN_BITS;
            int il = i.getNumberOfLiteralWords();
            for (int k = 0; k < il; ++k)
                answer += Integer.bitCount(i.getLiteralWordAt(k));
            if (!i.next())
                break;
        }
        return answer;
    }

    /**
     * @param x set of bitmaps we wish to iterate over
     * @return an array of iterators corresponding to the array of bitmaps
     */
    public static IteratingRLW32[] toIterators(
            final EWAHCompressedBitmap32... x) {
        IteratingRLW32[] X = new IteratingRLW32[x.length];
        for (int k = 0; k < X.length; ++k) {
            X[k] = new IteratingBufferedRunningLengthWord32(x[k]);
        }
        return X;
    }

    /**
     * Turn an iterator into a bitmap
     *
     * @param i   iterator we wish to materialize
     * @param c   where we write
     * @param max maximum number of words to materialize
     * @return how many words were actually materialized
     */
    public static long materialize(final IteratingRLW32 i, final BitmapStorage32 c, int max) {
        final int origMax = max;
        while (true) {
            if (i.getRunningLength() > 0) {
                int l = i.getRunningLength();
                if (l > max)
                    l = max;
                c.addStreamOfEmptyWords(i.getRunningBit(), l);
                max -= l;
            }
            long L = i.getNumberOfLiteralWords();
            for (int k = 0; k < L; ++k)
                c.addWord(i.getLiteralWordAt(k));
            if (max > 0) {
                if (!i.next())
                    break;
            } else
                break;
        }
        return origMax - max;
    }

    /**
     * Turn an iterator into a bitmap
     *
     *
     * This can be used to effectively clone a bitmap in the following
     * manner:
     *
     *  <code>
     *  EWAHCompressedBitmap32 n = IteratorUtil32.materialize(bitmap.getIteratingRLW()));
     *  n.setSizeInBitsWithinLastWord(bitmap.sizeInBits());
     *  </code>
     *
     * @param i iterator we wish to materialize
     * @return materialized version of the iterator
     */
    public static EWAHCompressedBitmap32 materialize(final IteratingRLW32 i) {
        EWAHCompressedBitmap32 ewah = new EWAHCompressedBitmap32();
        materialize(i, ewah);
        return ewah;
    }

}


package com.googlecode.javaewah32;

import com.googlecode.javaewah.CloneableIterator;

/*
 * Copyright 2009-2016, Daniel Lemire, Cliff Moon, David McIntosh, Robert Becho, Google Inc., Veronika Zenz, Owen Kaser, Gregory Ssi-Yan-Kai, Rory Graves
 * Licensed under the Apache License, Version 2.0.
 */

/**
 * This class can be used to iterate over blocks of bitmap data.
 *
 * @author Daniel Lemire
 */
public class BufferedIterator32 implements IteratingRLW32, Cloneable {
    /**
     * Instantiates a new iterating buffered running length word.
     *
     * @param iterator iterator
     */
    public BufferedIterator32(
            final CloneableIterator<EWAHIterator32> iterator) {
        this.masterIterator = iterator;
        if (this.masterIterator.hasNext()) {
            iteratingBrlw = new IteratingBufferedRunningLengthWord32(this.masterIterator.next());
        }
    }

    /**
     * Discard first words, iterating to the next running length word if
     * needed.
     *
     * @param x the number of words to be discarded
     */
    @Override
    public void discardFirstWords(int x) {
        while (x > 0) {
            if (this.iteratingBrlw.getRunningLength() > x) {
                this.iteratingBrlw.discardFirstWords(x);
                return;
            }
            this.iteratingBrlw.discardFirstWords(this.iteratingBrlw.getRunningLength());
            x -= this.iteratingBrlw.getRunningLength();
            int toDiscard = x > this.iteratingBrlw.getNumberOfLiteralWords()
                    ? this.iteratingBrlw.getNumberOfLiteralWords()
                    : x;

            this.iteratingBrlw.discardFirstWords(toDiscard);
            x -= toDiscard;
            if ((x > 0) || (this.iteratingBrlw.size() == 0)) {
                if (!this.next()) {
                    break;
                }
            }
        }
    }

	@Override
	public void discardLiteralWords(int x) {
		this.iteratingBrlw.discardLiteralWords(x);
        if (this.iteratingBrlw.getNumberOfLiteralWords() == 0)
            this.next();
	}

    @Override
    public void discardRunningWords() {
        this.iteratingBrlw.discardRunningWords();
        if (this.iteratingBrlw.getNumberOfLiteralWords() == 0)
            this.next();
    }

    /**
     * Move to the next RunningLengthWord
     *
     * @return whether the move was possible
     */
    @Override
    public boolean next() {
        if (!this.iteratingBrlw.next()) {
            if (!this.masterIterator.hasNext()) {
                return false;
            } else {
                this.iteratingBrlw = new IteratingBufferedRunningLengthWord32(this.masterIterator.next());
            }
        }
        return true;
    }

    /**
     * Get the nth literal word for the current running length word
     *
     * @param index zero based index
     * @return the literal word
     */
    @Override
    public int getLiteralWordAt(int index) {
        return this.iteratingBrlw.getLiteralWordAt(index);
    }

    /**
     * Gets the number of literal words for the current running length word.
     *
     * @return the number of literal words
     */
    @Override
    public int getNumberOfLiteralWords() {
        return this.iteratingBrlw.getNumberOfLiteralWords();
    }

    /**
     * Gets the running bit.
     *RunningBit
     * @return the running bit
     */
    @Override
    public boolean getRunningBit() {
        return this.iteratingBrlw.getRunningBit();
    }

    /**
     * Gets the running length.
     *
     * @return the running length
     */
    @Override
    public int getRunningLength() {
        return this.iteratingBrlw.getRunningLength();
    }

    /**
     * Size in uncompressed words of the current running length word.
     *
     * @return the size
     */
    @Override
    public int size() {
        return this.iteratingBrlw.size();
    }

    @Override
    public BufferedIterator32 clone() throws CloneNotSupportedException {
        BufferedIterator32 answer = (BufferedIterator32) super.clone();
        answer.iteratingBrlw = this.iteratingBrlw.clone();
        answer.masterIterator = this.masterIterator.clone();
        return answer;
    }

    private IteratingBufferedRunningLengthWord32 iteratingBrlw;
    private CloneableIterator<EWAHIterator32> masterIterator;

}


package com.googlecode.javaewah32;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.PriorityQueue;

/*
 * Copyright 2009-2016, Daniel Lemire, Cliff Moon, David McIntosh, Robert Becho, Google Inc., Veronika Zenz, Owen Kaser, Gregory Ssi-Yan-Kai, Rory Graves
 * Licensed under the Apache License, Version 2.0.
 */

/**
 * Fast algorithms to aggregate many bitmaps. These algorithms are just given as
 * reference. They may not be faster than the corresponding methods in the
 * EWAHCompressedBitmap class.
 *
 * @author Daniel Lemire
 */
public final class FastAggregation32 {

    /** Private constructor to prevent instantiation */
    private FastAggregation32() {}

    /**
     * Compute the and aggregate using a temporary uncompressed bitmap.
     *
     * This function does not seek to match the "sizeinbits" attributes
     * of the input bitmaps.
     *
     * @param bitmaps the source bitmaps
     * @param bufSize buffer size used during the computation in 64-bit
     *                words (per input bitmap)
     * @return the or aggregate.
     */
    public static EWAHCompressedBitmap32 bufferedand(final int bufSize,
                                                     final EWAHCompressedBitmap32... bitmaps) {
        EWAHCompressedBitmap32 answer = new EWAHCompressedBitmap32();
        bufferedandWithContainer(answer, bufSize, bitmaps);
        return answer;
    }

    /**
     * Compute the and aggregate using a temporary uncompressed bitmap.
     *
     * This function does not seek to match the "sizeinbits" attributes
     * of the input bitmaps.
     *
     * @param container where the aggregate is written
     * @param bufSize   buffer size used during the computation in 64-bit
     *                  words (per input bitmap)
     * @param bitmaps   the source bitmaps
     */
    public static void bufferedandWithContainer(
            final BitmapStorage32 container, final int bufSize,
            final EWAHCompressedBitmap32... bitmaps) {

        java.util.LinkedList<IteratingBufferedRunningLengthWord32> al = new java.util.LinkedList<IteratingBufferedRunningLengthWord32>();
        for (EWAHCompressedBitmap32 bitmap : bitmaps) {
            al.add(new IteratingBufferedRunningLengthWord32(bitmap));
        }
        int[] hardbitmap = new int[bufSize * bitmaps.length];

        for (IteratingRLW32 i : al)
            if (i.size() == 0) {
                al.clear();
                break;
            }

        while (!al.isEmpty()) {
            Arrays.fill(hardbitmap, ~0);
            int effective = Integer.MAX_VALUE;
            for (IteratingRLW32 i : al) {
                int eff = IteratorAggregation32.inplaceand(
                        hardbitmap, i);
                if (eff < effective)
                    effective = eff;
            }
            for (int k = 0; k < effective; ++k)
                container.addWord(hardbitmap[k]);
            for (IteratingRLW32 i : al)
                if (i.size() == 0) {
                    al.clear();
                    break;
                }
        }
    }

    /**
     * Compute the or aggregate using a temporary uncompressed bitmap.
     *
     * @param bitmaps the source bitmaps
     * @param bufSize buffer size used during the computation in 64-bit
     *                words
     * @return the or aggregate.
     */
    public static EWAHCompressedBitmap32 bufferedor(final int bufSize,
                                                    final EWAHCompressedBitmap32... bitmaps) {
        EWAHCompressedBitmap32 answer = new EWAHCompressedBitmap32();
        bufferedorWithContainer(answer, bufSize, bitmaps);
        return answer;
    }

    /**
     * Compute the or aggregate using a temporary uncompressed bitmap.
     *
     * @param container where the aggregate is written
     * @param bufSize   buffer size used during the computation in 64-bit
     *                  words
     * @param bitmaps   the source bitmaps
     */
    public static void bufferedorWithContainer(
            final BitmapStorage32 container, final int bufSize,
            final EWAHCompressedBitmap32... bitmaps) {
        int range = 0;
        EWAHCompressedBitmap32[] sbitmaps = bitmaps.clone();
        Arrays.sort(sbitmaps, new Comparator<EWAHCompressedBitmap32>() {
            @Override
            public int compare(EWAHCompressedBitmap32 a,
                               EWAHCompressedBitmap32 b) {
                return b.sizeInBits() - a.sizeInBits();
            }
        });

        java.util.ArrayList<IteratingBufferedRunningLengthWord32> al = new java.util.ArrayList<IteratingBufferedRunningLengthWord32>();
        for (EWAHCompressedBitmap32 bitmap : sbitmaps) {
            if (bitmap.sizeInBits() > range)
                range = bitmap.sizeInBits();
            al.add(new IteratingBufferedRunningLengthWord32(bitmap));
        }
        int[] hardbitmap = new int[bufSize];
        int maxr = al.size();
        while (maxr > 0) {
            int effective = 0;
            for (int k = 0; k < maxr; ++k) {
                if (al.get(k).size() > 0) {
                    int eff = IteratorAggregation32
                            .inplaceor(hardbitmap,
                                    al.get(k));
                    if (eff > effective)
                        effective = eff;
                } else
                    maxr = k;
            }
            for (int k = 0; k < effective; ++k)
                container.addWord(hardbitmap[k]);
            Arrays.fill(hardbitmap, 0);

        }
        container.setSizeInBitsWithinLastWord(range);
    }

    /**
     * Compute the xor aggregate using a temporary uncompressed bitmap.
     *
     * @param bitmaps the source bitmaps
     * @param bufSize buffer size used during the computation in 64-bit
     *                words
     * @return the xor aggregate.
     */
    public static EWAHCompressedBitmap32 bufferedxor(final int bufSize,
                                                     final EWAHCompressedBitmap32... bitmaps) {
        EWAHCompressedBitmap32 answer = new EWAHCompressedBitmap32();
        bufferedxorWithContainer(answer, bufSize, bitmaps);
        return answer;
    }

    /**
     * Compute the xor aggregate using a temporary uncompressed bitmap.
     *
     * @param container where the aggregate is written
     * @param bufSize   buffer size used during the computation in 64-bit
     *                  words
     * @param bitmaps   the source bitmaps
     */
    public static void bufferedxorWithContainer(
            final BitmapStorage32 container, final int bufSize,
            final EWAHCompressedBitmap32... bitmaps) {
        int range = 0;
        EWAHCompressedBitmap32[] sbitmaps = bitmaps.clone();
        Arrays.sort(sbitmaps, new Comparator<EWAHCompressedBitmap32>() {
            @Override
            public int compare(EWAHCompressedBitmap32 a,
                               EWAHCompressedBitmap32 b) {
                return b.sizeInBits() - a.sizeInBits();
            }
        });

        java.util.ArrayList<IteratingBufferedRunningLengthWord32> al = new java.util.ArrayList<IteratingBufferedRunningLengthWord32>();
        for (EWAHCompressedBitmap32 bitmap : sbitmaps) {
            if (bitmap.sizeInBits() > range)
                range = bitmap.sizeInBits();
            al.add(new IteratingBufferedRunningLengthWord32(bitmap));
        }
        int[] hardbitmap = new int[bufSize];
        int maxr = al.size();
        while (maxr > 0) {
            int effective = 0;
            for (int k = 0; k < maxr; ++k) {
                if (al.get(k).size() > 0) {
                    int eff = IteratorAggregation32
                            .inplacexor(hardbitmap,
                                    al.get(k));
                    if (eff > effective)
                        effective = eff;
                } else
                    maxr = k;
            }
            for (int k = 0; k < effective; ++k)
                container.addWord(hardbitmap[k]);
            Arrays.fill(hardbitmap, 0);
        }
        container.setSizeInBitsWithinLastWord(range);
    }

    /**
     * Uses a priority queue to compute the or aggregate.
     *
     * The content of the container is overwritten.
     *
     * This algorithm runs in linearithmic time (O(n log n)) with respect to the number of bitmaps.
     *
     * @param container where we write the result
     * @param bitmaps   to be aggregated
     */
    public static void orToContainer(final BitmapStorage32 container,
                                     final EWAHCompressedBitmap32... bitmaps) {
        if (bitmaps.length < 2)
            throw new IllegalArgumentException(
                    "We need at least two bitmaps");
        PriorityQueue<EWAHCompressedBitmap32> pq = new PriorityQueue<EWAHCompressedBitmap32>(
                bitmaps.length,
                new Comparator<EWAHCompressedBitmap32>() {
                    @Override
                    public int compare(EWAHCompressedBitmap32 a,
                                       EWAHCompressedBitmap32 b) {
                        return a.sizeInBytes()
                                - b.sizeInBytes();
                    }
                }
        );
        Collections.addAll(pq, bitmaps);
        while (pq.size() > 2) {
            EWAHCompressedBitmap32 x1 = pq.poll();
            EWAHCompressedBitmap32 x2 = pq.poll();
            pq.add(x1.or(x2));
        }
        pq.poll().orToContainer(pq.poll(), container);
    }

    /**
     * Simple algorithm that computes the OR aggregate.
     *
     * @param bitmaps input bitmaps
     * @return new bitmap containing the aggregate
     */
    public static EWAHCompressedBitmap32 or(final EWAHCompressedBitmap32... bitmaps) {
        PriorityQueue<EWAHCompressedBitmap32> pq = new PriorityQueue<EWAHCompressedBitmap32>(bitmaps.length,
                new Comparator<EWAHCompressedBitmap32>() {
                    @Override
                    public int compare(EWAHCompressedBitmap32 a, EWAHCompressedBitmap32 b) {
                        return a.sizeInBytes()
                                - b.sizeInBytes();
                    }
                }
        );
        Collections.addAll(pq, bitmaps);
        if(pq.isEmpty()) return new EWAHCompressedBitmap32();
        while (pq.size() > 1) {
            EWAHCompressedBitmap32 x1 = pq.poll();
            EWAHCompressedBitmap32 x2 = pq.poll();
            pq.add(x1.or(x2));
        }
        return pq.poll();
    }

    /**
     * Simple algorithm that computes the XOR aggregate.
     *
     * @param bitmaps input bitmaps
     * @return new bitmap containing the aggregate
     */
    public static EWAHCompressedBitmap32 xor(final EWAHCompressedBitmap32... bitmaps) {
        PriorityQueue<EWAHCompressedBitmap32> pq = new PriorityQueue<EWAHCompressedBitmap32>(bitmaps.length,
                new Comparator<EWAHCompressedBitmap32>() {
                    @Override
                    public int compare(EWAHCompressedBitmap32 a, EWAHCompressedBitmap32 b) {
                        return a.sizeInBytes()
                                - b.sizeInBytes();
                    }
                }
        );
        Collections.addAll(pq, bitmaps);
        if(pq.isEmpty()) return new EWAHCompressedBitmap32();
        while (pq.size() > 1) {
            EWAHCompressedBitmap32 x1 = pq.poll();
            EWAHCompressedBitmap32 x2 = pq.poll();
            pq.add(x1.xor(x2));
        }
        return pq.poll();
    }

    /**
     * Simple algorithm that computes the OR aggregate.
     *
     * @param bitmaps input bitmaps
     * @return new bitmap containing the aggregate
     */
    public static EWAHCompressedBitmap32 or(final Iterator<EWAHCompressedBitmap32> bitmaps) {
        PriorityQueue<EWAHCompressedBitmap32> pq = new PriorityQueue<EWAHCompressedBitmap32>(32,
                new Comparator<EWAHCompressedBitmap32>() {
                    @Override
                    public int compare(EWAHCompressedBitmap32 a, EWAHCompressedBitmap32 b) {
                        return a.sizeInBytes()
                                - b.sizeInBytes();
                    }
                }
        );
        while(bitmaps.hasNext())
            pq.add(bitmaps.next());
        if(pq.isEmpty()) return new EWAHCompressedBitmap32();
        while (pq.size() > 1) {
            EWAHCompressedBitmap32 x1 = pq.poll();
            EWAHCompressedBitmap32 x2 = pq.poll();
            pq.add(x1.or(x2));
        }
        return pq.poll();
    }

    /**
     * Simple algorithm that computes the XOR aggregate.
     *
     * @param bitmaps input bitmaps
     * @return new bitmap containing the aggregate
     */
    public static EWAHCompressedBitmap32 xor(final Iterator<EWAHCompressedBitmap32> bitmaps) {
        PriorityQueue<EWAHCompressedBitmap32> pq = new PriorityQueue<EWAHCompressedBitmap32>(32,
                new Comparator<EWAHCompressedBitmap32>() {
                    @Override
                    public int compare(EWAHCompressedBitmap32 a, EWAHCompressedBitmap32 b) {
                        return a.sizeInBytes()
                                - b.sizeInBytes();
                    }
                }
        );
        while(bitmaps.hasNext())
            pq.add(bitmaps.next());
        if(pq.isEmpty()) return new EWAHCompressedBitmap32();
        while (pq.size() > 1) {
            EWAHCompressedBitmap32 x1 = pq.poll();
            EWAHCompressedBitmap32 x2 = pq.poll();
            pq.add(x1.xor(x2));
        }
        return pq.poll();
    }

    /**
     * Uses a priority queue to compute the xor aggregate.
     *
     * The content of the container is overwritten.
     *
     * This algorithm runs in linearithmic time (O(n log n)) with respect to the number of bitmaps.
     *
     * @param container where we write the result
     * @param bitmaps   to be aggregated
     */
    public static void xorToContainer(final BitmapStorage32 container,
                                      final EWAHCompressedBitmap32... bitmaps) {
        if (bitmaps.length < 2)
            throw new IllegalArgumentException(
                    "We need at least two bitmaps");
        PriorityQueue<EWAHCompressedBitmap32> pq = new PriorityQueue<EWAHCompressedBitmap32>(
                bitmaps.length,
                new Comparator<EWAHCompressedBitmap32>() {
                    @Override
                    public int compare(EWAHCompressedBitmap32 a,
                                       EWAHCompressedBitmap32 b) {
                        return a.sizeInBytes()
                                - b.sizeInBytes();
                    }
                }
        );
        Collections.addAll(pq, bitmaps);
        while (pq.size() > 2) {
            EWAHCompressedBitmap32 x1 = pq.poll();
            EWAHCompressedBitmap32 x2 = pq.poll();
            pq.add(x1.xor(x2));
        }
        pq.poll().xorToContainer(pq.poll(), container);
    }

}


package com.googlecode.javaewah32;

/*
 * Copyright 2009-2016, Daniel Lemire, Cliff Moon, David McIntosh, Robert Becho, Google Inc., Veronika Zenz, Owen Kaser, Gregory Ssi-Yan-Kai, Rory Graves
 * Licensed under the Apache License, Version 2.0.
 */

/**
 * BitCounter is a fake bitset data structure. Instead of storing the actual
 * data, it only records the number of set bits.
 *
 * @author Daniel Lemire and David McIntosh
 * @since 0.5.0
 */

public final class BitCounter32 implements BitmapStorage32 {

    /**
     * Virtually add words directly to the bitmap
     *
     * @param newData the word
     */
    @Override
    public void addWord(final int newData) {
        this.oneBits += Integer.bitCount(newData);
    }

    /**
     * Virtually add literal words directly to the bitmap
     *
     * @param newData the word
     */
    @Override
    public void addLiteralWord(final int newData) {
        this.oneBits += Integer.bitCount(newData);
    }

    /**
     * virtually add several literal words.
     *
     * @param buffer the buffer wrapping the literal words
     * @param start  the starting point in the array
     * @param number the number of literal words to add
     */
    @Override
    public void addStreamOfLiteralWords(Buffer32 buffer, int start, int number) {
        for (int i = start; i < start + number; i++) {
            addLiteralWord(buffer.getWord(i));
        }
    }

    /**
     * virtually add many zeroes or ones.
     *
     * @param v      zeros or ones
     * @param number how many to words add
     */
    @Override
    public void addStreamOfEmptyWords(boolean v, int number) {
        if (v) {
            this.oneBits += number
                    * EWAHCompressedBitmap32.WORD_IN_BITS;
        }
    }

    /**
     * virtually add several negated literal words.
     *
     * @param buffer the buffer wrapping the literal words
     * @param start  the starting point in the array
     * @param number the number of literal words to add
     */
    @Override
    public void addStreamOfNegatedLiteralWords(Buffer32 buffer, int start,
                                               int number) {
        for (int i = start; i < start + number; i++) {
            addLiteralWord(~buffer.getWord(i));
        }
    }

    @Override
    public void clear() {
        this.oneBits = 0;
    }

    /**
     * As you act on this class, it records the number of set (true) bits.
     *
     * @return number of set bits
     */
    public int getCount() {
        return this.oneBits;
    }

    @Override
    public void setSizeInBitsWithinLastWord(int bits) {
        // no action
    }

    private int oneBits;

}


package com.googlecode.javaewah32.symmetric;

import com.googlecode.javaewah.datastructure.BitSet;
import com.googlecode.javaewah32.BitmapStorage32;

import java.util.Iterator;
import java.util.List;

/**
 * This is a Java specification for an "updatable" Boolean function meant to run
 * over EWAH bitmaps.
 *
 * Reference:
 *
 * Daniel Lemire, Owen Kaser, Kamel Aouiche, Sorting improves word-aligned
 * bitmap indexes. Data & Knowledge Engineering 69 (1), pages 3-28, 2010.
 *
 * @author Daniel Lemire
 * @since 0.8.2
 */
public abstract class UpdateableBitmapFunction32 {
    EWAHPointer32[] rw = new EWAHPointer32[0];
    int hammingWeight = 0;
    int litWeight = 0;
    boolean[] b = new boolean[0];
    final BitSet litwlist = new BitSet(0);

    UpdateableBitmapFunction32() {
    }

    /**
     * @return the current number of literal words
     */
    public final int getNumberOfLiterals() {
        return this.litwlist.cardinality();
    }

    /**
     * Goes through the literals.
     *
     * @return an iterator
     */
    public final Iterable<EWAHPointer32> getLiterals() {
        return new Iterable<EWAHPointer32>() {

            @Override
            public Iterator<EWAHPointer32> iterator() {
                return new Iterator<EWAHPointer32>() {
                    int k = UpdateableBitmapFunction32.this.litwlist
                            .nextSetBit(0);

                    @Override
                    public boolean hasNext() {
                        return this.k >= 0;
                    }

                    @Override
                    public EWAHPointer32 next() {
                        EWAHPointer32 answer = UpdateableBitmapFunction32.this.rw[this.k];
                        this.k = UpdateableBitmapFunction32.this.litwlist
                                .nextSetBit(this.k + 1);
                        return answer;
                    }

                    @Override
                    public void remove() {
                        throw new RuntimeException(
                                "N/A");
                    }
                };
            }
        };
    }

    /**
     * append to the list the literal words as EWAHPointer
     *
     * @param container where we write
     */
    public final void fillWithLiterals(final List<EWAHPointer32> container) {
        for (int k = this.litwlist.nextSetBit(0); k >= 0; k = this.litwlist
                .nextSetBit(k + 1)) {
            container.add(this.rw[k]);
        }
    }

    /**
     * @param newsize the number of inputs
     */
    public final void resize(final int newsize) {
        this.rw = java.util.Arrays.copyOf(this.rw, newsize);
        this.litwlist.resize(newsize);
        this.b = java.util.Arrays.copyOf(this.b, newsize);
    }

    /**
     * @param pos position of a literal
     */
    public void setLiteral(final int pos) {
        if (!this.litwlist.get(pos)) {
            this.litwlist.set(pos);
            this.litWeight++;
            if (this.b[pos]) {
                this.b[pos] = false;
                --this.hammingWeight;
            }
        }
    }

    /**
     * @param pos position where a literal was removed
     */
    public void clearLiteral(final int pos) {
        if (this.litwlist.get(pos)) {
            // litwlist.unset(pos);
            this.litwlist.set(pos, false);
            this.litWeight--;
        }
    }

    /**
     * @param pos position where a zero word was added
     */
    public final void setZero(final int pos) {
        if (this.b[pos]) {
            this.b[pos] = false;
            --this.hammingWeight;
        } else {
            clearLiteral(pos);
        }
    }

    /**
     * @param pos position were a 11...1 word was added
     */
    public final void setOne(final int pos) {
        if (!this.b[pos]) {
            clearLiteral(pos);
            this.b[pos] = true;
            ++this.hammingWeight;
        }
    }

    /**
     * Writes out the answer.
     *
     * @param out      output buffer
     * @param runBegin beginning of the run
     * @param runend   end of the run
     */
    public abstract void dispatch(BitmapStorage32 out, int runBegin,
                                  int runend);

}


package com.googlecode.javaewah;

/*
 * Copyright 2009-2016, Daniel Lemire, Cliff Moon, David McIntosh, Robert Becho, Google Inc., Veronika Zenz, Owen Kaser, Gregory Ssi-Yan-Kai, Rory Graves
 * Licensed under the Apache License, Version 2.0.
 */

/**
 * This class can be used to iterate over blocks of bitmap data.
 *
 * @author Daniel Lemire
 */
public class BufferedIterator implements IteratingRLW, Cloneable {

    /**
     * Instantiates a new iterating buffered running length word.
     *
     * @param iterator iterator
     */
    public BufferedIterator(final CloneableIterator<EWAHIterator> iterator) {
        this.masterIterator = iterator;
        if (this.masterIterator.hasNext()) {
            iteratingBrlw = new IteratingBufferedRunningLengthWord(this.masterIterator.next());
        }
    }

    /**
     * Discard first words, iterating to the next running length word if
     * needed.
     *
     * @param x the number of words to be discarded
     */
    @Override
    public void discardFirstWords(long x) {
        while (x > 0) {
            if (this.iteratingBrlw.getRunningLength() > x) {
                this.iteratingBrlw.discardFirstWords(x);
                return;
            }
            this.iteratingBrlw.discardFirstWords(this.iteratingBrlw.getRunningLength());
            x -= this.iteratingBrlw.getRunningLength();
            long toDiscard = x > this.iteratingBrlw.getNumberOfLiteralWords()
                    ? this.iteratingBrlw.getNumberOfLiteralWords()
                    : x;

            this.iteratingBrlw.discardFirstWords(toDiscard);
            x -= toDiscard;
            if ((x > 0) || (this.iteratingBrlw.size() == 0)) {
                if (!this.next()) {
                    break;
                }
            }
        }
    }
	@Override
	public void discardLiteralWords(long x) {
		this.iteratingBrlw.discardLiteralWords(x);
        if (this.iteratingBrlw.getNumberOfLiteralWords() == 0)
            this.next();
	}

    @Override
    public void discardRunningWords() {
        this.iteratingBrlw.discardRunningWords();
        if (this.iteratingBrlw.getNumberOfLiteralWords() == 0)
            this.next();
    }

    /**
     * Move to the next RunningLengthWord
     *
     * @return whether the move was possible
     */
    @Override
    public boolean next() {
        if (!this.iteratingBrlw.next()) {
            if (!this.masterIterator.hasNext()) {
                return false;
            } else {
                this.iteratingBrlw = new IteratingBufferedRunningLengthWord(this.masterIterator.next());
            }
        }
        return true;
    }

    /**
     * Get the nth literal word for the current running length word
     *
     * @param index zero based index
     * @return the literal word
     */
    @Override
    public long getLiteralWordAt(int index) {
        return this.iteratingBrlw.getLiteralWordAt(index);
    }

    /**
     * Gets the number of literal words for the current running length word.
     *
     * @return the number of literal words
     */
    @Override
    public int getNumberOfLiteralWords() {
        return this.iteratingBrlw.getNumberOfLiteralWords();
    }

    /**
     * Gets the running bit.
     *
     * @return the running bit
     */
    @Override
    public boolean getRunningBit() {
        return this.iteratingBrlw.getRunningBit();
    }

    /**
     * Gets the running length.
     *
     * @return the running length
     */
    @Override
    public long getRunningLength() {
        return this.iteratingBrlw.getRunningLength();
    }

    /**
     * Size in uncompressed words of the current running length word.
     *
     * @return the size
     */
    @Override
    public long size() {
        return this.iteratingBrlw.size();
    }

    @Override
    public BufferedIterator clone() throws CloneNotSupportedException {
        BufferedIterator answer = (BufferedIterator) super.clone();
        answer.iteratingBrlw = this.iteratingBrlw.clone();
        answer.masterIterator = this.masterIterator.clone();
        return answer;
    }

    private IteratingBufferedRunningLengthWord iteratingBrlw;
    private CloneableIterator<EWAHIterator> masterIterator;

}