module HaskellWorks.Data.Bits.Log2
  ( Log2(..)
  ) where

import qualified Data.Vector.Storable as DVS
import           Data.Word
import           HaskellWorks.Data.AtIndex
import           HaskellWorks.Data.Bits.BitWise

class Log2 a where
  log2 :: a -> Int

log2_64_tab :: DVS.Vector Int
log2_64_tab = DVS.fromList [
    63,  0, 58,  1, 59, 47, 53,  2,
    60, 39, 48, 27, 54, 33, 42,  3,
    61, 51, 37, 40, 49, 18, 28, 20,
    55, 30, 34, 11, 43, 14, 22,  4,
    62, 57, 46, 52, 38, 26, 32, 41,
    50, 36, 17, 19, 29, 10, 13, 21,
    56, 45, 25, 31, 35, 16,  9, 12,
    44, 24, 15,  8, 23,  7,  6,  5]

log2_32_tab :: DVS.Vector Int
log2_32_tab = DVS.fromList [
     0,  9,  1, 10, 13, 21,  2, 29,
    11, 14, 16, 18, 22, 25,  3, 30,
     8, 12, 20, 28, 15, 17, 24,  7,
    19, 27, 23,  6, 26,  5,  4, 31]

instance Log2 Word64 where
  log2 v0 =
      let v1 = v0 .|. (v0 .>.  1) in
      let v2 = v1 .|. (v1 .>.  2) in
      let v3 = v2 .|. (v2 .>.  4) in
      let v4 = v3 .|. (v3 .>.  8) in
      let v5 = v4 .|. (v4 .>. 16) in
      let v6 = v5 .|. (v5 .>. 32) in
      log2_64_tab !!! fromIntegral (((v6 - (v6 .>. 1)) * 0x07EDD5E59A4E28C2) .>. 58)

instance Log2 Word32 where
  log2 v0 =
      let v1 = v0 .|. (v0 .>.  1) in
      let v2 = v1 .|. (v1 .>.  2) in
      let v3 = v2 .|. (v2 .>.  4) in
      let v4 = v3 .|. (v3 .>.  8) in
      let v5 = v4 .|. (v4 .>. 16) in
      log2_32_tab !!! fromIntegral ((v5 * 0x07C4ACDD) .>. 27)