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

org.objectfabric.Bits Maven / Gradle / Ivy

The newest version!
/**
 * This file is part of ObjectFabric (http://objectfabric.org).
 *
 * ObjectFabric is licensed under the Apache License, Version 2.0, the terms
 * of which may be found at http://www.apache.org/licenses/LICENSE-2.0.html.
 * 
 * Copyright ObjectFabric Inc.
 * 
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

package org.objectfabric;

/**
 * Manipulates bits in arrays of integers. Bits are stored in integers because 32 bits
 * JVMs do not guarantee longs are read or written atomically.
 */
abstract class Bits {

    public static final int BITS_PER_UNIT_SHIFT = 5; // 2 ^ 5 == 32

    public static final int BITS_PER_UNIT = 1 << BITS_PER_UNIT_SHIFT;

    public static final int BIT_INDEX_MASK = BITS_PER_UNIT - 1;

    public static final int SPARSE_BITSET_DEFAULT_CAPACITY = 2;

    /**
     * For sparse arrays. Cannot use two arrays as elements must be written atomically
     * during object version merges.
     */
    public static final class Entry {

        public int IntIndex;

        public int Value;

        public Entry(int intIndex, int value) {
            IntIndex = intIndex;
            Value = value;
        }
    }

    private Bits() {
    }

    public static int arrayLength(int size) {
        if (Debug.ENABLED)
            Debug.assertion(size > 0);

        return intIndex(size - 1) + 1;
    }

    public static boolean get(int value, int index) {
        if (Debug.ENABLED)
            Debug.assertion(index >= 0 && index < Integer.SIZE);

        return (value & mask32(index)) != 0;
    }

    public static boolean get(Entry[] sparse, int index) {
        if (Debug.ENABLED)
            Debug.assertion(index >= 0);

        if (Debug.ENABLED)
            checkInvariants(sparse);

        if (sparse != null) {
            Entry entry = getEntry(sparse, intIndex(index));

            if (entry != null)
                return (entry.Value & maskArray(index)) != 0;
        }

        return false;
    }

    private static Entry getEntry(Entry[] sparse, int intIndex) {
        int foldedIntIndex = intIndex & (sparse.length - 1);

        for (int i = OpenMap.attemptsStart(sparse.length); i >= 0; i--) {
            Entry current = sparse[foldedIntIndex];

            if (current != null && current.IntIndex == intIndex)
                return current;

            foldedIntIndex = (foldedIntIndex + 1) & (sparse.length - 1);
        }

        return null;
    }

    public static int getFoldedIntIndexFromIndex(Entry[] sparse, int index) {
        int intIndex = intIndex(index);
        return getFoldedIntIndexFromIntIndex(sparse, intIndex);
    }

    public static int getFoldedIntIndexFromIntIndex(Entry[] sparse, int intIndex) {
        if (Debug.ENABLED)
            checkInvariants(sparse);

        int foldedIntIndex = intIndex & (sparse.length - 1);

        for (int i = OpenMap.attemptsStart(sparse.length); i >= 0; i--) {
            Entry current = sparse[foldedIntIndex];

            if (current != null && current.IntIndex == intIndex)
                return foldedIntIndex;

            foldedIntIndex = (foldedIntIndex + 1) & (sparse.length - 1);
        }

        return -1;
    }

    //

    public static int set(int set, int index) {
        if (Debug.ENABLED)
            Debug.assertion(index >= 0 && index < Integer.SIZE);

        return set | mask32(index);
    }

    public static int set(int set, int index, boolean value) {
        if (Debug.ENABLED)
            Debug.assertion(index >= 0 && index < Integer.SIZE);

        int mask = mask32(index);
        return value ? set | mask : set & ~mask;
    }

    public static Entry[] set(Entry[] sparse, int index) {
        if (sparse == null)
            sparse = new Bits.Entry[Bits.SPARSE_BITSET_DEFAULT_CAPACITY];

        while (!tryToSet(sparse, index))
            sparse = reindex(sparse);

        return sparse;
    }

    public static boolean tryToSet(Entry[] sparse, int index) {
        if (Debug.ENABLED)
            Debug.assertion(index >= 0);

        if (Debug.ENABLED)
            checkInvariants(sparse);

        int intIndex = intIndex(index);
        int foldedIntIndex = intIndex & (sparse.length - 1);

        for (int i = OpenMap.attemptsStart(sparse.length); i >= 0; i--) {
            Entry current = sparse[foldedIntIndex];

            if (current != null && current.IntIndex == intIndex) {
                current.Value |= maskArray(index);
                return true;
            }

            if (current == null) {
                sparse[foldedIntIndex] = new Bits.Entry(intIndex, maskArray(index));
                return true;
            }

            foldedIntIndex = (foldedIntIndex + 1) & (sparse.length - 1);
        }

        return false;
    }

