module Language.Lexer.Tlex.Data.EnumSet (
    EnumSet,
    empty,
    singleton,
    insert,
    union,
    intersection,
    difference,
    partition,
    fromList,
    toList,
    toIntSet,
) where

import           Language.Lexer.Tlex.Prelude hiding (empty, toList)

import qualified Data.Hashable               as Hashable
import qualified Data.IntSet                 as IntSet


newtype EnumSet a = EnumSet IntSet.IntSet
    deriving (EnumSet a -> EnumSet a -> Bool
(EnumSet a -> EnumSet a -> Bool)
-> (EnumSet a -> EnumSet a -> Bool) -> Eq (EnumSet a)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall k (a :: k). EnumSet a -> EnumSet a -> Bool
/= :: EnumSet a -> EnumSet a -> Bool
$c/= :: forall k (a :: k). EnumSet a -> EnumSet a -> Bool
== :: EnumSet a -> EnumSet a -> Bool
$c== :: forall k (a :: k). EnumSet a -> EnumSet a -> Bool
Eq, Int -> EnumSet a -> ShowS
[EnumSet a] -> ShowS
EnumSet a -> String
(Int -> EnumSet a -> ShowS)
-> (EnumSet a -> String)
-> ([EnumSet a] -> ShowS)
-> Show (EnumSet a)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall k (a :: k). Int -> EnumSet a -> ShowS
forall k (a :: k). [EnumSet a] -> ShowS
forall k (a :: k). EnumSet a -> String
showList :: [EnumSet a] -> ShowS
$cshowList :: forall k (a :: k). [EnumSet a] -> ShowS
show :: EnumSet a -> String
$cshow :: forall k (a :: k). EnumSet a -> String
showsPrec :: Int -> EnumSet a -> ShowS
$cshowsPrec :: forall k (a :: k). Int -> EnumSet a -> ShowS
Show)

instance Hashable.Hashable (EnumSet a) where
    hashWithSalt :: Int -> EnumSet a -> Int
hashWithSalt Int
s (EnumSet IntSet
x) = Int -> [Int] -> Int
forall a. Hashable a => Int -> a -> Int
Hashable.hashWithSalt Int
s do IntSet -> [Int]
IntSet.toAscList IntSet
x

instance Enum a => Semigroup (EnumSet a) where
    <> :: EnumSet a -> EnumSet a -> EnumSet a
(<>) = EnumSet a -> EnumSet a -> EnumSet a
forall a. Enum a => EnumSet a -> EnumSet a -> EnumSet a
union

instance Enum a => Monoid (EnumSet a) where
    mempty :: EnumSet a
mempty = EnumSet a
forall a. Enum a => EnumSet a
empty

empty :: Enum a => EnumSet a
empty :: EnumSet a
empty = IntSet -> EnumSet a
forall k (a :: k). IntSet -> EnumSet a
EnumSet IntSet
IntSet.empty

singleton :: Enum a => a -> EnumSet a
singleton :: a -> EnumSet a
singleton a
x = IntSet -> EnumSet a
forall k (a :: k). IntSet -> EnumSet a
EnumSet do Int -> IntSet
IntSet.singleton do a -> Int
forall a. Enum a => a -> Int
fromEnum a
x

insert :: Enum a => a -> EnumSet a -> EnumSet a
insert :: a -> EnumSet a -> EnumSet a
insert a
x (EnumSet IntSet
s) = IntSet -> EnumSet a
forall k (a :: k). IntSet -> EnumSet a
EnumSet
    do Int -> IntSet -> IntSet
IntSet.insert
        do a -> Int
forall a. Enum a => a -> Int
fromEnum a
x
        do IntSet
s

union :: Enum a => EnumSet a -> EnumSet a -> EnumSet a
union :: EnumSet a -> EnumSet a -> EnumSet a
union (EnumSet IntSet
s1) (EnumSet IntSet
s2) = IntSet -> EnumSet a
forall k (a :: k). IntSet -> EnumSet a
EnumSet do IntSet -> IntSet -> IntSet
IntSet.union IntSet
s1 IntSet
s2

intersection :: Enum a => EnumSet a -> EnumSet a -> EnumSet a
intersection :: EnumSet a -> EnumSet a -> EnumSet a
intersection (EnumSet IntSet
s1) (EnumSet IntSet
s2) = IntSet -> EnumSet a
forall k (a :: k). IntSet -> EnumSet a
EnumSet do IntSet -> IntSet -> IntSet
IntSet.intersection IntSet
s1 IntSet
s2

difference :: Enum a => EnumSet a -> EnumSet a -> EnumSet a
difference :: EnumSet a -> EnumSet a -> EnumSet a
difference (EnumSet IntSet
s1) (EnumSet IntSet
s2) = IntSet -> EnumSet a
forall k (a :: k). IntSet -> EnumSet a
EnumSet do IntSet -> IntSet -> IntSet
IntSet.difference IntSet
s1 IntSet
s2

partition :: Enum a => (a -> Bool) -> EnumSet a -> (EnumSet a, EnumSet a)
partition :: (a -> Bool) -> EnumSet a -> (EnumSet a, EnumSet a)
partition a -> Bool
p (EnumSet IntSet
s) = (IntSet, IntSet) -> (EnumSet a, EnumSet a)
coerce
    do (Int -> Bool) -> IntSet -> (IntSet, IntSet)
IntSet.partition
        do \Int
i -> a -> Bool
p do Int -> a
forall a. Enum a => Int -> a
toEnum Int
i
        IntSet
s

fromList :: Enum a => [a] -> EnumSet a
fromList :: [a] -> EnumSet a
fromList [a]
xs = IntSet -> EnumSet a
forall k (a :: k). IntSet -> EnumSet a
EnumSet do [Int] -> IntSet
IntSet.fromList [ a -> Int
forall a. Enum a => a -> Int
fromEnum a
x | a
x <- [a]
xs ]

toList :: Enum a => EnumSet a -> [a]
toList :: EnumSet a -> [a]
toList (EnumSet IntSet
xs) = [ Int -> a
forall a. Enum a => Int -> a
toEnum Int
x | Int
x <- IntSet -> [Int]
IntSet.toList IntSet
xs ]

toIntSet :: Enum a => EnumSet a -> IntSet.IntSet
toIntSet :: EnumSet a -> IntSet
toIntSet (EnumSet IntSet
m) = IntSet
m