hw-fingertree-strict-0.1.0.0: test/HaskellWorks/Data/SegmentSet/Naive.hs
module HaskellWorks.Data.SegmentSet.Naive
( empty
, fromList
, remove
, toList
, update
, Segment(..)
, SegmentSet(..)
) where
import Data.Foldable hiding (toList)
import Data.Maybe
import Debug.Trace
import HaskellWorks.Data.Segment.Strict
newtype SegmentSet a = SegmentSet [Segment a] deriving (Show, Eq)
empty :: SegmentSet a
empty = SegmentSet []
fromList :: (Ord a, Enum a) => [Segment a] -> SegmentSet a
fromList = foldr' update empty
toList :: SegmentSet a -> [Segment a]
toList (SegmentSet as) = as
update :: (Ord a, Enum a) => Segment a -> SegmentSet a -> SegmentSet a
update i (SegmentSet as) =
let (ls, b1, b2, rs) = splitSegment i as
i' = merge b1 i b2
in SegmentSet $ ls ++ (i':rs)
remove :: (Ord a, Enum a) => Segment a -> SegmentSet a -> SegmentSet a
remove i (SegmentSet as) =
let (ls, b1, b2, rs) = splitSegment i as
b1s = maybe [] (minus i) b1
b2s = maybe [] (minus i) b2
in SegmentSet $ ls ++ b1s ++ b2s ++ rs
splitSegment :: (Ord a, Enum a) => Segment a -> [Segment a] -> ([Segment a], Maybe (Segment a), Maybe (Segment a), [Segment a])
splitSegment (Segment s e) as = (ls, b1, b2, rs)
where (ls, xs ) = break (\(Segment x y) -> x >= s || y >= s) as
(b1, xs') = unconsMergeable (Segment s e) xs
(_ , rs') = break (\(Segment x y) -> x >= e || y >= e) xs'
(b2, rs ) = unconsMergeable (Segment s e) rs'
unconsMergeable ip ips = case uncons' ips of
(Just b', rs'') | overlapsOrAdjacent ip b' -> (Just b', rs'')
_ -> (Nothing, ips)
overlapsOrAdjacent :: (Ord a, Enum a) => Segment a -> Segment a -> Bool
overlapsOrAdjacent (Segment s1 e1) (Segment s2 e2) = if s1 <= s2 then succ e1 >= s2 else e2 >= s1
minus :: (Ord a, Enum a) => Segment a -> Segment a -> [Segment a]
minus (Segment s e) (Segment fs fe) =
let as = if s <= fs then Nothing else Just (Segment fs (pred s))
bs = if e >= fe then Nothing else Just (Segment (succ e) fe )
in catMaybes [as, bs]
merge :: (Ord a, Enum a) => Maybe (Segment a) -> Segment a -> Maybe (Segment a) -> Segment a
merge (Just (Segment sb1 _ )) (Segment s e) (Just (Segment _ eb2)) = Segment (min sb1 s) (max e eb2)
merge Nothing (Segment s e) (Just (Segment sb2 eb2)) = Segment (min sb2 s) (max e eb2)
merge (Just (Segment sb1 eb2)) (Segment s e) Nothing = Segment (min sb1 s) (max e eb2)
merge _ i _ = i
uncons' :: [a] -> (Maybe a, [a])
uncons' [] = (Nothing, [])
uncons' (a:as) = (Just a , as)