{- | Module : Data.RangeSet.List Description : A trivial implementation of range sets Copyright : (c) Oleg Grenrus 2014 License : MIT Maintainer : oleg.grenrus@iki.fi Stability : experimental Portability : non-portable (tested with GHC only) A trivial implementation of range sets. This module is intended to be imported qualified, to avoid name clashes with Prelude functions, e.g. > import Data.RangeSet.List (RSet) > import qualified Data.RangeSet.List as RSet The implementation of 'RSet' is based on /list/. Compared to 'Data.Set', this module imposes also 'Enum' restriction for many functions. We must be able to identify consecutive elements to be able to /glue/ and /split/ ranges properly. The implementation assumes that > x < succ x > pred x < x and there aren't elements in between (not true for 'Float' and 'Double'). Also 'succ' and 'pred' are never called for largest or smallest value respectively. -} module Data.RangeSet.List ( -- * Range set type RSet -- * Operators , (\\) -- * Query , null , member , notMember -- * Construction , empty , full , singleton , singletonRange , insert , insertRange , delete , deleteRange -- * Combine , union , difference , intersection -- * Complement , complement -- * Conversion , elems , toList , fromList , toRangeList , fromRangeList ) where import Prelude hiding (filter,foldl,foldr,null,map) import qualified Prelude import Data.Monoid (Monoid(..)) -- | Internally set is represented as sorted list of distinct inclusive ranges. newtype RSet a = RSet [(a, a)] deriving (Eq, Ord) instance Show a => Show (RSet a) where show (RSet xs) = "fromRangeList " ++ show xs instance (Ord a, Enum a) => Monoid (RSet a) where mempty = empty mappend = union {- Operators -} infixl 9 \\ -- -- | /O(n+m)/. See 'difference'. (\\) :: (Ord a, Enum a) => RSet a -> RSet a -> RSet a m1 \\ m2 = difference m1 m2 {- Query -} -- | /O(1)/. Is this the empty set? null :: RSet a -> Bool null = Prelude.null . toRangeList -- | /O(n)/. Is the element in the set? member :: (Ord a, Enum a) => a -> RSet a -> Bool member x (RSet xs) = any f $ takeWhile g xs where f (a, b) = a <= x && x <= b g (a,_) = a <= x -- | /O(n)/. Is the element not in the set? notMember :: (Ord a, Enum a) => a -> RSet a -> Bool notMember a r = not $ member a r {- Construction -} -- | /O(1)/. The empty set. empty :: RSet a empty = RSet [] -- | /O(1)/. The full set. full :: Bounded a => RSet a full = RSet [(minBound, maxBound)] -- | /O(1)/. Create a singleton set. singleton :: a -> RSet a singleton x = RSet [(x, x)] -- | /O(1)/. Create a continuos range set. singletonRange :: Ord a => (a, a) -> RSet a singletonRange (x, y) | x > y = empty | otherwise = RSet [(x, y)] {- Construction -} -- | /O(n)/. Insert an element in a set. insert :: (Ord a, Enum a) => a -> RSet a -> RSet a insert x = insertRange (x, x) -- | /O(n)/. Insert a continuos range in a set. insertRange :: (Ord a, Enum a) => (a, a) -> RSet a -> RSet a insertRange r@(x, y) set@(RSet xs) | x > y = set | otherwise = RSet $ insertRange' r xs -- There are three possibilities we consider, when inserting into non-empty set: -- * discretely less -- * discretely more -- * other insertRange' :: (Ord a, Enum a) => (a, a) -> [(a, a)] -> [(a, a)] insertRange' r [] = [r] insertRange' r@(x, y) set@(s@(u, v) : xs) | y < u && succ y /= u = r : set | v < x && succ v /= x = s : insertRange' r xs | otherwise = insertRange' (min x u, max y v) xs -- | /O(n). Delete an element from a set. delete :: (Ord a, Enum a) => a -> RSet a -> RSet a delete x = deleteRange (x, x) -- | /O(n). Delete a continuos range from a set. deleteRange :: (Ord a, Enum a) => (a, a) -> RSet a -> RSet a deleteRange r@(x, y) set@(RSet xs) | x > y = set | otherwise = RSet $ deleteRange' r xs -- There are 6 possibilities we consider, when deleting from non-empty set: -- * less -- * more -- * strictly inside (splits) -- * overlapping less-edge -- * overlapping more-edge -- * stricly larger -- -- TODO: is there simpler rules, with less cases deleteRange' :: (Ord a, Enum a) => (a, a) -> [(a, a)] -> [(a, a)] deleteRange' _ [] = [] deleteRange' r@(x, y) set@(s@(u, v) : xs) | y < u = set | v < x = s : deleteRange' r xs | u < x && y < v = (u, pred x) : (succ y, v) : xs | y < v = (succ y, v) : xs | u < x = (u, pred x) : deleteRange' r xs | otherwise = deleteRange' r xs {- Combination -} -- | /O(n*m)/. The union of two sets. union :: (Ord a, Enum a) => RSet a -> RSet a -> RSet a union set (RSet xs) = Prelude.foldr insertRange set xs -- | /O(n*m)/. Difference of two sets. difference :: (Ord a, Enum a) => RSet a -> RSet a -> RSet a difference set (RSet xs) = Prelude.foldr deleteRange set xs -- | /O(n*m)/. The intersection of two sets. intersection :: (Ord a, Enum a) => RSet a -> RSet a -> RSet a intersection a b = a \\ (a \\ b) {- Complement -} -- | /O(n)/. Complement of the set. complement :: (Ord a, Enum a, Bounded a) => RSet a -> RSet a complement a = full `difference` a {- Conversion -} -- | /O(n*r)/. Convert the set to a list of elements. /r/ is the size of longest range. elems :: Enum a => RSet a -> [a] elems = toList -- | /O(n*r)/. Convert the set to a list of elements. /r/ is the size of longest range. toList :: Enum a => RSet a -> [a] toList (RSet xs) = concatMap (uncurry enumFromTo) xs -- | /O(n^2)/. Create a set from a list of elements. fromList :: (Ord a, Enum a) => [a] -> RSet a fromList = fromRangeList . Prelude.map f where f a = (a, a) -- | /O(1)/. Convert the set to a list of range pairs. toRangeList :: RSet a -> [(a, a)] toRangeList (RSet xs) = xs -- | /O(n^2)/. Create a set from a list of range pairs. fromRangeList :: (Ord a, Enum a) => [(a, a)] -> RSet a fromRangeList = Prelude.foldr insertRange empty