    {-# LANGUAGE NoImplicitPrelude #-}
    {-# LANGUAGE MagicHash #-}
    {-# LANGUAGE BangPatterns #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  GHC.Unicode.Internal.Bits
    -- Copyright   : (c) 2020 Andrew Lelechenko
    --               (c) 2020 Composewell Technologies
    -- License     : BSD-3-Clause
    --
    -- Maintainer  :  streamly@composewell.com
    -- Stability   :  internal
    -- Portability :  non-portable (GHC extensions)
    --
    -- Fast, static bitmap lookup utilities
    --
    -----------------------------------------------------------------------------

    module GHC.Unicode.Internal.Bits
        ( lookupBit64,
          lookupIntN
        ) where

    import GHC.Base (Bool, Int(..), Word(..), Eq(..))
    import GHC.Bits (finiteBitSize, popCount)
    import {-# SOURCE #-} GHC.ByteOrder
    import GHC.Prim
           (Addr#,
            indexWordOffAddr#, indexWord8OffAddr#,
            andI#, uncheckedIShiftRL#,
            and#, word2Int#, uncheckedShiftL#,
            word8ToWord#, byteSwap#)
    import GHC.Num ((-))

    -- | @lookup64 addr index@ looks up the bit stored at bit index @index@ using a
    -- bitmap starting at the address @addr@. Looks up the 64-bit word containing
    -- the bit and then the bit in that word. The caller must make sure that the
    -- 64-bit word at the byte address (addr + index / 64) * 8 is legally
    -- accessible memory.
    --
    lookupBit64 :: Addr# -> Int -> Bool
    lookupBit64 :: Addr# -> Int -> Bool
    lookupBit64 Addr#
    addr# (I# Int#
    index#) = Word# -> Word
    W# (Word#
    word## Word# -> Word# -> Word#
    `and#` Word#
    bitMask##) Word -> Word -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Word
    0
      where
        !fbs :: Int
    fbs@(I# Int#
    fbs#) = Word -> Int
    forall b. FiniteBits b => b -> Int
    finiteBitSize (Word
    0 :: Word) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    1
        !(I# Int#
    logFbs#) = case Int
    fbs of
          Int
    31 -> Int
    5
          Int
    63 -> Int
    6
          Int
    _  -> Int -> Int
    forall a. Bits a => a -> Int
    popCount Int
    fbs -- this is a really weird architecture

        wordIndex# :: Int#
    wordIndex# = Int#
    index# Int# -> Int# -> Int#
    `uncheckedIShiftRL#` Int#
    logFbs#
        word## :: Word#
    word## = case ByteOrder
    targetByteOrder of
          ByteOrder
    BigEndian    -> Word# -> Word#
    byteSwap# (Addr# -> Int# -> Word#
    indexWordOffAddr# Addr#
    addr# Int#
    wordIndex#)
          ByteOrder
    LittleEndian -> Addr# -> Int# -> Word#
    indexWordOffAddr# Addr#
    addr# Int#
    wordIndex#
        bitIndex# :: Int#
    bitIndex# = Int#
    index# Int# -> Int# -> Int#
    `andI#` Int#
    fbs#
        bitMask## :: Word#
    bitMask## = Word#
    1## Word# -> Int# -> Word#
    `uncheckedShiftL#` Int#
    bitIndex#

    {-| @lookupIntN addr index@ looks up for the @index@-th @8@-bits word in
    the bitmap starting at @addr@, then convert it to an Int.

    The caller must make sure that:

    * @ceiling (addr + (n * 8))@ is legally accessible @Word8@.

    @since 0.3.0
    -}
    lookupIntN
      :: Addr# -- ^ Bitmap address
      -> Int   -- ^ Word index
      -> Int   -- ^ Resulting word as 'Int'
    lookupIntN :: Addr# -> Int -> Int
    lookupIntN Addr#
    addr# (I# Int#
    index#) =
      let word## :: Word#
    word## = Word8# -> Word#
    word8ToWord# (Addr# -> Int# -> Word8#
    indexWord8OffAddr# Addr#
    addr# Int#
    index#)
      in Int# -> Int
    I# (Word# -> Int#
    word2Int# Word#
    word##)