{-# LANGUAGE Safe #-}
module Data.RangeSet.Internal
( rangeSize
, rangeIsSubsetList
, isSubsetRangeList
, insertRangeList
, deleteRangeList
, unionRangeList
, differenceRangeList
, intersectRangeList
, complementRangeList
, fromAscElemList
, fromElemList
, normalizeRangeList
, validRangeList
) where
import Data.List (sort)
import Data.Monoid (Sum (..))
rangeSize :: Enum a => a -> a -> Sum Int
rangeSize a b = Sum $ succ $ fromEnum b - fromEnum a
rangeIsSubsetList :: Ord a => a -> a -> [(a, a)] -> Maybe [(a, a)]
rangeIsSubsetList x y ((u,v):s)
| x < u = Nothing
| y <= v = Just ((y,v):s)
| otherwise = rangeIsSubsetList x y s
rangeIsSubsetList _ _ [] = Nothing
isSubsetRangeList :: Ord a => [(a, a)] -> [(a, a)] -> Bool
isSubsetRangeList ((x,y):as) bs = maybe False (isSubsetRangeList as) $ rangeIsSubsetList x y bs
isSubsetRangeList [] _ = True
insertRangeList :: (Ord a, Enum a) => a -> a -> [(a, a)] -> [(a, a)]
insertRangeList x y set@(uv@(u,v) : xs)
| v < x && succ v /= x = uv : insertRangeList x y xs
| y < u && succ y /= u = (x,y) : set
| otherwise = prependRangeList (min x u) (max y v) xs
insertRangeList x y [] = [(x,y)]
prependRangeList :: (Ord a, Enum a) => a -> a -> [(a, a)] -> [(a, a)]
prependRangeList x y set@((u,v) : xs)
| y < u && succ y /= u = (x,y) : set
| otherwise = prependRangeList x (max y v) xs
prependRangeList x y [] = [(x,y)]
unionRangeList :: (Ord a, Enum a) => [(a, a)] -> [(a, a)] -> [(a, a)]
unionRangeList aset@(xy@(x,y):as) bset@(uv@(u,v):bs)
| y < u && succ y /= u = xy : unionRangeList as bset
| v < x && succ v /= x = uv : unionRangeList aset bs
| otherwise = prependRangeList (min x u) (max y v) $ unionRangeList as bs
unionRangeList s [] = s
unionRangeList [] s = s
deleteRangeList :: (Ord a, Enum a) => a -> a -> [(a, a)] -> [(a, a)]
deleteRangeList x y set@(s@(u,v) : xs)
| v < x = s : deleteRangeList x y xs
| y < u = set
| u < x = (u, pred x) : t
| otherwise = t where
t = trimRangeList' y v xs
deleteRangeList _ _ [] = []
trimRangeList' :: (Ord a, Enum a) => a -> a -> [(a, a)] -> [(a, a)]
trimRangeList' y v xs
| y < v = (succ y, v) : xs
| otherwise = trimRangeList y xs
trimRangeList :: (Ord a, Enum a) => a -> [(a, a)] -> [(a, a)]
trimRangeList y set@((u,v) : xs)
| y < u = set
| otherwise = trimRangeList' y v xs
trimRangeList _ [] = []
differenceRangeList :: (Ord a, Enum a) => [(a, a)] -> [(a, a)] -> [(a, a)]
differenceRangeList aset@(xy@(x,y):as) bset@((u,v):bs)
| y < u = xy : differenceRangeList as bset
| v < x = differenceRangeList aset bs
| x < u = (x, pred u) : t
| otherwise = t where
t = differenceRangeList (trimRangeList' v y as) bs
differenceRangeList s [] = s
differenceRangeList [] _ = []
intersectRangeList :: Ord a => [(a, a)] -> [(a, a)] -> [(a, a)]
intersectRangeList aset@((x,y):as) bset@((u,v):bs)
| y < u = intersectRangeList as bset
| v < x = intersectRangeList aset bs
| y < v = (max x u, y) : intersectRangeList as bset
| otherwise = (max x u, v) : intersectRangeList aset bs
intersectRangeList _ [] = []
intersectRangeList [] _ = []
complementRangeList' :: (Ord a, Enum a, Bounded a) => a -> [(a, a)] -> [(a, a)]
complementRangeList' x ((u,v):s) = (x,pred u) : complementRangeList'' v s
complementRangeList' x [] = [(x,maxBound)]
complementRangeList'' :: (Ord a, Enum a, Bounded a) => a -> [(a, a)] -> [(a, a)]
complementRangeList'' x s
| x == maxBound = []
| otherwise = complementRangeList' (succ x) s
complementRangeList :: (Ord a, Enum a, Bounded a) => [(a, a)] -> [(a, a)]
complementRangeList s@((x,y):s')
| x == minBound = complementRangeList'' y s'
| otherwise = complementRangeList' minBound s
complementRangeList [] = [(minBound, maxBound)]
takeWhileAdj :: (Eq a, Enum a) => a -> [a] -> (a, [a])
takeWhileAdj x yl@(y:l)
| x == y || succ x == y = takeWhileAdj y l
| otherwise = (x, yl)
takeWhileAdj x [] = (x, [])
takeWhileRangeAdj :: (Ord a, Enum a) => a -> [(a,a)] -> (a, [(a,a)])
takeWhileRangeAdj x yzl@((y,z):l)
| x >= y || succ x == y = takeWhileRangeAdj (max x z) l
| otherwise = (x, yzl)
takeWhileRangeAdj x [] = (x, [])
fromAscElemList :: (Eq a, Enum a) => [a] -> [(a, a)]
fromAscElemList (x:l) = (x, y) : fromAscElemList l' where
(y, l') = takeWhileAdj x l
fromAscElemList [] = []
fromElemList :: (Ord a, Enum a) => [a] -> [(a, a)]
fromElemList = fromAscElemList . sort
mergeRangeList :: (Ord a, Enum a) => [(a, a)] -> [(a, a)]
mergeRangeList ((x,y):l) = (x,y') : mergeRangeList l' where
(y', l') = takeWhileRangeAdj y l
mergeRangeList [] = []
normalizeRangeList :: (Ord a, Enum a) => [(a, a)] -> [(a, a)]
normalizeRangeList = mergeRangeList . sort . filter valid where
valid (x,y) = x <= y
validRangeList' :: (Ord a, Enum a, Bounded a) => a -> [(a, a)] -> Bool
validRangeList' b ((x,y):s) = b < maxBound && succ b < x && x <= y && validRangeList' y s
validRangeList' _ [] = True
validRangeList :: (Ord a, Enum a, Bounded a) => [(a, a)] -> Bool
validRangeList ((x,y):s) = x <= y && validRangeList' y s
validRangeList [] = True