{-# LANGUAGE ScopedTypeVariables #-}

module Data.Bits.BitSize where

import Data.Functor.Identity
import Data.Int
import Data.Word

import qualified Data.Bits            as B
import qualified Data.Vector          as DV
import qualified Data.Vector.Storable as DVS

class BitSize a where
  bitSize :: a -> Int
  bitCount :: a -> Word64
  bitCount = Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word64) -> (a -> Int) -> a -> Word64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Int
forall a. BitSize a => a -> Int
bitSize
  {-# INLINE bitCount #-}

instance BitSize () where
  bitSize :: () -> Int
bitSize ()
_ = Int
0
  {-# INLINE bitSize #-}

instance BitSize Bool where
  bitSize :: Bool -> Int
bitSize = Bool -> Int
forall b. FiniteBits b => b -> Int
B.finiteBitSize
  {-# INLINE bitSize #-}

instance BitSize Word where
  bitSize :: Word -> Int
bitSize = Word -> Int
forall b. FiniteBits b => b -> Int
B.finiteBitSize
  {-# INLINE bitSize #-}

instance BitSize Word64 where
  bitSize :: Word64 -> Int
bitSize = Word64 -> Int
forall b. FiniteBits b => b -> Int
B.finiteBitSize
  {-# INLINE bitSize #-}

instance BitSize Word32 where
  bitSize :: Word32 -> Int
bitSize = Word32 -> Int
forall b. FiniteBits b => b -> Int
B.finiteBitSize
  {-# INLINE bitSize #-}

instance BitSize Word16 where
  bitSize :: Word16 -> Int
bitSize = Word16 -> Int
forall b. FiniteBits b => b -> Int
B.finiteBitSize
  {-# INLINE bitSize #-}

instance BitSize Word8 where
  bitSize :: Word8 -> Int
bitSize = Word8 -> Int
forall b. FiniteBits b => b -> Int
B.finiteBitSize
  {-# INLINE bitSize #-}

instance BitSize Int where
  bitSize :: Int -> Int
bitSize = Int -> Int
forall b. FiniteBits b => b -> Int
B.finiteBitSize
  {-# INLINE bitSize #-}

instance BitSize Int64 where
  bitSize :: Int64 -> Int
bitSize = Int64 -> Int
forall b. FiniteBits b => b -> Int
B.finiteBitSize
  {-# INLINE bitSize #-}

instance BitSize Int32 where
  bitSize :: Int32 -> Int
bitSize = Int32 -> Int
forall b. FiniteBits b => b -> Int
B.finiteBitSize
  {-# INLINE bitSize #-}

instance BitSize Int16 where
  bitSize :: Int16 -> Int
bitSize = Int16 -> Int
forall b. FiniteBits b => b -> Int
B.finiteBitSize
  {-# INLINE bitSize #-}

instance BitSize Int8 where
  bitSize :: Int8 -> Int
bitSize = Int8 -> Int
forall b. FiniteBits b => b -> Int
B.finiteBitSize
  {-# INLINE bitSize #-}

instance BitSize a => BitSize (Identity a) where
  bitSize :: Identity a -> Int
bitSize = (Int -> a -> Int) -> Int -> Identity a -> Int
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl (\Int
a a
b -> Int
a Int -> Int -> Int
forall a. Num a => a -> a -> a
+ a -> Int
forall a. BitSize a => a -> Int
bitSize a
b) Int
0
  {-# INLINE bitSize #-}

instance BitSize a => BitSize [a] where
  bitSize :: [a] -> Int
bitSize = (Int -> a -> Int) -> Int -> [a] -> Int
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl (\Int
a a
b -> Int
a Int -> Int -> Int
forall a. Num a => a -> a -> a
+ a -> Int
forall a. BitSize a => a -> Int
bitSize a
b) Int
0
  {-# INLINE bitSize #-}

instance BitSize a => BitSize (DV.Vector a) where
  bitSize :: Vector a -> Int
bitSize = (Int -> a -> Int) -> Int -> Vector a -> Int
forall a b. (a -> b -> a) -> a -> Vector b -> a
DV.foldl (\Int
a a
b -> Int
a Int -> Int -> Int
forall a. Num a => a -> a -> a
+ a -> Int
forall a. BitSize a => a -> Int
bitSize a
b) Int
0
  {-# INLINE bitSize #-}

instance forall a. (BitSize a, DVS.Storable a) => BitSize (DVS.Vector a) where
  bitSize :: Vector a -> Int
bitSize Vector a
v = Vector a -> Int
forall a. Storable a => Vector a -> Int
DVS.length Vector a
v Int -> Int -> Int
forall a. Num a => a -> a -> a
* a -> Int
forall a. BitSize a => a -> Int
bitSize (a
forall a. HasCallStack => a
undefined :: a)
  {-# INLINE bitSize #-}