{-# LANGUAGE FlexibleInstances #-}

module HaskellWorks.Data.BalancedParens.FindOpenN
  ( FindOpenN(..)
  ) where

import Data.Word
import HaskellWorks.Data.BalancedParens.OpenAt
import HaskellWorks.Data.Bits.BitLength
import HaskellWorks.Data.Bits.BitShown
import HaskellWorks.Data.Bits.BitWise
import HaskellWorks.Data.Naive
import HaskellWorks.Data.Positioning

import qualified Data.Vector.Storable as DVS

class FindOpenN v where
  findOpenN :: v -> Count -> Count -> Maybe Count

findOpen' :: (BitLength a, OpenAt a, TestBit a) => a -> Count -> Count -> Maybe Count
findOpen' :: forall a.
(BitLength a, OpenAt a, TestBit a) =>
a -> Count -> Count -> Maybe Count
findOpen' a
v Count
c Count
p = if Count
0 forall a. Ord a => a -> a -> Bool
< Count
p Bool -> Bool -> Bool
&& Count
p forall a. Ord a => a -> a -> Bool
<= forall v. BitLength v => v -> Count
bitLength a
v
  then if a
v forall v. OpenAt v => v -> Count -> Bool
`openAt` Count
p
    then if Count
c forall a. Eq a => a -> a -> Bool
== Count
0
      then forall a. a -> Maybe a
Just Count
p
      else forall a.
(BitLength a, OpenAt a, TestBit a) =>
a -> Count -> Count -> Maybe Count
findOpen' a
v (Count
c forall a. Num a => a -> a -> a
- Count
1) (Count
p forall a. Num a => a -> a -> a
- Count
1)
    else forall a.
(BitLength a, OpenAt a, TestBit a) =>
a -> Count -> Count -> Maybe Count
findOpen' a
v (Count
c forall a. Num a => a -> a -> a
+ Count
1) (Count
p forall a. Num a => a -> a -> a
- Count
1)
  else forall a. Maybe a
Nothing
{-# INLINE findOpen' #-}

instance (BitLength a, OpenAt a, TestBit a) => FindOpenN (BitShown a) where
  findOpenN :: BitShown a -> Count -> Count -> Maybe Count
findOpenN  = forall a.
(BitLength a, OpenAt a, TestBit a) =>
a -> Count -> Count -> Maybe Count
findOpen' forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. BitShown a -> a
bitShown
  {-# INLINE findOpenN #-}

instance FindOpenN [Bool] where
  findOpenN :: [Bool] -> Count -> Count -> Maybe Count
findOpenN = forall a.
(BitLength a, OpenAt a, TestBit a) =>
a -> Count -> Count -> Maybe Count
findOpen'
  {-# INLINE findOpenN #-}

instance FindOpenN (DVS.Vector Word8) where
  findOpenN :: Vector Word8 -> Count -> Count -> Maybe Count
findOpenN = forall a.
(BitLength a, OpenAt a, TestBit a) =>
a -> Count -> Count -> Maybe Count
findOpen'
  {-# INLINE findOpenN   #-}

instance FindOpenN (DVS.Vector Word16) where
  findOpenN :: Vector Word16 -> Count -> Count -> Maybe Count
findOpenN = forall a.
(BitLength a, OpenAt a, TestBit a) =>
a -> Count -> Count -> Maybe Count
findOpen'
  {-# INLINE findOpenN #-}

instance FindOpenN (DVS.Vector Word32) where
  findOpenN :: Vector Word32 -> Count -> Count -> Maybe Count
findOpenN = forall a.
(BitLength a, OpenAt a, TestBit a) =>
a -> Count -> Count -> Maybe Count
findOpen'
  {-# INLINE findOpenN #-}

instance FindOpenN (DVS.Vector Word64) where
  findOpenN :: Vector Count -> Count -> Count -> Maybe Count
findOpenN = forall a.
(BitLength a, OpenAt a, TestBit a) =>
a -> Count -> Count -> Maybe Count
findOpen'
  {-# INLINE findOpenN #-}

instance FindOpenN Word8 where
  findOpenN :: Word8 -> Count -> Count -> Maybe Count
findOpenN = forall a.
(BitLength a, OpenAt a, TestBit a) =>
a -> Count -> Count -> Maybe Count
findOpen'
  {-# INLINE findOpenN #-}

instance FindOpenN Word16 where
  findOpenN :: Word16 -> Count -> Count -> Maybe Count
findOpenN = forall a.
(BitLength a, OpenAt a, TestBit a) =>
a -> Count -> Count -> Maybe Count
findOpen'
  {-# INLINE findOpenN #-}

instance FindOpenN Word32 where
  findOpenN :: Word32 -> Count -> Count -> Maybe Count
findOpenN = forall a.
(BitLength a, OpenAt a, TestBit a) =>
a -> Count -> Count -> Maybe Count
findOpen'
  {-# INLINE findOpenN   #-}

instance FindOpenN Word64 where
  findOpenN :: Count -> Count -> Count -> Maybe Count
findOpenN = forall a.
(BitLength a, OpenAt a, TestBit a) =>
a -> Count -> Count -> Maybe Count
findOpen'
  {-# INLINE findOpenN #-}

instance FindOpenN (Naive Word64) where
  findOpenN :: Naive Count -> Count -> Count -> Maybe Count
findOpenN = forall a.
(BitLength a, OpenAt a, TestBit a) =>
a -> Count -> Count -> Maybe Count
findOpen'
  {-# INLINE findOpenN #-}