{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -Wall #-}
module Data.Diet.Unbounded.Set.Internal
( Set
, empty
, singleton
, append
, member
, equals
, showsPrec
) where
import Prelude hiding (showsPrec)
import Data.Primitive.Contiguous (Contiguous,Element,Mutable)
import qualified Data.Diet.Set.Internal as S
import qualified Data.Primitive.Contiguous as I
data Set arr a
= SetSome !(Maybe a) !(S.Set arr a) !(Maybe a)
| SetAll
empty :: Contiguous arr => Set arr a
empty = SetSome Nothing S.empty Nothing
equals :: (Contiguous arr, Element arr a, Eq a) => Set arr a -> Set arr a -> Bool
equals SetAll SetAll = True
equals SetAll (SetSome _ _ _) = False
equals (SetSome _ _ _) SetAll = False
equals (SetSome a b c) (SetSome x y z) = a == x && c == z && S.equals b y
singleton :: (Contiguous arr, Element arr a, Ord a)
=> Maybe a
-> Maybe a
-> Set arr a
singleton Nothing Nothing = SetAll
singleton Nothing (Just hi) = SetSome (Just hi) S.empty Nothing
singleton (Just lo) Nothing = SetSome Nothing S.empty (Just lo)
singleton (Just lo) (Just hi) = SetSome Nothing (S.singleton lo hi) Nothing
append :: forall arr a. (Contiguous arr, Element arr a, Ord a, Enum a)
=> Set arr a
-> Set arr a
-> Set arr a
append SetAll _ = SetAll
append (SetSome _ _ _) SetAll = SetAll
append (SetSome Nothing a Nothing) (SetSome Nothing b Nothing) =
SetSome Nothing (S.append a b) Nothing
append (SetSome (Just infHiA) a Nothing) (SetSome Nothing b Nothing) =
let (infHi, trimmedB) = establishInfinityHi infHiA b
in SetSome (Just infHi) (S.append a trimmedB) Nothing
append (SetSome Nothing a Nothing) (SetSome (Just infHiB) b Nothing) =
let (infHi, trimmedA) = establishInfinityHi infHiB a
in SetSome (Just infHi) (S.append trimmedA b) Nothing
append (SetSome (Just infHiA) a Nothing) (SetSome (Just infHiB) b Nothing) =
case compare infHiA infHiB of
EQ -> SetSome (Just infHiA) (S.append a b) Nothing
LT ->
let (infHi, trimmedA) = establishInfinityHi infHiB a
in SetSome (Just infHi) (S.append trimmedA b) Nothing
GT ->
let (infHi, trimmedB) = establishInfinityHi infHiA b
in SetSome (Just infHi) (S.append a trimmedB) Nothing
append (SetSome Nothing a (Just infLoA)) (SetSome Nothing b Nothing) =
let (infLo, trimmedB) = establishInfinityLo infLoA b
in SetSome Nothing (S.append a trimmedB) (Just infLo)
append (SetSome Nothing a Nothing) (SetSome Nothing b (Just infLoB)) =
let (infLo, trimmedA) = establishInfinityLo infLoB a
in SetSome Nothing (S.append trimmedA b) (Just infLo)
append (SetSome Nothing a (Just infLoA)) (SetSome Nothing b (Just infLoB)) =
case compare infLoA infLoB of
EQ -> SetSome Nothing (S.append a b) (Just infLoB)
LT ->
let (infLo, trimmedB) = establishInfinityLo infLoA b
in SetSome Nothing (S.append a trimmedB) (Just infLo)
GT ->
let (infLo, trimmedA) = establishInfinityLo infLoB a
in SetSome Nothing (S.append trimmedA b) (Just infLo)
append (SetSome (Just infHiA) a (Just infLoA)) (SetSome Nothing b Nothing) =
case establishInfinityBoth infHiA infLoA b of
Nothing -> SetAll
Just (infHi,infLo,trimmedB) -> SetSome (Just infHi) (S.append a trimmedB) (Just infLo)
append (SetSome Nothing a Nothing) (SetSome (Just infHiB) b (Just infLoB)) =
case establishInfinityBoth infHiB infLoB a of
Nothing -> SetAll
Just (infHi,infLo,trimmedA) -> SetSome (Just infHi) (S.append trimmedA b) (Just infLo)
append (SetSome (Just infHiA) a (Just infLoA)) (SetSome (Just infHiB) b (Just infLoB)) =
generalAppend (max infHiA infHiB) (min infLoA infLoB) a b
append (SetSome Nothing a (Just infLoA)) (SetSome (Just infHiB) b (Just infLoB)) =
generalAppend infHiB (min infLoA infLoB) a b
append (SetSome (Just infHiA) a (Just infLoA)) (SetSome Nothing b (Just infLoB)) =
generalAppend infHiA (min infLoA infLoB) a b
append (SetSome (Just infHiA) a Nothing) (SetSome (Just infHiB) b (Just infLoB)) =
generalAppend (max infHiA infHiB) infLoB a b
append (SetSome (Just infHiA) a (Just infLoA)) (SetSome (Just infHiB) b Nothing) =
generalAppend (max infHiA infHiB) infLoA a b
append (SetSome Nothing a (Just infLoA)) (SetSome (Just infHiB) b Nothing) =
generalAppend infHiB infLoA a b
append (SetSome (Just infHiA) a Nothing) (SetSome Nothing b (Just infLoB)) =
generalAppend infHiA infLoB a b
generalAppend :: (Contiguous arr, Ord a, Enum a, Element arr a)
=> a -> a -> S.Set arr a -> S.Set arr a -> Set arr a
generalAppend infHiX infLoX a b =
case establishInfinityBoth infHiX infLoX (S.append a b) of
Nothing -> SetAll
Just (infHi,infLo,trimmed) -> SetSome (Just infHi) trimmed (Just infLo)
establishInfinityHi :: forall arr a. (Contiguous arr, Element arr a, Ord a, Enum a)
=> a
-> S.Set arr a
-> (a, S.Set arr a)
establishInfinityHi a s = case locateAdjacentAbove a s of
Right ix ->
let upper = S.indexUpper ix s
in (upper,S.slice (ix + 1) (S.size s - 1) s)
Left ix -> (a,S.slice ix (S.size s - 1) s)
establishInfinityLo :: forall arr a. (Contiguous arr, Element arr a, Ord a, Enum a)
=> a
-> S.Set arr a
-> (a, S.Set arr a)
establishInfinityLo a s = case locateAdjacentBelow a s of
Right ix ->
let lower = S.indexLower ix s
in (lower,S.slice 0 (ix - 1) s)
Left ix -> (a, S.slice 0 ix s)
locateAdjacentBelow :: forall arr a. (Contiguous arr, Element arr a, Ord a, Enum a)
=> a
-> S.Set arr a
-> Either Int Int
locateAdjacentBelow a s = case S.locate a s of
Right ix -> Right ix
Left ix -> if ix == 0
then Left (-1)
else if S.indexUpper (ix - 1) s == pred a
then Right (ix - 1)
else Left (ix - 1)
locateAdjacentAbove :: forall arr a. (Contiguous arr, Element arr a, Ord a, Enum a)
=> a
-> S.Set arr a
-> Either Int Int
locateAdjacentAbove a s = case S.locate a s of
Right ix -> Right ix
Left ix -> if ix == S.size s
then Left ix
else if S.indexLower ix s == succ a
then Right ix
else Left ix
establishInfinityBoth :: forall arr a. (Contiguous arr, Element arr a, Ord a, Enum a)
=> a
-> a
-> S.Set arr a
-> Maybe (a, a, S.Set arr a)
establishInfinityBoth negInfHi posInfLo s = if posInfLo <= negInfHi
then Nothing
else case locateAdjacentAbove negInfHi s of
Left loIx -> case locateAdjacentBelow posInfLo s of
Left hiIx -> Just (negInfHi,posInfLo,S.slice loIx hiIx s)
Right hiIx -> Just (negInfHi,S.indexLower hiIx s,S.slice loIx (hiIx - 1) s)
Right loIx -> case locateAdjacentBelow posInfLo s of
Left hiIx -> Just (S.indexUpper loIx s,posInfLo,S.slice (loIx + 1) hiIx s)
Right hiIx -> if hiIx <= loIx
then Nothing
else Just (S.indexUpper loIx s, S.indexLower hiIx s, S.slice (loIx + 1) (hiIx - 1) s)
member :: forall arr a. (Contiguous arr, Element arr a, Ord a)
=> a
-> Set arr a
-> Bool
member _ SetAll = True
member x (SetSome negInfHi s posInfLo) =
maybe False (\hi -> hi >= x) negInfHi
|| maybe False (\lo -> lo <= x) posInfLo
|| S.member x s
{-# INLINEABLE member #-}
showsPrec :: (Contiguous arr, Element arr a, Show a)
=> Int
-> Set arr a
-> ShowS
showsPrec _ SetAll = showString "[(-∞,+∞)]"
showsPrec p (SetSome negInfHi s posInfLo) = showParen (p > 10) $
showString "fromList " . showListInf shows negInfHi (S.toList s) posInfLo
showListInf :: (a -> ShowS) -> Maybe a -> [(a,a)] -> Maybe a -> ShowS
showListInf showx mnegInfHi [] mposInfLo s = case mnegInfHi of
Nothing -> case mposInfLo of
Nothing -> "[]" ++ s
Just posInfLo -> '[' : showPosInfLo showx posInfLo (']' : s)
Just negInfHi -> case mposInfLo of
Nothing -> '[' : showNegInfHi showx negInfHi (']' : s)
Just posInfLo -> '[' : showNegInfHi showx negInfHi (',' : showPosInfLo showx posInfLo (']' : s))
showListInf showx mnegInfHi ((a0,b0):xs) mposInfLo s =
'[' : maybe id (\negInfHi s' -> showNegInfHi showx negInfHi (',' : s')) mnegInfHi ('(' : showx a0 (',' : showx b0 (')' : showl xs)))
where
showl [] = maybe id (\posInfLo -> showChar ',' . showPosInfLo showx posInfLo) mposInfLo (']' : s)
showl ((a,b):ys) = ',' : '(' : showx a (',' : showx b (')' : showl ys))
showNegInfHi :: (a -> ShowS) -> a -> ShowS
showNegInfHi showx x s = "(-∞," ++ showx x (")" ++ s)
showPosInfLo :: (a -> ShowS) -> a -> ShowS
showPosInfLo showx x s = '(' : (showx x (",+∞)" ++ s))