{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE TypeFamilies          #-}

-- |
-- Copyright: 2016 John Ky
-- License: MIT
--
-- Succinct operations.
module HaskellWorks.Data.Bits.Broadword
  ( Broadword(..)
  , broadword
  , h
  , l
  , lsb
  , kBitDiff
  , kBitDiffPos
  , kBitDiffUnsafe
  ) where

import qualified Data.Bits                        as DB
import           Data.Word
import           HaskellWorks.Data.Bits.BitWise

newtype Broadword a = Broadword a deriving (Eq, Show)

broadword :: Broadword Word64 -> Word64
broadword (Broadword a) = a
{-# INLINE broadword #-}

l :: Int -> Word64
l 2   = 0x5555555555555555
l 4   = 0x1111111111111111
l 8   = 0x0101010101010101
l 16  = 0x0001000100010001
l 32  = 0x0000000100000001
l 64  = 0x0000000000000001
l k   = error ("Invalid h k where k = " ++ show k)
{-# INLINE l #-}

h :: Int -> Word64
h 2   = 0xaaaaaaaaaaaaaaaa
h 4   = 0x8888888888888888
h 8   = 0x8080808080808080
h 16  = 0x8000800080008000
h 32  = 0x8000000080000000
h 64  = 0x8000000000000000
h k   = error ("Invalid h k where k = " ++ show k)
{-# INLINE h #-}

kBitDiff :: Int -> Word64 -> Word64 -> Word64
kBitDiff k x y = ((x .|. h k) - (y .&. comp (h k))) .^. ((x .^. comp y) .&. h k)
{-# INLINE kBitDiff #-}

kBitDiffPos :: Int -> Word64 -> Word64 -> Word64
kBitDiffPos k x y = let d = kBitDiff k x y in d .&. ((d .>. fromIntegral (k - 1)) - 1)
{-# INLINE kBitDiffPos #-}

kBitDiffUnsafe :: Int -> Word64 -> Word64 -> Word64
kBitDiffUnsafe k x y = ((x .|. h k) - y) .^. h k
{-# INLINE kBitDiffUnsafe #-}

lsb :: Word64 -> Word64
lsb w = let r = fromIntegral (DB.countTrailingZeros w) in r .|. negate ((r .>. 6) .&. 0x1)
{-# INLINE lsb #-}