Added notMember to Data.IntSet and Data.IntMap
[haskell-directory.git] / Data / IntSet.hs
index a3cb766..9053098 100644 (file)
@@ -46,6 +46,7 @@ module Data.IntSet  (
             , null
             , size
             , member
+            , notMember
             , isSubsetOf
             , isProperSubsetOf
             
@@ -94,7 +95,7 @@ import Data.Bits
 import Data.Int
 
 import qualified Data.List as List
-import Data.Monoid
+import Data.Monoid (Monoid(..))
 import Data.Typeable
 
 {-
@@ -105,6 +106,7 @@ import qualified List
 -}
 
 #if __GLASGOW_HASKELL__
+import Text.Read
 import Data.Generics.Basics
 import Data.Generics.Instances
 #endif
@@ -159,6 +161,11 @@ data IntSet = Nil
 type Prefix = Int
 type Mask   = Int
 
+instance Monoid IntSet where
+    mempty  = empty
+    mappend = union
+    mconcat = unions
+
 #if __GLASGOW_HASKELL__
 
 {--------------------------------------------------------------------
@@ -203,6 +210,10 @@ member x t
       Tip y -> (x==y)
       Nil   -> False
     
+-- | /O(log n)/. Is the element not in the set?
+notMember :: Int -> IntSet -> Bool
+notMember k = not $ member k
+
 -- 'lookup' is used by 'intersection' for left-biasing
 lookup :: Int -> IntSet -> Maybe Int
 lookup k t
@@ -455,8 +466,24 @@ split :: Int -> IntSet -> (IntSet,IntSet)
 split x t
   = case t of
       Bin p m l r
-        | zero x m  -> let (lt,gt) = split x l in (lt,union gt r)
-        | otherwise -> let (lt,gt) = split x r in (union l lt,gt)
+        | m < 0       -> if x >= 0 then let (lt,gt) = split' x l in (union r lt, gt)
+                                   else let (lt,gt) = split' x r in (lt, union gt l)
+                                   -- handle negative numbers.
+        | otherwise   -> split' x t
+      Tip y 
+        | x>y         -> (t,Nil)
+        | x<y         -> (Nil,t)
+        | otherwise   -> (Nil,Nil)
+      Nil             -> (Nil, Nil)
+
+split' :: Int -> IntSet -> (IntSet,IntSet)
+split' x t
+  = case t of
+      Bin p m l r
+        | match x p m -> if zero x m then let (lt,gt) = split' x l in (lt,union gt r)
+                                     else let (lt,gt) = split' x r in (union l lt,gt)
+        | otherwise   -> if x < p then (Nil, t)
+                                  else (t, Nil)
       Tip y 
         | x>y       -> (t,Nil)
         | x<y       -> (Nil,t)
@@ -469,8 +496,24 @@ splitMember :: Int -> IntSet -> (IntSet,Bool,IntSet)
 splitMember x t
   = case t of
       Bin p m l r
-        | zero x m  -> let (lt,found,gt) = splitMember x l in (lt,found,union gt r)
-        | otherwise -> let (lt,found,gt) = splitMember x r in (union l lt,found,gt)
+        | m < 0       -> if x >= 0 then let (lt,found,gt) = splitMember' x l in (union r lt, found, gt)
+                                   else let (lt,found,gt) = splitMember' x r in (lt, found, union gt l)
+                                   -- handle negative numbers.
+        | otherwise   -> splitMember' x t
+      Tip y 
+        | x>y       -> (t,False,Nil)
+        | x<y       -> (Nil,False,t)
+        | otherwise -> (Nil,True,Nil)
+      Nil -> (Nil,False,Nil)
+
+splitMember' :: Int -> IntSet -> (IntSet,Bool,IntSet)
+splitMember' x t
+  = case t of
+      Bin p m l r
+         | match x p m ->  if zero x m then let (lt,found,gt) = splitMember x l in (lt,found,union gt r)
+                                       else let (lt,found,gt) = splitMember x r in (union l lt,found,gt)
+         | otherwise   -> if x < p then (Nil, False, t)
+                                   else (t, False, Nil)
       Tip y 
         | x>y       -> (t,False,Nil)
         | x<y       -> (Nil,False,t)
@@ -499,7 +542,12 @@ map f = fromList . List.map f . toList
 -- > elems set == fold (:) [] set
 fold :: (Int -> b -> b) -> b -> IntSet -> b
 fold f z t
-  = foldr f z t
+  = case t of
+      Bin 0 m l r | m < 0 -> foldr f (foldr f z l) r  
+      -- put negative numbers before.
+      Bin p m l r -> foldr f z t
+      Tip x       -> f x z
+      Nil         -> z
 
 foldr :: (Int -> b -> b) -> b -> IntSet -> b
 foldr f z t
@@ -526,9 +574,7 @@ toList t
 
 -- | /O(n)/. Convert the set to an ascending list of elements.
 toAscList :: IntSet -> [Int]
-toAscList t   
-  = -- NOTE: the following algorithm only works for big-endian trees
-    let (pos,neg) = span (>=0) (foldr (:) [] t) in neg ++ pos
+toAscList t = toList t
 
 -- | /O(n*min(n,W))/. Create a set from a list of integers.
 fromList :: [Int] -> IntSet
@@ -580,19 +626,11 @@ instance Ord IntSet where
     -- tentative implementation. See if more efficient exists.
 
 {--------------------------------------------------------------------
-  Monoid 
---------------------------------------------------------------------}
-
-instance Monoid IntSet where
-    mempty = empty
-    mappend = union
-    mconcat = unions
-
-{--------------------------------------------------------------------
   Show
 --------------------------------------------------------------------}
 instance Show IntSet where
-  showsPrec d s  = showSet (toList s)
+  showsPrec p xs = showParen (p > 10) $
+    showString "fromList " . shows (toList xs)
 
 showSet :: [Int] -> ShowS
 showSet []     
@@ -604,6 +642,24 @@ showSet (x:xs)
     showTail (x:xs) = showChar ',' . shows x . showTail xs
 
 {--------------------------------------------------------------------
+  Read
+--------------------------------------------------------------------}
+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
+
+{--------------------------------------------------------------------
   Typeable
 --------------------------------------------------------------------}