    private static Entry[] reindex(Entry[] sparse) {
        Entry[] old = sparse;

        for (;;) {
            sparse = new Bits.Entry[sparse.length << OpenMap.TIMES_TWO_SHIFT];

            if (reindex(old, sparse))
                break;
        }

        return sparse;
    }

    public static boolean reindex(Entry[] oldSparse, Entry[] newSparse) {
        if (Debug.ENABLED) {
            checkInvariants(oldSparse);
            checkInvariants(newSparse);
        }

        for (int i = oldSparse.length - 1; i >= 0; i--)
            if (oldSparse[i] != null)
                if (add(newSparse, oldSparse[i]) < 0)
                    return false;

        return true;
    }

    //

    public static int add(Entry[] sparse, Entry entry) {
        int foldedIntIndex = entry.IntIndex & (sparse.length - 1);

        for (int i = OpenMap.attemptsStart(sparse.length); i >= 0; i--) {
            Entry current = sparse[foldedIntIndex];

            if (Debug.ENABLED)
                if (current != null)
                    Debug.assertion(current.IntIndex != entry.IntIndex);

            if (current == null) {
                sparse[foldedIntIndex] = entry;
                return foldedIntIndex;
            }

            foldedIntIndex = (foldedIntIndex + 1) & (sparse.length - 1);
        }

        return -1;
    }

    //

    public static int unset(int set, int index) {
        if (Debug.ENABLED)
            Debug.assertion(index >= 0 && index < Integer.SIZE);

        return set & ~mask32(index);
    }

    public static void unset(Entry[] sparse, int index) {
        if (Debug.ENABLED)
            Debug.assertion(index >= 0);

        if (Debug.ENABLED)
            checkInvariants(sparse);

        int intIndex = intIndex(index);
        int foldedIntIndex = intIndex & (sparse.length - 1);

        for (int i = OpenMap.attemptsStart(sparse.length); i >= 0; i--) {
            Entry current = sparse[foldedIntIndex];

            if (current != null && current.IntIndex == intIndex) {
                current.Value &= ~maskArray(index);
                break;
            }

            if (current == null)
                break;

            foldedIntIndex = (foldedIntIndex + 1) & (sparse.length - 1);
        }
    }

    //

    public static boolean intersects(int a, int b) {
        return (a & b) != 0;
    }

    public static boolean intersects(Entry[] a, Entry[] b) {
        for (int i = a.length - 1; i >= 0; i--) {
            if (a[i] != null) {
                Entry current = getEntry(b, a[i].IntIndex);

                if (current != null)
                    if ((a[i].Value & current.Value) != 0)
                        return true;
            }
        }

        return false;
    }

    //

    public static int merge(int value, int source) {
        return value | source;
    }

    public static boolean mergeInPlace(Entry[] sparse, Entry[] source) {
        if (Debug.ENABLED) {
            checkInvariants(sparse);
            checkInvariants(source);
        }

        for (int i = source.length - 1; i >= 0; i--)
            if (source[i] != null && source[i].Value != 0)
                if (!mergeInPlace(sparse, source[i]))
                    return false;

        return true;
    }

    private static boolean mergeInPlace(Entry[] sparse, Entry entry) {
        int foldedIntIndex = entry.IntIndex & (sparse.length - 1);

        for (int i = OpenMap.attemptsStart(sparse.length); i >= 0; i--) {
            Entry current = sparse[foldedIntIndex];

            if (current != null && current.IntIndex == entry.IntIndex) {
                current.Value |= entry.Value;
                return true;
            }

            if (current == null) {
                sparse[foldedIntIndex] = entry;
                return true;
            }

            foldedIntIndex = (foldedIntIndex + 1) & (sparse.length - 1);
        }

        return false;
    }

    public static boolean mergeByCopy(Entry[] sparse, Entry[] source) {
        if (Debug.ENABLED) {
            checkInvariants(sparse);
            checkInvariants(source);
        }

        for (int i = source.length - 1; i >= 0; i--)
            if (source[i] != null && source[i].Value != 0)
                if (!mergeByCopy(sparse, source[i]))
                    return false;

        return true;
    }

    private static boolean mergeByCopy(Entry[] sparse, Entry entry) {
        int foldedIntIndex = entry.IntIndex & (sparse.length - 1);

        for (int i = OpenMap.attemptsStart(sparse.length); i >= 0; i--) {
            Entry current = sparse[foldedIntIndex];

            if (current != null && current.IntIndex == entry.IntIndex) {
                sparse[foldedIntIndex] = new Bits.Entry(current.IntIndex, current.Value | entry.Value);
                return true;
            }

            if (current == null) {
                sparse[foldedIntIndex] = entry;
                return true;
            }

            foldedIntIndex = (foldedIntIndex + 1) & (sparse.length - 1);
        }

        return false;
    }

    //

