packages feed

intern 0.5.1.1 → 0.5.2

raw patch · 3 files changed

+971/−1 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.Interned.IntSet: (\\) :: IntSet -> IntSet -> IntSet
+ Data.Interned.IntSet: data IntSet
+ Data.Interned.IntSet: delete :: Int -> IntSet -> IntSet
+ Data.Interned.IntSet: deleteFindMax :: IntSet -> (Int, IntSet)
+ Data.Interned.IntSet: deleteFindMin :: IntSet -> (Int, IntSet)
+ Data.Interned.IntSet: deleteMax :: IntSet -> IntSet
+ Data.Interned.IntSet: deleteMin :: IntSet -> IntSet
+ Data.Interned.IntSet: difference :: IntSet -> IntSet -> IntSet
+ Data.Interned.IntSet: elems :: IntSet -> [Int]
+ Data.Interned.IntSet: empty :: IntSet
+ Data.Interned.IntSet: filter :: (Int -> Bool) -> IntSet -> IntSet
+ Data.Interned.IntSet: findMax :: IntSet -> Int
+ Data.Interned.IntSet: findMin :: IntSet -> Int
+ Data.Interned.IntSet: fold :: (Int -> b -> b) -> b -> IntSet -> b
+ Data.Interned.IntSet: fromAscList :: [Int] -> IntSet
+ Data.Interned.IntSet: fromDistinctAscList :: [Int] -> IntSet
+ Data.Interned.IntSet: fromList :: [Int] -> IntSet
+ Data.Interned.IntSet: insert :: Int -> IntSet -> IntSet
+ Data.Interned.IntSet: instance Eq (Description IntSet)
+ Data.Interned.IntSet: instance Eq IntSet
+ Data.Interned.IntSet: instance Hashable (Description IntSet)
+ Data.Interned.IntSet: instance Hashable IntSet
+ Data.Interned.IntSet: instance Interned IntSet
+ Data.Interned.IntSet: instance Monoid IntSet
+ Data.Interned.IntSet: instance Ord IntSet
+ Data.Interned.IntSet: instance Read IntSet
+ Data.Interned.IntSet: instance Show IntSet
+ Data.Interned.IntSet: instance Uninternable IntSet
+ Data.Interned.IntSet: intersection :: IntSet -> IntSet -> IntSet
+ Data.Interned.IntSet: isProperSubsetOf :: IntSet -> IntSet -> Bool
+ Data.Interned.IntSet: isSubsetOf :: IntSet -> IntSet -> Bool
+ Data.Interned.IntSet: map :: (Int -> Int) -> IntSet -> IntSet
+ Data.Interned.IntSet: maxView :: IntSet -> Maybe (Int, IntSet)
+ Data.Interned.IntSet: member :: Int -> IntSet -> Bool
+ Data.Interned.IntSet: minView :: IntSet -> Maybe (Int, IntSet)
+ Data.Interned.IntSet: notMember :: Int -> IntSet -> Bool
+ Data.Interned.IntSet: null :: IntSet -> Bool
+ Data.Interned.IntSet: partition :: (Int -> Bool) -> IntSet -> (IntSet, IntSet)
+ Data.Interned.IntSet: showTree :: IntSet -> String
+ Data.Interned.IntSet: showTreeWith :: Bool -> Bool -> IntSet -> String
+ Data.Interned.IntSet: singleton :: Int -> IntSet
+ Data.Interned.IntSet: size :: IntSet -> Int
+ Data.Interned.IntSet: split :: Int -> IntSet -> (IntSet, IntSet)
+ Data.Interned.IntSet: splitMember :: Int -> IntSet -> (IntSet, Bool, IntSet)
+ Data.Interned.IntSet: toAscList :: IntSet -> [Int]
+ Data.Interned.IntSet: toList :: IntSet -> [Int]
+ Data.Interned.IntSet: union :: IntSet -> IntSet -> IntSet
+ Data.Interned.IntSet: unions :: [IntSet] -> IntSet

Files

