> -- | this module contains the defs of common data types and type classes
> module Text.Regex.PDeriv.Common 
>     ( Range
>     , Letter
>     , IsEmpty (..)
>     , my_hash
>     , my_lookup
>     , GFlag (..)
>     , IsGreedy (..)
>     , nub2
>     , nub3
>     ) where
> import Data.Char (ord)
> import qualified Data.IntMap as IM
> import qualified Data.BitSet as BS
> import Data.List (nubBy)
> -- | (sub)words represent by range
> type Range  = (Int,Int)      
> -- | a character and its index (position)
> type Letter = (Char,Int)     
> class IsEmpty a where
>     isEmpty :: a -> Bool
> my_hash :: Int -> Char -> Int
> my_hash i x = (ord x) + 256 * i
the lookup function
> my_lookup :: Int -> Char -> IM.IntMap [Int] -> [Int]
> my_lookup i x dict = case IM.lookup (my_hash i x) dict of
>                      Just ys -> ys
>                      Nothing -> []
> -- | The greediness flag
> data GFlag = Greedy    -- ^ greedy
>            | NotGreedy -- ^ not greedy
>              deriving Eq
> instance Show GFlag where
>     show Greedy = ""
>     show NotGreedy = "?"
> class IsGreedy a where
>     isGreedy :: a -> Bool
> -- | remove duplications in a list of pairs, using the first components as key.
> nub2 :: [(Int,a)] -> [(Int,a)]
> nub2 [] = []
> nub2 [x] = [x]                                        -- optimization
> -- nub2 ls@[x,y] = nubBy (\ (x,_) (y,_) -> x == y) ls    -- optimization
> nub2 ls = nub2sub IM.empty ls
>           -- nub2aux BS.empty ls []
> nub2sub im [] = []
> nub2sub im (x@(k,_):xs) = 
> --    im `seq` k `seq` 
>            case IM.lookup k im of
>            Just _  -> xs `seq` nub2sub im xs
>            Nothing -> let im' = IM.insert k () im 
>                       in im' `seq` xs `seq` x:(nub2sub im' xs)
> {-
> nub2sub im [] = []
> nub2sub im (x@(k,_):xs) = 
> --    im `seq` k `seq` 
>            if not (IM.notMember k im)
>            then xs `seq` nub2sub im xs
>            else let im' = IM.insert k () im 
>                 in im' `seq` xs `seq` x:(nub2sub im' xs)
> -}
> nub2aux bs [] acc = reverse acc 
> nub2aux bs (x@(k,_):xs) acc = 
>     case bs `seq` k `seq` BS.member k bs of 
>       True  -> xs `seq` nub2aux bs xs acc
>       False -> let bs' = BS.insert k bs
>                in bs' `seq` xs `seq` (nub2aux bs' xs (x:acc))
> nub3 :: [(Int,a,Int)] -> [(Int,a,Int)]
> nub3 [] = []
> nub3 [x] = [x]                                            -- optimization
> nub3 ls = nub3subsimple IM.empty ls
let (_,ls') = nub3sub IM.empty ls in ls'
> nub3subsimple :: IM.IntMap () -> [(Int,a,Int)] -> [(Int,a,Int)]
> nub3subsimple im [] = []
> nub3subsimple im [ x ] = [ x ]
> nub3subsimple im (x@(k,f,0):xs) = x:(nub3subsimple im xs)
> nub3subsimple im (x@(k,f,1):xs) = let im' = IM.insert k () im
>                                   in x:(nub3subsimple im' xs)
> nub3subsimple im (x@(k,f,n):xs) = case IM.lookup k im of 
>                                   Just _ -> nub3subsimple im xs
>                                   Nothing -> let im' = IM.insert k () im
>                                              in im' `seq` xs `seq` x:(nub3subsimple im' xs)
> nub3sub :: IM.IntMap () -> [(Int,a,Int)] -> (IM.IntMap (), [(Int,a,Int)])
> {-# INLINE nub3sub #-}
> nub3sub im [] = (im,[])
> nub3sub im [(k,f,0)] = (im, [(k,f,0)]) -- 0 means deterministic
> nub3sub im [(k,f,1)] = let im' = IM.insert k () im  -- 1 means greedy
>                        in (im', [(k,f,1)])
> nub3sub im (x@(k,f,0):xs) = let (im',xs') = nub3sub im xs
>                             in (im',x:xs')
> nub3sub im (x@(k,f,1):xs) = let im' = IM.insert k () im
>                                 (im'', xs') = nub3sub im' xs
>                             in (im'', x:xs')
> nub3sub im (x@(k,f,n):xs) = case IM.lookup k im of 
>                               Just _ -> nub3sub im xs
>                               Nothing -> let (im', xs') = nub3sub im xs
>                                          in case IM.lookup k im' of 
>                                               Just _ -> (im', xs')
>                                               Nothing -> (im', x:xs')