module Data.RangeSet
(
RangeSet
, empty
, singleton
, rangeSet
, insert
, member
, notMember
, size
, isEmpty
, isSingleton
, ranges
, union
, unions
, toList
, toAscList
, toDescList
) where
import qualified Data.List as List
import Data.Range (Range)
import qualified Data.Range as R
import Data.Semigroup (Semigroup(..))
newtype RangeSet a = RangeSet { _ranges :: [Range a] } deriving (Eq, Show)
instance (Ord a, Enum a, Bounded a) => Semigroup (RangeSet a) where
(<>) = union
stimes n rs
| n < 0 = error "stimes: RangeSet, negative multiplier"
| n == 0 = empty
| otherwise = rs
instance (Ord a, Enum a, Bounded a) => Monoid (RangeSet a) where
mempty = empty
mappend = (<>)
empty :: RangeSet a
empty = RangeSet []
singleton :: Enum a => a -> RangeSet a
singleton a = RangeSet [R.singleton a]
rangeSet :: (Ord a, Enum a) => a -> a -> RangeSet a
rangeSet a b
| a <= b = RangeSet [R.range a b]
| otherwise = RangeSet [R.range b a]
member :: Ord a => a -> RangeSet a -> Bool
member a RangeSet{_ranges} = any (R.member a) _ranges
notMember :: Ord a => a -> RangeSet a -> Bool
notMember a = not . member a
ranges :: RangeSet a -> [Range a]
ranges RangeSet{_ranges} = _ranges
safePred :: (Eq a, Enum a, Bounded a) => a -> a
safePred a
| a == minBound = a
| otherwise = pred a
append :: (Ord a, Enum a, Bounded a) => RangeSet a -> Range a -> RangeSet a
append RangeSet{_ranges} range = RangeSet (lt ++ (mid : gt))
where (lt, ranges') = List.partition (
\r -> R.rangeMax r < safePred (R.rangeMin range)) _ranges
(gt, overlap) = List.partition (
\r -> safePred (R.rangeMin r) > R.rangeMax range) ranges'
mid = case overlap of
[] -> range
_ -> foldr (<>) range overlap
union :: (Ord a, Enum a, Bounded a) => RangeSet a -> RangeSet a -> RangeSet a
union rs RangeSet{_ranges} = List.foldl' append rs _ranges
unions :: (Ord a, Enum a, Bounded a, Foldable t) => t (RangeSet a) -> RangeSet a
unions = List.foldl' union mempty
size :: Num a => RangeSet a -> a
size RangeSet{_ranges} = sum (map R.size _ranges)
isEmpty :: RangeSet a -> Bool
isEmpty (RangeSet []) = True
isEmpty _ = False
isSingleton :: Eq a => RangeSet a -> Bool
isSingleton (RangeSet [r]) = R.isSingleton r
isSingleton _ = False
insert :: (Enum a, Ord a, Bounded a) => a -> RangeSet a -> RangeSet a
insert a rs = append rs (R.singleton a)
toList :: Enum a => RangeSet a -> [a]
toList = toAscList
toAscList :: Enum a => RangeSet a -> [a]
toAscList RangeSet{_ranges} = concatMap R.toList _ranges
toDescList :: Enum a => RangeSet a -> [a]
toDescList RangeSet{_ranges} = concatMap R.toDescList _ranges