Livt packages

Eccelerators.BitTwiddling

Version 0.1.1

Readable 32-bit bit manipulation, counting, scanning, permutation, and arithmetic utilities for Livt.

Published files (26)

src/counting/BitScanning.lvt

namespace Eccelerators.BitTwiddling.Counting

/**
 * Locates significant bits and zero runs in unsigned 32-bit values.
 *
 * Bit positions use the least-significant-bit convention: bit 0 is the low
 * bit and bit 31 is the high bit. Functions that cannot identify a set bit in
 * zero return the documented sentinel rather than an ambiguous valid index.
 */
class BitScanning
{
    /**
     * Counts consecutive zero bits from bit 31 toward bit 0.
     *
     * The result ranges from 0 through 32. A zero input returns 32.
     */
    public static fn CountLeadingZeros[](value: uint) int
    {
        if (value == (0 as uint))
        {
            return 32
        }

        var workingValue: uint = value
        var count: int = 0

        if (workingValue <= (0x0000FFFF as uint))
        {
            workingValue = workingValue << 16
            count = count + 16
        }
        if (workingValue <= (0x00FFFFFF as uint))
        {
            workingValue = workingValue << 8
            count = count + 8
        }
        if (workingValue <= (0x0FFFFFFF as uint))
        {
            workingValue = workingValue << 4
            count = count + 4
        }
        if (workingValue <= (0x3FFFFFFF as uint))
        {
            workingValue = workingValue << 2
            count = count + 2
        }
        if (workingValue <= (0x7FFFFFFF as uint))
        {
            count = count + 1
        }

        return count
    }

    /**
     * Returns the index of value's most-significant set bit.
     *
     * Valid indices range from 0 through 31. A zero input returns -1.
     */
    public static fn HighestSetBit[](value: uint) int
    {
        if (value == (0 as uint))
        {
            return -1
        }

        var workingValue: uint = value
        var result: int = 0
        while (workingValue > (1 as uint))
        {
            workingValue = workingValue >> 1
            result = result + 1
        }
        return result
    }

    /**
     * Returns the index of value's least-significant set bit.
     *
     * Valid indices range from 0 through 31. A zero input returns -1.
     */
    public static fn LowestSetBit[](value: uint) int
    {
        if (value == (0 as uint))
        {
            return -1
        }

        var workingValue: uint = value
        var result: int = 0
        while ((workingValue & (1 as uint)) == (0 as uint))
        {
            workingValue = workingValue >> 1
            result = result + 1
        }
        return result
    }

    /**
     * Returns floor(log2(value)), which is also the highest set-bit index.
     *
     * Positive inputs return a result from 0 through 31. Zero returns -1.
     * This implementation uses a fixed five-stage binary search.
     */
    public static fn Log2Floor[](value: uint) int
    {
        if (value == (0 as uint))
        {
            return -1
        }

        var workingValue: uint = value
        var result: int = 0

        if (workingValue >= (0x00010000 as uint))
        {
            workingValue = workingValue >> 16
            result = result + 16
        }
        if (workingValue >= (0x00000100 as uint))
        {
            workingValue = workingValue >> 8
            result = result + 8
        }
        if (workingValue >= (0x00000010 as uint))
        {
            workingValue = workingValue >> 4
            result = result + 4
        }
        if (workingValue >= (0x00000004 as uint))
        {
            workingValue = workingValue >> 2
            result = result + 2
        }
        if (workingValue >= (0x00000002 as uint))
        {
            result = result + 1
        }

        return result
    }

    /**
     * Counts consecutive zero bits from bit 0 toward bit 31.
     *
     * The result ranges from 0 through 32. A zero input returns 32.
     */
    public static fn CountTrailingZeros[](value: uint) int
    {
        if (value == (0 as uint))
        {
            return 32
        }

        var workingValue: uint = value
        var count: int = 0

        if ((workingValue & (0x0000FFFF as uint)) == (0 as uint))
        {
            workingValue = workingValue >> 16
            count = count + 16
        }
        if ((workingValue & (0x000000FF as uint)) == (0 as uint))
        {
            workingValue = workingValue >> 8
            count = count + 8
        }
        if ((workingValue & (0x0000000F as uint)) == (0 as uint))
        {
            workingValue = workingValue >> 4
            count = count + 4
        }
        if ((workingValue & (0x00000003 as uint)) == (0 as uint))
        {
            workingValue = workingValue >> 2
            count = count + 2
        }
        if ((workingValue & (1 as uint)) == (0 as uint))
        {
            count = count + 1
        }

        return count
    }
}