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

instance FindOpenN [Bool] where
  findOpenN :: [Bool] -> Count -> Count -> Maybe Count
findOpenN = [Bool] -> Count -> Count -> Maybe Count
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 = Vector Word8 -> Count -> Count -> Maybe Count
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 = Vector Word16 -> Count -> Count -> Maybe Count
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 = Vector Word32 -> Count -> Count -> Maybe Count
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 = Vector Count -> Count -> Count -> Maybe Count
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 = Word8 -> Count -> Count -> Maybe Count
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 = Word16 -> Count -> Count -> Maybe Count
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 = Word32 -> Count -> Count -> Maybe Count
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 = Count -> Count -> Count -> Maybe Count
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 = Naive Count -> Count -> Count -> Maybe Count
forall a.
(BitLength a, OpenAt a, TestBit a) =>
a -> Count -> Count -> Maybe Count
findOpen'
  {-# INLINE findOpenN #-}