module Data.IntSet.Translatable (
IntSet
, (\\)
, null
, size
, member
, notMember
, empty
, singleton
, insert
, delete
, union
, unions
, difference
, intersection
, filter
, partition
, split
, splitMember
, findMin
, findMax
, deleteMin
, deleteMax
, deleteFindMin
, deleteFindMax
, maxView
, minView
, map
, translate
, fold
, elems
, toList
, fromList
, toAscList
, fromAscList
, fromDistinctAscList
) where
import Prelude hiding (null, filter, map)
#if __GLASGOW_HASKELL__
import Text.Read
#endif
import Data.Monoid (Monoid(..))
import qualified Data.List as List
import Data.List (group, sort, foldl')
import Data.Maybe (fromMaybe)
import Control.Arrow ((***))
import Control.Monad (join)
import qualified Data.FingerTree as FingerTree
import Data.FingerTree (FingerTree, Measured, measure, (<|), (|>), (><),
ViewL(..), ViewR(..), viewl, viewr)
newtype Diff = Diff { getDiff :: Int } deriving Eq
data DiffSum = DiffSum { getSum :: !Int
, getSize :: !Int
}
instance Monoid DiffSum where
mempty = DiffSum 0 0
mappend a b = DiffSum { getSum = getSum a + getSum b
, getSize = getSize a + getSize b }
instance Measured DiffSum Diff where
measure a = DiffSum { getSum = getDiff a, getSize = 1}
newtype IntSet = IntSet (FingerTree DiffSum Diff) deriving Eq
instance Ord IntSet where
compare s1 s2 = compare (toAscList s1) (toAscList s2)
instance Show IntSet where
showsPrec p xs = showParen (p > 10) $
showString "fromList " . shows (toList xs)
instance Read IntSet where
#ifdef __GLASGOW_HASKELL__
readPrec = parens $ prec 10 $ do
Ident "fromList" <- lexP
xs <- readPrec
return (fromList xs)
readListPrec = readListPrecDefault
#else
readsPrec p = readParen (p > 10) $ \ r -> do
("fromList",s) <- lex r
(xs,t) <- reads s
return (fromList xs,t)
#endif
instance Monoid IntSet where
mempty = empty
mappend = union
mconcat = unions
(\\) :: IntSet -> IntSet -> IntSet
m1 \\ m2 = difference m1 m2
null :: IntSet -> Bool
null (IntSet xs) = FingerTree.null xs
size :: IntSet -> Int
size (IntSet xs) = getSize $ measure xs
member :: Int -> IntSet -> Bool
member k (IntSet s) = case FingerTree.split ((> k) . getSum) s of
(ls, _) | FingerTree.null ls -> False
| getSum (measure ls) == k -> True
| otherwise -> False
notMember :: Int -> IntSet -> Bool
notMember k = not . member k
empty :: IntSet
empty = IntSet FingerTree.empty
singleton :: Int -> IntSet
singleton = IntSet . FingerTree.singleton . Diff
insert :: Int -> IntSet -> IntSet
insert k (IntSet s) = IntSet $ case FingerTree.split ((> k) . getSum) s of
(ls, rs) | FingerTree.null ls -> Diff k <| translate' (k) rs
| d == 0 -> s
| otherwise -> ls >< Diff d <| translate' (d) rs
where d = k getSum (measure ls)
delete :: Int -> IntSet -> IntSet
delete k (IntSet s) = IntSet $ case FingerTree.split ((> k) . getSum) s of
(ls, rs) | getSum (measure ls) == k ->
case viewr ls of
EmptyR -> s
ls' :> _ -> ls' >< translate' (k getSum (measure ls')) rs
| otherwise -> s
union :: IntSet -> IntSet -> IntSet
union (IntSet xs) (IntSet ys) = IntSet $ merge xs ys
where merge as bs = case viewl bs of
EmptyL -> as
Diff b :< bs' -> ls >< d <|? merge bs' (translate' (d) rs)
where (ls, rs) = FingerTree.split (\v -> getSum v > b) as
d = b getSum (measure ls)
0 <|? as | not $ FingerTree.null ls = as
a <|? as = Diff a <| as
unions :: [IntSet] -> IntSet
unions xs = foldl' union empty xs
difference :: IntSet -> IntSet -> IntSet
difference (IntSet xs) (IntSet ys) = IntSet $ diffF xs ys
where diffF as bs = case viewl bs of
EmptyL -> as
Diff b :< bs'
| FingerTree.null ls -> diffR (translate' b bs') rs
| d == 0 ->
case viewr ls of
ls' :> Diff m -> ls' >< translate' (d + m) (diffR bs' rs)
| otherwise -> ls >< diffR (translate' d bs') rs
where (ls, rs) = FingerTree.split (\v -> getSum v > b) as
d = b getSum (measure ls)
diffR as bs = case viewl bs of
EmptyL -> bs
Diff b :< bs'
| FingerTree.null ls -> Diff b <| diffF bs' (translate' (b) rs)
| d == 0 ->
case viewr ls of
ls' :> Diff m -> translate' b $ diffF bs' rs
| otherwise -> Diff b <| diffF bs' (translate' (d) rs)
where (ls, rs) = FingerTree.split (\v -> getSum v > b) as
d = b getSum (measure ls)
intersection :: IntSet -> IntSet -> IntSet
intersection (IntSet xs) (IntSet ys) = IntSet $ both xs ys
where both as bs = case viewl bs of
EmptyL -> bs
Diff b :< bs'
| FingerTree.null ls -> both (translate' b bs') rs
| d == 0 -> Diff b <| both bs' rs
| otherwise -> both (translate' b bs') (translate' m rs)
where (ls, rs) = FingerTree.split (\v -> getSum v > b) as
m = getSum (measure ls)
d = b m
filter :: (Int -> Bool) -> IntSet -> IntSet
filter p = fromDistinctAscList . List.filter p . toList
partition :: (Int -> Bool) -> IntSet -> (IntSet, IntSet)
partition p = join (***) fromDistinctAscList . List.partition p . toList
split :: Int -> IntSet -> (IntSet, IntSet)
split k s = case splitMember k s of
(a, _, b) -> (a, b)
splitMember :: Int -> IntSet -> (IntSet, Bool, IntSet)
splitMember k (IntSet s) =
case FingerTree.split ((> k) . getSum) s of
(ls, rs) | FingerTree.null ls -> (IntSet ls, False, IntSet rs)
| getSum (measure ls) == k ->
case viewr ls of
ls' :> _ -> (IntSet ls', True, IntSet rs')
| otherwise -> (IntSet ls, False, IntSet rs')
where d = getSum (measure ls)
rs' = translate' d rs
findMin :: IntSet -> Int
findMin =
maybe (error "findMin: empty set has no minimal element") fst . minView
findMax :: IntSet -> Int
findMax =
maybe (error "findMax: empty set has no maximal element") fst . maxView
deleteMin :: IntSet -> IntSet
deleteMin =
maybe (error "deleteMin: empty set has no minimal element") snd . minView
deleteMax :: IntSet -> IntSet
deleteMax =
maybe (error "deleteMax: empty set has no maximal element") snd . maxView
deleteFindMin :: IntSet -> (Int, IntSet)
deleteFindMin =
fromMaybe (error "deleteFindMin: empty set has no minimal element") . minView
deleteFindMax :: IntSet -> (Int, IntSet)
deleteFindMax =
fromMaybe (error "deleteFindMax: empty set has no maximal element") . maxView
maxView :: IntSet -> Maybe (Int, IntSet)
maxView (IntSet xs) = case viewr xs of
EmptyR -> Nothing
xs' :> _ -> Just (getSum $ measure xs, IntSet xs')
minView :: IntSet -> Maybe (Int, IntSet)
minView (IntSet xs) = case viewl xs of
EmptyL -> Nothing
Diff x :< xs' -> Just (x, IntSet $ translate' x xs')
map :: (Int -> Int) -> IntSet -> IntSet
map f = fromList . List.map f . toList
translate :: Int -> IntSet -> IntSet
translate x (IntSet xs) = IntSet $ translate' x xs
fold :: (Int -> b -> b) -> b -> IntSet -> b
fold f i = foldr f i . toList
elems :: IntSet -> [Int]
elems = toList
toList :: IntSet -> [Int]
toList = toAscList
fromList :: [Int] -> IntSet
fromList = fromAscList . sort
toAscList :: IntSet -> [Int]
toAscList (IntSet xs) = toList xs 0
where toList xs d = case viewl xs of
EmptyL -> []
Diff x :< xs -> x + d : toList xs (x + d)
fromAscList :: [Int] -> IntSet
fromAscList = fromDistinctAscList . List.map head . group
fromDistinctAscList :: [Int] -> IntSet
fromDistinctAscList xs = IntSet $ foldl step FingerTree.empty xs
where step as x = as |> Diff (x getSum (measure as))
translate' 0 xs = xs
translate' d xs = case viewl xs of
EmptyL -> FingerTree.empty
Diff x :< xs -> Diff (x + d) <| xs