module HaskellWorks.Prim.Bits.Emul
  ( pdep32
  , pdep64
  , pext32
  , pext64
  ) where

import Data.Bits
import Data.Int
import Data.Word

pdep64 :: Word64 -> Word64 -> Word64
pdep64 :: Word64 -> Word64 -> Word64
pdep64 = Word64 -> Word64 -> Word64 -> Word64
pdep64' Word64
0

pdep32 :: Word32 -> Word32 -> Word32
pdep32 :: Word32 -> Word32 -> Word32
pdep32 Word32
src Word32
mask = Word64 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Word64 -> Word64
pdep64 (Word32 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
src) (Word32 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
mask))

pdep64' :: Word64 -> Word64 -> Word64 -> Word64
pdep64' :: Word64 -> Word64 -> Word64 -> Word64
pdep64' Word64
result Word64
src Word64
mask = if Word64
lowest Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word64
0
  then Word64 -> Word64 -> Word64 -> Word64
pdep64' (Word64
result Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
lsb Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
lowest)) (Word64
src Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
1) (Word64
mask Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64 -> Word64
forall a. Bits a => a -> a
complement Word64
lowest)
  else Word64
result
  where lowest :: Word64
lowest  = (-Word64
mask) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
mask
        lsb :: Word64
lsb     = Int64 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word64 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
src Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
63) :: Int64) Int64 -> Int -> Int64
forall a. Bits a => a -> Int -> a
`shiftR` Int
63)


pext64 :: Word64 -> Word64 -> Word64
pext64 :: Word64 -> Word64 -> Word64
pext64 = Word64 -> Int -> Int -> Word64 -> Word64 -> Word64
pext64' Word64
0 Int
0 Int
0

pext32 :: Word32 -> Word32 -> Word32
pext32 :: Word32 -> Word32 -> Word32
pext32 Word32
src Word32
mask = Word64 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Word64 -> Word64
pext64 (Word32 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
src) (Word32 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
mask))

pext64' :: Word64 -> Int -> Int -> Word64 -> Word64 -> Word64
pext64' :: Word64 -> Int -> Int -> Word64 -> Word64 -> Word64
pext64' Word64
result Int
offset Int
index Word64
src Word64
mask = if Int
index Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
64
  then if Word64
maskBit Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word64
0
          then Word64 -> Int -> Int -> Word64 -> Word64 -> Word64
pext64' (Word64
result Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
srcBit Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
offset)) (Int
offset Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
index Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Word64
src Word64
mask
          else Word64 -> Int -> Int -> Word64 -> Word64 -> Word64
pext64'  Word64
result                               Int
offset       (Int
index Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Word64
src Word64
mask
  else Word64
result
  where srcBit :: Word64
srcBit  = (Word64
src  Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
index) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
1
        maskBit :: Word64
maskBit = (Word64
mask Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
index) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
1