+ Data/Interned/IntSet.hs view
@@ -0,0 +1,968 @@+{-# LANGUAGE MagicHash, TypeFamilies, FlexibleInstances #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  Data.Interned.IntSet+-- Copyright   :  (c) Daan Leijen 2002+--                (c) Edward Kmett 2011+-- License     :  BSD-style+-- Maintainer  :  libraries@haskell.org+-- Stability   :  provisional+-- Portability :  non-portable (TypeFamilies, MagicHash)+--+-- An efficient implementation of integer sets.+--+-- Since many function names (but not the type name) clash with+-- "Prelude" names, this module is usually imported @qualified@, e.g.+--+-- >  import Data.IntSet (IntSet)+-- >  import qualified Data.IntSet as IntSet+--+-- The implementation is based on /big-endian patricia trees/.  This data+-- structure performs especially well on binary operations like 'union'+-- and 'intersection'.  However, my benchmarks show that it is also+-- (much) faster on insertions and deletions when compared to a generic+-- size-balanced set implementation (see "Data.Set").+--+--    * Chris Okasaki and Andy Gill,  \"/Fast Mergeable Integer Maps/\",+--      Workshop on ML, September 1998, pages 77-86,+--      <http://citeseer.ist.psu.edu/okasaki98fast.html>+--+--    * D.R. Morrison, \"/PATRICIA -- Practical Algorithm To Retrieve+--      Information Coded In Alphanumeric/\", Journal of the ACM, 15(4),+--      October 1968, pages 514-534.+--+-- Many operations have a worst-case complexity of /O(min(n,W))/.+-- This means that the operation can become linear in the number of+-- elements with a maximum of /W/ -- the number of bits in an 'Int'+-- (32 or 64).+--+-- Unlike the reference implementation in Data.IntSet, Data.Interned.IntSet+-- uses hash consing to ensure that there is only ever one copy of any given+-- IntSet in memory. This is enabled by the normal form of the PATRICIA trie.+--+-- This can mean a drastic reduction in the memory footprint of a program+-- in exchange for much more costly set manipulation.+-- +-----------------------------------------------------------------------------++module Data.Interned.IntSet  ( +            -- * Set type+              IntSet          -- instance Eq,Show++            -- * Operators+            , (\\)++            -- * Query+            , null+            , size+            , member+            , notMember+            , isSubsetOf+            , isProperSubsetOf+            +            -- * Construction+            , empty+            , singleton+            , insert+            , delete+            +            -- * Combine+            , union, unions+            , difference+            , intersection+            +            -- * Filter+            , filter+            , partition+            , split+            , splitMember++            -- * Min\/Max+            , findMin   +            , findMax+            , deleteMin+            , deleteMax+            , deleteFindMin+            , deleteFindMax+            , maxView+            , minView++            -- * Map+	    , map++            -- * Fold+            , fold++            -- * Conversion+            -- ** List+            , elems+            , toList+            , fromList+            +            -- ** Ordered list+            , toAscList+            , fromAscList+            , fromDistinctAscList+                        +            -- * Debugging+            , showTree+            , showTreeWith+            ) where++import Prelude hiding (lookup,filter,foldr,foldl,null,map)+import Data.Bits +import qualified Data.List as List+import Data.Monoid (Monoid(..))+import Data.Maybe (fromMaybe)+import Data.Interned+import Data.Function (on)+import Data.Hashable+import Text.Read+import GHC.Exts ( Word(..), Int(..), shiftRL# )++-- import Data.Typeable+-- import Data.Data (Data(..), mkNoRepType)++infixl 9 \\{-This comment teaches CPP correct behaviour -}++-- A "Nat" is a natural machine word (an unsigned Int)+type Nat = Word++natFromInt :: Int -> Nat+natFromInt i = fromIntegral i++intFromNat :: Nat -> Int+intFromNat w = fromIntegral w++shiftRL :: Nat -> Int -> Nat+shiftRL (W# x) (I# i) = W# (shiftRL# x i)++{--------------------------------------------------------------------+  Operators+--------------------------------------------------------------------}+-- | /O(n+m)/. See 'difference'.+(\\) :: IntSet -> IntSet -> IntSet+m1 \\ m2 = difference m1 m2++{--------------------------------------------------------------------+  Types  +--------------------------------------------------------------------}+-- | A set of integers.+data IntSet +  = Nil+  | Tip {-# UNPACK #-} !Id {-# UNPACK #-} !Int+  | Bin {-# UNPACK #-} !Id {-# UNPACK #-} !Int {-# UNPACK #-} !Prefix {-# UNPACK #-} !Mask !IntSet !IntSet+-- Invariant: Nil is never found as a child of Bin.+-- Invariant: The Mask is a power of 2.  It is the largest bit position at which+--            two elements of the set differ.+-- Invariant: Prefix is the common high-order bits that all elements share to+--            the left of the Mask bit.+-- Invariant: In Bin prefix mask left right, left consists of the elements that+--            don't have the mask bit set; right is all the elements that do.++data UninternedIntSet +  = UNil +  | UTip !Int+  | UBin {-# UNPACK #-} !Prefix {-# UNPACK #-} !Mask !IntSet !IntSet++tip :: Int -> IntSet+tip n = intern (UTip n) ++bin_ :: Prefix -> Mask -> IntSet -> IntSet -> IntSet+bin_ p m l r = intern (UBin p m l r) ++instance Interned IntSet where+  type Uninterned IntSet = UninternedIntSet+  data Description IntSet +    = DNil +    | DTip {-# UNPACK #-} !Int +    | DBin {-# UNPACK #-} !Prefix {-# UNPACK #-} !Mask {-# UNPACK #-} !Id {-# UNPACK #-} !Id+    deriving Eq+  describe UNil = DNil+  describe (UTip j) = DTip j+  describe (UBin p m l r) = DBin p m (identity l) (identity r)+  identity Nil = 0+  identity (Tip i _) = i+  identity (Bin i _ _ _ _ _) = i+  seedIdentity _ = 1+  identify _ UNil = Nil+  identify i (UTip j) = Tip i j +  identify i (UBin p m l r) = Bin i (size l + size r) p m l r+  cache = intSetCache ++instance Hashable (Description IntSet) where+  hash DNil = 0+  hash (DTip n) = hash n+  hash (DBin p m l r) = hash p `hashWithSalt` m `hashWithSalt` l `hashWithSalt` r++intSetCache :: Cache IntSet+intSetCache = mkCache+{-# NOINLINE intSetCache #-}+  +instance Uninternable IntSet where+  unintern Nil = UNil+  unintern (Tip _ j) = UTip j+  unintern (Bin _ _ p m l r) = UBin p m l r++type Prefix = Int+type Mask   = Int++instance Monoid IntSet where+    mempty  = empty+    mappend = union+    mconcat = unions+++{--------------------------------------------------------------------+  Query+--------------------------------------------------------------------}+-- | /O(1)/. Is the set empty?+null :: IntSet -> Bool+null Nil = True+null _   = False++-- | /O(1)/. Cardinality of the set.+size :: IntSet -> Int+size t+  = case t of+      Bin _ s _ _ _ _ -> s+      Tip _ _ -> 1+      Nil   -> 0+++-- | /O(min(n,W))/. Is the value a member of the set?+member :: Int -> IntSet -> Bool+member x t+  = case t of+      Bin _ _ p m l r +        | nomatch x p m -> False+        | zero x m      -> member x l+        | otherwise     -> member x r+      Tip _ y -> (x==y)+      Nil     -> False++-- | /O(min(n,W))/. 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+  = let nk = natFromInt k  in seq nk (lookupN nk t)++lookupN :: Nat -> IntSet -> Maybe Int+lookupN k t+  = case t of+      Bin _ _ _ m l r+        | zeroN k (natFromInt m) -> lookupN k l+        | otherwise              -> lookupN k r+      Tip _ kx+        | (k == natFromInt kx)  -> Just kx+        | otherwise             -> Nothing+      Nil -> Nothing+++{--------------------------------------------------------------------+  Construction+--------------------------------------------------------------------}+-- | /O(1)/. The empty set.+empty :: IntSet+empty = Nil++-- | /O(1)/. A set of one element.+singleton :: Int -> IntSet+singleton x = tip x++++{--------------------------------------------------------------------+  Insert+--------------------------------------------------------------------}+-- | /O(min(n,W))/. Add a value to the set. When the value is already+-- an element of the set, it is replaced by the new one, ie. 'insert'+-- is left-biased.+insert :: Int -> IntSet -> IntSet+insert x t+  = case t of+      Bin _ _ p m l r +        | nomatch x p m -> join x (tip x) p t+        | zero x m      -> bin_ p m (insert x l) r+        | otherwise     -> bin_ p m l (insert x r)+      Tip _ y +        | x==y          -> tip x+        | otherwise     -> join x (tip x) y t+      Nil -> tip x++-- right-biased insertion, used by 'union'+insertR :: Int -> IntSet -> IntSet+insertR x t+  = case t of+      Bin _ _ p m l r +        | nomatch x p m -> join x (tip x) p t+        | zero x m      -> bin_ p m (insert x l) r+        | otherwise     -> bin_ p m l (insert x r)+      Tip _ y +        | x==y          -> t+        | otherwise     -> join x (tip x) y t+      Nil -> tip x++-- | /O(min(n,W))/. Delete a value in the set. Returns the+-- original set when the value was not present.+delete :: Int -> IntSet -> IntSet+delete x t+  = case t of+      Bin _ _ p m l r +        | nomatch x p m -> t+        | zero x m      -> bin p m (delete x l) r+        | otherwise     -> bin p m l (delete x r)+      Tip _ y +        | x==y          -> Nil+        | otherwise     -> t+      Nil -> Nil+++{--------------------------------------------------------------------+  Union+--------------------------------------------------------------------}+-- | The union of a list of sets.+unions :: [IntSet] -> IntSet+unions xs = foldlStrict union empty xs+++-- | /O(n+m)/. The union of two sets. +union :: IntSet -> IntSet -> IntSet+union t1@(Bin _ _ p1 m1 l1 r1) t2@(Bin _ _ p2 m2 l2 r2)+  | shorter m1 m2  = union1+  | shorter m2 m1  = union2+  | p1 == p2       = bin_ p1 m1 (union l1 l2) (union r1 r2)+  | otherwise      = join p1 t1 p2 t2+  where+    union1  | nomatch p2 p1 m1  = join p1 t1 p2 t2+            | zero p2 m1        = bin_ p1 m1 (union l1 t2) r1+            | otherwise         = bin_ p1 m1 l1 (union r1 t2)++    union2  | nomatch p1 p2 m2  = join p1 t1 p2 t2+            | zero p1 m2        = bin_ p2 m2 (union t1 l2) r2+            | otherwise         = bin_ p2 m2 l2 (union t1 r2)++union (Tip _ x) t = insert x t+union t (Tip _ x) = insertR x t  -- right bias+union Nil t       = t+union t Nil       = t+++{--------------------------------------------------------------------+  Difference+--------------------------------------------------------------------}+-- | /O(n+m)/. Difference between two sets. +difference :: IntSet -> IntSet -> IntSet+difference t1@(Bin _ _ p1 m1 l1 r1) t2@(Bin _ _ p2 m2 l2 r2)+  | shorter m1 m2  = difference1+  | shorter m2 m1  = difference2+  | p1 == p2       = bin p1 m1 (difference l1 l2) (difference r1 r2)+  | otherwise      = t1+  where+    difference1 | nomatch p2 p1 m1  = t1+                | zero p2 m1        = bin p1 m1 (difference l1 t2) r1+                | otherwise         = bin p1 m1 l1 (difference r1 t2)++    difference2 | nomatch p1 p2 m2  = t1+                | zero p1 m2        = difference t1 l2+                | otherwise         = difference t1 r2++difference t1@(Tip _ x) t2 +  | member x t2  = Nil+  | otherwise    = t1++difference Nil _       = Nil+difference t (Tip _ x) = delete x t+difference t Nil       = t++++{--------------------------------------------------------------------+  Intersection+--------------------------------------------------------------------}+-- | /O(n+m)/. The intersection of two sets. +intersection :: IntSet -> IntSet -> IntSet+intersection t1@(Bin _ _ p1 m1 l1 r1) t2@(Bin _ _ p2 m2 l2 r2)+  | shorter m1 m2  = intersection1+  | shorter m2 m1  = intersection2+  | p1 == p2       = bin p1 m1 (intersection l1 l2) (intersection r1 r2)+  | otherwise      = Nil+  where+    intersection1 | nomatch p2 p1 m1  = Nil+                  | zero p2 m1        = intersection l1 t2+                  | otherwise         = intersection r1 t2++    intersection2 | nomatch p1 p2 m2  = Nil+                  | zero p1 m2        = intersection t1 l2+                  | otherwise         = intersection t1 r2++intersection t1@(Tip _ x) t2 +  | member x t2  = t1+  | otherwise    = Nil+intersection t (Tip _ x) +  = case lookup x t of+      Just y  -> tip y+      Nothing -> Nil+intersection Nil _ = Nil+intersection _ Nil = Nil+++{--------------------------------------------------------------------+  Subset+--------------------------------------------------------------------}+-- | /O(n+m)/. Is this a proper subset? (ie. a subset but not equal).+isProperSubsetOf :: IntSet -> IntSet -> Bool+isProperSubsetOf t1 t2+  = case subsetCmp t1 t2 of +      LT -> True+      _  -> False++subsetCmp :: IntSet -> IntSet -> Ordering+subsetCmp t1@(Bin _ _ p1 m1 l1 r1) (Bin _ _ p2 m2 l2 r2)+  | shorter m1 m2  = GT+  | shorter m2 m1  = case subsetCmpLt of+                       GT -> GT+                       _ -> LT+  | p1 == p2       = subsetCmpEq+  | otherwise      = GT  -- disjoint+  where+    subsetCmpLt | nomatch p1 p2 m2  = GT+                | zero p1 m2        = subsetCmp t1 l2+                | otherwise         = subsetCmp t1 r2+    subsetCmpEq = case (subsetCmp l1 l2, subsetCmp r1 r2) of+                    (GT,_ ) -> GT+                    (_ ,GT) -> GT+                    (EQ,EQ) -> EQ+                    _       -> LT++subsetCmp (Bin _ _ _ _ _ _) _  = GT+subsetCmp (Tip _ x) (Tip _ y)  +  | x==y       = EQ+  | otherwise  = GT  -- disjoint+subsetCmp (Tip _ x) t        +  | member x t = LT+  | otherwise  = GT  -- disjoint+subsetCmp Nil Nil = EQ+subsetCmp Nil _   = LT++-- | /O(n+m)/. Is this a subset?+-- @(s1 `isSubsetOf` s2)@ tells whether @s1@ is a subset of @s2@.++isSubsetOf :: IntSet -> IntSet -> Bool+isSubsetOf t1@(Bin _ _ p1 m1 l1 r1) (Bin _ _ p2 m2 l2 r2)+  | shorter m1 m2  = False+  | shorter m2 m1  = match p1 p2 m2 && (if zero p1 m2 then isSubsetOf t1 l2+                                                      else isSubsetOf t1 r2)                     +  | otherwise      = (p1==p2) && isSubsetOf l1 l2 && isSubsetOf r1 r2+isSubsetOf (Bin _ _ _ _ _ _) _  = False+isSubsetOf (Tip _ x) t          = member x t+isSubsetOf Nil _                = True+++{--------------------------------------------------------------------+  Filter+--------------------------------------------------------------------}+-- | /O(n)/. Filter all elements that satisfy some predicate.+filter :: (Int -> Bool) -> IntSet -> IntSet+filter predicate t+  = case t of+      Bin _ _ p m l r +        -> bin p m (filter predicate l) (filter predicate r)+      Tip _ x +        | predicate x -> t+        | otherwise   -> Nil+      Nil -> Nil++-- | /O(n)/. partition the set according to some predicate.+partition :: (Int -> Bool) -> IntSet -> (IntSet,IntSet)+partition predicate t+  = case t of+      Bin _ _ p m l r +        -> let (l1,l2) = partition predicate l+               (r1,r2) = partition predicate r+           in (bin p m l1 r1, bin p m l2 r2)+      Tip _ x +        | predicate x -> (t,Nil)+        | otherwise   -> (Nil,t)+      Nil -> (Nil,Nil)+++-- | /O(min(n,W))/. The expression (@'split' x set@) is a pair @(set1,set2)@+-- where @set1@ comprises the elements of @set@ less than @x@ and @set2@+-- comprises the elements of @set@ greater than @x@.+--+-- > split 3 (fromList [1..5]) == (fromList [1,2], fromList [4,5])+split :: Int -> IntSet -> (IntSet,IntSet)+split x t+  = case t of+      Bin _ _ _ m l r+        | 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)+        | otherwise -> (Nil,Nil)+      Nil -> (Nil,Nil)++-- | /O(min(n,W))/. Performs a 'split' but also returns whether the pivot+-- element was found in the original set.+splitMember :: Int -> IntSet -> (IntSet,Bool,IntSet)+splitMember x t+  = case t of+      Bin _ _ _ m l r+        | 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)+        | otherwise -> (Nil,True,Nil)+      Nil -> (Nil,False,Nil)++++{----------------------------------------------------------------------+  Min/Max+----------------------------------------------------------------------}++-- | /O(min(n,W))/. Retrieves the maximal key of the set, and the set+-- stripped of that element, or 'Nothing' if passed an empty set.+maxView :: IntSet -> Maybe (Int, IntSet)+maxView t+    = case t of+        Bin _ _ p m l r | m < 0 -> let (result,t') = maxViewUnsigned l in Just (result, bin p m t' r)+        Bin _ _ p m l r         -> let (result,t') = maxViewUnsigned r in Just (result, bin p m l t')            +        Tip _ y -> Just (y,Nil)+        Nil -> Nothing++maxViewUnsigned :: IntSet -> (Int, IntSet)+maxViewUnsigned t +    = case t of+        Bin _ _ p m l r -> let (result,t') = maxViewUnsigned r in (result, bin p m l t')+        Tip _ y -> (y, Nil)+        Nil -> error "maxViewUnsigned Nil"++-- | /O(min(n,W))/. Retrieves the minimal key of the set, and the set+-- stripped of that element, or 'Nothing' if passed an empty set.+minView :: IntSet -> Maybe (Int, IntSet)+minView t+    = case t of+        Bin _ _ p m l r | m < 0 -> let (result,t') = minViewUnsigned r in Just (result, bin p m l t')            +        Bin _ _ p m l r         -> let (result,t') = minViewUnsigned l in Just (result, bin p m t' r)+        Tip _ y -> Just (y, Nil)+        Nil -> Nothing++minViewUnsigned :: IntSet -> (Int, IntSet)+minViewUnsigned t +    = case t of+        Bin _ _ p m l r -> let (result,t') = minViewUnsigned l in (result, bin p m t' r)+        Tip _ y -> (y, Nil)+        Nil -> error "minViewUnsigned Nil"++-- | /O(min(n,W))/. Delete and find the minimal element.+-- +-- > deleteFindMin set = (findMin set, deleteMin set)+deleteFindMin :: IntSet -> (Int, IntSet)+deleteFindMin = fromMaybe (error "deleteFindMin: empty set has no minimal element") . minView++-- | /O(min(n,W))/. Delete and find the maximal element.+-- +-- > deleteFindMax set = (findMax set, deleteMax set)+deleteFindMax :: IntSet -> (Int, IntSet)+deleteFindMax = fromMaybe (error "deleteFindMax: empty set has no maximal element") . maxView+++-- | /O(min(n,W))/. The minimal element of the set.+findMin :: IntSet -> Int+findMin Nil = error "findMin: empty set has no minimal element"+findMin (Tip _ x) = x+findMin (Bin _ _ _ m l r)+  |   m < 0   = find r+  | otherwise = find l+    where find (Tip _ x)          = x+          find (Bin _ _ _ _ l' _) = find l'+          find Nil                = error "findMin Nil"++-- | /O(min(n,W))/. The maximal element of a set.+findMax :: IntSet -> Int+findMax Nil = error "findMax: empty set has no maximal element"+findMax (Tip _ x) = x+findMax (Bin _ _ _ m l r)+  |   m < 0   = find l+  | otherwise = find r+    where find (Tip _ x)          = x+          find (Bin _ _ _ _ _ r') = find r'+          find Nil                = error "findMax Nil"+++-- | /O(min(n,W))/. Delete the minimal element.+deleteMin :: IntSet -> IntSet+deleteMin = maybe (error "deleteMin: empty set has no minimal element") snd . minView++-- | /O(min(n,W))/. Delete the maximal element.+deleteMax :: IntSet -> IntSet+deleteMax = maybe (error "deleteMax: empty set has no maximal element") snd . maxView++{----------------------------------------------------------------------+  Map+----------------------------------------------------------------------}++-- | /O(n*min(n,W))/. +-- @'map' f s@ is the set obtained by applying @f@ to each element of @s@.+-- +-- It's worth noting that the size of the result may be smaller if,+-- for some @(x,y)@, @x \/= y && f x == f y@++map :: (Int->Int) -> IntSet -> IntSet+map f = fromList . List.map f . toList++{--------------------------------------------------------------------+  Fold+--------------------------------------------------------------------}+-- | /O(n)/. Fold over the elements of a set in an unspecified order.+--+-- > sum set   == fold (+) 0 set+-- > elems set == fold (:) [] set+fold :: (Int -> b -> b) -> b -> IntSet -> b+fold 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 _ _ _ _ _ _ -> foldr f z t+      Tip _ x         -> f x z+      Nil             -> z++foldr :: (Int -> b -> b) -> b -> IntSet -> b+foldr f z t+  = case t of+      Bin _ _ _ _ l r -> foldr f (foldr f z r) l+      Tip _ x         -> f x z+      Nil             -> z+          +{--------------------------------------------------------------------+  List variations +--------------------------------------------------------------------}+-- | /O(n)/. The elements of a set. (For sets, this is equivalent to toList)+elems :: IntSet -> [Int]+elems s = toList s++{--------------------------------------------------------------------+  Lists +--------------------------------------------------------------------}+-- | /O(n)/. Convert the set to a list of elements.+toList :: IntSet -> [Int]+toList t = fold (:) [] t++-- | /O(n)/. Convert the set to an ascending list of elements.+toAscList :: IntSet -> [Int]+toAscList t = toList t++-- | /O(n*min(n,W))/. Create a set from a list of integers.+fromList :: [Int] -> IntSet+fromList xs = foldlStrict ins empty xs+  where+    ins t x  = insert x t++-- | /O(n)/. Build a set from an ascending list of elements.+-- /The precondition (input list is ascending) is not checked./+fromAscList :: [Int] -> IntSet +fromAscList [] = Nil+fromAscList (x0 : xs0) = fromDistinctAscList (combineEq x0 xs0)+  where +    combineEq x' [] = [x']+    combineEq x' (x:xs) +      | x==x'     = combineEq x' xs+      | otherwise = x' : combineEq x xs++-- | /O(n)/. Build a set from an ascending list of distinct elements.+-- /The precondition (input list is strictly ascending) is not checked./+fromDistinctAscList :: [Int] -> IntSet+fromDistinctAscList []         = Nil+fromDistinctAscList (z0 : zs0) = work z0 zs0 Nada+  where+    work x []     stk = finish x (tip x) stk+    work x (z:zs) stk = reduce z zs (branchMask z x) x (tip x) stk++    reduce z zs _ px tx Nada = work z zs (Push px tx Nada)+    reduce z zs m px tx stk@(Push py ty stk') =+        let mxy = branchMask px py+            pxy = mask px mxy+        in  if shorter m mxy+                 then reduce z zs m pxy (bin_ pxy mxy ty tx) stk'+                 else work z zs (Push px tx stk)++    finish _  t  Nada = t+    finish px tx (Push py ty stk) = finish p (join py ty px tx) stk+        where m = branchMask px py+              p = mask px m++data Stack = Push {-# UNPACK #-} !Prefix !IntSet !Stack | Nada++{--------------------------------------------------------------------+  Debugging+--------------------------------------------------------------------}+-- | /O(n)/. Show the tree that implements the set. The tree is shown+-- in a compressed, hanging format.+showTree :: IntSet -> String+showTree s+  = showTreeWith True False s++{- | /O(n)/. The expression (@'showTreeWith' hang wide map@) shows+ the tree that implements the set. If @hang@ is+ 'True', a /hanging/ tree is shown otherwise a rotated tree is shown. If+ @wide@ is 'True', an extra wide version is shown.+-}+showTreeWith :: Bool -> Bool -> IntSet -> String+showTreeWith hang wide t+  | hang      = (showsTreeHang wide [] t) ""+  | otherwise = (showsTree wide [] [] t) ""++showsTree :: Bool -> [String] -> [String] -> IntSet -> ShowS+showsTree wide lbars rbars t+  = case t of+      Bin _ _ p m l r+          -> showsTree wide (withBar rbars) (withEmpty rbars) r .+             showWide wide rbars .+             showsBars lbars . showString (showBin p m) . showString "\n" .+             showWide wide lbars .+             showsTree wide (withEmpty lbars) (withBar lbars) l+      Tip _ x+          -> showsBars lbars . showString " " . shows x . showString "\n" +      Nil -> showsBars lbars . showString "|\n"++showsTreeHang :: Bool -> [String] -> IntSet -> ShowS+showsTreeHang wide bars t+  = case t of+      Bin _ _ p m l r+          -> showsBars bars . showString (showBin p m) . showString "\n" . +             showWide wide bars .+             showsTreeHang wide (withBar bars) l .+             showWide wide bars .+             showsTreeHang wide (withEmpty bars) r+      Tip _ x+          -> showsBars bars . showString " " . shows x . showString "\n" +      Nil -> showsBars bars . showString "|\n" ++showBin :: Prefix -> Mask -> String+showBin _ _+  = "*" -- ++ show (p,m)++showWide :: Bool -> [String] -> String -> String+showWide wide bars +  | wide      = showString (concat (reverse bars)) . showString "|\n" +  | otherwise = id++showsBars :: [String] -> ShowS+showsBars bars+  = case bars of+      [] -> id+      _  -> showString (concat (reverse (tail bars))) . showString node++node :: String+node           = "+--"++withBar, withEmpty :: [String] -> [String]+withBar bars   = "|  ":bars+withEmpty bars = "   ":bars++{--------------------------------------------------------------------+  Eq +--------------------------------------------------------------------}++-- /O(1)/+instance Eq IntSet where+  (==) = (==) `on` identity++{--------------------------------------------------------------------+  Ord +  NB: this ordering is not the ordering implied by the elements+      but is usable for comparison+--------------------------------------------------------------------}+instance Ord IntSet where+  compare = compare `on` identity+  -- compare s1 s2 = compare (toAscList s1) (toAscList s2) ++{--------------------------------------------------------------------+  Eq +--------------------------------------------------------------------}+instance Hashable IntSet where+  hash = hash . identity++{--------------------------------------------------------------------+  Show+--------------------------------------------------------------------}+instance Show IntSet where+  showsPrec p xs = showParen (p > 10) $+    showString "fromList " . shows (toList xs)+++{--------------------------------------------------------------------+  Read+--------------------------------------------------------------------}+instance Read IntSet where+  readPrec = parens $ prec 10 $ do+    Ident "fromList" <- lexP+    xs <- readPrec+    return (fromList xs)++  readListPrec = readListPrecDefault+++{--------------------------------------------------------------------+  Helpers+--------------------------------------------------------------------}+{--------------------------------------------------------------------+  Join+--------------------------------------------------------------------}+join :: Prefix -> IntSet -> Prefix -> IntSet -> IntSet+join p1 t1 p2 t2+  | zero p1 m = bin_ p m t1 t2+  | otherwise = bin_ p m t2 t1+  where+    m = branchMask p1 p2+    p = mask p1 m++{--------------------------------------------------------------------+  @bin@ assures that we never have empty trees within a tree.+--------------------------------------------------------------------}+bin :: Prefix -> Mask -> IntSet -> IntSet -> IntSet+bin _ _ l Nil = l+bin _ _ Nil r = r+bin p m l r   = bin_ p m l r++  +{--------------------------------------------------------------------+  Endian independent bit twiddling+--------------------------------------------------------------------}+zero :: Int -> Mask -> Bool+zero i m+  = (natFromInt i) .&. (natFromInt m) == 0++nomatch,match :: Int -> Prefix -> Mask -> Bool+nomatch i p m+  = (mask i m) /= p++match i p m+  = (mask i m) == p++-- Suppose a is largest such that 2^a divides 2*m.+-- Then mask i m is i with the low a bits zeroed out.+mask :: Int -> Mask -> Prefix+mask i m+  = maskW (natFromInt i) (natFromInt m)++zeroN :: Nat -> Nat -> Bool+zeroN i m = (i .&. m) == 0++{--------------------------------------------------------------------+  Big endian operations  +--------------------------------------------------------------------}+maskW :: Nat -> Nat -> Prefix+maskW i m+  = intFromNat (i .&. (complement (m-1) `xor` m))++shorter :: Mask -> Mask -> Bool+shorter m1 m2+  = (natFromInt m1) > (natFromInt m2)++branchMask :: Prefix -> Prefix -> Mask+branchMask p1 p2+  = intFromNat (highestBitMask (natFromInt p1 `xor` natFromInt p2))+  +{----------------------------------------------------------------------+  Finding the highest bit (mask) in a word [x] can be done efficiently in+  three ways:+  * convert to a floating point value and the mantissa tells us the +    [log2(x)] that corresponds with the highest bit position. The mantissa +    is retrieved either via the standard C function [frexp] or by some bit +    twiddling on IEEE compatible numbers (float). Note that one needs to +    use at least [double] precision for an accurate mantissa of 32 bit +    numbers.+  * use bit twiddling, a logarithmic sequence of bitwise or's and shifts (bit).+  * use processor specific assembler instruction (asm).++  The most portable way would be [bit], but is it efficient enough?+  I have measured the cycle counts of the different methods on an AMD +  Athlon-XP 1800 (~ Pentium III 1.8Ghz) using the RDTSC instruction:++  highestBitMask: method  cycles+                  --------------+                   frexp   200+                   float    33+                   bit      11+                   asm      12++  highestBit:     method  cycles+                  --------------+                   frexp   195+                   float    33+                   bit      11+                   asm      11++  Wow, the bit twiddling is on today's RISC like machines even faster+  than a single CISC instruction (BSR)!+----------------------------------------------------------------------}++{----------------------------------------------------------------------+  [highestBitMask] returns a word where only the highest bit is set.+  It is found by first setting all bits in lower positions than the +  highest bit and than taking an exclusive or with the original value.+  Allthough the function may look expensive, GHC compiles this into+  excellent C code that subsequently compiled into highly efficient+  machine code. The algorithm is derived from Jorg Arndt's FXT library.+----------------------------------------------------------------------}+highestBitMask :: Nat -> Nat+highestBitMask x0+  = case (x0 .|. shiftRL x0 1) of+     x1 -> case (x1 .|. shiftRL x1 2) of+      x2 -> case (x2 .|. shiftRL x2 4) of+       x3 -> case (x3 .|. shiftRL x3 8) of+        x4 -> case (x4 .|. shiftRL x4 16) of+         x5 -> case (x5 .|. shiftRL x5 32) of   -- for 64 bit platforms+          x6 -> (x6 `xor` (shiftRL x6 1))+++{--------------------------------------------------------------------+  Utilities +--------------------------------------------------------------------}+foldlStrict :: (a -> b -> a) -> a -> [b] -> a+foldlStrict f z xs+  = case xs of+      []     -> z+      (x:xx) -> let z' = f z x in seq z' (foldlStrict f z' xx)++
LICENSE view
@@ -1,4 +1,5 @@ Copyright 2011 Edward Kmett+Copyright 2002 Daan Leijen  All rights reserved. 
intern.cabal view
@@ -1,6 +1,6 @@ name:          intern category:      Data, Data Structures-version:       0.5.1.1+version:       0.5.2 license:       BSD3 cabal-version: >= 1.6 license-file:  LICENSE@@ -32,6 +32,7 @@     Data.Interned.ByteString     Data.Interned.String     Data.Interned.Text+    Data.Interned.IntSet     Data.Interned.Internal     Data.Interned.Internal.ByteString     Data.Interned.Internal.String