    public static Entry[] clone(Entry[] sparse) {
        if (Debug.ENABLED)
            checkInvariants(sparse);

        Entry[] clone = new Bits.Entry[sparse.length];

        for (int i = sparse.length - 1; i >= 0; i--)
            if (sparse[i] != null)
                clone[i] = new Bits.Entry(sparse[i].IntIndex, sparse[i].Value);

        return clone;
    }

    //

    public static int and(int a, int b) {
        return a & b;
    }

    public static Entry[] and(Entry[] a, Entry[] b) {
        if (Debug.ENABLED) {
            checkInvariants(a);
            checkInvariants(b);
        }

        if (Debug.ENABLED) { // Should not call for nothing
            boolean empty = true;

            for (int i = b.length - 1; i >= 0; i--) {
                if (b[i] != null) {
                    Debug.assertion(b[i].Value != 0);
                    empty = false;
                }
            }

            Debug.assertion(!empty);
        }

        Entry[] result = new Bits.Entry[a.length];

        for (int i = a.length - 1; i >= 0; i--)
            if (a[i] != null)
                result[i] = and(a[i], b);

        return result;
    }

    private static Entry and(Entry entry, Entry[] mask) {
        int foldedIntIndex = entry.IntIndex & (mask.length - 1);

        for (int i = OpenMap.attemptsStart(mask.length); i >= 0; i--) {
            Entry current = mask[foldedIntIndex];

            if (current != null && current.IntIndex == entry.IntIndex)
                return new Bits.Entry(entry.IntIndex, entry.Value & current.Value);

            if (current == null)
                return entry;

            foldedIntIndex = (foldedIntIndex + 1) & (mask.length - 1);
        }

        return entry;
    }

    //

    public static int andNot(int a, int b) {
        return a & ~b;
    }

    public static Entry[] andNot(Entry[] a, Entry[] b) {
        if (Debug.ENABLED) {
            checkInvariants(a);
            checkInvariants(b);
        }

        Entry[] result = null;

        if (a != null) {
            for (int i = a.length - 1; i >= 0; i--) {
                if (a[i] != null) {
                    Entry entry = andNot(a[i], b);

                    if (entry != null) {
                        if (result == null)
                            result = new Bits.Entry[a.length];

                        result[i] = entry;
                    }
                }
            }
        }

        return result;
    }

    private static Entry andNot(Entry entry, Entry[] mask) {
        if (mask != null) {
            int foldedIntIndex = entry.IntIndex & (mask.length - 1);

            for (int i = OpenMap.attemptsStart(mask.length); i >= 0; i--) {
                Entry current = mask[foldedIntIndex];

                if (current != null && current.IntIndex == entry.IntIndex) {
                    int value = entry.Value & ~current.Value;

                    if (value == 0)
                        return null;

                    return new Bits.Entry(entry.IntIndex, value);
                }

                if (current == null)
                    return entry;

                foldedIntIndex = (foldedIntIndex + 1) & (mask.length - 1);
            }
        }

        return entry;
    }

    //

    public static boolean isEmpty(int value) {
        return value == 0;
    }

    public static boolean isEmpty(Entry[] sparse) {
        /*
         * TODO make sure everywhere if array is created, it is not empty, switch test to
         * != null.
         */
        if (sparse != null)
            for (int i = sparse.length - 1; i >= 0; i--)
                if (sparse[i] != null && sparse[i].Value != 0)
                    return false;

        return true;
    }

    //

    public static int remove(int set, int index) {
        int mod = index & BIT_INDEX_MASK;

        if (mod == 0) // Cannot shift by 32
            return set >>> 1;

        return (set & (-1 >>> (32 - mod))) | ((set >>> 1) & (-1 << mod));
    }

    //

    /**
     * Given a bit index return unit index containing it.
     */
    private static int intIndex(int index) {
        return index >> BITS_PER_UNIT_SHIFT;
    }

    /**
     * Given a bit index, return a integer that masks that bit in its integer.
     */
    private static int mask32(int index) {
        if (Debug.ENABLED)
            Debug.assertion(index == (index & BIT_INDEX_MASK));

        return 1 << index;
    }

    private static int maskArray(int index) {
        return 1 << (index & BIT_INDEX_MASK);
    }

    // Debug

    private static void checkInvariants(Entry[] sparse) {
        if (!Debug.ENABLED)
            Debug.assertAlways(false);

        if (sparse != null) {
            Debug.assertion(Utils.nextPowerOf2(sparse.length) == sparse.length);

            for (int j = sparse.length - 1; j >= 0; j--) {
                if (sparse[j] != null) {
                    if (j != (sparse[j].IntIndex & (sparse.length - 1)))
                        Debug.assertion(sparse[(j - 1) & (sparse.length - 1)] != null);

                    if (Debug.SLOW_CHECKS)
                        for (int i = sparse.length - 1; i > j; i--)
                            Debug.assertion(sparse[j] == null || sparse[i] == null || sparse[j].IntIndex != sparse[i].IntIndex);
                }
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy