{-|
Module      : Data.Bits.Pdep.Prim
Description : Parallel deposit operations (emulated)
Copyright   : (c) John Ky, 2018-2019
License     : BSD-3-Clause
Maintainer  : newhoggy@gmail.com
Stability   : stable
-}
module Data.Bits.Pdep.Slow
  ( SlowPdep(..)
  ) where

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

-- | Bitwise parallel deposit for 'Word64'.  Deposits bits from the source at the locations
-- described by the mask.
--
-- Copies lower order bits from 'src' to 'mask' 1-bit locations in the return value;
-- 'mask' 0-bit locations in the return value will be cleared.
--
-- >>> slowPdep64 1 1
-- 1
slowPdep64 :: Word64 -> Word64 -> Word64
slowPdep64 :: Word64 -> Word64 -> Word64
slowPdep64 = Word64 -> Word64 -> Word64 -> Word64
slowPdep64' Word64
0

lsb :: Word64 -> Word64
lsb :: Word64 -> Word64
lsb Word64
src = 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)

slowPdep64' :: Word64 -> Word64 -> Word64 -> Word64
slowPdep64' :: Word64 -> Word64 -> Word64 -> Word64
slowPdep64' 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
slowPdep64' Word64
newResult (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
        newResult :: Word64
newResult = Word64
result Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64 -> Word64
lsb Word64
src Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
lowest)

-- | Bitwise parallel deposit (emulated).  Deposits bits from the source at the
-- locations described by the mask.
class SlowPdep a where
  slowPdep :: a -> a -> a

instance SlowPdep Word where
  slowPdep :: Word -> Word -> Word
slowPdep Word
s Word
m = Word64 -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Word64 -> Word64
slowPdep64 (Word -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
s) (Word -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
m))

instance SlowPdep Word8 where
  slowPdep :: Word8 -> Word8 -> Word8
slowPdep Word8
s Word8
m = Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Word64 -> Word64
slowPdep64 (Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
s) (Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
m))

instance SlowPdep Word16 where
  slowPdep :: Word16 -> Word16 -> Word16
slowPdep Word16
s Word16
m = Word64 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Word64 -> Word64
slowPdep64 (Word16 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
s) (Word16 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
m))

instance SlowPdep Word32 where
  slowPdep :: Word32 -> Word32 -> Word32
slowPdep Word32
s Word32
m = Word64 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Word64 -> Word64
slowPdep64 (Word32 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
s) (Word32 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
m))

instance SlowPdep Word64 where
  slowPdep :: Word64 -> Word64 -> Word64
slowPdep Word64
s Word64
m = Word64 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Word64 -> Word64
slowPdep64 (Word64 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
s) (Word64 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
m))