{-|
Copyright  :  (C) 2019, QBayLogic
License    :  BSD2 (see the file LICENSE)
Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>
-}

{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}

{-# OPTIONS_GHC -fplugin=GHC.TypeLits.Extra.Solver #-}
{-# OPTIONS_GHC -fplugin=GHC.TypeLits.Normalise #-}
{-# OPTIONS_GHC -fplugin=GHC.TypeLits.KnownNat.Solver #-}
{-# OPTIONS_HADDOCK show-extensions #-}

#include "MachDeps.h"

module Clash.Class.Parity
  ( Parity (..) )
where

import Prelude hiding                 (even, odd)

import Data.Int
import Data.Word
import Foreign.C.Types                (CUShort)
import GHC.TypeLits                   (KnownNat)

import Clash.Class.BitPack            (pack)
import Clash.Sized.Internal.BitVector (BitVector, high, low, lsb#)
import Clash.Promoted.Nat             (SNat(..), snatToNum)

{- $setup
>>> :m -Prelude
>>> import Clash.Prelude
>>> import Clash.Class.Parity
-}

-- | Determine whether value is odd or even
class Parity a where
  -- | Check if value is even
  --
  -- >>> even (4 :: Unsigned 4)
  -- True
  even :: a -> Bool
  even = Bool -> Bool
not (Bool -> Bool) -> (a -> Bool) -> a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Bool
forall a. Parity a => a -> Bool
odd

  -- | Check if value is odd
  --
  -- >>> odd (4 :: Unsigned 4)
  -- False
  odd :: a -> Bool
  odd = Bool -> Bool
not (Bool -> Bool) -> (a -> Bool) -> a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Bool
forall a. Parity a => a -> Bool
even
  {-# MINIMAL even | odd #-}

instance Parity Integer
  where
    even :: Integer -> Bool
even Integer
a = Integer
a Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
2 Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
0
    odd :: Integer -> Bool
odd Integer
a = Integer
a Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
2 Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
1

instance KnownNat n => Parity (BitVector n) where
  even :: BitVector n -> Bool
even BitVector n
a =
    case SNat n -> Integer
forall a (n :: Nat). Num a => SNat n -> a
snatToNum @Integer (KnownNat n => SNat n
forall (n :: Nat). KnownNat n => SNat n
SNat @n) of
      Integer
0 -> Bool
True
      Integer
_ -> (Bit -> Bit -> Bool
forall a. Eq a => a -> a -> Bool
==Bit
low) (Bit -> Bool) -> Bit -> Bool
forall a b. (a -> b) -> a -> b
$ BitVector n -> Bit
forall (n :: Nat). BitVector n -> Bit
lsb# BitVector n
a
  odd :: BitVector n -> Bool
odd BitVector n
a =
    case SNat n -> Integer
forall a (n :: Nat). Num a => SNat n -> a
snatToNum @Integer (KnownNat n => SNat n
forall (n :: Nat). KnownNat n => SNat n
SNat @n) of
      Integer
0 -> Bool
False
      Integer
_ -> (Bit -> Bit -> Bool
forall a. Eq a => a -> a -> Bool
==Bit
high) (Bit -> Bool) -> Bit -> Bool
forall a b. (a -> b) -> a -> b
$ BitVector n -> Bit
forall (n :: Nat). BitVector n -> Bit
lsb# BitVector n
a

instance Parity Bool where
  even :: Bool -> Bool
even = BitVector 1 -> Bool
forall a. Parity a => a -> Bool
even (BitVector 1 -> Bool) -> (Bool -> BitVector 1) -> Bool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> BitVector 1
forall a. BitPack a => a -> BitVector (BitSize a)
pack
  odd :: Bool -> Bool
odd = BitVector 1 -> Bool
forall a. Parity a => a -> Bool
odd (BitVector 1 -> Bool) -> (Bool -> BitVector 1) -> Bool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> BitVector 1
forall a. BitPack a => a -> BitVector (BitSize a)
pack

instance Parity CUShort where
  even :: CUShort -> Bool
even = BitVector 16 -> Bool
forall a. Parity a => a -> Bool
even (BitVector 16 -> Bool)
-> (CUShort -> BitVector 16) -> CUShort -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CUShort -> BitVector 16
forall a. BitPack a => a -> BitVector (BitSize a)
pack
  odd :: CUShort -> Bool
odd = BitVector 16 -> Bool
forall a. Parity a => a -> Bool
odd (BitVector 16 -> Bool)
-> (CUShort -> BitVector 16) -> CUShort -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CUShort -> BitVector 16
forall a. BitPack a => a -> BitVector (BitSize a)
pack

instance Parity Word where
  even :: Word -> Bool
even = BitVector 64 -> Bool
forall a. Parity a => a -> Bool
even (BitVector 64 -> Bool) -> (Word -> BitVector 64) -> Word -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word -> BitVector 64
forall a. BitPack a => a -> BitVector (BitSize a)
pack
  odd :: Word -> Bool
odd = BitVector 64 -> Bool
forall a. Parity a => a -> Bool
odd (BitVector 64 -> Bool) -> (Word -> BitVector 64) -> Word -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word -> BitVector 64
forall a. BitPack a => a -> BitVector (BitSize a)
pack

instance Parity Word8 where
  even :: Word8 -> Bool
even = BitVector 8 -> Bool
forall a. Parity a => a -> Bool
even (BitVector 8 -> Bool) -> (Word8 -> BitVector 8) -> Word8 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> BitVector 8
forall a. BitPack a => a -> BitVector (BitSize a)
pack
  odd :: Word8 -> Bool
odd = BitVector 8 -> Bool
forall a. Parity a => a -> Bool
odd (BitVector 8 -> Bool) -> (Word8 -> BitVector 8) -> Word8 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> BitVector 8
forall a. BitPack a => a -> BitVector (BitSize a)
pack

instance Parity Word16 where
  even :: Word16 -> Bool
even = BitVector 16 -> Bool
forall a. Parity a => a -> Bool
even (BitVector 16 -> Bool)
-> (Word16 -> BitVector 16) -> Word16 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word16 -> BitVector 16
forall a. BitPack a => a -> BitVector (BitSize a)
pack
  odd :: Word16 -> Bool
odd = BitVector 16 -> Bool
forall a. Parity a => a -> Bool
odd (BitVector 16 -> Bool)
-> (Word16 -> BitVector 16) -> Word16 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word16 -> BitVector 16
forall a. BitPack a => a -> BitVector (BitSize a)
pack

instance Parity Word32 where
  even :: Word32 -> Bool
even = BitVector 32 -> Bool
forall a. Parity a => a -> Bool
even (BitVector 32 -> Bool)
-> (Word32 -> BitVector 32) -> Word32 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word32 -> BitVector 32
forall a. BitPack a => a -> BitVector (BitSize a)
pack
  odd :: Word32 -> Bool
odd = BitVector 32 -> Bool
forall a. Parity a => a -> Bool
odd (BitVector 32 -> Bool)
-> (Word32 -> BitVector 32) -> Word32 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word32 -> BitVector 32
forall a. BitPack a => a -> BitVector (BitSize a)
pack

instance Parity Word64 where
  even :: Word64 -> Bool
even = BitVector 64 -> Bool
forall a. Parity a => a -> Bool
even (BitVector 64 -> Bool)
-> (Word64 -> BitVector 64) -> Word64 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> BitVector 64
forall a. BitPack a => a -> BitVector (BitSize a)
pack
  odd :: Word64 -> Bool
odd = BitVector 64 -> Bool
forall a. Parity a => a -> Bool
odd (BitVector 64 -> Bool)
-> (Word64 -> BitVector 64) -> Word64 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> BitVector 64
forall a. BitPack a => a -> BitVector (BitSize a)
pack

instance Parity Int where
  even :: Int -> Bool
even = BitVector 64 -> Bool
forall a. Parity a => a -> Bool
even (BitVector 64 -> Bool) -> (Int -> BitVector 64) -> Int -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> BitVector 64
forall a. BitPack a => a -> BitVector (BitSize a)
pack
  odd :: Int -> Bool
odd = BitVector 64 -> Bool
forall a. Parity a => a -> Bool
odd (BitVector 64 -> Bool) -> (Int -> BitVector 64) -> Int -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> BitVector 64
forall a. BitPack a => a -> BitVector (BitSize a)
pack

instance Parity Int8 where
  even :: Int8 -> Bool
even = BitVector 8 -> Bool
forall a. Parity a => a -> Bool
even (BitVector 8 -> Bool) -> (Int8 -> BitVector 8) -> Int8 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int8 -> BitVector 8
forall a. BitPack a => a -> BitVector (BitSize a)
pack
  odd :: Int8 -> Bool
odd = BitVector 8 -> Bool
forall a. Parity a => a -> Bool
odd (BitVector 8 -> Bool) -> (Int8 -> BitVector 8) -> Int8 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int8 -> BitVector 8
forall a. BitPack a => a -> BitVector (BitSize a)
pack

instance Parity Int16 where
  even :: Int16 -> Bool
even = BitVector 16 -> Bool
forall a. Parity a => a -> Bool
even (BitVector 16 -> Bool) -> (Int16 -> BitVector 16) -> Int16 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int16 -> BitVector 16
forall a. BitPack a => a -> BitVector (BitSize a)
pack
  odd :: Int16 -> Bool
odd = BitVector 16 -> Bool
forall a. Parity a => a -> Bool
odd (BitVector 16 -> Bool) -> (Int16 -> BitVector 16) -> Int16 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int16 -> BitVector 16
forall a. BitPack a => a -> BitVector (BitSize a)
pack

instance Parity Int32 where
  even :: Int32 -> Bool
even = BitVector 32 -> Bool
forall a. Parity a => a -> Bool
even (BitVector 32 -> Bool) -> (Int32 -> BitVector 32) -> Int32 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int32 -> BitVector 32
forall a. BitPack a => a -> BitVector (BitSize a)
pack
  odd :: Int32 -> Bool
odd = BitVector 32 -> Bool
forall a. Parity a => a -> Bool
odd (BitVector 32 -> Bool) -> (Int32 -> BitVector 32) -> Int32 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int32 -> BitVector 32
forall a. BitPack a => a -> BitVector (BitSize a)
pack

instance Parity Int64 where
  even :: Int64 -> Bool
even = BitVector 64 -> Bool
forall a. Parity a => a -> Bool
even (BitVector 64 -> Bool) -> (Int64 -> BitVector 64) -> Int64 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> BitVector 64
forall a. BitPack a => a -> BitVector (BitSize a)
pack
  odd :: Int64 -> Bool
odd = BitVector 64 -> Bool
forall a. Parity a => a -> Bool
odd (BitVector 64 -> Bool) -> (Int64 -> BitVector 64) -> Int64 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> BitVector 64
forall a. BitPack a => a -> BitVector (BitSize a)
pack