{-# LANGUAGE DeriveAnyClass     #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric      #-}
{-# LANGUAGE DeriveLift         #-}
module Dhall.Set (
      Set(..)
    , toList
    , toAscList
    , toSet
    , toSeq
    , fromList
    , fromSet
    , append
    , empty
    , difference
    , sort
    , isSorted
    , null
    , size
    ) where
import Control.DeepSeq            (NFData)
import Data.Data                  (Data)
import Data.List                  (foldl')
import Data.Sequence              (Seq, (|>))
import GHC.Generics               (Generic)
import Instances.TH.Lift          ()
import Language.Haskell.TH.Syntax (Lift)
import Prelude                    hiding (null)
import qualified Data.Foldable
import qualified Data.Sequence
import qualified Data.Set
data Set a = Set (Data.Set.Set a) (Seq a)
    deriving (Generic, Show, Data, NFData, Lift)
instance Eq a => Eq (Set a) where
    (Set _ x) == (Set _ y) = x == y
    {-# INLINABLE (==) #-}
instance Ord a => Ord (Set a) where
    compare (Set _ x) (Set _ y) = compare x y
    {-# INLINABLE compare #-}
instance Foldable Set where
    foldMap f (Set _ x) = foldMap f x
    {-# INLINABLE foldMap #-}
    toList = Dhall.Set.toList
    {-# INLINABLE toList #-}
    null = Dhall.Set.null
    {-# INLINABLE null #-}
    length = Dhall.Set.size
    {-# INLINABLE length #-}
toSet :: Set a -> Data.Set.Set a
toSet (Set s _) = s
toSeq :: Set a -> Seq a
toSeq (Set _ xs) = xs
toList :: Set a -> [a]
toList (Set _ xs) = Data.Foldable.toList xs
toAscList :: Set a -> [a]
toAscList (Set s _) = Data.Set.toAscList s
fromList :: Ord a => [a] -> Set a
fromList = foldl' (flip append) empty
fromSet :: Data.Set.Set a -> Set a
fromSet s = Set s (Data.Sequence.fromList (Data.Set.elems s))
append :: Ord a => a -> Set a -> Set a
append x os@(Set s xs)
    | Data.Set.member x s = os
    | otherwise = Set (Data.Set.insert x s) (xs |> x)
empty :: Set a
empty = Set Data.Set.empty Data.Sequence.empty
difference :: Ord a => Set a -> Set a -> [a]
difference os (Set s _) =
    filter (\ x -> not (Data.Set.member x s)) (toList os)
sort :: Ord a => Set a -> Set a
sort (Set s _) = Set s (Data.Sequence.fromList (Data.Set.toList s))
isSorted :: Ord a => Set a -> Bool
isSorted s = toList s == Data.Set.toList (toSet s)
null :: Set a -> Bool
null (Set s _) = Data.Set.null s
size :: Set a -> Int
size (Set s _) = Data.Set.size s