anagrep-0.1.0.1: Text/Regex/Anagram/Types.hs
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Text.Regex.Anagram.Types
where
import Control.DeepSeq (NFData(..), NFData1(..), rnf1)
import Data.CaseInsensitive (FoldCase(..))
import Data.Functor.Identity (Identity)
import qualified Data.IntMap.Strict as M
import qualified Data.IntSet as S
import Data.Ord (comparing)
import Data.Semigroup (stimes)
import qualified Data.Vector as V
-- |run-length encoding element (item and repeat count)
data RL a = RL
{ unRL :: !a
, rl :: !Int
} deriving (Eq, Ord, Show)
instance Functor RL where
fmap f (RL a n) = RL (f a) n
newtype RLEof f a = RLE{ unRLE :: f (RL a) }
-- |run-length encoded list
type RLE = RLEof []
type RLEV = RLEof V.Vector
deriving instance Show a => Show (RLE a)
deriving instance Show a => Show (RLEV a)
instance Functor f => Functor (RLEof f) where
fmap f (RLE l) = RLE $ fmap (fmap f) l
deriving instance Semigroup (RLE a)
deriving instance Monoid (RLE a)
data Inf a
= Fin !a
| Inf
deriving (Eq, Ord, Show)
-- we don't really use this whole instance
instance (Eq a, Num a) => Num (Inf a) where
Fin a + Fin b = Fin $ a + b
Inf + _ = Inf
_ + Inf = Inf
Fin a * Fin b = Fin $ a * b
Inf * Fin 0 = Fin 0
Inf * _ = Inf
Fin 0 * Inf = Fin 0
_ * Inf = Inf
abs (Fin a) = Fin a
abs Inf = Inf
signum (Fin a) = Fin (signum a)
signum Inf = Fin 1
negate (Fin a) = Fin (negate a)
negate Inf = error "negate Inf"
fromInteger = Fin . fromInteger
-- |We use Int for all Chars, mainly to use IntSet.
type Chr = Int
type ChrSet = S.IntSet
-- |A permuted string: a bag of characters mapping character to repeat count.
type ChrStr = M.IntMap Int
-- |Match for a single character.
data PatChar
= PatChr !Chr -- ^literal single character
| PatSet ChrSet -- ^one of a set "[a-z]"
| PatNot ChrSet -- ^not one of a set "[^a-z]"
deriving (Eq, Show)
instance Semigroup PatChar where
PatSet s <> x | S.null s = x -- opt
PatSet s <> PatChr c = PatSet (S.insert c s)
PatSet s <> PatSet t = PatSet (S.union s t)
PatSet s <> PatNot n = PatNot (S.difference n s)
PatChr c <> PatChr d
| c == d = PatChr c
| otherwise = PatSet (S.fromList [c,d])
PatChr c <> PatNot n = PatNot (S.delete c n)
PatNot n <> PatNot m = PatNot (S.intersection n m)
a <> b = b <> a
instance Monoid PatChar where
mempty = PatSet S.empty
instance Ord PatChar where
compare (PatChr c1) (PatChr c2) = compare c1 c2
compare (PatSet s1) (PatSet s2) = comparing S.size s1 s2 <> compare s1 s2
compare (PatNot s1) (PatNot s2) = comparing S.size s2 s1 <> compare s1 s2
compare (PatChr _) _ = LT
compare (PatSet _) (PatNot _) = LT
compare _ _ = GT
-- |The parsed characters from a regex pattern
data PatCharsOf f = PatChars
{ patReqs :: f PatChar -- ^requried chars
, patOpts :: f PatChar -- ^optional chars (x?)
, patStar :: PatChar -- ^extra chars (x*)
}
type PatChars = PatCharsOf []
deriving instance Show PatChars
deriving instance Show (PatCharsOf RLE)
deriving instance Show (PatCharsOf Identity)
instance Semigroup PatChars where
PatChars l1 o1 e1 <> PatChars l2 o2 e2 =
PatChars (l1 <> l2) (o1 <> o2) (e1 <> e2)
stimes n (PatChars l o e) = PatChars (stimes n l) (stimes n o) e
instance Monoid PatChars where
mempty = PatChars mempty mempty mempty
foldCaseChr :: Chr -> Chr
foldCaseChr c = fromEnum (foldCase (toEnum c :: Char))
instance FoldCase PatChar where
foldCase (PatChr c) = PatChr (foldCaseChr c)
foldCase (PatSet s) = PatSet (S.map foldCaseChr s)
foldCase (PatNot s) = PatNot (S.map foldCaseChr s)
instance Functor f => FoldCase (PatCharsOf f) where
foldCase p@PatChars{..} = p
{ patReqs = fmap foldCase patReqs
, patOpts = fmap foldCase patOpts
, patStar = foldCase patStar
}
instance NFData a => NFData (RL a) where
rnf = rnf1
instance NFData1 RL where
liftRnf f (RL a _) = f a
instance (NFData1 f, NFData a) => NFData (RLEof f a) where
rnf = rnf1
instance NFData1 f => NFData1 (RLEof f) where
liftRnf f (RLE l) = liftRnf (liftRnf f) l
instance NFData PatChar where
rnf (PatChr _) = ()
rnf (PatSet s) = rnf s
rnf (PatNot n) = rnf n
instance NFData1 f => NFData (PatCharsOf f) where
rnf (PatChars l o s) = rnf1 l `seq` rnf1 o `seq` rnf s
instance NFData a => NFData (Inf a) where
rnf (Fin a) = rnf a
rnf Inf = ()