packages feed

critbit 0.0.0.0 → 0.1.0.0

raw patch · 12 files changed

+3586/−716 lines, 12 filesdep +arraydep +transformersdep ~QuickCheckdep ~basedep ~textPVP ok

version bump matches the API change (PVP)

Dependencies added: array, transformers

Dependency ranges changed: QuickCheck, base, text

API changes (from Hackage documentation)

+ Data.CritBit.Map.Lazy: (!) :: CritBitKey k => CritBit k v -> k -> v
+ Data.CritBit.Map.Lazy: (\\) :: CritBitKey k => CritBit k v -> CritBit k w -> CritBit k v
+ Data.CritBit.Map.Lazy: adjust :: CritBitKey k => (v -> v) -> k -> CritBit k v -> CritBit k v
+ Data.CritBit.Map.Lazy: adjustWithKey :: CritBitKey k => (k -> v -> v) -> k -> CritBit k v -> CritBit k v
+ Data.CritBit.Map.Lazy: alter :: CritBitKey k => (Maybe v -> Maybe v) -> k -> CritBit k v -> CritBit k v
+ Data.CritBit.Map.Lazy: assocs :: CritBit k v -> [(k, v)]
+ Data.CritBit.Map.Lazy: deleteFindMax :: CritBit k v -> ((k, v), CritBit k v)
+ Data.CritBit.Map.Lazy: deleteFindMin :: CritBit k v -> ((k, v), CritBit k v)
+ Data.CritBit.Map.Lazy: deleteMax :: CritBit k v -> CritBit k v
+ Data.CritBit.Map.Lazy: deleteMin :: CritBit k v -> CritBit k v
+ Data.CritBit.Map.Lazy: difference :: CritBitKey k => CritBit k v -> CritBit k w -> CritBit k v
+ Data.CritBit.Map.Lazy: differenceWith :: CritBitKey k => (v -> w -> Maybe v) -> CritBit k v -> CritBit k w -> CritBit k v
+ Data.CritBit.Map.Lazy: differenceWithKey :: CritBitKey k => (k -> v -> w -> Maybe v) -> CritBit k v -> CritBit k w -> CritBit k v
+ Data.CritBit.Map.Lazy: elems :: CritBit k v -> [v]
+ Data.CritBit.Map.Lazy: filter :: (v -> Bool) -> CritBit k v -> CritBit k v
+ Data.CritBit.Map.Lazy: filterWithKey :: (k -> v -> Bool) -> CritBit k v -> CritBit k v
+ Data.CritBit.Map.Lazy: findMax :: CritBit k v -> (k, v)
+ Data.CritBit.Map.Lazy: findMin :: CritBit k v -> (k, v)
+ Data.CritBit.Map.Lazy: fromAscList :: CritBitKey k => [(k, a)] -> CritBit k a
+ Data.CritBit.Map.Lazy: fromAscListWith :: CritBitKey k => (a -> a -> a) -> [(k, a)] -> CritBit k a
+ Data.CritBit.Map.Lazy: fromAscListWithKey :: CritBitKey k => (k -> a -> a -> a) -> [(k, a)] -> CritBit k a
+ Data.CritBit.Map.Lazy: fromDistinctAscList :: CritBitKey k => [(k, a)] -> CritBit k a
+ Data.CritBit.Map.Lazy: fromListWith :: CritBitKey k => (v -> v -> v) -> [(k, v)] -> CritBit k v
+ Data.CritBit.Map.Lazy: fromListWithKey :: CritBitKey k => (k -> v -> v -> v) -> [(k, v)] -> CritBit k v
+ Data.CritBit.Map.Lazy: fromSet :: (k -> v) -> Set k -> CritBit k v
+ Data.CritBit.Map.Lazy: insertLookupWithKey :: CritBitKey k => (k -> v -> v -> v) -> k -> v -> CritBit k v -> (Maybe v, CritBit k v)
+ Data.CritBit.Map.Lazy: insertWith :: CritBitKey k => (v -> v -> v) -> k -> v -> CritBit k v -> CritBit k v
+ Data.CritBit.Map.Lazy: insertWithKey :: CritBitKey k => (k -> v -> v -> v) -> k -> v -> CritBit k v -> CritBit k v
+ Data.CritBit.Map.Lazy: intersection :: CritBitKey k => CritBit k v -> CritBit k w -> CritBit k v
+ Data.CritBit.Map.Lazy: intersectionWith :: CritBitKey k => (v -> w -> x) -> CritBit k v -> CritBit k w -> CritBit k x
+ Data.CritBit.Map.Lazy: intersectionWithKey :: CritBitKey k => (k -> v -> w -> x) -> CritBit k v -> CritBit k w -> CritBit k x
+ Data.CritBit.Map.Lazy: isProperSubmapOf :: (CritBitKey k, Eq v) => CritBit k v -> CritBit k v -> Bool
+ Data.CritBit.Map.Lazy: isProperSubmapOfBy :: CritBitKey k => (a -> b -> Bool) -> CritBit k a -> CritBit k b -> Bool
+ Data.CritBit.Map.Lazy: isSubmapOf :: (CritBitKey k, Eq v) => CritBit k v -> CritBit k v -> Bool
+ Data.CritBit.Map.Lazy: isSubmapOfBy :: CritBitKey k => (a -> b -> Bool) -> CritBit k a -> CritBit k b -> Bool
+ Data.CritBit.Map.Lazy: keysSet :: CritBit k v -> Set k
+ Data.CritBit.Map.Lazy: lookupGE :: CritBitKey k => k -> CritBit k v -> Maybe (k, v)
+ Data.CritBit.Map.Lazy: lookupLE :: CritBitKey k => k -> CritBit k v -> Maybe (k, v)
+ Data.CritBit.Map.Lazy: lookupLT :: CritBitKey k => k -> CritBit k v -> Maybe (k, v)
+ Data.CritBit.Map.Lazy: map :: CritBitKey k => (v -> w) -> CritBit k v -> CritBit k w
+ Data.CritBit.Map.Lazy: mapAccum :: CritBitKey k => (a -> v -> (a, w)) -> a -> CritBit k v -> (a, CritBit k w)
+ Data.CritBit.Map.Lazy: mapAccumRWithKey :: CritBitKey k => (a -> k -> v -> (a, w)) -> a -> CritBit k v -> (a, CritBit k w)
+ Data.CritBit.Map.Lazy: mapAccumWithKey :: CritBitKey k => (a -> k -> v -> (a, w)) -> a -> CritBit k v -> (a, CritBit k w)
+ Data.CritBit.Map.Lazy: mapEither :: (a -> Either b c) -> CritBit k a -> (CritBit k b, CritBit k c)
+ Data.CritBit.Map.Lazy: mapEitherWithKey :: (k -> v -> Either v1 v2) -> CritBit k v -> (CritBit k v1, CritBit k v2)
+ Data.CritBit.Map.Lazy: mapKeys :: CritBitKey k2 => (k1 -> k2) -> CritBit k1 v -> CritBit k2 v
+ Data.CritBit.Map.Lazy: mapKeysMonotonic :: CritBitKey k => (a -> k) -> CritBit a v -> CritBit k v
+ Data.CritBit.Map.Lazy: mapKeysWith :: CritBitKey k2 => (v -> v -> v) -> (k1 -> k2) -> CritBit k1 v -> CritBit k2 v
+ Data.CritBit.Map.Lazy: mapMaybe :: (a -> Maybe b) -> CritBit k a -> CritBit k b
+ Data.CritBit.Map.Lazy: mapMaybeWithKey :: (k -> v -> Maybe v') -> CritBit k v -> CritBit k v'
+ Data.CritBit.Map.Lazy: mapWithKey :: (k -> v -> w) -> CritBit k v -> CritBit k w
+ Data.CritBit.Map.Lazy: maxView :: CritBit k v -> Maybe (v, CritBit k v)
+ Data.CritBit.Map.Lazy: maxViewWithKey :: CritBit k v -> Maybe ((k, v), CritBit k v)
+ Data.CritBit.Map.Lazy: minView :: CritBit k v -> Maybe (v, CritBit k v)
+ Data.CritBit.Map.Lazy: minViewWithKey :: CritBit k v -> Maybe ((k, v), CritBit k v)
+ Data.CritBit.Map.Lazy: partition :: CritBitKey k => (v -> Bool) -> CritBit k v -> (CritBit k v, CritBit k v)
+ Data.CritBit.Map.Lazy: partitionWithKey :: CritBitKey k => (k -> v -> Bool) -> CritBit k v -> (CritBit k v, CritBit k v)
+ Data.CritBit.Map.Lazy: split :: CritBitKey k => k -> CritBit k v -> (CritBit k v, CritBit k v)
+ Data.CritBit.Map.Lazy: splitLookup :: CritBitKey k => k -> CritBit k v -> (CritBit k v, Maybe v, CritBit k v)
+ Data.CritBit.Map.Lazy: toAscList :: CritBit k v -> [(k, v)]
+ Data.CritBit.Map.Lazy: toDescList :: CritBit k v -> [(k, v)]
+ Data.CritBit.Map.Lazy: traverseWithKey :: (CritBitKey k, Applicative t) => (k -> v -> t w) -> CritBit k v -> t (CritBit k w)
+ Data.CritBit.Map.Lazy: unionWith :: CritBitKey k => (v -> v -> v) -> CritBit k v -> CritBit k v -> CritBit k v
+ Data.CritBit.Map.Lazy: unionWithKey :: CritBitKey k => (k -> v -> v -> v) -> CritBit k v -> CritBit k v -> CritBit k v
+ Data.CritBit.Map.Lazy: unions :: CritBitKey k => [CritBit k v] -> CritBit k v
+ Data.CritBit.Map.Lazy: unionsWith :: CritBitKey k => (v -> v -> v) -> [CritBit k v] -> CritBit k v
+ Data.CritBit.Map.Lazy: update :: CritBitKey k => (v -> Maybe v) -> k -> CritBit k v -> CritBit k v
+ Data.CritBit.Map.Lazy: updateLookupWithKey :: CritBitKey k => (k -> v -> Maybe v) -> k -> CritBit k v -> (Maybe v, CritBit k v)
+ Data.CritBit.Map.Lazy: updateMax :: (v -> Maybe v) -> CritBit k v -> CritBit k v
+ Data.CritBit.Map.Lazy: updateMaxWithKey :: (k -> v -> Maybe v) -> CritBit k v -> CritBit k v
+ Data.CritBit.Map.Lazy: updateMin :: (v -> Maybe v) -> CritBit k v -> CritBit k v
+ Data.CritBit.Map.Lazy: updateMinWithKey :: (k -> v -> Maybe v) -> CritBit k v -> CritBit k v
+ Data.CritBit.Map.Lazy: updateWithKey :: CritBitKey k => (k -> v -> Maybe v) -> k -> CritBit k v -> CritBit k v
+ Data.CritBit.Set: (\\) :: CritBitKey a => Set a -> Set a -> Set a
+ Data.CritBit.Set: data Set a
+ Data.CritBit.Set: delete :: CritBitKey a => a -> Set a -> Set a
+ Data.CritBit.Set: deleteFindMax :: Set a -> (a, Set a)
+ Data.CritBit.Set: deleteFindMin :: Set a -> (a, Set a)
+ Data.CritBit.Set: deleteMax :: Set a -> Set a
+ Data.CritBit.Set: deleteMin :: Set a -> Set a
+ Data.CritBit.Set: difference :: CritBitKey a => Set a -> Set a -> Set a
+ Data.CritBit.Set: elems :: Set a -> [a]
+ Data.CritBit.Set: empty :: Set a
+ Data.CritBit.Set: filter :: (a -> Bool) -> Set a -> Set a
+ Data.CritBit.Set: findMax :: Set a -> a
+ Data.CritBit.Set: findMin :: Set a -> a
+ Data.CritBit.Set: foldl :: (a -> b -> a) -> a -> Set b -> a
+ Data.CritBit.Set: foldl' :: (a -> b -> a) -> a -> Set b -> a
+ Data.CritBit.Set: foldr :: (a -> b -> b) -> b -> Set a -> b
+ Data.CritBit.Set: foldr' :: (a -> b -> b) -> b -> Set a -> b
+ Data.CritBit.Set: fromAscList :: CritBitKey a => [a] -> Set a
+ Data.CritBit.Set: fromDistinctAscList :: CritBitKey a => [a] -> Set a
+ Data.CritBit.Set: fromList :: CritBitKey a => [a] -> Set a
+ Data.CritBit.Set: insert :: CritBitKey a => a -> Set a -> Set a
+ Data.CritBit.Set: instance CritBitKey k => Monoid (Set k)
+ Data.CritBit.Set: instance Foldable Set
+ Data.CritBit.Set: instance Show a => Show (Set a)
+ Data.CritBit.Set: intersection :: CritBitKey a => Set a -> Set a -> Set a
+ Data.CritBit.Set: isProperSubsetOf :: CritBitKey a => Set a -> Set a -> Bool
+ Data.CritBit.Set: isSubsetOf :: CritBitKey a => Set a -> Set a -> Bool
+ Data.CritBit.Set: lookupGE :: CritBitKey a => a -> Set a -> Maybe a
+ Data.CritBit.Set: lookupGT :: CritBitKey a => a -> Set a -> Maybe a
+ Data.CritBit.Set: lookupLE :: CritBitKey a => a -> Set a -> Maybe a
+ Data.CritBit.Set: lookupLT :: CritBitKey a => a -> Set a -> Maybe a
+ Data.CritBit.Set: map :: CritBitKey a2 => (a1 -> a2) -> Set a1 -> Set a2
+ Data.CritBit.Set: mapMonotonic :: CritBitKey a2 => (a1 -> a2) -> Set a1 -> Set a2
+ Data.CritBit.Set: maxView :: Set a -> Maybe (a, Set a)
+ Data.CritBit.Set: member :: CritBitKey a => a -> Set a -> Bool
+ Data.CritBit.Set: minView :: Set a -> Maybe (a, Set a)
+ Data.CritBit.Set: notMember :: CritBitKey a => a -> Set a -> Bool
+ Data.CritBit.Set: null :: Set a -> Bool
+ Data.CritBit.Set: partition :: CritBitKey a => (a -> Bool) -> Set a -> (Set a, Set a)
+ Data.CritBit.Set: singleton :: a -> Set a
+ Data.CritBit.Set: size :: Set a -> Int
+ Data.CritBit.Set: split :: CritBitKey a => a -> Set a -> (Set a, Set a)
+ Data.CritBit.Set: splitMember :: CritBitKey a => a -> Set a -> (Set a, Bool, Set a)
+ Data.CritBit.Set: toAscList :: Set a -> [a]
+ Data.CritBit.Set: toDescList :: Set a -> [a]
+ Data.CritBit.Set: toList :: Set a -> [a]
+ Data.CritBit.Set: union :: CritBitKey a => Set a -> Set a -> Set a
+ Data.CritBit.Set: unions :: CritBitKey a => [Set a] -> Set a

Files

Data/CritBit/Core.hs view
@@ -1,5 +1,6 @@+{-# LANGUAGE BangPatterns, RecordWildCards, ScopedTypeVariables #-} -- |--- Module      :  Data.CritBit.Tree+-- Module      :  Data.CritBit.Core -- Copyright   :  (c) Bryan O'Sullivan 2013 -- License     :  BSD-style -- Maintainer  :  bos@serpentine.com@@ -17,54 +18,150 @@ module Data.CritBit.Core     (     -- * Public functions-      insert+      insertWithKey+    , insertLookupWithKey+    , insertLookupGen     , lookupWith-    , delete+    , updateLookupWithKey+    , leftmost+    , rightmost     -- * Internal functions-    , calcDirection-    , direction+    , Diff(..)+    , diffOrd     , followPrefixes+    , followPrefixesFrom+    , followPrefixesByteFrom+    , findPosition+    -- ** Predicates+    , onLeft+    , above+    -- ** Smart constructors+    , setLeft+    , setRight+    , setLeft'+    , setRight'+    , internal     ) where  import Data.Bits ((.|.), (.&.), complement, shiftR, xor) import Data.CritBit.Types.Internal-import Data.Word (Word16) --- | /O(log n)/. Insert a new key and value in the map.  If the key is--- already present in the map, the associated value is replaced with--- the supplied value. 'insert' is equivalent to @'insertWith'--- 'const'@.+-- | /O(k)/. Insert with a function, combining key, new value and old value.+-- @'insertWithKey' f key value cb@+-- will insert the pair (key, value) into cb if key does not exist in the map.+-- If the key does exist, the function will insert the pair+-- @(key,f key new_value old_value)@.+-- Note that the key passed to f is the same key passed to insertWithKey. ----- > insert "b" 7 (fromList [("a",5), ("b",3)]) == fromList [("a",5), ("b",7)]--- > insert "x" 7 (fromList [("a",5), ("b",3)]) == fromList [("a",5), ("b",3), ("x",7)]--- > insert "x" 5 empty                         == singleton "x" 5-insert :: (CritBitKey k) => k -> v -> CritBit k v -> CritBit k v-insert k v (CritBit root) = CritBit . go $ root+-- > let f key new_value old_value = byteCount key + new_value + old_value+-- > insertWithKey f "a" 1 (fromList [("a",5), ("b",3)]) == fromList [("a",7), ("b",3)]+-- > insertWithKey f "c" 1 (fromList [("a",5), ("b",3)]) == fromList [("a",5), ("b",3), ("c",1)]+-- > insertWithKey f "a" 1 empty                         == singleton "a" 1+insertWithKey :: CritBitKey k => (k -> v -> v -> v) -> k -> v -> CritBit k v+              -> CritBit k v+insertWithKey f k v m = insertLookupGen (flip const) f k v m+{-# INLINABLE insertWithKey #-}++-- | /O(k)/. Combines insert operation with old value retrieval.+-- The expression (@'insertLookupWithKey' f k x map@)+-- is a pair where the first element is equal to (@'lookup' k map@)+-- and the second element equal to (@'insertWithKey' f k x map@).+--+-- > let f key new_value old_value = length key + old_value + new_value+-- > insertLookupWithKey f "a" 2 (fromList [("a",5), ("b",3)]) == (Just 5, fromList [("a",8), ("b",3)])+-- > insertLookupWithKey f "c" 2 (fromList [(5,"a"), (3,"b")]) == (Nothing, fromList [("a",5), ("b",3), ("c",2)])+-- > insertLookupWithKey f "a" 2 empty                         == (Nothing, singleton "a" 2)+--+-- This is how to define @insertLookup@ using @insertLookupWithKey@:+--+-- > let insertLookup kx x t = insertLookupWithKey (\_ a _ -> a) kx x t+-- > insertLookup "a" 1 (fromList [("a",5), ("b",3)]) == (Just 5, fromList [("a",1), ("b",3)])+-- > insertLookup "c" 1 (fromList [("a",5), ("b",3)]) == (Nothing,  fromList [("a",5), ("b",3), ("c",1)])+insertLookupWithKey :: CritBitKey k+                    => (k -> v -> v -> v)+                    -> k -> v -> CritBit k v+                    -> (Maybe v, CritBit k v)+insertLookupWithKey f k v m = insertLookupGen (,) f k v m+{-# INLINABLE insertLookupWithKey #-}++-- | General function used to implement all insert functions.+insertLookupGen :: CritBitKey k+                => (Maybe v -> CritBit k v -> a)+                -> (k -> v -> v -> v)+                -> k -> v -> CritBit k v -> a+insertLookupGen ret f !k v m = findPosition ret' finish setLeft setRight k m   where-    go i@(Internal left right _ _)-      | direction k i == 0 = go left-      | otherwise          = go right-    go (Leaf lk _)         = rewalk root+    finish _ Empty = Leaf k v+    finish diff (Leaf _ v') | diffOrd diff == EQ = Leaf k $ f k v v'+    finish diff node = internal diff node (Leaf k v)++    ret' a b = ret a (CritBit b)+{-# INLINE insertLookupGen #-}++-- | Common part of key finding/insert functions+findPosition :: (CritBitKey k)+             => (Maybe v -> r -> t) -> (Diff -> Node k v -> r)+             -> (Node k v -> r -> r) -> (Node k v -> r -> r)+             -> k -> CritBit k v -> t+findPosition ret finish toLeft toRight k (CritBit root) = go root+  where+    go i@(Internal {..})+      | k `onLeft` i = go ileft+      | otherwise    = go iright+    go (Leaf lk lv)+      | diffOrd diff == EQ = ret (Just lv) $ rewalk root+      | otherwise          = ret Nothing   $ rewalk root       where-        rewalk i@(Internal left right byte otherBits)-          | byte > n                     = finish i-          | byte == n && otherBits > nob = finish i-          | direction k i == 0           = i { ileft = rewalk left }-          | otherwise                    = i { iright = rewalk right }-        rewalk i                         = finish i+        rewalk i@(Internal left right _ _)+          | diff `above` i = finish diff i+          | k `onLeft` i   = toLeft  i (rewalk left )+          | otherwise      = toRight i (rewalk right)+        rewalk i           = finish diff i -        finish (Leaf _ _) | k == lk = Leaf lk v-        finish node-          | nd == 0   = Internal { ileft = node, iright = Leaf k v,-                                   ibyte = n, iotherBits = nob }-          | otherwise = Internal { ileft = Leaf k v, iright = node,-                                   ibyte = n, iotherBits = nob }+        diff               = followPrefixes k lk+    go Empty = ret Nothing $ finish undefined Empty+{-# INLINE findPosition #-} -        (n, nob, c) = followPrefixes k lk-        nd         = calcDirection nob c-    go Empty = Leaf k v-{-# INLINABLE insert #-}+data Diff = Diff {-# UNPACK #-} !Int+                 {-# UNPACK #-} !BitMask+                 {-# UNPACK #-} !BitMask +-- | Smart consturctor for Internal nodes+internal :: Diff -> Node k v -> Node k v -> Node k v+internal diff@(Diff byte bits _) child1 child2 = case diffOrd diff of+  LT -> Internal child1 child2 byte bits+  GT -> Internal child2 child1 byte bits+  EQ -> error "Data.CritBit.Cord.internal: Equal."+{-# INLINE internal #-}++setLeft :: Node k v -> Node k v -> Node k v+setLeft i@(Internal{}) node = i { ileft = node }+setLeft _ _ = error "Data.CritBit.Core.setLeft: Non-Internal node"+{-# INLINE setLeft #-}++setRight :: Node k v -> Node k v -> Node k v+setRight i@(Internal{}) node = i { iright = node }+setRight _ _ = error "Data.CritBit.Core.setRight: Non-Internal node"+{-# INLINE setRight #-}++setLeft' :: Node k v -> Node k v -> Node k v+setLeft' i@(Internal{}) Empty = iright i+setLeft' i@(Internal{}) child = i { ileft = child }+setLeft' _ _ = error "Data.CritBit.Core.setLeft': Non-internal node"+{-# INLINE setLeft' #-}++setRight' :: Node k v -> Node k v -> Node k v+setRight' i@(Internal{}) Empty = ileft i+setRight' i@(Internal{}) child = i { iright = child }+setRight' _ _ = error "Data.CritBit.Core.alter.setRight': Non-internal node"+{-# INLINE setRight' #-}++above :: Diff -> Node k v -> Bool+above (Diff dbyte dbits _) (Internal _ _ byte bits) =+    dbyte < byte || dbyte == byte && dbits < bits+above _ _ = error "Data.CritBit.Core.above: Non-Internal node"+{-# INLINE above #-}+ lookupWith :: (CritBitKey k) =>               a                 -- ^ Failure continuation            -> (v -> a)          -- ^ Success continuation@@ -74,57 +171,61 @@ -- algorithm with trivial variations. lookupWith notFound found k (CritBit root) = go root   where-    go i@(Internal left right _ _)-       | direction k i == 0  = go left-       | otherwise           = go right+    go i@(Internal {..})+       | k `onLeft` i = go ileft+       | otherwise    = go iright     go (Leaf lk v) | k == lk = found v     go _                     = notFound {-# INLINE lookupWith #-} --- | /O(log n)/. Delete a key and its value from the map. When the key--- is not a member of the map, the original map is returned.+-- | /O(k)/. Lookup and update; see also 'updateWithKey'.+-- This function returns the changed value if it is updated, or+-- the original value if the entry is deleted. ----- > delete "a" (fromList [("a",5), ("b",3)]) == singleton "b" 3--- > delete "c" (fromList [("a",5), ("b",3)]) == fromList [("a",5), ("b",3)]--- > delete "a" empty                         == empty-delete :: (CritBitKey k) => k -> CritBit k v -> CritBit k v+-- > let f k x = if x == 5 then Just (x + fromEnum (k < "d")) else Nothing+-- > updateLookupWithKey f "a" (fromList [("b",3), ("a",5)]) == (Just 6, fromList [("a", 6), ("b",3)])+-- > updateLookupWithKey f "c" (fromList [("a",5), ("b",3)]) == (Nothing, fromList [("a",5), ("b",3)])+-- > updateLookupWithKey f "b" (fromList [("a",5), ("b",3)]) == (Just 3, singleton "a" 5)+updateLookupWithKey :: (CritBitKey k) => (k -> v -> Maybe v) -> k+                       -> CritBit k v -> (Maybe v, CritBit k v) -- Once again with the continuations! It's somewhat faster to do -- things this way than to expicitly unwind our recursion once we've -- found the leaf to delete. It's also a ton less code. -- -- (If you want a good little exercise, rewrite this function without -- using continuations, and benchmark the two versions.)-delete k t@(CritBit root) = go root CritBit+updateLookupWithKey f k t@(CritBit root) = go root (CritBit Empty) CritBit   where-    go i@(Internal left right _ _) cont-      | direction k i == 0 = go left $ \new ->-                             case new of-                               Empty -> cont right-                               l     -> cont $! i { ileft = l }-      | otherwise          = go right $ \new ->-                             case new of-                               Empty -> cont left-                               r     -> cont $! i { iright = r }-    go (Leaf lk _) cont-       | k == lk = cont Empty-    go _ _       = t-{-# INLINABLE delete #-}+    go i@(Internal left right _ _) _ cont = dispatch i left right cont+    go (Leaf lk lv) other cont+      | k == lk = case f lk lv of+                    Just lv' -> (Just lv', cont $! Leaf lk lv')+                    Nothing  -> (Just lv, other)+      | otherwise = (Nothing, t)+    go Empty _ _ = (Nothing, t)+    {-# INLINE go #-} --- | Determine which direction we should move down the tree based on--- the critical bitmask at the current node and the corresponding byte--- in the key. Left is 0, right is 1.-direction :: (CritBitKey k) => k -> Node k v -> Int-direction k (Internal _ _ byte otherBits) =-    calcDirection otherBits (getByte k byte)-direction _ _ = error "Data.CritBit.Core.direction: unpossible!"-{-# INLINE direction #-}+    dispatch i left right cont+      | k `onLeft` i = go left (cont right) $ (cont $!) . setLeft'  i+      | otherwise    = go right (cont left) $ (cont $!) . setRight' i+{-# INLINABLE updateLookupWithKey #-} --- Given a critical bitmask and a byte, return 0 to move left, 1 to--- move right.-calcDirection :: BitMask -> Word16 -> Int-calcDirection otherBits c = (1 + fromIntegral (otherBits .|. c)) `shiftR` 9-{-# INLINE calcDirection #-}+-- | Determine whether specified key is on the left subtree of the+-- 'Internal' node.+onLeft :: (CritBitKey k) => k -> Node k v -> Bool+onLeft k (Internal _ _ byte bits) =+  (1 + (bits .|. getByte k byte)) `shiftR` 9 == 0+onLeft _ _ = error "Data.CritBit.Core.onLeft: Non-Internal node"+{-# INLINE onLeft #-} +-- | Given a diff of two keys determines result of comparison of them.+diffOrd :: Diff -> Ordering+diffOrd (Diff _ bits c)+  | bits == 0x1ff                      = EQ+  | (1 + (bits .|. c)) `shiftR` 9 == 0 = LT+  | otherwise                          = GT+{-# INLINE diffOrd #-}+ -- | Figure out the byte offset at which the key we are interested in -- differs from the leaf we reached when we initially walked the tree. --@@ -133,20 +234,65 @@ followPrefixes :: (CritBitKey k) =>                   k             -- ^ The key from "outside" the tree.                -> k             -- ^ Key from the leaf we reached.-               -> (Int, BitMask, Word16)+               -> Diff+followPrefixes = followPrefixesFrom 0 {-# INLINE followPrefixes #-}-followPrefixes k l = go 0++-- | Figure out the offset of the first different byte in two keys,+-- starting from specified position.+--+-- We return some auxiliary stuff that we'll bang on to help us figure+-- out which direction to go in to insert a new node.+followPrefixesFrom :: (CritBitKey k) =>+                      Int           -- ^ Positition to start from+                   -> k             -- ^ First key.+                   -> k             -- ^ Second key.+                   -> Diff+followPrefixesFrom !position !k !l = Diff n (maskLowerBits (b `xor` c)) c   where-    go n | n == byteCount k = (n, maskLowerBits c, c)-         | n == byteCount l = (n, maskLowerBits b, 0)-         | b /= c           = (n, maskLowerBits (b `xor` c), c)-         | otherwise        = go (n+1)-      where b = getByte k n-            c = getByte l n+    n = followPrefixesByteFrom position k l+    b = getByte k n+    c = getByte l n -    maskLowerBits v = (n3 .&. (complement (n3 `shiftR` 1))) `xor` 511+    maskLowerBits v = (n3 .&. complement (n3 `shiftR` 1)) `xor` 0x1FF       where         n3 = n2 .|. (n2 `shiftR` 8)         n2 = n1 .|. (n1 `shiftR` 4)         n1 = n0 .|. (n0 `shiftR` 2)         n0 = v  .|. (v  `shiftR` 1)+{-# INLINE followPrefixesFrom #-}++-- | Figure out the offset of the first different byte in two keys,+-- starting from specified position.+followPrefixesByteFrom :: (CritBitKey k) =>+                          Int           -- ^ Positition to start from+                       -> k             -- ^ First key.+                       -> k             -- ^ Second key.+                       -> Int+followPrefixesByteFrom !position !k !l = go position+  where+    go !n | b /= c || b == 0 || c == 0 = n+          | otherwise                  = go (n + 1)+      where b = getByte k n+            c = getByte l n+{-# INLINE followPrefixesByteFrom #-}++leftmost, rightmost :: a -> (k -> v -> a) -> Node k v -> a+leftmost  = extremity ileft+{-# INLINE leftmost #-}+rightmost = extremity iright+{-# INLINE rightmost #-}++-- | Generic function so we can easily implement 'leftmost' and 'rightmost'.+extremity :: (Node k v -> Node k v) -- ^ Either 'ileft' or 'iright'.+          -> a                      -- ^ 'Empty' continuation.+          -> (k -> v -> a)          -- ^ 'Leaf' continuation.+          -> Node k v+          -> a+extremity direct onEmpty onLeaf node = go node+  where+    go i@(Internal{}) = go $ direct i+    go (Leaf k v)     = onLeaf k v+    go _              = onEmpty+    {-# INLINE go #-}+{-# INLINE extremity #-}
+ Data/CritBit/Set.hs view
@@ -0,0 +1,456 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}++-- |+-- Module      :  Data.CritBit.Set+-- Copyright   :  (c) Bryan O'Sullivan and others 2013-2014+-- License     :  BSD-style+-- Maintainer  :  bos@serpentine.com+-- Stability   :  experimental+-- Portability :  GHC+--+-- A set type that uses crit-bit trees internally.+--+-- For every /n/ key-value pairs stored, a crit-bit tree uses /n/-1+-- internal nodes, for a total of 2/n/-1 internal nodes and leaves.+module Data.CritBit.Set+    (+    -- * Set type+    Set++    -- * Operators+    , (\\)++    -- * Query+    , null+    , size+    , member+    , notMember+    , lookupLT+    , lookupGT+    , lookupLE+    , lookupGE+    , isSubsetOf+    , isProperSubsetOf++    -- * Construction+    , empty+    , singleton+    , insert+    , delete++    -- * Combine+    , union+    , unions+    , difference+    , intersection++    -- * Filter+    , filter+    , partition+    , split+    , splitMember++    -- * Map+    , map+    , mapMonotonic++    -- * Folds+    , foldr+    , foldl+    -- ** Strict folds+    , foldr'+    , foldl'++    -- * Min\/Max+    , findMin+    , findMax+    , deleteMin+    , deleteMax+    , deleteFindMin+    , deleteFindMax+    , maxView+    , minView++    -- * Conversion++    -- ** List+    , elems+    , toList+    , fromList++    -- ** Ordered list+    , toAscList+    , toDescList+    , fromAscList+    , fromDistinctAscList+    ) where++import Control.Arrow ((***))+import Data.CritBit.Types.Internal (CritBit(..), Set(..), CritBitKey, Node(..))+import Data.Foldable (Foldable, foldMap)+import Data.Maybe (isJust)+import Data.Monoid (Monoid(..))+import Prelude hiding (null, filter, map, foldl, foldr)+import qualified Data.CritBit.Tree as T+import qualified Data.List as List++instance (Show a) => Show (Set a) where+    show s = "fromList " ++ show (toList s)++instance CritBitKey k => Monoid (Set k) where+    mempty  = empty+    mappend = union+    mconcat = unions++instance Foldable Set where+    foldMap f (Set (CritBit n)) = foldSet f n++foldSet :: (Monoid m) => (a -> m) -> Node a () -> m+foldSet f (Internal l r _ _) = mappend (foldSet f l) (foldSet f r)+foldSet f (Leaf k _)         = f k+foldSet _ Empty              = mempty+{-# INLINABLE foldSet #-}++-- | Same as 'difference'.+(\\) :: CritBitKey a => Set a -> Set a -> Set a+s \\ p = difference s p+{-# INLINABLE (\\) #-}++-- | /O(1)/. Is the set empty?+--+-- > null (empty)         == True+-- > null (singleton "a") == False+null :: Set a -> Bool+null (Set a) = T.null a++-- | /O(1)/. The empty set.+--+-- > empty      == fromList []+-- > size empty == 0+empty :: Set a+empty = Set T.empty+{-# INLINABLE empty #-}++-- | /O(1)/. A set with a single element.+--+-- > singleton "a"        == fromList ["a"]+singleton :: a -> Set a+singleton a = Set $ T.singleton a ()+{-# INLINE singleton #-}++-- | /O(k)/. Build a set from a list of values.+--+-- > fromList [] == empty+-- > fromList ["a", "b", "a"] == fromList ["a", "b"]+fromList :: (CritBitKey a) => [a] -> Set a+fromList = liftFromList T.fromList+{-# INLINABLE fromList #-}++-- | /O(n)/. An alias of 'toList'.+--+-- Returns the elements of a set in ascending order.+elems :: Set a -> [a]+elems = toList++-- | /O(n)/. Convert the set to a list of values. The list returned+-- will be sorted in lexicographically ascending order.+--+-- > toList (fromList ["b", "a"]) == ["a", "b"]+-- > toList empty == []+toList :: Set a -> [a]+toList = wrapS id T.keys+{-# INLINABLE toList #-}++-- | /O(n)/. The number of elements in the set.+--+-- > size empty                      == 0+-- > size (singleton "a")            == 1+-- > size (fromList ["a", "c", "b"]) == 3+size :: Set a -> Int+size = wrapS id T.size+{-# INLINABLE size #-}++-- | /O(k)/. Is the element in the set?+--+-- > member "a" (fromList ["a", "b"]) == True+-- > member "c" (fromList ["a", "b"]) == False+--+-- See also 'notMember'.+member :: (CritBitKey a) => a -> Set a -> Bool+member a (Set s) = T.member a s+{-# INLINABLE member #-}++-- | /O(k)/. Is the element not in the set?+--+-- > notMember "a" (fromList ["a", "b"]) == False+-- > notMember "c" (fromList ["a", "b"]) == True+--+-- See also 'member'.+notMember :: (CritBitKey a) => a -> Set a -> Bool+notMember a (Set s) = T.notMember a s+{-# INLINABLE notMember #-}++-- | /O(k)/. Find largest element smaller than the given one.+--+-- > lookupLT "b"  (fromList ["a", "b"]) == Just "a"+-- > lookupLT "aa" (fromList ["a", "b"]) == Just "a"+-- > lookupLT "a"  (fromList ["a", "b"]) == Nothing+lookupLT :: (CritBitKey a) => a -> Set a -> Maybe a+lookupLT = wrapVS (fmap fst) T.lookupLT+{-# INLINABLE lookupLT #-}++-- | /O(k)/. Find smallest element greater than the given one.+--+-- > lookupGT "b"  (fromList ["a", "b"]) == Nothing+-- > lookupGT "aa" (fromList ["a", "b"]) == Just "b"+-- > lookupGT "a"  (fromList ["a", "b"]) == Just "b"+lookupGT :: (CritBitKey a) => a -> Set a -> Maybe a+lookupGT = wrapVS (fmap fst) T.lookupGT+{-# INLINABLE lookupGT #-}++-- | /O(k)/. Find largest element smaller than or equal to the given one.+--+-- > lookupGE "b"  (fromList ["a", "b"]) == Just "b"+-- > lookupGE "aa" (fromList ["a", "b"]) == Just "b"+-- > lookupGE "a"  (fromList ["a", "b"]) == Just "a"+-- > lookupGE ""   (fromList ["a", "b"]) == Nothing+lookupLE :: (CritBitKey a) => a -> Set a -> Maybe a+lookupLE = wrapVS (fmap fst) T.lookupLE+{-# INLINABLE lookupLE #-}++-- | /O(k)/. Find smallest element greater than or equal to the given one.+--+-- > lookupGE "aa" (fromList ["a", "b"]) == Just "b"+-- > lookupGE "b"  (fromList ["a", "b"]) == Just "b"+-- > lookupGE "bb" (fromList ["a", "b"]) == Nothing+lookupGE :: (CritBitKey a) => a -> Set a -> Maybe a+lookupGE = wrapVS (fmap fst) T.lookupGE+{-# INLINABLE lookupGE #-}++-- | /O(n+m)/. Is this a subset?+-- @(s1 `isSubsetOf` s2)@ tells whether @s1@ is a subset of @s2@.+isSubsetOf :: (CritBitKey a) => Set a -> Set a -> Bool+isSubsetOf = wrapSS id T.isSubmapOf+{-# INLINABLE isSubsetOf #-}++-- | /O(n+m)/. Is this a proper subset (ie. a subset but not equal)?+-- @(s1 `isSubsetOf` s2)@ tells whether @s1@ is a proper subset of @s2@.+isProperSubsetOf :: (CritBitKey a) => Set a -> Set a -> Bool+isProperSubsetOf = wrapSS id T.isProperSubmapOf+{-# INLINABLE isProperSubsetOf #-}++-- | /O(k)/. Insert an element in a set.+-- If the set already contains an element equal to the given value,+-- it is replaced with the new value.+insert :: (CritBitKey a) => a -> Set a -> Set a+insert = wrapVS Set (`T.insert` ())+{-# INLINABLE insert #-}++-- | /O(k)/. Delete an element from a set.+delete :: (CritBitKey a) => a -> Set a -> Set a+delete = wrapVS Set T.delete+{-# INLINABLE delete #-}++-- | /O(k)/. The union of two sets, preferring the first set when+-- equal elements are encountered.+union :: (CritBitKey a) => Set a -> Set a -> Set a+union = wrapSS Set T.union+{-# INLINABLE union #-}++-- | The union of a list of sets: (@'unions' == 'foldl' 'union' 'empty'@).+unions :: (CritBitKey a) => [Set a] -> Set a+unions = List.foldl' union empty+{-# INLINABLE unions #-}++-- | /O(k)/. The difference of two sets.+difference :: (CritBitKey a) => Set a -> Set a -> Set a+difference = wrapSS Set T.difference+{-# INLINABLE difference #-}++-- | /O(k)/. The intersection of two sets. Elements of the+-- result come from the first set.+intersection :: (CritBitKey a) => Set a -> Set a -> Set a+intersection = wrapSS Set T.intersection+{-# INLINABLE intersection #-}++-- | /O(n)/. Filter all elements that satisfy the predicate.+--+-- > filter (> "a") (fromList ["a", "b"]) == fromList [("3","b")]+-- > filter (> "x") (fromList ["a", "b"]) == empty+-- > filter (< "a") (fromList ["a", "b"]) == empty+filter :: (a -> Bool) -> Set a -> Set a+filter = wrapVS Set (T.filterWithKey . (const .))+{-# INLINABLE filter #-}++-- | /O(n)/. Partition the set into two sets, one with all elements that satisfy+-- the predicate and one with all elements that don't satisfy the predicate.+-- See also 'split'.+partition :: (CritBitKey a) => (a -> Bool) -> Set a -> (Set a, Set a)+partition = wrapVS (Set *** Set) (T.partitionWithKey . (const .))+{-# INLINABLE partition #-}++-- | /O(k)/. 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 "a" (fromList ["b", "d"]) == (empty, fromList ["b", "d")])+-- > split "b" (fromList ["b", "d"]) == (empty, singleton "d")+-- > split "c" (fromList ["b", "d"]) == (singleton "b", singleton "d")+-- > split "d" (fromList ["b", "d"]) == (singleton "b", empty)+-- > split "e" (fromList ["b", "d"]) == (fromList ["b", "d"], empty)+split :: (CritBitKey a) => a -> Set a -> (Set a, Set a)+split = wrapVS (Set *** Set) T.split+{-# INLINABLE split #-}++-- | /O(k)/. Performs a 'split' but also returns whether the pivot+-- element was found in the original set.+--+-- > splitMember "a" (fromList ["b", "d"]) == (empty, False, fromList ["b", "d"])+-- > splitMember "b" (fromList ["b", "d"]) == (empty, True, singleton "d")+-- > splitMember "c" (fromList ["b", "d"]) == (singleton "b", False, singleton "d")+-- > splitMember "d" (fromList ["b", "d"]) == (singleton "b", True, empty)+-- > splitMember "e" (fromList ["b", "d"]) == (fromList ["b", "d"], False, empty)+splitMember :: (CritBitKey a) => a -> Set a -> (Set a, Bool, Set a)+splitMember = wrapVS pack T.splitLookup+  where pack (l, m, r) = (Set l, isJust m, Set r)+{-# INLINABLE splitMember #-}++-- | /O(k)/. @'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 :: (CritBitKey a2) => (a1 -> a2) -> Set a1 -> Set a2+map = wrapVS Set T.mapKeys+{-# INLINABLE map #-}++-- | /O(n)/. The @'mapMonotonic' f s == 'map' f s@, but works only when+-- @f@ is monotonic.+-- /The precondition is not checked./+-- Semi-formally, we have:+--+-- > and [x < y ==> f x < f y | x <- ls, y <- ls]+-- >                     ==> mapMonotonic f s == map f s+-- >     where ls = toList s+mapMonotonic :: (CritBitKey a2) => (a1 -> a2) -> Set a1 -> Set a2+mapMonotonic = wrapVS Set T.mapKeysMonotonic+{-# INLINABLE mapMonotonic #-}++-- | /O(n)/. Fold the elements in the set using the given left-associative+-- binary operator, such that @'foldl' f z == 'Prelude.foldl' f z . 'toAscList'@.+--+-- For example,+--+-- > toDescList set = foldl (flip (:)) [] set+foldl :: (a -> b -> a) -> a -> Set b -> a+foldl f = wrapVS id (T.foldlWithKey ((const .) . f))+{-# INLINE foldl #-}++-- | /O(n)/. A strict version of 'foldl'. Each application of the operator is+-- evaluated before using the result in the next application. This+-- function is strict in the starting value.+foldl' :: (a -> b -> a) -> a -> Set b -> a+foldl' f = wrapVS id (T.foldlWithKey' ((const .) . f))+{-# INLINE foldl' #-}++-- | /O(n)/. Fold the elements in the set using the given right-associative+-- binary operator, such that @'foldr' f z == 'Prelude.foldr' f z . 'toAscList'@.+--+-- For example,+--+-- > toAscList set = foldr (:) [] set+foldr :: (a -> b -> b) -> b -> Set a -> b+foldr f = wrapVS id (T.foldrWithKey (const . f))+{-# INLINE foldr #-}++-- | /O(n)/. A strict version of 'foldr'. Each application of the operator is+-- evaluated before using the result in the next application. This+-- function is strict in the starting value.+foldr' :: (a -> b -> b) -> b -> Set a -> b+foldr' f = wrapVS id (T.foldrWithKey' (const . f))+{-# INLINE foldr' #-}++-- | /O(k')/. The minimal element of a set.+findMin :: Set a -> a+findMin = wrapS fst T.findMin+{-# INLINE findMin #-}++-- | /O(k)/. The maximal element of a set.+findMax :: Set a -> a+findMax = wrapS fst T.findMax+{-# INLINE findMax #-}++-- | /O(k')/. Delete the minimal element. Returns an empty set if the+-- set is empty.+deleteMin :: Set a -> Set a+deleteMin = wrapS Set T.deleteMin+{-# INLINE deleteMin #-}++-- | /O(k)/. Delete the maximal element. Returns an empty set if the+-- set is empty.+deleteMax :: Set a -> Set a+deleteMax = wrapS Set T.deleteMax+{-# INLINE deleteMax #-}++-- | /O(k')/. Delete and find the minimal element.+--+-- > deleteFindMin set = (findMin set, deleteMin set)+deleteFindMin :: Set a -> (a, Set a)+deleteFindMin = wrapS (fst *** Set) T.deleteFindMin+{-# INLINE deleteFindMin #-}++-- | /O(k)/. Delete and find the maximal element.+--+-- > deleteFindMax set = (findMax set, deleteMax set)+deleteFindMax :: Set a -> (a, Set a)+deleteFindMax = wrapS (fst *** Set) T.deleteFindMax+{-# INLINE deleteFindMax #-}++-- | /O(k')/. Retrieves the minimal key of the set, and the set+-- stripped of that element, or 'Nothing' if passed an empty set.+minView :: Set a -> Maybe (a, Set a)+minView = wrapS (fmap (fst *** Set)) T.minViewWithKey+{-# INLINE minView #-}++-- | /O(k)/. Retrieves the maximal key of the set, and the set+-- stripped of that element, or 'Nothing' if passed an empty set.+maxView :: Set a -> Maybe (a, Set a)+maxView = wrapS (fmap (fst *** Set)) T.maxViewWithKey+{-# INLINE maxView #-}++-- | /O(n)/. Convert the set to an ascending list of elements.+toAscList :: Set a -> [a]+toAscList = toList++-- | /O(n)/. Convert the set to a descending list of elements.+toDescList :: Set a -> [a]+toDescList = reverse . toAscList++-- | /O(n)/. Build a set from an ascending list in linear time.+-- /The precondition (input list is ascending) is not checked./+fromAscList :: (CritBitKey a) => [a] -> Set a+fromAscList = liftFromList T.fromAscList++-- | /O(n)/. Build a set from an ascending list in linear time.+-- /The precondition (input list is ascending) is not checked./+fromDistinctAscList :: (CritBitKey a) => [a] -> Set a+fromDistinctAscList = liftFromList T.fromDistinctAscList++-- | Wraps tree operation to set operation+wrapS :: (r -> q) -> (CritBit a () -> r) -> Set a -> q+wrapS f g (Set s) = f $ g s+{-# INLINE wrapS #-}++-- | Wraps (value, tree) operation to (value, set) operation+wrapVS :: (r -> q) -> (t -> CritBit a () -> r) -> t -> Set a -> q+wrapVS f g a (Set s) = f $ g a s+{-# INLINE wrapVS #-}++-- | Wraps (tree, tree) operation to (set, set) operation+wrapSS :: (r -> q) -> (CritBit a () -> CritBit a () -> r) -> Set a -> Set a -> q+wrapSS f g (Set s1) (Set s2) = f $ g s1 s2+{-# INLINE wrapSS #-}++liftFromList :: ([(a, ())] -> CritBit a ()) -> [a] -> Set a+liftFromList f xs = Set . f . zip xs . repeat $ ()+{-# INLINE liftFromList #-}
Data/CritBit/Tree.hs view
@@ -1,421 +1,1520 @@ {-# LANGUAGE BangPatterns, RecordWildCards, ScopedTypeVariables #-}---- |--- Module      :  Data.CritBit.Tree--- Copyright   :  (c) Bryan O'Sullivan 2013--- License     :  BSD-style--- Maintainer  :  bos@serpentine.com--- Stability   :  experimental--- Portability :  GHC-module Data.CritBit.Tree-    (-    -- * Operators-    -- , (!)-    -- , (\\)--    -- * Query-      null-    , size-    , member-    , notMember-    , lookup-    , findWithDefault-    , lookupGT-    -- , lookupGE--    -- * Construction-    , empty-    , singleton--    -- * Insertion-    , insert-    -- , insertWith-    -- , insertWithKey-    -- , insertLookupWithKey--    -- * Deletion-    , delete-    -- , adjust-    -- , adjustWithKey-    -- , update-    -- , updateWithKey-    -- , updateLookupWithKey-    -- , alter--    -- * Combination-    -- ** Union-    , union-    -- , unionWith-    -- , unionWithKey-    -- , unions-    -- , unionsWith-    , unionL-    , unionR--    -- ** Difference-    -- , difference-    -- , differenceWith-    -- , differenceWithKey--    -- ** Intersection-    -- , intersection-    -- , intersectionWith-    -- , intersectionWithKey--    -- * Traversal-    -- ** Map-    -- , map-    -- , mapWithKey-    -- , traverseWithKey-    -- , mapAccum-    -- , mapAccumWithKey-    -- , mapAccumRWithKey-    -- , mapKeys-    -- , mapKeysWith-    -- , mapKeysMonotonic--    -- * Folds-    , foldl-    , foldr-    , foldlWithKey-    , foldrWithKey--    -- ** Strict folds-    , foldl'-    , foldr'-    , foldlWithKey'-    , foldrWithKey'--    -- * Conversion-    -- , elems-    , keys-    -- , assocs-    -- , keysSet-    -- , fromSet--    -- ** Lists-    , toList-    , fromList-    -- , fromListWith-    -- , fromListWithKey--    -- ** Ordered lists-    -- , toAscList-    -- , toDescList-    -- , fromAscList-    -- , fromAscListWith-    -- , fromAscListWithKey-    -- , fromDistinctAscList--    -- * Filter-    -- , filter-    -- , filterWithKey-    -- , partition-    -- , partitionWithKey--    -- , mapMaybe-    -- , mapMaybeWithKey-    -- , mapEither-    -- , mapEitherWithKey--    -- , split-    -- , splitLookup--    -- * Submap-    -- , isSubmapOf-    -- , isSubmapOfBy-    -- , isProperSubmapOf-    -- , isProperSubmapOfBy--    -- -- * Min\/Max-    -- , findMin-    -- , findMax-    -- , deleteMin-    -- , deleteMax-    -- , deleteFindMin-    -- , deleteFindMax-    -- , updateMin-    -- , updateMax-    -- , updateMinWithKey-    -- , updateMaxWithKey-    -- , minView-    -- , maxView-    -- , minViewWithKey-    -- , maxViewWithKey-    ) where--import Data.CritBit.Core-import Data.CritBit.Types.Internal-import Prelude hiding (foldl, foldr, lookup, null)-import qualified Data.List as List---- | /O(1)/. Is the map empty?------ > null (empty)           == True--- > null (singleton 1 'a') == False-null :: CritBit k v -> Bool-null (CritBit Empty) = True-null _               = False---- | /O(1)/. The empty map.------ > empty      == fromList []--- > size empty == 0-empty :: CritBit k v-empty = CritBit { cbRoot = Empty }---- | /O(log n)/. Is the key a member of the map?------ > member "a" (fromList [("a",5), ("b",3)]) == True--- > member "c" (fromList [("a",5), ("b",3)]) == False------ See also 'notMember'.-member :: (CritBitKey k) => k -> CritBit k v -> Bool-member k m = lookupWith False (const True) k m-{-# INLINABLE member #-}---- | /O(log n)/. Is the key not a member of the map?------ > notMember "a" (fromList [("a",5), ("b",3)]) == False--- > notMember "c" (fromList [("a",5), ("b",3)]) == True------ See also 'member'.-notMember :: (CritBitKey k) => k -> CritBit k v -> Bool-notMember k m = lookupWith True (const False) k m-{-# INLINE notMember #-}---- | /O(log n)/. Lookup the value at a key in the map.------ The function will return the corresponding value as @('Just' value)@,--- or 'Nothing' if the key isn't in the map.------ An example of using @lookup@:------ > {-# LANGUAGE OverloadedStrings #-}--- > import Data.Text--- > import Prelude hiding (lookup)--- > import Data.CritBit.Map.Lazy--- >--- > employeeDept, deptCountry, countryCurrency :: CritBit Text Text--- > employeeDept = fromList [("John","Sales"), ("Bob","IT")]--- > deptCountry = fromList [("IT","USA"), ("Sales","France")]--- > countryCurrency = fromList [("USA", "Dollar"), ("France", "Euro")]--- >--- > employeeCurrency :: Text -> Maybe Text--- > employeeCurrency name = do--- >   dept <- lookup name employeeDept--- >   country <- lookup dept deptCountry--- >   lookup country countryCurrency--- >--- > main = do--- >   putStrLn $ "John's currency: " ++ (show (employeeCurrency "John"))--- >   putStrLn $ "Pete's currency: " ++ (show (employeeCurrency "Pete"))------ The output of this program:------ >   John's currency: Just "Euro"--- >   Pete's currency: Nothing-lookup :: (CritBitKey k) => k -> CritBit k v -> Maybe v-lookup k m = lookupWith Nothing Just k m-{-# INLINABLE lookup #-}---- | /O(log n)/. Returns the value associated with the given key, or--- the given default value if the key is not in the map.------ > findWithDefault 1 "x" (fromList [("a",5), ("b",3)]) == 1--- > findWithDefault 1 "a" (fromList [("a",5), ("b",3)]) == 5-findWithDefault :: (CritBitKey k) =>-                   v -- ^ Default value to return if lookup fails.-                -> k -> CritBit k v -> v-findWithDefault d k m = lookupWith d id k m-{-# INLINABLE findWithDefault #-}---- | /O(log n)/. Find smallest key greater than the given one and--- return the corresponding (key, value) pair.------ > lookupGT "aa" (fromList [("a",3), ("b",5)]) == Just ("b",5)--- > lookupGT "b"  (fromList [("a",3), ("b",5)]) == Nothing-lookupGT :: (CritBitKey k) => k -> CritBit k v -> Maybe (k, v)-lookupGT k (CritBit root) = go root-  where-    go i@(Internal left right _ _)-      | direction k i == 0 = go left-      | otherwise          = go right-    go (Leaf lk lv)        = rewalk root-      where-        finish (Leaf _ _) = case byteCompare k lk of-                              LT -> Just (lk, lv)-                              _ -> Nothing-        finish node-          | calcDirection nob c == 0 = Nothing-          | otherwise                = leftmost node-        rewalk i@(Internal left right byte otherBits)-          | byte > n                     = finish i-          | byte == n && otherBits > nob = finish i-          | direction k i == 0           = case rewalk left of-                                             Nothing -> leftmost right-                                             wat     -> wat-          | otherwise                    = rewalk right-        rewalk i                         = finish i-        (n, nob, c) = followPrefixes k lk-    go Empty = Nothing-    leftmost (Internal left _ _ _) = leftmost left-    leftmost (Leaf lmk lmv)        = Just (lmk, lmv)-    leftmost _                     = Nothing-{-# INLINABLE lookupGT #-}--byteCompare :: (CritBitKey k) => k -> k -> Ordering-byteCompare a b = go 0-  where-    go i = case ba `compare` getByte b i of-             EQ | ba /= 0   -> go (i + 1)-             wat            -> wat-      where ba = getByte a i-{-# INLINABLE byteCompare #-}---- | /O(n*log n)/. Build a map from a list of key\/value pairs.  If--- the list contains more than one value for the same key, the last--- value for the key is retained.------ > fromList [] == empty--- > fromList [("a",5), ("b",3), ("a",2)] == fromList [("a",2), ("b",3)]-fromList :: (CritBitKey k) => [(k, v)] -> CritBit k v-fromList = List.foldl' (flip (uncurry insert)) empty-{-# INLINABLE fromList #-}---- | /O(1)/. A map with a single element.------ > singleton "a" 1        == fromList [("a", 1)]-singleton :: k -> v -> CritBit k v-singleton k v = CritBit (Leaf k v)-{-# INLINE singleton #-}---- | /O(n)/. The number of elements in the map.------ > size empty                                  == 0--- > size (singleton "a" 1)                      == 1--- > size (fromList [("a",1), ("c",2), ("b",3)]) == 3-size :: CritBit k v -> Int-size (CritBit root) = go root-  where-    go (Internal l r _ _) = go l + go r-    go (Leaf _ _) = 1-    go Empty      = 0---- | /O(n)/. Fold the values in the map using the given--- left-associative function, such that--- @'foldl' f z == 'Prelude.foldl' f z . 'elems'@.------ Examples:------ > elems = reverse . foldl (flip (:)) []------ > foldl (+) 0 (fromList [("a",5), ("bbb",3)]) == 8-foldl :: (a -> v -> a) -> a -> CritBit k v -> a-foldl f z m = foldlWithKeyWith (\_ b -> b) (\a _ v -> f a v) z m-{-# INLINABLE foldl #-}---- | /O(n)/. A strict version of 'foldl'. Each application of the--- function is evaluated before using the result in the next--- application. This function is strict in the starting value.-foldl' :: (a -> v -> a) -> a -> CritBit k v -> a-foldl' f z m = foldlWithKeyWith seq (\a _ v -> f a v) z m-{-# INLINABLE foldl' #-}---- | /O(n)/. Fold the keys and values in the map using the given--- left-associative function, such that--- @'foldlWithKey' f z == 'Prelude.foldl' (\\z' (kx, x) -> f z' kx x) z . 'toAscList'@.------ Examples:------ > keys = reverse . foldlWithKey (\ks k x -> k:ks) []------ > let f result k a = result ++ "(" ++ show k ++ ":" ++ a ++ ")"--- > foldlWithKey f "Map: " (fromList [("a",5), ("b",3)]) == "Map: (b:3)(a:5)"-foldlWithKey :: (a -> k -> v -> a) -> a -> CritBit k v -> a-foldlWithKey f z m = foldlWithKeyWith (\_ b -> b) f z m-{-# INLINABLE foldlWithKey #-}---- | /O(n)/. A strict version of 'foldlWithKey'. Each application of--- the function is evaluated before using the result in the next--- application. This function is strict in the starting value.-foldlWithKey' :: (a -> k -> v -> a) -> a -> CritBit k v -> a-foldlWithKey' f z m = foldlWithKeyWith seq f z m-{-# INLINABLE foldlWithKey' #-}--foldlWithKeyWith :: (a -> a -> a) -> (a -> k -> v -> a) -> a -> CritBit k v -> a-foldlWithKeyWith maybeSeq f z0 (CritBit root) = go z0 root-  where-    go z (Internal left right _ _) = let z' = go z left-                                     in z' `maybeSeq` go z' right-    go z (Leaf k v)                = f z k v-    go z Empty                     = z-{-# INLINE foldlWithKeyWith #-}---- | /O(n)/. Fold the values in the map using the given--- right-associative function, such that--- @'foldr' f z == 'Prelude.foldr' f z . 'elems'@.------ Example:------ > elems map = foldr (:) [] map-foldr :: (v -> a -> a) -> a -> CritBit k v -> a-foldr f z m = foldrWithKeyWith (\_ b -> b) (\_ v a -> f v a) z m-{-# INLINABLE foldr #-}---- | /O(n)/. A strict version of 'foldr'. Each application of the--- function is evaluated before using the result in the next--- application. This function is strict in the starting value.-foldr' :: (v -> a -> a) -> a -> CritBit k v -> a-foldr' f z m = foldrWithKeyWith seq (\_ v a -> f v a) z m-{-# INLINABLE foldr' #-}---- | /O(n)/. Fold the keys and values in the map using the given--- right-associative function, such that--- @'foldrWithKey' f z == 'Prelude.foldr' ('uncurry' f) z . 'toAscList'@.------ Examples:------ > keys map = foldrWithKey (\k x ks -> k:ks) [] map------ > let f k a result = result ++ "(" ++ (show k) ++ ":" ++ a ++ ")"--- > foldrWithKey f "Map: " (fromList [("a",5), ("b",3)]) == "Map: (a:5)(b:3)"-foldrWithKey :: (k -> v -> a -> a) -> a -> CritBit k v -> a-foldrWithKey f z m = foldrWithKeyWith (\_ b -> b) f z m-{-# INLINABLE foldrWithKey #-}---- | /O(n)/. A strict version of 'foldrWithKey'. Each application of--- the function is evaluated before using the result in the next--- application. This function is strict in the starting value.-foldrWithKey' :: (k -> v -> a -> a) -> a -> CritBit k v -> a-foldrWithKey' f z m = foldrWithKeyWith seq f z m-{-# INLINABLE foldrWithKey' #-}--foldrWithKeyWith :: (a -> a -> a) -> (k -> v -> a -> a) -> a -> CritBit k v -> a-foldrWithKeyWith maybeSeq f z0 (CritBit root) = go root z0-  where-    go (Internal left right _ _) z = let z' = go right z-                                     in z' `maybeSeq` go left z'-    go (Leaf k v) z                = f k v z-    go Empty z                     = z-{-# INLINE foldrWithKeyWith #-}---- | /O(n)/. Return all keys of the map in ascending order.------ > keys (fromList [("b",5), ("a",3)]) == ["a","b"]--- > keys empty == []-keys :: CritBit k v -> [k]-keys m = foldrWithKey f [] m-  where f k _ ks = k : ks--unionL :: (CritBitKey k) => CritBit k v -> CritBit k v -> CritBit k v-unionL a b = foldlWithKey' (\m k v -> insert k v m) b a-{-# INLINABLE unionL #-}--unionR :: (CritBitKey k) => CritBit k v -> CritBit k v -> CritBit k v-unionR a b = foldlWithKey' (\m k v -> insert k v m) a b-{-# INLINABLE unionR #-}--union :: (CritBitKey k) => CritBit k v -> CritBit k v -> CritBit k v-union a b = unionL a b-{-# INLINE union #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++-- |+-- Module      :  Data.CritBit.Tree+-- Copyright   :  (c) Bryan O'Sullivan and others 2013-2014+-- License     :  BSD-style+-- Maintainer  :  bos@serpentine.com+-- Stability   :  experimental+-- Portability :  GHC+module Data.CritBit.Tree+    (+    -- * Operators+      (!)+    , (\\)++    -- * Query+    , null+    , size+    , member+    , notMember+    , lookup+    , findWithDefault+    , lookupGT+    , lookupGE+    , lookupLT+    , lookupLE++    -- * Construction+    , empty+    , singleton++    -- * Insertion+    , insert+    , insertWith+    , insertWithKey+    , insertLookupWithKey++    -- * Deletion+    , delete+    , adjust+    , adjustWithKey+    , update+    , updateWithKey+    , updateLookupWithKey+    , alter++    -- * Combination+    -- ** Union+    , union+    , unionWith+    , unionWithKey+    , unions+    , unionsWith+    , unionL+    , unionR++    -- ** Difference+    , difference+    , differenceWith+    , differenceWithKey++    -- ** Intersection+    , intersection+    , intersectionWith+    , intersectionWithKey++    -- * Traversal+    -- ** Map+    , map+    , mapWithKey+    , traverseWithKey+    , mapAccum+    , mapAccumWithKey+    , mapAccumRWithKey+    , mapKeys+    , mapKeysWith+    , mapKeysMonotonic++    -- * Folds+    , foldl+    , foldr+    , foldlWithKey+    , foldrWithKey++    -- ** Strict folds+    , foldl'+    , foldr'+    , foldlWithKey'+    , foldrWithKey'++    -- * Conversion+    , elems+    , keys+    , assocs+    , keysSet+    , fromSet++    -- ** Lists+    , toList+    , fromList+    , fromListWith+    , fromListWithKey++    -- ** Ordered lists+    , toAscList+    , toDescList+    , fromAscList+    , fromAscListWith+    , fromAscListWithKey+    , fromDistinctAscList++    -- * Filter+    , filter+    , filterWithKey+    , partition+    , partitionWithKey++    , mapMaybe+    , mapMaybeWithKey+    , mapEither+    , mapEitherWithKey++    , split+    , splitLookup++    -- * Submap+    , isSubmapOf+    , isSubmapOfBy+    , isProperSubmapOf+    , isProperSubmapOfBy++    -- -- * Min\/Max+    , findMin+    , findMax+    , deleteMin+    , deleteMax+    , deleteFindMin+    , deleteFindMax+    , updateMin+    , updateMax+    , updateMinWithKey+    , updateMaxWithKey+    , minView+    , maxView+    , minViewWithKey+    , maxViewWithKey+    ) where++import Control.Applicative (Applicative(..), (<$>), (<|>))+import Control.Arrow (second, (***))+import Data.CritBit.Core+import Data.CritBit.Types.Internal+import Data.Maybe (fromMaybe)+import Data.Monoid (Monoid(..))+import Data.Traversable (Traversable(traverse))+import Prelude hiding (foldl, foldr, lookup, null, map, filter)+import qualified Data.Array as A+import qualified Data.Foldable as Foldable+import qualified Data.List as List++instance CritBitKey k => Monoid (CritBit k v) where+    mempty  = empty+    mappend = union+    mconcat = unions++instance CritBitKey k => Traversable (CritBit k) where+    traverse f m = traverseWithKey (\_ v -> f v) m++infixl 9 !, \\++-- | /O(k)/. Find the value at a key.+-- Calls 'error' when the element can not be found.+--+-- > fromList [("a",5), ("b",3)] ! "c"    Error: element not in the map+-- > fromList [("a",5), ("b",3)] ! "a" == 5+(!) :: CritBitKey k => CritBit k v -> k -> v+(!) m k = lookupWith err id k m+  where err = error "CritBit.!: given key is not an element in the map"+{-# INLINABLE (!) #-}++-- | Same as 'difference'.+(\\) :: CritBitKey k => CritBit k v -> CritBit k w -> CritBit k v+(\\) m n = difference m n+{-# INLINABLE (\\) #-}++-- | /O(1)/. Is the map empty?+--+-- > null (empty)           == True+-- > null (singleton 1 'a') == False+null :: CritBit k v -> Bool+null (CritBit Empty) = True+null _               = False++-- | /O(1)/. The empty map.+--+-- > empty      == fromList []+-- > size empty == 0+empty :: CritBit k v+empty = CritBit Empty++-- | /O(k)/. Is the key a member of the map?+--+-- > member "a" (fromList [("a",5), ("b",3)]) == True+-- > member "c" (fromList [("a",5), ("b",3)]) == False+--+-- See also 'notMember'.+member :: (CritBitKey k) => k -> CritBit k v -> Bool+member k m = lookupWith False (const True) k m+{-# INLINABLE member #-}++-- | /O(k)/. Is the key not a member of the map?+--+-- > notMember "a" (fromList [("a",5), ("b",3)]) == False+-- > notMember "c" (fromList [("a",5), ("b",3)]) == True+--+-- See also 'member'.+notMember :: (CritBitKey k) => k -> CritBit k v -> Bool+notMember k m = lookupWith True (const False) k m+{-# INLINE notMember #-}++-- | /O(k)/. Lookup the value at a key in the map.+--+-- The function will return the corresponding value as @('Just' value)@,+-- or 'Nothing' if the key isn't in the map.+--+-- An example of using @lookup@:+--+-- > {-# LANGUAGE OverloadedStrings #-}+-- > import Data.Text+-- > import Prelude hiding (lookup)+-- > import Data.CritBit.Map.Lazy+-- >+-- > employeeDept, deptCountry, countryCurrency :: CritBit Text Text+-- > employeeDept = fromList [("John","Sales"), ("Bob","IT")]+-- > deptCountry = fromList [("IT","USA"), ("Sales","France")]+-- > countryCurrency = fromList [("USA", "Dollar"), ("France", "Euro")]+-- >+-- > employeeCurrency :: Text -> Maybe Text+-- > employeeCurrency name = do+-- >   dept <- lookup name employeeDept+-- >   country <- lookup dept deptCountry+-- >   lookup country countryCurrency+-- >+-- > main = do+-- >   putStrLn $ "John's currency: " ++ show (employeeCurrency "John")+-- >   putStrLn $ "Pete's currency: " ++ show (employeeCurrency "Pete")+--+-- The output of this program:+--+-- >   John's currency: Just "Euro"+-- >   Pete's currency: Nothing+lookup :: (CritBitKey k) => k -> CritBit k v -> Maybe v+lookup k m = lookupWith Nothing Just k m+{-# INLINABLE lookup #-}++-- | /O(k)/. Delete a key and its value from the map. When the key+-- is not a member of the map, the original map is returned.+--+-- > delete "a" (fromList [("a",5), ("b",3)]) == singleton "b" 3+-- > delete "c" (fromList [("a",5), ("b",3)]) == fromList [("a",5), ("b",3)]+-- > delete "a" empty                         == empty+delete :: (CritBitKey k) => k -> CritBit k v -> CritBit k v+delete k t@(CritBit root) = go root empty CritBit+  where+    go i@(Internal left right _ _) _ cont+      | k `onLeft` i = go left (cont right) $ ((cont $!) . setLeft  i)+      | otherwise    = go right (cont left) $ ((cont $!) . setRight i)+    go (Leaf lk _) other _+      | k == lk   = other+      | otherwise = t+    go Empty _ _ = t+{-# INLINABLE delete #-}++-- | /O(k)/. The expression (@'update' f k map@ updates the value @x@+-- at @k@ (if it is in the map). If (@f x@) is 'Nothing', the element is+-- deleted. If it is (@'Just' y@), the key @k@ is bound to the new value @y@.+--+-- > let f x = if x == 5 then Just 50 else Nothing+-- > update f "a" (fromList [("b",3), ("a",5)]) == fromList [("a", 50), ("b",3)]+-- > update f "c" (fromList [("b",3), ("a",5)]) == fromList [("a", 50), ("b",3)]+-- > update f "b" (fromList [("b",3), ("a",5)]) == singleton "a" 5+update :: (CritBitKey k) => (v -> Maybe v) -> k -> CritBit k v -> CritBit k v+update f = updateWithKey (const f)+{-# INLINABLE update #-}++-- | /O(log n)/. The expression (@'updateWithKey' f k map@) updates the+-- value @x@ at @k@ (if it is in the map). If (@f k x@) is 'Nothing',+-- the element is deleted. If it is (@'Just' y@), the key @k@ is bound+-- to the new value @y@.+--+-- > let f k x = if x == 5 then Just (x + fromEnum (k < "d")) else Nothing+-- > updateWithKey f "a" (fromList [("b",3), ("a",5)]) == fromList [("a", 6), ("b",3)]+-- > updateWithKey f "c" (fromList [("a",5), ("b",3)]) == fromList [("a",5), ("b",3)]+-- > updateWithKey f "b" (fromList [("a",5), ("b",3)]) == singleton "a" 5+updateWithKey :: (CritBitKey k) => (k -> v -> Maybe v) -> k -> CritBit k v+              -> CritBit k v+updateWithKey f k = snd . updateLookupWithKey f k+{-# INLINABLE updateWithKey #-}++-- | /O(k)/. Update a value at a specific key with the result of the+-- provided function. When the key is not a member of the map, the original+-- map is returned.+--+-- > let f k x = x + 1+-- > adjustWithKey f "a" (fromList [("b",3), ("a",5)]) == fromList [("a", 6), ("b",3)]+-- > adjustWithKey f "c" (fromList [("a",5), ("b",3)]) == fromList [("a",5), ("b",3)]+-- > adjustWithKey f "c" empty                         == empty+adjust :: (CritBitKey k) => (v -> v) -> k -> CritBit k v -> CritBit k v+adjust f = updateWithKey (\_ v -> Just (f v))+{-# INLINABLE adjust #-}++-- | /O(k)/. Adjust a value at a specific key. When the key is not+-- a member of the map, the original map is returned.+--+-- > let f k x = x + fromEnum (k < "d")+-- > adjustWithKey f "a" (fromList [("b",3), ("a",5)]) == fromList [("a", 6), ("b",3)]+-- > adjustWithKey f "c" (fromList [("a",5), ("b",3)]) == fromList [("a",5), ("b",3)]+-- > adjustWithKey f "c" empty                         == empty+adjustWithKey :: (CritBitKey k) => (k -> v -> v) -> k -> CritBit k v+              -> CritBit k v+adjustWithKey f = updateWithKey (\k v -> Just (f k v))+{-# INLINABLE adjustWithKey #-}++-- | /O(k)/. Returns the value associated with the given key, or+-- the given default value if the key is not in the map.+--+-- > findWithDefault 1 "x" (fromList [("a",5), ("b",3)]) == 1+-- > findWithDefault 1 "a" (fromList [("a",5), ("b",3)]) == 5+findWithDefault :: (CritBitKey k) =>+                   v -- ^ Default value to return if lookup fails.+                -> k -> CritBit k v -> v+findWithDefault d k m = lookupWith d id k m+{-# INLINABLE findWithDefault #-}++-- | /O(k)/. Find smallest key greater than the given one and+-- return the corresponding (key, value) pair.+--+-- > lookupGT "aa" (fromList [("a",3), ("b",5)]) == Just ("b",5)+-- > lookupGT "b"  (fromList [("a",3), ("b",5)]) == Nothing+lookupGT :: (CritBitKey k) => k -> CritBit k v -> Maybe (k, v)+lookupGT k r = lookupOrd (GT ==) k r+{-# INLINABLE lookupGT #-}++-- | /O(k)/. Find smallest key greater than or equal to the given one and+-- return the corresponding (key, value) pair.+--+-- > lookupGE "aa" (fromList [("a",3), ("b",5)]) == Just("b",5)+-- > lookupGE "b"  (fromList [("a",3), ("b",5)]) == Just("b",5)+-- > lookupGE "bb" (fromList [("a",3), ("b",5)]) == Nothing+lookupGE :: (CritBitKey k) => k -> CritBit k v -> Maybe (k, v)+lookupGE k r = lookupOrd (LT /=) k r+{-# INLINABLE lookupGE #-}++-- | /O(k)/. Find largest key smaller than the given one and+-- return the corresponding (key, value) pair.+--+-- > lookupLT "aa" (fromList [("a",3), ("b",5)]) == Just ("a",3)+-- > lookupLT "a"  (fromList [("a",3), ("b",5)]) == Nothing+lookupLT :: (CritBitKey k) => k -> CritBit k v -> Maybe (k, v)+lookupLT k r = lookupOrd (LT ==) k r+{-# INLINABLE lookupLT #-}++-- | /O(k)/. Find largest key smaller than or equal to the given one and+-- return the corresponding (key, value) pair.+--+-- > lookupGE "bb" (fromList [("aa",3), ("b",5)]) == Just("b",5)+-- > lookupGE "aa" (fromList [("aa",3), ("b",5)]) == Just("aa",5)+-- > lookupGE "a"  (fromList [("aa",3), ("b",5)]) == Nothing+lookupLE :: (CritBitKey k) => k -> CritBit k v -> Maybe (k, v)+lookupLE k r = lookupOrd (GT /=) k r+{-# INLINABLE lookupLE #-}++-- | /O(k)/. Common part of lookupXX functions.+lookupOrd :: (CritBitKey k) =>+             (Ordering -> Bool) -> k -> CritBit k v -> Maybe (k, v)+lookupOrd accepts k m = findPosition (const id) finish toLeft toRight k m+  where+    finish _ Empty = Nothing+    finish diff (Leaf lk lv)+      | accepts (diffOrd diff) = pair lk lv+      | otherwise              = Nothing+    finish diff i@(Internal{}) = case diffOrd diff of+      LT -> ifLT i+      GT -> ifGT i+      EQ -> error "Data.CritBit.Tree.lookupOrd.finish: Unpossible."++    toLeft  i = (<|> ifGT (iright i))+    toRight i = (<|> ifLT (ileft  i))+    pair a b = Just (a, b)+    ifGT = test GT  leftmost+    ifLT = test LT rightmost+    test v f node+      | accepts v = f Nothing pair node+      | otherwise = Nothing+{-# INLINE lookupOrd #-}++-- | /O(k)/. Build a map from a list of key\/value pairs.  If+-- the list contains more than one value for the same key, the last+-- value for the key is retained.+--+-- > fromList [] == empty+-- > fromList [("a",5), ("b",3), ("a",2)] == fromList [("a",2), ("b",3)]+fromList :: (CritBitKey k) => [(k, v)] -> CritBit k v+fromList = List.foldl' ins empty+    where+    ins t (k,x) = insert k x t+{-# INLINABLE fromList #-}++-- | /O(k)/. Build a map from a list of key\/value pairs+-- with a combining function. See also 'fromAscListWith'.+--+-- > fromListWith (+) [("a",5), ("b",5), ("b",3), ("a",3), ("a",5)] ==+-- >                        fromList [("a",13), ("b",8)]+-- > fromListWith (+) [] == empty+fromListWith :: (CritBitKey k) => (v -> v -> v) -> [(k,v)] -> CritBit k v+fromListWith f xs = fromListWithKey (const f) xs+{-# INLINABLE fromListWith #-}++-- | /O(k)/. Build a map from a list of key\/value pairs+-- with a combining function. See also 'fromAscListWithKey'.+--+-- > let f key a1 a2 = byteCount key + a1 + a2+-- > fromListWithKey f [("a",5), ("b",5), ("b",3), ("a",3), ("a",5)] ==+-- >                        fromList [("a",16), ("b",10)]+-- > fromListWithKey f [] == empty+fromListWithKey :: (CritBitKey k) => (k -> v -> v -> v) -> [(k,v)] -> CritBit k v+fromListWithKey f xs+  = List.foldl' ins empty xs+  where+    ins t (k,x) = insertWithKey f k x t+{-# INLINABLE fromListWithKey #-}++-- | /O(1)/. A map with a single element.+--+-- > singleton "a" 1        == fromList [("a",1)]+singleton :: k -> v -> CritBit k v+singleton k v = CritBit (Leaf k v)+{-# INLINE singleton #-}++-- | /O(n)/. The number of elements in the map.+--+-- > size empty                                  == 0+-- > size (singleton "a" 1)                      == 1+-- > size (fromList [("a",1), ("c",2), ("b",3)]) == 3+size :: CritBit k v -> Int+size (CritBit root) = go root 0+  where+    go (Internal{..}) !c = go iright (go ileft c)+    go (Leaf{})        c = c + 1+    go Empty           c = c++-- | /O(n)/. Fold the values in the map using the given+-- left-associative function, such that+-- @'foldl' f z == 'Prelude.foldl' f z . 'elems'@.+--+-- Examples:+--+-- > elems = reverse . foldl (flip (:)) []+--+-- > foldl (+) 0 (fromList [("a",5), ("bbb",3)]) == 8+foldl :: (a -> v -> a) -> a -> CritBit k v -> a+foldl f z m = Foldable.foldl f z m+{-# INLINE foldl #-}++-- | /O(n)/. A strict version of 'foldl'. Each application of the+-- function is evaluated before using the result in the next+-- application. This function is strict in the starting value.+foldl' :: (a -> v -> a) -> a -> CritBit k v -> a+foldl' f z m = foldlWithKey' (\a _ v -> f a v) z m+{-# INLINABLE foldl' #-}++-- | /O(n)/. Fold the values in the map using the given+-- right-associative function, such that+-- @'foldr' f z == 'Prelude.foldr' f z . 'elems'@.+--+-- Example:+--+-- > elems map = foldr (:) [] map+foldr :: (v -> a -> a) -> a -> CritBit k v -> a+foldr f z m = Foldable.foldr f z m+{-# INLINE foldr #-}++-- | /O(n)/. A strict version of 'foldr'. Each application of the+-- function is evaluated before using the result in the next+-- application. This function is strict in the starting value.+foldr' :: (v -> a -> a) -> a -> CritBit k v -> a+foldr' f z m = foldrWithKey' (const f) z m+{-# INLINABLE foldr' #-}++-- | /O(n)/. Return all the elements of the map in ascending order of+-- their keys.+--+-- > elems (fromList [("b",5), ("a",3)]) == [3,5]+-- > elems empty == []+elems :: CritBit k v -> [v]+elems m = foldr (:) [] m+{-# INLINE elems #-}++-- | /O(n)/. An alias for 'toAscList'. Return all key/value pairs in the map in+-- ascending order.+--+-- > assocs (fromList [(5,"a"), (3,"b")]) == [(3,"b"), (5,"a")]+-- > assocs empty == []+assocs :: CritBit k v -> [(k,v)]+assocs m = toAscList m++-- | /O(n)/. Return set of all keys of the map.+--+-- > keysSet (fromList [("b",5), ("a",3)]) == Set.fromList ["a", "b"]+-- > keysSet empty == []+keysSet :: CritBit k v -> Set k+keysSet m = Set (fmap (const ()) m)+{-# INLINABLE keysSet #-}++-- | /O(n)/. Build a map from a set of keys and a function which for each key+-- computes its value.+--+-- > fromSet (\k -> length k) (Data.IntSet.fromList ["a", "bb"]) == fromList [("a",1), ("bb",2)]+-- > fromSet undefined Data.IntSet.empty == empty+fromSet :: (k -> v) -> Set k -> CritBit k v+fromSet f (Set s) = mapWithKey (const . f) s+{-# INLINABLE fromSet #-}++-- | /O(n)/. Return all keys of the map in ascending order.+--+-- > keys (fromList [("b",5), ("a",3)]) == ["a","b"]+-- > keys empty == []+keys :: CritBit k v -> [k]+keys (CritBit root) = go root []+  where+    go (Internal{..}) acc = go ileft $ go iright acc+    go (Leaf k _)     acc = k : acc+    go Empty          acc = acc+{-# INLINABLE keys #-}++unionL :: (CritBitKey k) => CritBit k v -> CritBit k v -> CritBit k v+unionL a b = unionWithKey (\_ x _ -> x) a b+{-# INLINABLE unionL #-}++unionR :: (CritBitKey k) => CritBit k v -> CritBit k v -> CritBit k v+unionR a b = unionWithKey (\_ x _ -> x) b a+{-# INLINABLE unionR #-}++-- | /O(n+m)/.  The expression (@'union' t1 t2@) takes the left-biased+-- union of @t1@ and @t2@.+--+-- It prefers @t1@ when duplicate keys are encountered,+-- i.e. (@'union' == 'unionWith' 'const'@).+--+-- > union (fromList [("a", 5), ("b", 3)]) (fromList [("a", 4), ("c", 7)]) == fromList [("a", 5), ("b", "3"), ("c", 7)]+union :: (CritBitKey k) => CritBit k v -> CritBit k v -> CritBit k v+union a b = unionL a b+{-# INLINE union #-}++-- | Union with a combining function.+--+-- > let l = fromList [("a", 5), ("b", 3)]+-- > let r = fromList [("A", 5), ("b", 7)]+-- > unionWith (+) l r == fromList [("A",5),("a",5),("b",10)]+unionWith :: (CritBitKey k) => (v -> v -> v)+          -> CritBit k v -> CritBit k v -> CritBit k v+unionWith f a b = unionWithKey (const f) a b++-- | Union with a combining function.+--+-- > let f key new_value old_value = byteCount key + new_value + old_value+-- > let l = fromList [("a", 5), ("b", 3)]+-- > let r = fromList [("A", 5), ("C", 7)]+-- > unionWithKey f l r == fromList [("A",5),("C",7),("a",5),("b",3)]+unionWithKey :: (CritBitKey k) => (k -> v -> v -> v)+             -> CritBit k v -> CritBit k v -> CritBit k v+unionWithKey f (CritBit lt) (CritBit rt) = CritBit (top lt rt)+  where+    -- Assumes that empty nodes exist only on the top level+    top Empty b = b+    top a Empty = a+    top a b = go a (minKey a) b (minKey b)++    -- Each node is followed by the minimum key in that node.+    -- This trick assures that overall time spend by minKey in O(n+m)+    go a@(Leaf ak av) _ b@(Leaf bk bv) _+        | ak == bk = Leaf ak (f ak av bv)+        | otherwise = fork a ak b bk+    go a@(Leaf{}) ak b@(Internal{}) bk =+      leafBranch a b bk (splitB a ak b bk) (fork a ak b bk)+    go a@(Internal{}) ak b@(Leaf{}) bk =+      leafBranch b a ak (splitA a ak b bk) (fork a ak b bk)+    go a@(Internal al ar abyte abits) ak b@(Internal bl br bbyte bbits) bk+      | (dbyte, dbits) < min (abyte, abits) (bbyte, bbits) = fork a ak b bk+      | otherwise =+           case compare (abyte, abits) (bbyte, bbits) of+             LT -> splitA a ak b bk+             GT -> splitB a ak b bk+             EQ -> setBoth' a (go al ak bl bk) (go ar (minKey ar) br (minKey br))+      where+        Diff dbyte dbits _ = followPrefixes ak bk+    -- Assumes that empty nodes exist only on the top level+    go _ _ _ _ = error "Data.CritBit.Tree.unionWithKey.go: Empty"++    splitA a@(Internal al ar _ _) ak b bk =+      switch bk a (go al ak b bk) ar al (go ar (minKey ar) b bk)+    splitA _ _ _ _ =+      error "Data.CritBit.Tree.unionWithKey.splitA: unpossible"+    {-# INLINE splitA #-}++    splitB a ak b@(Internal bl br _ _) bk =+      switch ak b (go a ak bl bk) br bl (go a ak br (minKey br))+    splitB _ _ _ _ =+      error "Data.CritBit.Tree.unionWithKey.splitB: unpossible"+    {-# INLINE splitB #-}++    fork a ak b bk = internal (followPrefixes ak bk) b a+    {-# INLINE fork #-}+{-# INLINEABLE unionWithKey #-}++-- | The union of a list of maps:+-- (@'unions' == 'List.foldl' 'union' 'empty'@).+--+-- > unions [(fromList [("a", 5), ("b", 3)]), (fromList [("a", 6), ("c", 7)]), (fromList [("a", 9), ("b", 5)])]+-- >     == fromList [("a", 5), ("b", 4), (c, 7)]+-- > unions [(fromList [("a", 9), ("b", 8)]), (fromList [("ab", 5), ("c",7)]), (fromList [("a", 5), ("b", 3)])]+-- >     == fromList [("a", 9), ("ab", 5), ("b", 8), ("c", 7)]+unions :: (CritBitKey k) => [CritBit k v] -> CritBit k v+unions cs = List.foldl' union empty cs++-- | The union of a list of maps, with a combining operation:+-- (@'unionsWith' f == 'List.foldl' ('unionWith' f) 'empty'@).+--+-- > unionsWith (+) [(fromList [("a",5), ("b", 3)]), (fromList [("a", 3), ("c", 7)]), (fromList [("a", 5), ("b", 5)])]+-- >     == fromList [("a", 12), ("b", 8), ("c")]+unionsWith :: (CritBitKey k) => (v -> v -> v) -> [CritBit k v] -> CritBit k v+unionsWith f cs = List.foldl' (unionWith f) empty cs++-- | /O(n+m)/. Difference of two maps.+-- | Return data in the first map not existing in the second map.+--+-- > let l = fromList [("a", 5), ("b", 3)]+-- > let r = fromList [("A", 2), ("b", 7)]+-- > difference l r == fromList [("a", 5)]+difference :: (CritBitKey k) => CritBit k v -> CritBit k w -> CritBit k v+difference a b = differenceWithKey (\_ _ _ -> Nothing) a b+{-# INLINEABLE difference #-}++-- | /O(n+m)/. Difference with a combining function.+-- | When two equal keys are encountered, the combining function is applied+-- | to the values of theese keys. If it returns 'Nothing', the element is+-- | discarded (proper set difference). If it returns (@'Just' y@),+-- | the element is updated with a new value @y@.+--+-- > let f av bv = if av == 3 then Just (av + bv) else Nothing+-- > let l = fromList [(pack "a", 5), (pack "b", 3), (pack "c", 8)]+-- > let r = fromList [(pack "a", 2), (pack "b", 7), (pack "d", 8)]+-- > differenceWith f l r == fromList [(pack "b", 10), (pack "c", 8)]+differenceWith :: (CritBitKey k) => (v -> w -> Maybe v)+                 -> CritBit k v -> CritBit k w -> CritBit k v+differenceWith f a b = differenceWithKey (const f) a b+{-# INLINEABLE differenceWith #-}++-- | /O(n+m)/. Difference with a combining function.+-- | When two equal keys are encountered, the combining function is applied+-- | to the key and both values. If it returns 'Nothing', the element is+-- | discarded (proper set difference). If it returns (@'Just' y@),+-- | the element is updated with a new value @y@.+--+-- > let f k av bv = if k == "b" then Just (length k + av + bv) else Nothing+-- > let l = fromList [("a", 5), ("b", 3), ("c", 8)]+-- > let r = fromList [("a", 2), ("b", 7), ("d", 8)]+-- > differenceWithKey f l r == fromList [("b", 11), ("c", 8)]+differenceWithKey :: (CritBitKey k) => (k -> v -> w -> Maybe v)+                    -> CritBit k v -> CritBit k w -> CritBit k v+differenceWithKey = binarySetOpWithKey id+{-# INLINEABLE differenceWithKey #-}++-- | /O(n+m)/. Intersection of two maps.+-- | Return data in the first map for the keys existing in both maps.+--+-- > let l = fromList [("a", 5), ("b", 3)]+-- > let r = fromList [("A", 2), ("b", 7)]+-- > intersection l r == fromList [("b", 3)]+intersection :: (CritBitKey k) => CritBit k v -> CritBit k w -> CritBit k v+intersection a b = intersectionWithKey (\_ x _ -> x) a b+{-# INLINEABLE intersection #-}++-- | /O(n+m)/. Intersection with a combining function.+--+-- > let l = fromList [("a", 5), ("b", 3)]+-- > let r = fromList [("A", 2), ("b", 7)]+-- > intersectionWith (+) l r == fromList [("b", 10)]+intersectionWith :: (CritBitKey k) => (v -> w -> x)+                 -> CritBit k v -> CritBit k w -> CritBit k x+intersectionWith f a b = intersectionWithKey (const f) a b+{-# INLINEABLE intersectionWith #-}++-- | /O(n+m)/. Intersection with a combining function.+--+-- > let f key new_value old_value = length key + new_value + old_value+-- > let l = fromList [("a", 5), ("b", 3)]+-- > let r = fromList [("A", 2), ("b", 7)]+-- > intersectionWithKey f l r == fromList [("b", 11)]+intersectionWithKey :: (CritBitKey k) => (k -> v -> w -> x)+                    -> CritBit k v -> CritBit k w -> CritBit k x+intersectionWithKey f = binarySetOpWithKey (const Empty) f'+  where+    f' k v1 v2 = Just (f k v1 v2)++-- | Perform binary set operation on two maps.+binarySetOpWithKey :: (CritBitKey k)+    => (Node k v -> Node k x) -- ^ Process unmatched node in first map+    -> (k -> v -> w -> Maybe x) -- ^ Process matching values+    -> CritBit k v -- ^ First map+    -> CritBit k w -- ^ Second map+    -> CritBit k x+binarySetOpWithKey left both (CritBit lt) (CritBit rt) = CritBit $ top lt rt+  where+    -- Assumes that empty nodes exist only on the top level.+    top Empty _ = Empty+    top a Empty = left a+    top a b = go a (minKey a) b (minKey b)++    -- Each node is followed by the minimum key in that node.+    -- This trick assures that overall time spend by minKey is O(n+m).+    go a@(Leaf ak av) _ (Leaf bk bv) _+        | ak == bk = case both ak av bv of+                       Just v  -> Leaf ak v+                       Nothing -> Empty+        | otherwise = left a+    go a@(Leaf{}) ak b@(Internal{}) bk =+      leafBranch a b bk (splitB a ak b bk) (left a)+    go a@(Internal{}) ak b@(Leaf{}) bk =+      leafBranch b a ak (splitA a ak b bk) (left a)+    go a@(Internal al ar abyte abits) ak b@(Internal bl br bbyte bbits) bk =+      case compare (abyte, abits) (bbyte, bbits) of+        LT -> splitA a ak b bk+        GT -> splitB a ak b bk+        EQ -> setBoth' a (go al ak bl bk) (go ar (minKey ar) br (minKey br))+    -- Assumes that empty nodes exist only on the top level.+    go _ _ _ _ = error "Data.CritBit.Tree.binarySetOpWithKey.go: Empty"++    splitA a@(Internal al ar _ _) ak b bk =+        switch bk a (go al ak b bk) (left ar) (left al) (go ar (minKey ar) b bk)+    splitA _ _ _ _ =+        error "Data.CritBit.Tree.binarySetOpWithKey.splitA: unpossible"+    {-# INLINE splitA #-}++    splitB a ak b@(Internal bl br _ _) bk =+        switch ak b (go a ak bl bk) Empty Empty (go a ak br (minKey br))+    splitB _ _ _ _ =+        error "Data.CritBit.Tree.binarySetOpWithKey.splitB: unpossible"+    {-# INLINE splitB #-}+{-# INLINEABLE binarySetOpWithKey #-}++-- | Detect whether branch in 'Internal' node comes 'before' or+-- 'after' branch initiated by 'Leaf'.+leafBranch :: CritBitKey k => Node k v -> Node k w -> k -> t -> t -> t+leafBranch (Leaf lk _) i@(Internal{}) sk before after+    | followPrefixes lk sk `above` i = after+    | otherwise                      = before+leafBranch _ _ _ _ _ = error "Data.CritBit.Tree.leafBranch: unpossible"+{-# INLINE leafBranch #-}++-- | Select child to link under node 'n' by 'k'.+switch :: (CritBitKey k) => k -> Node k v -> Node k w -> Node k w+       -> Node k w -> Node k w -> Node k w+switch k n a0 b0 a1 b1+  | k `onLeft` n = setBoth' n a0 b0+  | otherwise    = setBoth' n a1 b1+{-# INLINE switch #-}++-- | Extract minimum key from the subtree.+minKey :: (CritBitKey k) => Node k v -> k+minKey n = leftmost+    (error "Data.CritBit.Tree.minKey: Empty")+    const n+{-# INLINE minKey #-}++-- | Extract maximum key from the subtree.+maxKey :: (CritBitKey k) => Node k v -> k+maxKey n = rightmost+    (error "Data.CritBit.Tree.maxKey: Empty")+    const n+{-# INLINE maxKey #-}++-- | Sets both children to the parent node.+setBoth' :: Node k v -> Node k w -> Node k w -> Node k w+setBoth' _ Empty b = b+setBoth' _ a Empty = a+setBoth' (Internal _ _ byte bits) !a !b = Internal a b byte bits+setBoth' _ _ _ = error "Data.CritBit.Tree.setBoth': unpossible"+{-# INLINE setBoth' #-}++setBoth :: Node k v -> Node k w -> Node k w -> Node k w+setBoth (Internal _ _ byte bits) !a !b = Internal a b byte bits+setBoth _ _ _ = error "Data.CritBit.Tree.setBoth: unpossible"+{-# INLINE setBoth #-}++-- | /O(n)/. Apply a function to all values.+--+-- > map show (fromList [("b",5), ("a",3)]) == fromList [("b","5"), ("a","3")]+map :: (CritBitKey k) => (v -> w) -> CritBit k v -> CritBit k w+map = fmap++-- | /O(k)/.+-- @mapKeys f@ applies the function @f@ to the keys of the map.+--+-- If @f@ maps multiple keys to the same new key, the new key is+-- associated with the value of the greatest of the original keys.+--+-- > let f = fromString . (++ "1") . show+-- > mapKeys f (fromList [("a", 5), ("b", 3)])            == fromList ([("a1", 5), ("b1", 3)])+-- > mapKeys (\ _ -> "a") (fromList [("a", 5), ("b", 3)]) == singleton "a" 3+mapKeys :: (CritBitKey k2)+        => (k1 -> k2)+        -> CritBit k1 v -> CritBit k2 v+mapKeys f m = mapKeysWith (\_ v -> v) f m+{-# INLINABLE mapKeys #-}++-- | /O(k)/.+-- @'mapKeysWith' c f s@ is the map obtained by applying @f@ to each key of @s@.+--+-- The size of the result may be smaller if @f@ maps two or more distinct+-- keys to the same new key.  In this case the associated values will be+-- combined using @c@.+--+-- > mapKeysWith (+) (\ _ -> "a") (fromList [("b",1), ("a",2), ("d",3), ("c",4)]) == singleton "a" 10+mapKeysWith :: (CritBitKey k2)+            => (v -> v -> v)+            -> (k1 -> k2)+            -> CritBit k1 v -> CritBit k2 v+mapKeysWith c f m = foldrWithKey ins empty m+  where ins k v nm = insertWith c (f k) v nm+{-# INLINABLE mapKeysWith #-}++-- | /O(k)/.+-- @'mapKeysMonotonic' f s == 'mapKeys' f s@, but works only when @f@+-- is strictly monotonic.+-- That is, for any values @x@ and @y@, if @x@ < @y@ then @f x@ < @f y@.+-- /The precondition is not checked./+-- Semi-formally, we have:+--+-- > and [x < y ==> f x < f y | x <- ls, y <- ls]+-- >                     ==> mapKeysMonotonic f s == mapKeys f s+-- >     where ls = keys s+--+-- This means that @f@ maps distinct original keys to distinct resulting keys.+-- This function has slightly better performance than 'mapKeys'.+--+-- > mapKeysMonotonic (\ k -> succ k) (fromList [("a",5), ("b",3)]) == fromList [("b",5), ("c",3)]+mapKeysMonotonic :: (CritBitKey k)+                 => (a -> k) -> CritBit a v -> CritBit k v+mapKeysMonotonic f m = foldlWithKey (insertRight f) empty m+{-# INLINABLE mapKeysMonotonic #-}++insertRight :: CritBitKey k+            => (a -> k) -> CritBit k v -> a -> v -> CritBit k v+insertRight f (CritBit root) ok v+  | Empty <- root = CritBit $ Leaf k v+  | otherwise     = CritBit $ go root+  where+    k = f ok+    go i@(Internal _ right _ _)+      | diff `above` i = append i+      | otherwise      = setRight' i $ go right+    go i = append i++    append i = internal diff i (Leaf k v)++    diff = followPrefixes k $ maxKey root+{-# INLINE insertRight #-}++-- | /O(n)/. Convert the map to a list of key/value pairs where the keys are in+-- ascending order.+--+-- > toAscList (fromList [(5,"a"), (3,"b")]) == [(3,"b"), (5,"a")]+toAscList :: CritBit k v -> [(k,v)]+toAscList m = foldrWithKey f [] m+  where f k v vs = (k,v) : vs++-- | /O(n)/. Convert the map to a list of key/value pairs where the keys are in+-- descending order.+--+-- > toDescList (fromList [(5,"a"), (3,"b")]) == [(5,"a"), (3,"b")]+toDescList :: CritBit k v -> [(k,v)]+toDescList m = foldlWithKey f [] m+  where f vs k v = (k,v):vs++-- | /O(n)/. Build a tree from an ascending list in linear time.+-- /The precondition (input list is ascending) is not checked./+--+-- > fromAscList [(3,"b"), (5,"a")]          == fromList [(3, "b"), (5, "a")]+-- > fromAscList [(3,"b"), (5,"a"), (5,"b")] == fromList [(3, "b"), (5, "b")]+-- > valid (fromAscList [(3,"b"), (5,"a"), (5,"b")]) == True+-- > valid (fromAscList [(5,"a"), (3,"b"), (5,"b")]) == False+fromAscList :: (CritBitKey k) => [(k, a)] -> CritBit k a+fromAscList = fromAscListWithKey (\_ x _ -> x)+{-# INLINABLE fromAscList #-}++-- | /O(n)/. Build a tree from an ascending list in linear time+-- with a combining function for equal keys.+-- /The precondition (input list is ascending) is not checked./+--+-- > fromAscListWith (++) [(3,"b"), (5,"a"), (5,"b")] == fromList [(3, "b"), (5, "ba")]+-- > valid (fromAscListWith (++) [(3,"b"), (5,"a"), (5,"b")]) == True+-- > valid (fromAscListWith (++) [(5,"a"), (3,"b"), (5,"b")]) == False+fromAscListWith :: (CritBitKey k) => (a -> a -> a) -> [(k,a)] -> CritBit k a+fromAscListWith f = fromAscListWithKey (const f)+{-# INLINABLE fromAscListWith #-}++-- | /O(n)/. Build a map from an ascending list in linear time with a+-- combining function for equal keys.+-- /The precondition (input list is ascending) is not checked./+--+-- > let f k a1 a2 = (show k) ++ ":" ++ a1 ++ a2+-- > fromAscListWithKey f [(3,"b"), (5,"a"), (5,"b"), (5,"b")] == fromList [(3, "b"), (5, "5:b5:ba")]+-- > valid (fromAscListWithKey f [(3,"b"), (5,"a"), (5,"b"), (5,"b")]) == True+-- > valid (fromAscListWithKey f [(5,"a"), (3,"b"), (5,"b"), (5,"b")]) == False+fromAscListWithKey :: (CritBitKey k) =>+                      (k -> a -> a -> a) -> [(k,a)] -> CritBit k a+fromAscListWithKey _ [] = empty+fromAscListWithKey _ [(k, v)] = singleton k v+fromAscListWithKey f kvs = build 0 1 upper fromContext kvs RCNil+  -- This implementation is based on the idea of binary search in+  -- a suffix array using LCP array.+  --+  -- Input list is converted to array and processed top-down.+  -- When building tree for interval we finds the length of+  -- the common prefix of all keys in this interval. We never+  -- compare known common prefixes, thus reducing number of+  -- comparisons. Then we merge trees, building recursively on+  -- halves of this interval.+  --+  -- This algorithm runs in /O(n+K)/ time, where /K/ is the total+  -- length of all keys minus . When many keys have equal prefixes,+  -- the second summand may be much smaller.+  --+  -- See also:+  --+  -- Manber, Udi; Myers, Gene (1990). "Suffix arrays: a new method for+  -- on-line string searches". In Proceedings of the first annual+  -- ACM-SIAM symposium on Discrete algorithms 90 (319): 327.+  where+    upper = length kvs - 1+    array = fst . (A.listArray (0, upper) kvs A.!)++    fromContext = add (Diff 0 0 0)+        (const $ \(RCCons node _ _ _) -> CritBit node)++    build z left right cont xs cx+      | left == right = add diffI cont xs cx+      | otherwise     = (build diffO left      mid    $+                         build diffO (mid + 1) right  cont) xs cx+      where+        mid = (left + right - 1) `div` 2+        diffO = followPrefixesByteFrom z (fst (head xs)) (array right)+        diffI = followPrefixesFrom     z (fst (head xs)) (array right)+    {-# INLINE build #-}++    add (Diff byte bits _) cont (x:xs) cx+        | bits == 0x1ff = let (k, v1) = x; (_, v2) = head xs+                          in cont ((k, f k v2 v1) : tail xs) cx+        | otherwise     = cont xs $ pop (uncurry Leaf x) cx+      where+        pop right cs@(RCCons left cbyte cbits cs')+          | cbyte > byte || cbyte == byte && cbits > bits+                = pop (Internal left right cbyte cbits) cs'+          | otherwise = RCCons right byte bits cs+        pop right cs  = RCCons right byte bits cs+    add _ _ _ _ = error "CritBit.fromAscListWithKey.add: Unpossible"+    {-# INLINE add #-}+{-# INLINABLE fromAscListWithKey #-}++-- | /O(n)/. Build a tree from an ascending list of distinct elements+-- in linear time.+-- /The precondition is not checked./+--+-- > fromDistinctAscList [(3,"b"), (5,"a")] == fromList [(3, "b"), (5, "a")]+-- > valid (fromDistinctAscList [(3,"b"), (5,"a")])          == True+-- > valid (fromDistinctAscList [(3,"b"), (5,"a"), (5,"b")]) == False+fromDistinctAscList :: (CritBitKey k) => [(k,a)] -> CritBit k a+fromDistinctAscList = fromAscListWithKey undefined+{-# INLINABLE fromDistinctAscList #-}++-- | One-hole CritBit context focused on the maximum leaf+data RightContext k v+    = RCNil+    | RCCons !(Node k v) !Int !BitMask !(RightContext k v)++-- | /O(n)/. Filter all values that satisfy the predicate.+--+-- > filter (> "a") (fromList [("5","a"), ("3","b")]) == fromList [("3","b")]+-- > filter (> "x") (fromList [("5","a"), ("3","b")]) == empty+-- > filter (< "a") (fromList [("5","a"), ("3","b")]) == empty+filter :: (v -> Bool) -> CritBit k v -> CritBit k v+filter p m = filterWithKey (const p) m++-- | /O(n)/. Filter all keys\/values that satisfy the predicate.+--+-- > filterWithKey (\k _ -> k > "4") (fromList [("5","a"), ("3","b")]) == fromList[("5","a")]+filterWithKey :: (k -> v -> Bool) -> CritBit k v -> CritBit k v+filterWithKey p (CritBit root) = CritBit $ go root+  where+    go i@(Internal left right _ _) = setBoth' i (go left) (go right)+    go leaf@(Leaf k v) | p k v = leaf+    go _ = Empty+{-# INLINABLE filterWithKey #-}++-- | /O(n)/. Map values and collect the 'Just' results.+--+-- > let f x = if x == 5 then Just 10 else Nothing+-- > mapMaybe f (fromList [("a",5), ("b",3)]) == singleton "a" 10+mapMaybe :: (a -> Maybe b) -> CritBit k a -> CritBit k b+mapMaybe = mapMaybeWithKey . const++-- | /O(n)/. Map keys\/values and collect the 'Just' results.+--+-- > let f k v = if k == "a" then Just ("k,v: " ++ show k ++ "," ++ show v) else Nothing+-- > mapMaybeWithKey f (fromList [("a",5), ("b",3)]) == singleton "a" "k,v: \"a\",3"+mapMaybeWithKey :: (k -> v -> Maybe v') -> CritBit k v -> CritBit k v'+mapMaybeWithKey f (CritBit root) = CritBit $ go root+  where+    go i@(Internal left right _ _) = setBoth' i (go left) (go right)+    go (Leaf k v) = maybe Empty (Leaf k) $ f k v+    go Empty      = Empty+{-# INLINABLE mapMaybeWithKey #-}++-- | /O(n)/. Map values and separate the 'Left' and 'Right' results.+--+-- > let f a = if a < 5 then Left a else Right a+-- > mapEither f (fromList [("a",5), ("b",3), ("x",1), ("z",7)])+-- >     == (fromList [("b",3), ("x",1)], fromList [("a",5), ("z",7)])+-- >+-- > mapEither (\ a -> Right a) (fromList [("a",5), ("b",3), ("x",1), ("z",7)])+-- >     == (empty, fromList [("a",5), ("b",3), ("x",1), ("z",7)])+mapEither :: (a -> Either b c) -> CritBit k a -> (CritBit k b, CritBit k c)+mapEither = mapEitherWithKey . const++-- | /O(n)/. Map keys\/values and separate the 'Left' and 'Right' results.+--+-- > let f k a = if k < "c" then Left (k ++ k) else Right (a * 2)+-- > mapEitherWithKey f (fromList [("a",5), ("b",3), ("x",1), ("z",7)])+-- >     == (fromList [("a","aa"), ("b","bb")], fromList [("x",2), ("z",14)])+-- >+-- > mapEitherWithKey (\_ a -> Right a) (fromList [("a",5), ("b",3), ("x",1), ("z",7)])+-- >     == (empty, fromList [("x",1), ("b",3), ("a",5), ("z",7)])+mapEitherWithKey :: (k -> v -> Either v1 v2)+                 -> CritBit k v -> (CritBit k v1, CritBit k v2)+mapEitherWithKey f (CritBit root) = (CritBit *** CritBit) $ go root+  where+    go i@(Internal l r _ _) = (setBoth' i ll rl, setBoth' i lr rr)+      where+        (ll, lr) = go l+        (rl, rr) = go r+    go (Leaf k v) = case f k v of+                      Left  v' -> (Leaf k v', Empty)+                      Right v' -> (Empty, Leaf k v')+    go Empty = (Empty, Empty)+{-# INLINABLE mapEitherWithKey #-}++-- | /O(k)/. The expression (@'split' k map@) is a pair+-- @(map1,map2)@ where the keys in @map1@ are smaller than @k@ and the+-- keys in @map2@ larger than @k@.  Any key equal to @k@ is found in+-- neither @map1@ nor @map2@.+--+-- > split "a" (fromList [("b",1), ("d",2)]) == (empty, fromList [("b",1), ("d",2)])+-- > split "b" (fromList [("b",1), ("d",2)]) == (empty, singleton "d" 2)+-- > split "c" (fromList [("b",1), ("d",2)]) == (singleton "b" 1, singleton "d" 2)+-- > split "d" (fromList [("b",1), ("d",2)]) == (singleton "b" 1, empty)+-- > split "e" (fromList [("b",1), ("d",2)]) == (fromList [("b",1), ("d",2)], empty)+split :: (CritBitKey k) => k -> CritBit k v -> (CritBit k v, CritBit k v)+-- Note that this is nontrivially faster than an implementation+-- in terms of 'splitLookup'.+split k m = CritBit *** CritBit $+            findPosition (const id) finish goLeft goRight k m+  where+    finish _ Empty = (Empty, Empty)+    finish diff node = case diffOrd diff of+      LT -> (node, Empty)+      GT -> (Empty, node)+      EQ -> (Empty, Empty)++    goLeft i (lt, Empty) = (lt, iright i)+    goLeft i (lt, gt   ) = (lt, setLeft i gt)++    goRight i (Empty, gt) = (ileft i, gt)+    goRight i (lt   , gt) = (setRight i lt, gt)+{-# INLINABLE split #-}++-- | /O(k)/. The expression (@'splitLookup' k map@) splits a map just+-- like 'split' but also returns @'lookup' k map@.+--+-- > splitLookup "a" (fromList [("b",1), ("d",2)]) == (empty, Nothing, fromList [("b",1), ("d",2)])+-- > splitLookup "b" (fromList [("b",1), ("d",2)]) == (empty, Just 1, singleton "d" 2)+-- > splitLookup "c" (fromList [("b",1), ("d",2)]) == (singleton "b" 1, Nothing, singleton "d" 2)+-- > splitLookup "d" (fromList [("b",1), ("d",2)]) == (singleton "b" 1, Just 2, empty)+-- > splitLookup "e" (fromList [("b",1), ("d",2)]) == (fromList [("b",1), ("d",2)], Nothing, empty)+splitLookup :: (CritBitKey k) => k -> CritBit k v+               -> (CritBit k v, Maybe v, CritBit k v)+splitLookup k m = (\(lt, eq, gt) -> (CritBit lt, eq, CritBit gt)) $+                  findPosition (const id) finish goLeft goRight k m+  where+    finish _ Empty = (Empty, Nothing, Empty)+    finish diff node = case diffOrd diff of+      LT -> (node,  Nothing  , Empty)+      GT -> (Empty, Nothing  , node )+      EQ -> (Empty, leaf node, Empty)++    leaf (Leaf _ v) = Just v+    leaf _ = error "Data.CritBit.Tree.splitLookup.leaf: Unpossible."++    goLeft i (lt, eq, Empty) = (lt, eq, iright i)+    goLeft i (lt, eq, gt   ) = (lt, eq, setLeft i gt)++    goRight i (Empty, eq, gt) = (ileft i      , eq, gt)+    goRight i (lt   , eq, gt) = (setRight i lt, eq, gt)+{-# INLINABLE splitLookup #-}++-- | /O(n+m)/. This function is defined as+--   (@'isSubmapOf' = 'isSubmapOfBy' (==)@).+isSubmapOf :: (CritBitKey k, Eq v) => CritBit k v -> CritBit k v -> Bool+isSubmapOf = isSubmapOfBy (==)+{-# INLINABLE isSubmapOf #-}++-- | /O(n+m)/. The expression (@'isSubmapOfBy' f t1 t2@) returns 'True' if+--   all keys in @t1@ are in map @t2@, and when @f@ returns 'True' when+--   applied to their respective values. For example, the following+--   expressions are all 'True':+--+-- > isSubmapOfBy (==) (fromList [("a",1)]) (fromList [("a",1),("b",2)])+-- > isSubmapOfBy (<=) (fromList [("a",1)]) (fromList [("a",1),("b",2)])+-- > isSubmapOfBy (==) (fromList [("a",1),("b",2)]) (fromList [("a",1),("b",2)])+--+-- But the following are all 'False':+--+-- > isSubmapOfBy (==) (fromList [("a",2)]) (fromList [("a",1),("b",2)])+-- > isSubmapOfBy (<)  (fromList [("a",1)]) (fromList [("a",1),("b",2)])+-- > isSubmapOfBy (==) (fromList [("a",1),("b",2)]) (fromList [("a",1)])+isSubmapOfBy :: (CritBitKey k) => (a -> b -> Bool) -> CritBit k a+             -> CritBit k b -> Bool+isSubmapOfBy f a b = submapTypeBy f a b /= No+{-# INLINABLE isSubmapOfBy #-}++-- | /O(n+m)/. Is this a proper submap? (ie. a submap but not equal).+--   Defined as (@'isProperSubmapOf' = 'isProperSubmapOfBy' (==)@).+isProperSubmapOf :: (CritBitKey k, Eq v) => CritBit k v -> CritBit k v -> Bool+isProperSubmapOf = isProperSubmapOfBy (==)+{-# INLINABLE isProperSubmapOf #-}++-- | /O(n+m)/. Is this a proper submap? (ie. a submap but not equal).+--   The expression (@'isProperSubmapOfBy' f m1 m2@) returns 'True' when+--   @m1@ and @m2@ are not equal,+--   all keys in @m1@ are in @m2@, and when @f@ returns 'True' when+--   applied to their respective values. For example, the following+--   expressions are all 'True':+--+-- > isProperSubmapOfBy (==) (fromList [("a",1)]) (fromList [("a",1),("b",2)])+-- > isProperSubmapOfBy (<=) (fromList [("a",0)]) (fromList [("a",1),("b",2)])+--+-- But the following are all 'False':+--+-- > isProperSubmapOfBy (==) (fromList [("a",1),("b",2)]) (fromList [("a",1),("b",2)])+-- > isProperSubmapOfBy (==) (fromList ["a",1),("b",2)])  (fromList [("a",1)])+-- > isProperSubmapOfBy (<)  (fromList [("a",1)])         (fromList [("a",1),("b",2)])+isProperSubmapOfBy :: (CritBitKey k) =>+                      (a -> b -> Bool) -> CritBit k a -> CritBit k b -> Bool+isProperSubmapOfBy f a b = submapTypeBy f a b == Yes+{-# INLINABLE isProperSubmapOfBy #-}++data SubmapType = No | Yes | Equal deriving (Eq, Ord)+submapTypeBy :: (CritBitKey k) =>+                (a -> b -> Bool) -> CritBit k a -> CritBit k b -> SubmapType+submapTypeBy f (CritBit root1) (CritBit root2) = top root1 root2+  where+    -- Assumes that empty nodes exist only on the top level+    top Empty Empty = Equal+    top Empty _ = Yes+    top _ Empty = No+    top a b = go a (minKey a) b (minKey b)+    {-# INLINE top #-}++    -- Each node is followed by the minimum key in that node.+    -- This trick assures that overall time spend by minKey in O(n+m)+    go (Leaf ak av) _ (Leaf bk bv) _+        | ak == bk  = if f av bv then Equal else No+        | otherwise = No+    go a@(Leaf{}) ak b@(Internal{}) bk =+      leafBranch a b bk (splitB a ak b bk) No+    go (Internal{}) _ (Leaf{}) _ = No+    go a@(Internal al ar abyte abits) ak b@(Internal bl br bbyte bbits) bk =+      case compare (abyte, abits) (bbyte, bbits) of+        LT -> No+        GT -> splitB a ak b bk+        EQ -> min (go al ak bl bk) (go ar (minKey ar) br (minKey br))+    -- Assumes that empty nodes exist only on the top level+    go _ _ _ _ = error "Data.CritBit.Tree.isSubmapOfBy.go: Empty"++    splitB a ak b@(Internal bl br _ _) bk = if t == No then No else Yes+      where+        t = if ak `onLeft` b then go a ak bl bk+                             else go a ak br (minKey br)++    splitB _ _ _ _ =+        error "Data.CritBit.Tree.isSubmapOfBy.splitB: unpossible"+    {-# INLINE splitB #-}+{-# INLINABLE submapTypeBy #-}++-- | /O(minimum K)/. The minimal key of the map. Calls 'error' if the map+-- is empty.+--+-- > findMin (fromList [("b",3), ("a",5)]) == ("a",5)+-- > findMin empty                       Error: empty map has no minimal element+findMin :: CritBit k v -> (k,v)+findMin (CritBit root) = leftmost emptyMap (,) root+  where+    emptyMap = error "CritBit.findMin: empty map has no minimal element"+{-# INLINABLE findMin #-}++-- | /O(k)/. The maximal key of the map. Calls 'error' if the map+-- is empty.+--+-- > findMax empty                       Error: empty map has no minimal element+findMax :: CritBit k v -> (k,v)+findMax (CritBit root) = rightmost emptyMap (,) root+  where+    emptyMap = error "CritBit.findMax: empty map has no maximal element"+{-# INLINABLE findMax #-}++-- | /O(k')/. Delete the minimal key. Returns an empty map if the+-- map is empty.+--+-- > deleteMin (fromList [("a",5), ("b",3), ("c",7)]) == fromList [("b",3), ("c",7)]+-- > deleteMin empty == empty+deleteMin :: CritBit k v -> CritBit k v+deleteMin m = updateMinWithKey (\_ _ -> Nothing) m+{-# INLINABLE deleteMin #-}++-- | /O(k)/. Delete the maximal key. Returns an empty map if the+-- map is empty.+--+-- > deleteMin (fromList [("a",5), ("b",3), ("c",7)]) == fromList [("a",5), ("b","3")]+-- > deleteMin empty == empty+deleteMax :: CritBit k v -> CritBit k v+deleteMax m = updateMaxWithKey (\_ _ -> Nothing) m+{-# INLINABLE deleteMax #-}++-- | /O(k')/. Delete and find the minimal element.+--+-- > deleteFindMin (fromList [("a",5), ("b",3), ("c",10)]) == (("a",5), fromList[("b",3), ("c",10)])+-- > deleteFindMin     Error: can not return the minimal element of an empty map+deleteFindMin :: CritBit k v -> ((k, v), CritBit k v)+deleteFindMin = fromMaybe (error msg) . minViewWithKey+  where msg = "CritBit.deleteFindMin: cannot return the minimal \+              \element of an empty map"+{-# INLINABLE deleteFindMin #-}++-- | /O(k)/. Delete and find the maximal element.+--+-- > deleteFindMax (fromList [("a",5), ("b",3), ("c",10)]) == (("c",10), fromList[("a",5), ("b",3)])+-- > deleteFindMax     Error: can not return the maximal element of an empty map+deleteFindMax :: CritBit k v -> ((k, v), CritBit k v)+deleteFindMax = fromMaybe (error msg) . maxViewWithKey+  where msg = "CritBit.deleteFindMax: cannot return the minimal \+              \element of an empty map"+{-# INLINABLE deleteFindMax #-}++-- | /O(k')/. Retrieves the value associated with minimal key of the+-- map, and the map stripped of that element, or 'Nothing' if passed an+-- empty map.+--+-- > minView (fromList [("a",5), ("b",3)]) == Just (5, fromList [("b",3)])+-- > minView empty == Nothing+minView :: CritBit k v -> Maybe (v, CritBit k v)+minView = fmap (first snd) . minViewWithKey+{-# INLINABLE minView #-}++-- | /O(k)/. Retrieves the value associated with maximal key of the+-- map, and the map stripped of that element, or 'Nothing' if passed an+-- empty map.+--+-- > maxView (fromList [("a",5), ("b",3)]) == Just (3, fromList [("a",5)])+-- > maxView empty == Nothing+maxView :: CritBit k v -> Maybe (v, CritBit k v)+maxView = fmap (first snd) . maxViewWithKey+{-# INLINABLE maxView #-}++-- | /O(k')/. Retrieves the minimal (key,value) pair of the map, and+-- the map stripped of that element, or 'Nothing' if passed an empty map.+--+-- > minViewWithKey (fromList [("a",5), ("b",3)]) == Just (("a",5), fromList [("b",3)])+-- > minViewWithKey empty == Nothing+minViewWithKey :: CritBit k v -> Maybe ((k, v), CritBit k v)+minViewWithKey (CritBit root) = go root CritBit+  where+    go (Internal (Leaf lk lv) right _ _) cont = Just ((lk,lv), cont right)+    go i@(Internal left _ _ _) cont = go left $ (cont $!) . setLeft i+    go (Leaf lk lv) _ = Just ((lk,lv),empty)+    go _ _ = Nothing+{-# INLINABLE minViewWithKey #-}++-- | /O(k)/. Retrieves the maximal (key,value) pair of the map, and+-- the map stripped of that element, or 'Nothing' if passed an empty map.+--+-- > maxViewWithKey (fromList [("a",5), ("b",3)]) == Just (("b",3), fromList [("a",5)])+-- > maxViewWithKey empty == Nothing+maxViewWithKey :: CritBit k v -> Maybe ((k,v), CritBit k v)+maxViewWithKey (CritBit root) = go root CritBit+  where+    go (Internal left (Leaf lk lv) _ _) cont = Just ((lk,lv), cont left)+    go i@(Internal _ right _ _) cont = go right $ (cont $!) . setRight i+    go (Leaf lk lv) _ = Just ((lk,lv),empty)+    go _ _ = Nothing+{-# INLINABLE maxViewWithKey #-}++first :: (a -> b) -> (a,c) -> (b,c)+first f (x,y) = (f x, y)+{-# INLINE first #-}++-- | /O(k')/. Update the value at the minimal key.+--+-- > updateMin (\ a -> Just (a + 7)) (fromList [("a",5), ("b",3)]) == fromList [("a",12), ("b",3)]+-- > updateMin (\ _ -> Nothing)      (fromList [("a",5), ("b",3)]) == fromList [("b",3)]+updateMin :: (v -> Maybe v) -> CritBit k v -> CritBit k v+updateMin f m = updateMinWithKey (const f) m+{-# INLINABLE updateMin #-}++-- | /O(k)/. Update the value at the maximal key.+--+-- > updateMax (\ a -> Just (a + 7)) (fromList [("a",5), ("b",3)]) == fromList [("a",5), ("b",10)]+-- > updateMax (\ _ -> Nothing)      (fromList [("a",5), ("b",3)]) == fromList [("a",5)]+updateMax :: (v -> Maybe v) -> CritBit k v -> CritBit k v+updateMax f m = updateMaxWithKey (const f) m+{-# INLINABLE updateMax #-}++-- | /O(k')/. Update the value at the minimal key.+--+-- > updateMinWithKey (\ k a -> Just (length k + a)) (fromList [("a",5), ("b",3)]) == fromList [("a",6), ("b",3)]+-- > updateMinWithKey (\ _ _ -> Nothing)             (fromList [("a",5), ("b",3)]) == fromList [("b",3)]+updateMinWithKey :: (k -> v -> Maybe v) -> CritBit k v -> CritBit k v+updateMinWithKey maybeUpdate (CritBit root) = CritBit $ go root+  where+    go i@(Internal left _ _ _) = setLeft' i (go left)+    go (Leaf k v) = maybe Empty (Leaf k) $ maybeUpdate k v+    go _ = Empty+{-# INLINABLE updateMinWithKey #-}++-- | /O(k)/. Update the value at the maximal key.+--+-- > updateMaxWithKey (\ k a -> Just (length k + a)) (fromList [("a",5), ("b",3)]) == fromList [("a",5), ("b",4)]+-- > updateMaxWithKey (\ _ _ -> Nothing)             (fromList [("a",5), ("b",3)]) == fromList [("a",5)]+updateMaxWithKey :: (k -> v -> Maybe v) -> CritBit k v -> CritBit k v+updateMaxWithKey maybeUpdate (CritBit root) = CritBit $ go root+  where+    go i@(Internal _ right _ _) = setRight' i (go right)+    go (Leaf k v) = maybe Empty (Leaf k) $ maybeUpdate k v+    go _ = Empty+{-# INLINABLE updateMaxWithKey #-}++-- | /O(k)/. Insert a new key and value in the map.  If the key is+-- already present in the map, the associated value is replaced with+-- the supplied value. 'insert' is equivalent to @'insertWith'+-- 'const'@.+--+-- > insert "b" 7 (fromList [("a",5), ("b",3)]) == fromList [("a",5), ("b",7)]+-- > insert "x" 7 (fromList [("a",5), ("b",3)]) == fromList [("a",5), ("b",3), ("x",7)]+-- > insert "x" 5 empty                         == singleton "x" 5+insert :: (CritBitKey k) => k -> v -> CritBit k v -> CritBit k v+insert = insertLookupGen (flip const) (\_ v _ -> v)+{-# INLINABLE insert #-}++-- | /O(k)/. Insert with a function, combining new value and old value.+-- @'insertWith' f key value cb@+-- will insert the pair (key, value) into @cb@ if key does+-- not exist in the map. If the key does exist, the function will+-- insert the pair @(key, f new_value old_value)@.+--+-- > insertWith (+) "a" 1 (fromList [("a",5), ("b",3)]) == fromList [("a",6), ("b",3)]+-- > insertWith (+) "c" 7 (fromList [("a",5), ("b",3)]) == fromList [("a",5), ("b",3), ("c",7)]+-- > insertWith (+) "x" 5 empty                         == singleton "x" 5+--+insertWith :: CritBitKey k =>+              (v -> v -> v) -> k -> v -> CritBit k v -> CritBit k v+insertWith f = insertLookupGen (flip const) (const f)+{-# INLINABLE insertWith #-}++-- | /O(n)/. Apply a function to all values.+--+-- >  let f key x = show key ++ ":" ++ show x+-- >  mapWithKey f (fromList [("a",5), ("b",3)]) == fromList [("a","a:5"), ("b","b:3")]+mapWithKey :: (k -> v -> w) -> CritBit k v -> CritBit k w+mapWithKey f (CritBit root) = CritBit (go root)+  where+    go i@(Internal l r _ _) = setBoth i (go l) (go r)+    go (Leaf k v)        = Leaf k (f k v)+    go  Empty            = Empty+{-# INLINABLE mapWithKey #-}++-- | /O(n)/. The function 'mapAccumRWithKey' threads an accumulating+-- argument through the map in descending order of keys.+mapAccumRWithKey :: (CritBitKey k) => (a -> k -> v -> (a, w)) -> a+                 -> CritBit k v -> (a, CritBit k w)+mapAccumRWithKey f start (CritBit root) = second CritBit (go start root)+  where+    go a i@(Internal{..}) = let (a0, r')  = go a iright+                                (a1, l')  = go a0 ileft+                            in (a1, setBoth i l' r')+    go a (Leaf k v)       = let (a0, w) = f a k v in (a0, Leaf k w)+    go a Empty            = (a, Empty)+{-# INLINABLE mapAccumRWithKey #-}++-- | /O(n)/.+-- @'traverseWithKey' f s == 'fromList' <$> 'traverse' (\(k, v) -> (,) k <$> f k v) ('toList' m)@+--+-- That is, behaves exactly like a regular 'traverse' except+-- that the traversing function also has access to the key associated+-- with a value.+--+-- > let f key value = show key ++ ":" ++ show value+-- > traverseWithKey (\k v -> if odd v then Just (f k v) else Nothing) (fromList [("a",3), ("b",5)]) == Just (fromList [("a","a:3"), ("b","b:5")])+-- > traverseWithKey (\k v -> if odd v then Just (f k v) else Nothing) (fromList [("c", 2)])           == Nothing+traverseWithKey :: (CritBitKey k, Applicative t)+                => (k -> v -> t w)+                -> CritBit k v+                -> t (CritBit k w)+traverseWithKey f (CritBit root) = fmap CritBit (go root)+  where+    go i@(Internal l r _ _) = setBoth i <$> go l <*> go r+    go (Leaf k v)           = Leaf k <$> f k v+    go Empty                = pure Empty+{-# INLINABLE traverseWithKey #-}++-- | /O(n)/. The function 'mapAccum' threads an accumulating+-- argument through the map in ascending order of keys.+--+-- > let f a b = (a ++ show b, show b ++ "X")+-- > mapAccum f "Everything: " (fromList [("a",5), ("b",3)]) == ("Everything: 53", fromList [("a","5X"), ("b","3X")])+mapAccum :: (CritBitKey k)+         => (a -> v -> (a, w))+         -> a+         -> CritBit k v+         -> (a, CritBit k w)+mapAccum f = mapAccumWithKey (\a _ v -> f a v)+{-# INLINE mapAccum #-}++-- | /O(n)/. The function 'mapAccumWithKey' threads an accumulating+-- argument through the map in ascending order of keys.+--+-- > let f a k b = (a ++ " " ++ show k ++ "-" ++ show b, show b ++ "X")+-- > mapAccumWithKey f "Everything: " (fromList [("a",5), ("b",3)]) == ("Everything: a-5 b-3", fromList [("a","5X"), ("b","3X")])+mapAccumWithKey :: (CritBitKey k)+                => (a -> k -> v -> (a, w))+                -> a+                -> CritBit k v+                -> (a, CritBit k w)+mapAccumWithKey f start (CritBit root) = second CritBit (go start root)+  where+    go a i@(Internal{..}) = let (a0, l')  = go a ileft+                                (a1, r')  = go a0 iright+                            in (a1, setBoth i l' r')++    go a (Leaf k v)       = let (a0, w) = f a k v in (a0, Leaf k w)+    go a Empty            = (a, Empty)+{-# INLINABLE mapAccumWithKey #-}++-- | /O(k)/. The expression (@'alter' f k map@) alters the value @x@+-- at @k@, or absence thereof.  'alter' can be used to insert, delete,+-- or update a value in a 'CritBit'.  In short : @'lookup' k ('alter'+-- f k m) = f ('lookup' k m)@.+--+-- > let f _ = Nothing+-- > alter f "c" (fromList [("a",5), ("b",3)]) == fromList [("a",5), ("b",3)]+-- > alter f "a" (fromList [("a",5), ("b",3)]) == fromList [("b",3)]+-- >+-- > let f _ = Just 1+-- > alter f "c" (fromList [("a",5), ("b",3)]) == fromList [("a",5), ("b",3), ("c",1)]+-- > alter f "a" (fromList [(5,"a"), (3,"b")]) == fromList [("a",1), ("b",3)]+alter :: (CritBitKey k)+      => (Maybe v -> Maybe v) -> k -> CritBit k v -> CritBit k v+alter f !k m = findPosition (const CritBit) finish setLeft' setRight' k m+  where+    finish _ Empty = maybe Empty (Leaf k) $ f Nothing+    finish diff (Leaf _ v) | diffOrd diff == EQ =+      maybe Empty (Leaf k) $ f (Just v)+    finish diff node = maybe node (internal diff node . Leaf k) $ f Nothing+{-# INLINABLE alter #-}++-- | /O(n)/. Partition the map according to a predicate. The first+-- map contains all elements that satisfy the predicate, the second all+-- elements that fail the predicate. See also 'split'.+--+-- > partitionWithKey (\ k _ -> k < "b") (fromList [("a",5), ("b",3)]) == (fromList [("a",5)], fromList [("b",3)])+-- > partitionWithKey (\ k _ -> k < "c") (fromList [(5,"a"), (3,"b")]) == (fromList [("a",5), ("b",3)], empty)+-- > partitionWithKey (\ k _ -> k > "c") (fromList [(5,"a"), (3,"b")]) == (empty, fromList [("a",5), ("b",3)])+partitionWithKey :: (CritBitKey k)+                 => (k -> v -> Bool)+                 -> CritBit k v+                 -> (CritBit k v, CritBit k v)+partitionWithKey f (CritBit root) = CritBit *** CritBit $ go root+  where+    go l@(Leaf k v)+      | f k v     = (l,Empty)+      | otherwise = (Empty,l)+    go i@(Internal{..}) = (setBoth' i l1 r1, setBoth' i l2 r2)+      where+        (!l1,!l2) = go ileft+        (!r1,!r2) = go iright+    go _ = (Empty,Empty)+{-# INLINABLE partitionWithKey #-}++-- | /O(n)/. Partition the map according to a predicate. The first+-- map contains all elements that satisfy the predicate, the second all+-- elements that fail the predicate. See also 'split'.+--+-- > partition (> 4) (fromList [("a",5), ("b",3)]) == (fromList [("a",5)], fromList [("b",3)])+-- > partition (< 6) (fromList [("a",5), ("b",3)]) == (fromList [("a",5), ("b",3)], empty)+-- > partition (> 6) (fromList [("a",5), ("b",3)]) == (empty, fromList [("a",5), ("b",3)])+partition :: (CritBitKey k)+          => (v -> Bool)+          -> CritBit k v+          -> (CritBit k v, CritBit k v)+partition f m = partitionWithKey (const f) m+{-# INLINABLE partition #-}
Data/CritBit/Types/Internal.hs view
@@ -1,29 +1,44 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE CPP, FlexibleInstances, GeneralizedNewtypeDeriving #-} -- | -- Module      :  Data.CritBit.Types.Internal--- Copyright   :  (c) Bryan O'Sullivan 2013+-- Copyright   :  (c) Bryan O'Sullivan and others 2013-2014 -- License     :  BSD-style -- Maintainer  :  bos@serpentine.com -- Stability   :  experimental -- Portability :  GHC++#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__)+#include "MachDeps.h"+#endif+ module Data.CritBit.Types.Internal     (       CritBitKey(..)     , CritBit(..)+    , Set(..)     , BitMask     , Node(..)+    , foldlWithKey+    , foldlWithKey'+    , foldrWithKey+    , foldrWithKey'     , toList     ) where  import Control.DeepSeq (NFData(..))-import Data.Bits ((.|.), (.&.), shiftL, shiftR)+import Data.Bits (Bits, (.|.), (.&.), shiftL, shiftR) import Data.ByteString (ByteString)+import Data.Foldable hiding (toList)+import Data.Monoid (Monoid(..)) import Data.Text () import Data.Text.Internal (Text(..))-import Data.Word (Word16)+import Data.Word (Word, Word8, Word16, Word32, Word64) import qualified Data.ByteString as B import qualified Data.ByteString.Unsafe as B import qualified Data.Text.Array as T+import qualified Data.Vector.Generic as G+import qualified Data.Vector.Unboxed as U+import qualified Data.Vector as V  type BitMask = Word16 @@ -35,7 +50,9 @@     , iotherBits    :: !BitMask     -- ^ The bitmask representing the critical bit within the     -- differing byte. If the critical bit is e.g. 0x8, the bitmask-    -- will have every bit below 0x8 set, hence 0x7.+    -- will have every bit other than 0x8 set, hence 0x1F7+    -- (the ninth bit is set because we're using 9 bits for representing+    -- bytes).     }     | Leaf k v     | Empty@@ -52,10 +69,83 @@     rnf (Leaf k v)         = rnf k `seq` rnf v     rnf Empty              = () +instance Functor (Node k) where+    fmap f i@(Internal l r _ _) = i { ileft = fmap f l, iright = fmap f r }+    fmap f (Leaf k v)           = Leaf k (f v)+    fmap _ Empty                = Empty++instance Foldable (Node k) where+    foldl f z m = foldlWithKey (\a _ v -> f a v) z (CritBit m)+    foldr f z m = foldrWithKey (\_ v a -> f v a) z (CritBit m)++    foldMap f (Internal l r _ _) = mappend (foldMap f l) (foldMap f r)+    foldMap f (Leaf _ v)         = f v+    foldMap _ Empty              = mempty+    {-# INLINABLE foldMap #-}++-- | /O(n)/. Fold the keys and values in the map using the given+-- left-associative function, such that+-- @'foldlWithKey' f z == 'Prelude.foldl' (\\z' (kx, x) -> f z' kx x) z . 'toAscList'@.+--+-- Examples:+--+-- > keys = reverse . foldlWithKey (\ks k x -> k:ks) []+--+-- > let f result k a = result ++ "(" ++ show k ++ ":" ++ a ++ ")"+-- > foldlWithKey f "Map: " (fromList [("a",5), ("b",3)]) == "Map: (b:3)(a:5)"+foldlWithKey :: (a -> k -> v -> a) -> a -> CritBit k v -> a+foldlWithKey f z m = foldlWithKeyWith (\_ b -> b) f z m+{-# INLINABLE foldlWithKey #-}++-- | /O(n)/. A strict version of 'foldlWithKey'. Each application of+-- the function is evaluated before using the result in the next+-- application. This function is strict in the starting value.+foldlWithKey' :: (a -> k -> v -> a) -> a -> CritBit k v -> a+foldlWithKey' f z m = foldlWithKeyWith seq f z m+{-# INLINABLE foldlWithKey' #-}++-- | /O(n)/. Fold the keys and values in the map using the given+-- right-associative function, such that+-- @'foldrWithKey' f z == 'Prelude.foldr' ('uncurry' f) z . 'toAscList'@.+--+-- Examples:+--+-- > keys map = foldrWithKey (\k x ks -> k:ks) [] map+--+-- > let f k a result = result ++ "(" ++ show k ++ ":" ++ a ++ ")"+-- > foldrWithKey f "Map: " (fromList [("a",5), ("b",3)]) == "Map: (a:5)(b:3)"+foldrWithKey :: (k -> v -> a -> a) -> a -> CritBit k v -> a+foldrWithKey f z m = foldrWithKeyWith (\_ b -> b) f z m+{-# INLINABLE foldrWithKey #-}++-- | /O(n)/. A strict version of 'foldrWithKey'. Each application of+-- the function is evaluated before using the result in the next+-- application. This function is strict in the starting value.+foldrWithKey' :: (k -> v -> a -> a) -> a -> CritBit k v -> a+foldrWithKey' f z m = foldrWithKeyWith seq f z m+{-# INLINABLE foldrWithKey' #-}++foldlWithKeyWith :: (a -> a -> a) -> (a -> k -> v -> a) -> a -> CritBit k v -> a+foldlWithKeyWith maybeSeq f z0 (CritBit root) = go z0 root+  where+    go z (Internal left right _ _) = let z' = go z left+                                     in z' `maybeSeq` go z' right+    go z (Leaf k v)                = f z k v+    go z Empty                     = z+{-# INLINE foldlWithKeyWith #-}++foldrWithKeyWith :: (a -> a -> a) -> (k -> v -> a -> a) -> a -> CritBit k v -> a+foldrWithKeyWith maybeSeq f z0 (CritBit root) = go root z0+  where+    go (Internal left right _ _) z = let z' = go right z+                                     in z' `maybeSeq` go left z'+    go (Leaf k v) z                = f k v z+    go Empty z                     = z+{-# INLINE foldrWithKeyWith #-}+ -- | A crit-bit tree.-newtype CritBit k v = CritBit {-      cbRoot :: Node k v-    } deriving (Eq, NFData)+newtype CritBit k v = CritBit (Node k v)+                      deriving (Eq, NFData, Functor, Foldable)  instance (Show k, Show v) => Show (CritBit k v) where     show t = "fromList " ++ show (toList t)@@ -106,6 +196,83 @@         | otherwise       = 0     {-# INLINE getByte #-} +#if WORD_SIZE_IN_BITS == 64+# define WORD_SHIFT 3+#else+# define WORD_SHIFT 2+#endif++instance CritBitKey (U.Vector Word8) where+    byteCount = G.length+    getByte   = getByteV 0++instance CritBitKey (U.Vector Word16) where+    byteCount = (`shiftL` 1) . G.length+    getByte   = getByteV 1++instance CritBitKey (U.Vector Word32) where+    byteCount = (`shiftL` 2) . G.length+    getByte   = getByteV 2++instance CritBitKey (U.Vector Word64) where+    byteCount = (`shiftL` 3) . G.length+    getByte   = getByteV 3++instance CritBitKey (U.Vector Word) where+    byteCount = (`shiftL` WORD_SHIFT) . G.length+    getByte   = getByteV WORD_SHIFT++instance CritBitKey (U.Vector Char) where+    byteCount = (`shiftL` 2) . G.length+    getByte   = getByteV_ fromEnum 2++instance CritBitKey (V.Vector Word8) where+    byteCount = G.length+    getByte   = getByteV 0++instance CritBitKey (V.Vector Word16) where+    byteCount = (`shiftL` 1) . G.length+    getByte   = getByteV 1++instance CritBitKey (V.Vector Word32) where+    byteCount = (`shiftL` 2) . G.length+    getByte   = getByteV 2++instance CritBitKey (V.Vector Word64) where+    byteCount = (`shiftL` 3) . G.length+    getByte   = getByteV 3++instance CritBitKey (V.Vector Word) where+    byteCount = (`shiftL` WORD_SHIFT) . G.length+    getByte   = getByteV WORD_SHIFT++instance CritBitKey (V.Vector Char) where+    byteCount = (`shiftL` 2) . G.length+    getByte   = getByteV_ fromEnum 2++getByteV :: (Bits a, Integral a, G.Vector v a) => Int -> v a -> Int -> Word16+getByteV = getByteV_ id+{-# INLINE getByteV #-}++getByteV_ :: (Bits a, Integral a, G.Vector v b) =>+             (b -> a) -> Int -> v b -> Int -> Word16+getByteV_ convert shiftSize = \v n ->+  if n < G.length v `shiftL` shiftSize+  then reindex shiftSize n $ \wordOffset shiftRight ->+       let word       = convert (G.unsafeIndex v wordOffset)+           byteInWord = (word `shiftR` shiftRight) .&. 255+       in fromIntegral byteInWord .|. 256+  else 0+{-# INLINE getByteV_ #-}++reindex :: Int -> Int -> (Int -> Int -> r) -> r+reindex shiftSize n f = f wordOffset shiftRight+  where+    wordOffset = n `shiftR` shiftSize+    shiftRight = (size - (n .&. size)) `shiftL` 3+      where size = (1 `shiftL` shiftSize) - 1+{-# INLINE reindex #-}+ -- | /O(n)/. Convert the map to a list of key\/value pairs. The list -- returned will be sorted in lexicographically ascending order. --@@ -117,3 +284,8 @@     go (Internal l r _ _) next = go l (go r next)     go (Leaf k v) next         = (k,v) : next     go Empty next              = next+++-- | A set based on crit-bit trees.+newtype Set a = Set (CritBit a ())+    deriving (Eq, NFData)
README.markdown view
@@ -1,9 +1,13 @@ Crit-bit trees for Haskell ==== -This is the first purely functional implementation of crit-bit trees-that I'm aware of.+This is the first purely functional implementation of [crit-bit+trees](http://cr.yp.to/critbit.html) that I'm aware of. +A crit-bit tree is a key/value container that allows efficient lookups+and ordered traversal for data that can be represented as a string of+bits.+ This package exists in part with education in mind:  * The core data structures are simple.@@ -13,17 +17,17 @@ * I have intentionally structured the source to be easy to follow and   extend. -* I've *deliberately* left the package incomplete. Ever thought to-  yourself, "I'd write a bit of Haskell if only I had a project to-  work on"?  Well, here's your chance!  I will set aside time to-  review your code and answer what questions I can.+* Originally, I *deliberately* left the package incomplete.  (It has+  since been substantially fleshed out.)  Ever thought to yourself,+  "I'd write a bit of Haskell if only I had a project to work on"?+  Well, here's your chance!  I will set aside time to review your code+  and answer what questions I can.  Education aside, crit-bit trees offer some interesting features compared to other key/value container types in Haskell. -* For many operations, they are much faster than `Data.Map` from the-  `containers` package. For instance, [`lookup` is about 3x-  faster](http://htmlpreview.github.io/?https://github.com/bos/critbit/blob/master/doc/criterion-sample-lookup.html).+* For some operations, they are much faster than `Data.Map` from the+  `containers` package, while for others, they are slower.  * Compared to `Data.HashMap`, you get about the same lookup   performance, but also some features that a hash-based structure@@ -78,13 +82,6 @@      cabal update -Install the latest version of the `cabal` command, without which you-won't be able to build or run benchmarks. You'll also want a sandbox-environment. I like `cabal-dev`, and there are plenty of others.--    cabal install cabal-install-    cabal install cabal-dev- Both the new `cabal` command and `cabal-dev` will install to `$HOME/.cabal/bin`, so put that directory at the front of your shell's search path before you continue.@@ -95,39 +92,41 @@  Set up a sandbox. -The first time through, you need to download and install a ton of+The first time through, you may need to download and install a ton of dependencies, so hang in there.      cd critbit-    cabal-dev install \-        --enable-tests \-        --enable-benchmarks \-        --only-dependencies \-        -j+    cabal sandbox init+    cabal install \+	--enable-tests \+	--enable-benchmarks \+    	--only-dependencies \+	-j -The `cabal-dev` command is just a sandboxing wrapper around the-`cabal` command.  The `-j` flag above tells `cabal` to use all of your-CPUs, so even the initial build shouldn't take more than a few-minutes.+The `-j` flag above tells `cabal` to use all of your CPUs, so even the+initial build shouldn't take more than a few minutes. -    cabal-dev configure \-        --enable-tests \-        --enable-benchmarks-    cabal-dev build+To actually build: +    cabal build + Running the test suite ---- -Once you've built the code, you can run the entire test suite in a few-seconds.+Once you've built the code, you can run the entire test suite fairly+quickly.  This takes about 30 seconds on my oldish 8-core Mac laptop:      dist/build/tests/tests +RTS -N  (The `+RTS -N` above tells GHC's runtime system to use all available cores.) -If you want to explore, the `tests` program accepts a `--help`+If you're feeling impatient, run a subset of the test suite:++    dist/build/tests/tests -t properties/map/bytestring +RTS -N++And if you want to explore, the `tests` program accepts a `--help` option. Try it out.  @@ -195,14 +194,26 @@ formatting" review, and then you'll be sad too.  -Setting expectations-====+What your commits should look like+---- -I have no idea whether this experiment will attract zero contributors-or a hundred. If the former, that's too bad, and I'll flesh the-library out at my own pace. If the latter, I'll do my best to keep up,-and we'll be more systematic if necessary (it would be a shame to see-several redundant pull requests implementing the same functions, is-what I'm thinking).+Please follow the guidelines below, as they make it easier to review+your pull request and deal with your commits afterwards. -But the main point of this is: have fun!+* One logical idea per commit! If you want to add five functions,+  that's fine, but please spread them across five commits.++* Do not reorganize or refactor unrelated code in a commit whose+  purpose is to add new code.++* When you add a new function, add its tests and benchmarks in the+  same commit.++* <b>Do not add trailing whitespace</b>. Follow the same formatting+  and naming conventions as you already see in the code around you.++* Keep your maximum line length at 80 columns for everything except+  lines of example code in documentation.++(If you can't follow the guidelines, there's a good chance I'll ask+you to fix your commits and resubmit them.)
benchmarks/Benchmarks.hs view
@@ -1,33 +1,40 @@-{-# LANGUAGE CPP, Rank2Types, ScopedTypeVariables #-}+{-# LANGUAGE CPP, Rank2Types, ScopedTypeVariables, OverloadedStrings #-} module Main (main) where  import Control.Applicative ((<$>)) import Control.Arrow (first) import Control.DeepSeq (NFData(..))-import Control.Exception (catch, evaluate) import Control.Monad (when) import Control.Monad.Trans (liftIO) import Criterion.Main (bench, bgroup, defaultMain, nf, whnf) import Criterion.Types (Pure)+import Data.Foldable (foldMap)+import Data.Functor.Identity (Identity(..)) import Data.Hashable (Hashable(..), hashByteArray)-import Data.Maybe (fromMaybe)+import Data.Maybe (fromMaybe, fromJust)+import Data.Monoid (Sum(..),mappend) import Data.Text.Array (aBA) import Data.Text.Encoding (decodeUtf8) import Data.Text.Internal (Text(..))-import System.Environment (lookupEnv)+import System.Environment (getEnv) import System.IO (hPutStrLn, stderr) import System.IO.Error (ioError, isDoesNotExistError) import System.Random.MWC (GenIO, GenST, asGenST, create, uniform, uniformR)+import qualified Control.Exception as Exc import qualified Data.ByteString.Char8 as B import qualified Data.CritBit.Map.Lazy as C+import qualified Data.CritBit.Set as CSet import qualified Data.HashMap.Lazy as H import qualified Data.Map as Map+import qualified Data.Set as Set import qualified Data.Text as T+import qualified Data.Trie as Trie+import qualified Data.Trie.Convenience as TC import qualified Data.Vector as V import qualified Data.Vector.Generic as G-import qualified Data.Vector.Unboxed as U-import qualified Data.Trie as Trie import qualified Data.Vector.Generic.Mutable as M+import qualified Data.Vector.Unboxed as U+import qualified Data.List as L  #if 0 instance Hashable Text where@@ -35,9 +42,19 @@     {-# INLINE hash #-} #endif +#if !MIN_VERSION_bytestring(0,10,0)+instance NFData B.ByteString+#endif+ instance (NFData a) => NFData (Trie.Trie a) where     rnf = rnf . Trie.toList +forcePair :: (a,b) -> ()+forcePair (a,b) = a `seq` b `seq` ()++addvs :: (Num v) => k -> v -> v -> v+addvs _ v1 v2 = v1 + v2+ every k = go 0   where     go i (x:xs)@@ -70,17 +87,31 @@         putStrLn $ show prob ++ " " ++ show (fromIntegral mismatches / nxs)   mapM_ go [0..100] +mapFKey :: (Num v, C.CritBitKey k) => k -> v -> v+mapFKey _ x = x + 1 +mapAccumFKey :: (C.CritBitKey k, Num v) => Int -> k -> v -> (Int, v)+mapAccumFKey a _ v = (a + 1, v + 1)++updateFKey :: Num v => k -> v -> Maybe v+updateFKey _ v = Just $ v + 1++updateFVal :: Num v => v -> Maybe v+updateFVal v = updateFKey undefined v+ main = do-  fileName <- fromMaybe "/usr/share/dict/words" <$> lookupEnv "WORDS"-  ordKeys <- (every 5 . B.words) <$> B.readFile fileName-             `catch` \(err::IOError) -> do-               when (isDoesNotExistError err) $ do+  fileName <- getEnv "WORDS" `Exc.catch` \(_::IOError) ->+              return "/usr/share/dict/words"+  ordKeys <- L.sort <$> (every 5 . B.words) <$> B.readFile fileName+             `Exc.catch` \(err::IOError) -> do+               when (isDoesNotExistError err) $                  hPutStrLn stderr                     ("(point the 'WORDS' environment variable at a file " ++                      "to use it for benchmark data)")                ioError err   let b_ordKVs = zip ordKeys [(0::Int)..]+      prefix = B.concat $ L.map fst b_ordKVs+      b_longKVs = map (first (B.append prefix)) b_ordKVs       b_revKVs = reverse b_ordKVs   b_randKVs <- do     gen <- create@@ -90,10 +121,10 @@   let t_ordKVs  = map (first decodeUtf8) b_ordKVs       t_randKVs = map (first decodeUtf8) b_randKVs       t_revKVs = map (first decodeUtf8) b_revKVs-      b_critbit = C.fromList b_ordKVs-      b_map = Map.fromList b_ordKVs-      b_hashmap = H.fromList b_ordKVs-      b_trie = Trie.fromList b_ordKVs+      b_critbit = C.fromList b_randKVs+      b_map = Map.fromList b_randKVs+      b_hashmap = H.fromList b_randKVs+      b_trie = Trie.fromList b_randKVs       key = fst . head $ b_randKVs       b_critbit_1 = C.delete key b_critbit       b_map_1 = Map.delete key b_map@@ -116,6 +147,18 @@         , bench "map" $ whnf Map.fromList kvs         , bench "hashmap" $ whnf H.fromList kvs         ]+      fromListWith kvs = [+          bench "critbit" $ whnf (C.fromListWith (+)) kvs+        , bench "map" $ whnf (Map.fromListWith (+)) kvs+        , bench "hashmap" $ whnf (H.fromListWith (+)) kvs+        , bench "trie" $ whnf (TC.fromListWith (+)) kvs+        ]+      fromListWithKey kvs = [+          bench "critbit" $ whnf (C.fromListWithKey addvs) kvs+        , bench "map" $ whnf (Map.fromListWithKey addvs) kvs+        -- , bench "hashmap" $ whnf (H.fromListWithKey (\a b -> a+b)) kvs+        -- , bench "trie" $ whnf (TC.fromListWithKey (\a b -> a+b)) kvs+        ]       keyed critbit map hashmap trie =         [           bgroup "present" [@@ -144,7 +187,7 @@        , bench "hashmap" $ eval hashmap b_hashmap        , bench "trie" $ eval trie b_trie        ]-  evaluate $ rnf [rnf b_critbit, rnf b_critbit_1, rnf b_map, rnf b_map_1,+  Exc.evaluate $ rnf [rnf b_critbit, rnf b_critbit_1, rnf b_map, rnf b_map_1,                   rnf b_hashmap, rnf b_hashmap_1, rnf b_trie, rnf b_trie_1,                   rnf b_randKVs, rnf b_revKVs, rnf key,                   rnf b_critbit_13, rnf b_critbit_23,@@ -153,7 +196,8 @@                   rnf b_trie_13, rnf b_trie_23]   defaultMain     [ bgroup "bytestring" [-        bgroup "fromList" [+        bgroup "size" $ function whnf C.size Map.size H.size Trie.size+      , bgroup "fromList" [           bgroup "ordered" $ fromList b_ordKVs ++                              [ bench "trie" $ whnf Trie.fromList b_ordKVs ]         , bgroup "random" $ fromList b_randKVs ++@@ -161,14 +205,149 @@         , bgroup "reversed" $ fromList b_revKVs ++                               [ bench "trie" $ whnf Trie.fromList b_revKVs ]         ]+      , bgroup "fromListWith" [+          bgroup "ordered" $ fromListWith b_ordKVs+        , bgroup "random" $ fromListWith b_randKVs+        , bgroup "reversed" $ fromListWith b_revKVs+        ]+      , bgroup "fromListWithKey" [+          bgroup "ordered" $ fromListWithKey b_ordKVs+        , bgroup "random" $ fromListWithKey b_randKVs+        , bgroup "reversed" $ fromListWithKey b_revKVs+        ]       , bgroup "delete" $ keyed C.delete Map.delete H.delete Trie.delete-      , bgroup "insert" $ keyed (flip C.insert 1) (flip Map.insert 1)-                                (flip H.insert 1) (flip Trie.insert 1)+      , bgroup "insert" $ keyed (`C.insert` 1) (`Map.insert` 1)+                                (`H.insert` 1) (`Trie.insert` 1)+      , bgroup "insertWith" [+          bgroup "present" [+            bench "critbit" $ whnf (C.insertWith (+) key 1) b_critbit+          , bench "map" $ whnf (Map.insertWith (+) key 1) b_map+          , bench "hashmap" $ whnf (H.insertWith (+) key 1) b_hashmap+          ]+        , bgroup "missing" [+            bench "critbit" $ whnf (C.insertWith (+) key 1) b_critbit_1+          , bench "map" $ whnf (Map.insertWith (+) key 1) b_map_1+          , bench "hashmap" $ whnf (H.insertWith (+) key 1) b_hashmap_1+          ]+        ]+      , bgroup "insertWithKey" [+          bgroup "present" [+            bench "critbit" $ whnf (C.insertWithKey addvs key 1) b_critbit+          , bench "map" $ whnf (Map.insertWithKey addvs key 1) b_map+          ]+        , bgroup "missing" [+            bench "critbit" $ whnf (C.insertWithKey addvs key 1) b_critbit_1+          , bench "map" $ whnf (Map.insertWithKey addvs key 1) b_map_1+          ]+        ]+      , bgroup "insertLookupWithKey" [+          bgroup "present" [+            bench "critbit" $+                whnf (forcePair . C.insertLookupWithKey addvs key 1) b_critbit+          , bench "map" $+                whnf (forcePair . Map.insertLookupWithKey addvs key 1) b_map+          ]+        , bgroup "missing" [+            bench "critbit" $+                whnf (forcePair . C.insertLookupWithKey addvs key 1) b_critbit_1+          , bench "map" $+                whnf (forcePair . Map.insertLookupWithKey addvs key 1) b_map_1+          ]+        ]+      , bgroup "adjust" $+        let f v = (v + 10) in [+          bgroup "present" [+            bench "critbit" $ whnf   (C.adjust f key) b_critbit+          , bench "map"     $ whnf (Map.adjust f key) b_map+          ]+        , bgroup "missing" [+            bench "critbit" $ whnf   (C.adjust f key) b_critbit_1+          , bench "map"     $ whnf (Map.adjust f key) b_map_1+          ]+        ]+      , bgroup "adjustWithKey" $+        let f k v = (v + fromIntegral (C.byteCount k)) in [+          bgroup "present" [+            bench "critbit" $ whnf   (C.adjustWithKey f key) b_critbit+          , bench "map"     $ whnf (Map.adjustWithKey f key) b_map+          , bench "trie"    $ whnf  (TC.adjustWithKey f key) b_trie+          ]+        , bgroup "missing" [+            bench "critbit" $ whnf   (C.adjustWithKey f key) b_critbit_1+          , bench "map"     $ whnf (Map.adjustWithKey f key) b_map_1+          , bench "trie"    $ whnf  (TC.adjustWithKey f key) b_trie_1+          ]+        ]+      , bgroup "updateWithKey" $+        let f k v = Just (v + fromIntegral (C.byteCount k)) in [+          bgroup "present" [+            bench "critbit" $ whnf (C.updateWithKey f key) b_critbit+          , bench "map" $ whnf (Map.updateWithKey f key) b_map+          , bench "trie" $ whnf (TC.updateWithKey f key) b_trie+          ]+        , bgroup "missing" [+            bench "critbit" $ whnf (C.updateWithKey f key) b_critbit_1+          , bench "map" $ whnf (Map.updateWithKey f key) b_map_1+          , bench "trie" $ whnf (TC.updateWithKey f key) b_trie_1+          ]+        ]+      , bgroup "update" $+        let f = updateFVal in [+          bgroup "present" [+            bench "critbit" $ whnf (C.update f key) b_critbit+          , bench "map" $ whnf (Map.update f key) b_map+          , bench "trie" $ whnf (TC.update f key) b_trie+          ]+        , bgroup "missing" [+            bench "critbit" $ whnf (C.update f key) b_critbit_1+          , bench "map" $ whnf (Map.update f key) b_map_1+          , bench "trie" $ whnf (TC.update f key) b_trie_1+          ]+        ]+      , bgroup "updateLookupWithKey" $+        -- The Map implementation immediately returns a tuple with lazy values,+        -- so we need to force it to evaluate the update.+        let f k v = Just (v + fromIntegral (C.byteCount k)) in [+          bgroup "present" [+            bench "critbit" $ whnf+              (snd . C.updateLookupWithKey f key) b_critbit+          , bench "map" $ whnf+              (snd . Map.updateLookupWithKey f key) b_map+          ]+        , bgroup "missing" [+            bench "critbit" $ whnf+              (snd . C.updateLookupWithKey f key) b_critbit_1+          , bench "map" $ whnf+              (snd . Map.updateLookupWithKey f key) b_map_1+          ]+        ]       , bgroup "lookup" $ keyed C.lookup Map.lookup H.lookup Trie.lookup+#if MIN_VERSION_containers(0,5,0)       , bgroup "lookupGT" $ [           bench "critbit" $ whnf (C.lookupGT key) b_critbit         , bench "map" $ whnf (Map.lookupGT key) b_map         ]+      , bgroup "lookupGE" $ [+          bench "critbit" $ whnf (C.lookupGE key) b_critbit+        , bench "map" $ whnf (Map.lookupGE key) b_map+        ]+      , bgroup "lookupLT" $ [+          bench "critbit" $ whnf (C.lookupLT key) b_critbit+        , bench "map" $ whnf (Map.lookupLT key) b_map+        ]+      , bgroup "lookupLE" $ [+          bench "critbit" $ whnf (C.lookupLE key) b_critbit+        , bench "map" $ whnf (Map.lookupLE key) b_map+        ]+      , bgroup "fromSet" $+        let+          keys = map fst t_ordKVs+          f = length . show+        in [+          bench "critbit" $ nf (C.fromSet f) (CSet.fromList keys)+        , bench "map" $ nf (Map.fromSet f) (Set.fromList keys)+        ]+#endif       , bgroup "member" $ keyed C.member Map.member H.member Trie.member       , bgroup "foldlWithKey'" $ let f a _ b = a + b                                  in function whnf (C.foldlWithKey' f 0)@@ -176,14 +355,279 @@                                     (H.foldlWithKey' f 0) id       , bgroup "foldl'" $ function whnf (C.foldl' (+) 0) (Map.foldl' (+) 0)                           (H.foldl' (+) 0) id+      , bgroup "elems" $ function nf C.elems Map.elems H.elems Trie.elems       , bgroup "keys" $ function nf C.keys Map.keys H.keys Trie.keys+      , bgroup "keysSet" [+          bench "critbit" $ nf C.keysSet b_critbit+        , bench "map" $ nf Map.keysSet b_map+        ]+      , bgroup "map"  $ let f = (+3)+                        in function nf (C.map f) (Map.map f) (H.map f) (fmap f)+      , bgroup "mapWithKey" [+          bench "critbit" $ whnf (C.mapWithKey mapFKey) b_critbit+        , bench "map" $ whnf (Map.mapWithKey mapFKey) b_map+        ]+      , bgroup "mapKeys" $ let f = (`mappend` "test") in [+          bench "critbit" $ nf (C.mapKeys f) b_critbit+        , bench "map" $ nf (Map.mapKeys f) b_map+        ]+	    , bgroup "mapKeysWith" $ let f = (`mappend` "test") in [+          bench "critbit" $ nf (C.mapKeysWith (+) f) b_critbit+        , bench "map" $ nf (Map.mapKeysWith (+) f) b_map+        ]+      , bgroup "mapKeysMonotonic" $ let f = mappend "test" in [+          bench "critbit" $ nf (C.mapKeysMonotonic f) b_critbit+        , bench "map" $ nf (Map.mapKeysMonotonic f) b_map+        ]+      , bgroup "mapAccumWithKey" [+          bench "critbit" $ whnf (C.mapAccumWithKey mapAccumFKey 0) b_critbit+        , bench "map" $ whnf (Map.mapAccumWithKey mapAccumFKey 0) b_map+        ]+      , bgroup "mapAccumRWithKey" [+          bench "critbit" $ whnf (C.mapAccumRWithKey mapAccumFKey 0) b_critbit+        , bench "map" $ whnf (Map.mapAccumRWithKey mapAccumFKey 0) b_map+        ]       , bgroup "union" $ twoMaps C.unionR Map.union H.union Trie.unionR-      ]+      , bgroup "unionWith" [+          bench "critbit" $ whnf (C.unionWith (+) b_critbit_13) b_critbit_23+        , bench "map" $ whnf (Map.unionWith (+) b_map_13) b_map_23+        ]+      , bgroup "unionWithKey" [+          bench "critbit" $ whnf (C.unionWithKey addvs b_critbit_13) b_critbit_23+        , bench "map" $ whnf (Map.unionWithKey addvs b_map_13) b_map_23+        ]+      , bgroup "unions" [+          bench "critbit" $ whnf C.unions [b_critbit_13, b_critbit_23]+        , bench "map" $ whnf Map.unions [b_map_13, b_map_23]+        ]+      , bgroup "unionsWith" [+          bench "critbit" $ whnf (C.unionsWith (+)) [b_critbit_13, b_critbit_23]+        , bench "map" $ whnf (Map.unionsWith (+)) [b_map_13, b_map_23]+        ]+      , bgroup "difference" [+          bench "critbit" $ whnf (C.difference b_critbit_13) b_critbit_23+        , bench "map" $ whnf (Map.difference b_map_13) b_map_23+        , bench "hashmap" $ whnf (H.difference b_hashmap_13) b_hashmap_23+        ]+      , bgroup "differenceWith" $ let f a b = Just (a + b) in [+          bench "critbit" $ whnf (C.differenceWith f b_critbit_13) b_critbit_23+        , bench "map" $ whnf (Map.differenceWith f b_map_13) b_map_23+        ]+      , bgroup "differenceWithKey" $ let f _ a b = Just(a + b) in [+          bench "critbit" $ whnf (C.differenceWithKey f b_critbit_13) b_critbit_23+        , bench "map" $ whnf (Map.differenceWithKey f b_map_13) b_map_23+        ]+      , bgroup "intersection" [+          bench "critbit" $ whnf (C.intersection b_critbit_13) b_critbit_23+        , bench "map" $ whnf (Map.intersection b_map_13) b_map_23+        , bench "hashmap" $ whnf (H.intersection b_hashmap_13) b_hashmap_23+        ]+      , bgroup "intersectionWith" [+          bench "critbit" $ whnf (C.intersectionWith (+) b_critbit_13) b_critbit_23+        , bench "map" $ whnf (Map.intersectionWith (+) b_map_13) b_map_23+        , bench "hashmap" $ whnf (H.intersectionWith (+) b_hashmap_13) b_hashmap_23+        ]+      , bgroup "intersectionWithKey" [+          bench "critbit" $+              whnf (C.intersectionWithKey addvs b_critbit_13) b_critbit_23+        , bench "map" $+              whnf (Map.intersectionWithKey addvs b_map_13) b_map_23+        ]+      , bgroup "toAscList" $ function nf C.toAscList Map.toAscList id id+      , bgroup "toDescList" $ function nf C.toDescList Map.toDescList id id+      , bgroup "fromAscList_short" [+          bench "critbit" $ nf   C.fromAscList b_ordKVs+        , bench "map"     $ nf Map.fromAscList b_ordKVs+        ]+      , bgroup "fromAscList_long" [+          bench "critbit" $ nf   C.fromAscList b_longKVs+        , bench "map"     $ nf Map.fromAscList b_longKVs+        ]+      , bgroup "fromAscListWith" [+          bench "critbit" $ nf (  C.fromAscListWith (+)) b_ordKVs+        , bench "map"     $ nf (Map.fromAscListWith (+)) b_ordKVs+        ]+      , bgroup "fromAscListWithKey" [+          bench "critbit" $ nf (  C.fromAscListWithKey (const (+))) b_ordKVs+        , bench "map"     $ nf (Map.fromAscListWithKey (const (+))) b_ordKVs+        ]+      , bgroup "fromAscDistinctList_short" [+          bench "critbit" $ nf   C.fromDistinctAscList b_ordKVs+        , bench "map"     $ nf Map.fromDistinctAscList b_ordKVs+        ]+      , bgroup "fromAscDistinctList_long" [+          bench "critbit" $ nf    C.fromDistinctAscList b_longKVs+        , bench "map"     $ nf  Map.fromDistinctAscList b_longKVs+        ]+      , bgroup "filter" $ let p  = (< 128)+                              p' = \e -> if p e then Just e else Nothing+                          in  function nf (C.filter p) (Map.filter p)+                                          (H.filter p) (Trie.filterMap p')+      , bgroup "mapMaybe" $+        let f x = if even x then Just (2 * x) else Nothing+        in [+          bench "critbit" $ whnf (C.mapMaybe f) b_critbit+        , bench "map" $ whnf (Map.mapMaybe f) b_map+        ]+      , bgroup "mapMaybeWithKey" $+        let f k v | even (fromIntegral v :: Int) =+                    Just (v + fromIntegral (C.byteCount k))+                  | otherwise = Nothing+        in [+          bench "critbit" $ whnf (C.mapMaybeWithKey f) b_critbit+        , bench "map" $ whnf (Map.mapMaybeWithKey f) b_map+        ]+      , bgroup "mapEither" $+        let f x = if even x then Left (2 * x) else Right (3 * x)+        in [+          bench "critbit" $ whnf (C.mapEither f) b_critbit+        , bench "map" $ whnf (Map.mapEither f) b_map+        ]+      , bgroup "mapEitherWithKey" $+        let f k v | even (fromIntegral v :: Int) =+                    Left (v + fromIntegral (C.byteCount k))+                  | otherwise = Right (2 * v)+        in [+          bench "critbit" $ nf (C.mapEitherWithKey f) b_critbit+        , bench "map" $ nf (Map.mapEitherWithKey f) b_map+        ]+      , bgroup "split" [+          bench "critbit" $ whnf (forcePair . C.split key) b_critbit+        , bench "map" $ whnf (forcePair . Map.split key) b_map+        ]+      , bgroup "splitLookup" $+        let forceTriple (a,_,b) = a `seq` b `seq` ()+        in [+          bench "critbit" $ whnf (forceTriple . C.splitLookup key) b_critbit+        , bench "map" $ whnf (forceTriple . Map.splitLookup key) b_map+        ]+      , bgroup "isSubmapOf" [+          bench "critbit" $ whnf (C.isSubmapOf b_critbit_1) b_critbit+        , bench "map" $ whnf (Map.isSubmapOf b_map_1) b_map+        ]+      , bgroup "isSubmapOfBy" [+          bench "critbit" $ whnf (C.isSubmapOfBy (<=) b_critbit_1) b_critbit+        , bench "map" $ whnf (Map.isSubmapOfBy (<=) b_map_1) b_map+        ]+      , bgroup "isProperSubmapOf" [+          bench "critbit" $ whnf (C.isProperSubmapOf b_critbit_1) b_critbit+        , bench "map" $ whnf (Map.isProperSubmapOf b_map_1) b_map+        ]+      , bgroup "isProperSubmapOfBy" [+          bench "critbit" $+            whnf (C.isProperSubmapOfBy (<=) b_critbit_1) b_critbit+        , bench "map" $+            whnf (Map.isProperSubmapOfBy (<=) b_map_1) b_map+        ]+      , bgroup "findMin" [+          bench "critbit" $ whnf C.findMin b_critbit+        , bench "map" $ whnf Map.findMin b_map+        ]+      , bgroup "findMax" [+          bench "critbit" $ whnf C.findMax b_critbit+        , bench "map" $ whnf Map.findMax b_map+        ]+      , bgroup "deleteMin" [+          bench "critbit" $ whnf C.deleteMin b_critbit+        , bench "map" $ whnf Map.deleteMin b_map+        ]+      , bgroup "deleteMax" [+          bench "critbit" $ whnf C.deleteMax b_critbit+        , bench "map" $ whnf Map.deleteMax b_map+       ]+      , bgroup "deleteFindMin" [+          bench "critbit" $ whnf (snd . C.deleteFindMin) b_critbit+        , bench "map" $ whnf (snd . Map.deleteFindMin) b_map+        ]+      , bgroup "deleteFindMax" [+          bench "critbit" $ whnf (snd . C.deleteFindMax) b_critbit+        , bench "map" $ whnf (snd . Map.deleteFindMax) b_map+        ]+      , bgroup "minView" [+          bench "critbit" $ whnf (snd . fromJust . C.minView) b_critbit+        , bench "map" $ whnf (snd . fromJust . Map.minView) b_map+        ]+      , bgroup "maxView" [+          bench "critbit" $ whnf (snd . fromJust . C.maxView) b_critbit+        , bench "map" $ whnf (snd . fromJust . Map.maxView) b_map+        ]+      , bgroup "minViewWithKey" [+          bench "critbit" $ whnf (snd . fromJust . C.minViewWithKey) b_critbit+        , bench "map" $ whnf (snd . fromJust . Map.minViewWithKey) b_map+        ]+      , bgroup "maxViewWithKey" [+          bench "critbit" $ whnf (snd . fromJust . C.minViewWithKey) b_critbit+        , bench "map" $ whnf (snd . fromJust . Map.minViewWithKey) b_map+        ]+      , bgroup "updateMin" [+          bench "critbit" $ whnf (C.updateMin updateFVal) b_critbit+        , bench "map" $ whnf (Map.updateMin updateFVal) b_map+        ]+      , bgroup "updateMax" [+          bench "critbit" $ whnf (C.updateMax updateFVal) b_critbit+        , bench "map" $ whnf (Map.updateMax updateFVal) b_map+        ]+      , bgroup "traverseWithKey" $ let f _ = Identity . (+3) in [+          bench "critbit" $ nf (runIdentity . C.traverseWithKey f) b_critbit+#if MIN_VERSION_containers(0,5,0)+        , bench "map" $ nf (runIdentity . Map.traverseWithKey f) b_map+#endif+        , bench "hashmap" $ nf (runIdentity . H.traverseWithKey f) b_hashmap+        , bench "trie" $ nf (fmap f) b_trie+        ]+      , bgroup "updateMinWithKey" [+          bench "critbit" $ whnf (C.updateMinWithKey updateFKey) b_critbit+        , bench "map" $ whnf (Map.updateMinWithKey updateFKey) b_map+        ]+      , bgroup "updateMaxWithKey" [+          bench "critbit" $ whnf (C.updateMaxWithKey updateFKey) b_critbit+        , bench "map" $ whnf (Map.updateMaxWithKey updateFKey) b_map+        ]+      , bgroup "foldMap" [+          bench "critbit" $ let c_foldmap :: (C.CritBitKey k, Num v)+                                          => C.CritBit k v+                                          -> Sum v+                                c_foldmap = foldMap Sum+                            in whnf c_foldmap b_critbit+        , bench "map" $ let m_foldmap :: (Eq k, Num v)+                                      => Map.Map k v+                                      -> Sum v+                            m_foldmap = foldMap Sum+                        in whnf m_foldmap b_map+        ]+      , bgroup "alter" $ let altF (Just v) =+                                  if odd v+                                    then Just (v+1)+                                    else Nothing+                             altF Nothing  = Just 1+                          in [+          bench "critbit" $  whnf (C.alter altF key) b_critbit+        , bench "map" $ whnf (Map.alter altF key) b_map+        ]+     , bgroup "partitionWithKey" $ let predicate k _ = odd $ C.byteCount k in [+          bench "critbit" $ whnf (forcePair . C.partitionWithKey predicate) b_critbit+        , bench "map" $ whnf (forcePair . Map.partitionWithKey predicate) b_map+     ]+     , bgroup "partition" [+          bench "critbit" $ whnf (forcePair . C.partition odd) b_critbit+        , bench "map" $ whnf (forcePair . Map.partition odd) b_map+     ]+    ]     , bgroup "text" [         bgroup "fromList" [           bgroup "ordered" $ fromList t_ordKVs         , bgroup "random" $ fromList t_randKVs         , bgroup "reversed" $ fromList t_revKVs+        ]+      , bgroup "fromListWith" [+          bgroup "ordered" $ fromListWith b_ordKVs+        , bgroup "random" $ fromListWith b_randKVs+        , bgroup "reversed" $ fromListWith b_revKVs+        ]+      , bgroup "fromListWithKey" [+          bgroup "ordered" $ fromListWithKey b_ordKVs+        , bgroup "random" $ fromListWithKey b_randKVs+        , bgroup "reversed" $ fromListWithKey b_revKVs         ]       ]     ]
critbit.cabal view
@@ -1,18 +1,29 @@ name:           critbit-version:        0.0.0.0+version:        0.1.0.0 homepage:       https://github.com/bos/critbit bug-reports:    https://github.com/bos/critbit/issues synopsis:       Crit-bit maps and sets description:-    Whee.+    This package implements crit-bit trees, a key-value container type+    for storing keys that can be treated as bitstrings (e.g.+    'ByteString' and 'Text').+    .+    Compared to the data structures from the containers and+    unordered-containers packages, you will find that sometimes the+    functions implemented in this package are faster, sometimes+    slower.+    .+    In many cases, a 'CritBit' tree provides performance close to that+    of a 'HashMap', while providing ordered storage and traversal+    like a 'Map'. license:        BSD3 license-file:   LICENSE author:         Bryan O'Sullivan <bos@serpentine.com> maintainer:     Bryan O'Sullivan <bos@serpentine.com>-copyright:      2013 Bryan O'Sullivan+copyright:      2013-2014 Bryan O'Sullivan and others category:       Data build-type:     Simple-cabal-version:  >= 1.8+cabal-version:  >= 1.14 extra-source-files:     README.markdown @@ -21,18 +32,21 @@   default: False  library+  default-language: Haskell2010   exposed-modules:     Data.CritBit.Map.Lazy+    Data.CritBit.Set   other-modules:     Data.CritBit.Core     Data.CritBit.Types.Internal     Data.CritBit.Tree    build-depends:+    array,     base >= 4 && < 5,     bytestring >= 0.9,     deepseq,-    text >= 0.11.3.1,+    text >= 0.11.2.3,     vector    ghc-options: -Wall -funbox-strict-fields -O2 -fwarn-tabs@@ -42,26 +56,33 @@     cpp-options: -DASSERTS  test-suite tests+  default-language: Haskell2010   type:           exitcode-stdio-1.0   hs-source-dirs: tests   main-is:        Main.hs   if impl(ghc >= 7.4)-    other-modules:  Properties+    other-modules:+      Properties.Common+      Properties.Map+      Properties.Set    ghc-options:-    -Wall -threaded -rtsopts+    -Wall -threaded -rtsopts -with-rtsopts=-N    build-depends:+    QuickCheck >= 2.7,     base >= 4 && < 5,     bytestring,     containers,     critbit,-    QuickCheck >= 2.4,     test-framework >= 0.4,     test-framework-quickcheck2 >= 0.2,-    text+    text,+    transformers >= 0.3,+    vector  benchmark benchmarks+  default-language: Haskell2010   type:           exitcode-stdio-1.0   hs-source-dirs: benchmarks   main-is:        Benchmarks.hs@@ -79,6 +100,7 @@     mtl,     mwc-random,     text,+    transformers >= 0.3,     unordered-containers,     vector 
tests/Main.hs view
@@ -4,7 +4,12 @@ import Test.Framework  #if MIN_VERSION_base(4,5,0)-import Properties (properties)+import qualified Properties.Map as Map+import qualified Properties.Set as Set++properties :: [Test]+properties = [ testGroup "map" Map.properties,+               testGroup "set" Set.properties ] #else import Test.Framework.Providers.QuickCheck2 (testProperty) 
− tests/Properties.hs
@@ -1,137 +0,0 @@-{-# LANGUAGE CPP, GeneralizedNewtypeDeriving #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-module Properties-    where--import Control.Applicative ((<$>))-import Data.ByteString (ByteString)-import Data.CritBit.Map.Lazy (CritBitKey, CritBit)-import Data.Text (Text)-import Data.Word (Word8)-import Test.Framework (Test, testGroup)-import Test.Framework.Providers.QuickCheck2 (testProperty)-import Test.QuickCheck (Arbitrary(..), Args(..), quickCheckWith, stdArgs)-import Test.QuickCheck.Property (Testable)-import qualified Data.ByteString as BB-import qualified Data.ByteString.Char8 as B-import qualified Data.CritBit.Map.Lazy as C-import qualified Data.Map as Map-import qualified Data.Text as T--instance Arbitrary ByteString where-    arbitrary = BB.pack <$> arbitrary-    shrink    = map B.pack . shrink . B.unpack--instance Arbitrary Text where-    arbitrary = T.pack <$> arbitrary-    shrink    = map T.pack . shrink . T.unpack--type V = Word8--newtype KV a = KV { fromKV :: [(a, V)] }-        deriving (Show, Eq, Ord)--instance Arbitrary a => Arbitrary (KV a) where-    arbitrary = (KV . flip zip [0..]) <$> arbitrary-    shrink = map (KV . flip zip [0..]) . shrink . map fst . fromKV--instance (CritBitKey k, Arbitrary k, Arbitrary v) =>-  Arbitrary (CritBit k v) where-    arbitrary = C.fromList <$> arbitrary-    shrink = map C.fromList . shrink . C.toList--newtype CB k = CB (CritBit k V)-    deriving (Show, Eq, Arbitrary)--t_lookup_present :: (CritBitKey k) => k -> k -> V -> CB k -> Bool-t_lookup_present _ k v (CB m) = C.lookup k (C.insert k v m) == Just v--t_lookup_missing :: (CritBitKey k) => k -> k -> CB k -> Bool-t_lookup_missing _ k (CB m) = C.lookup k (C.delete k m) == Nothing--#if MIN_VERSION_containers(0,5,0)-t_lookupGT :: (Ord k, CritBitKey k) => k -> k -> KV k -> Bool-t_lookupGT _ k (KV kvs) =-    C.lookupGT k (C.fromList kvs) == Map.lookupGT k (Map.fromList kvs)-#endif--t_fromList_toList :: (CritBitKey k, Ord k) => k -> KV k -> Bool-t_fromList_toList _ (KV kvs) =-    Map.toList (Map.fromList kvs) == C.toList (C.fromList kvs)--t_fromList_size :: (CritBitKey k, Ord k) => k -> KV k -> Bool-t_fromList_size _ (KV kvs) =-    Map.size (Map.fromList kvs) == C.size (C.fromList kvs)--t_delete_present :: (CritBitKey k, Ord k) => k -> KV k -> k -> V -> Bool-t_delete_present _ (KV kvs) k v =-    C.toList (C.delete k c) == Map.toList (Map.delete k m)-  where-    c = C.insert k v $ C.fromList kvs-    m = Map.insert k v $ Map.fromList kvs--t_unionL :: (CritBitKey k, Ord k) => k -> KV k -> KV k -> Bool-t_unionL _ (KV kv0) (KV kv1) =-    Map.toList (Map.fromList kv0 `Map.union` Map.fromList kv1) ==-    C.toList (C.fromList kv0 `C.unionL` C.fromList kv1)--t_foldl :: (CritBitKey k) => k -> CritBit k V -> Bool-t_foldl _ m = C.foldl (+) 0 m == C.foldr (+) 0 m--t_foldlWithKey :: (CritBitKey k, Ord k) => k -> KV k -> Bool-t_foldlWithKey _ (KV kvs) =-    C.foldlWithKey f ([], 0) (C.fromList kvs) ==-    Map.foldlWithKey f ([], 0) (Map.fromList kvs)-  where-    f (l,s) k v = (k:l,s+v)--t_foldl' :: (CritBitKey k) => k -> CritBit k V -> Bool-t_foldl' _ m = C.foldl' (+) 0 m == C.foldl (+) 0 m--t_foldlWithKey' :: (CritBitKey k, Ord k) => k -> KV k -> Bool-t_foldlWithKey' _ (KV kvs) =-    C.foldlWithKey' f ([], 0) (C.fromList kvs) ==-    Map.foldlWithKey' f ([], 0) (Map.fromList kvs)-  where-    f (l,s) k v = (k:l,s+v)--t_keys :: (CritBitKey k, Ord k) => k -> KV k -> Bool-t_keys _ (KV kvs) = C.keys (C.fromList kvs) == Map.keys (Map.fromList kvs)--propertiesFor :: (Arbitrary k, CritBitKey k, Ord k, Show k) => k -> [Test]-propertiesFor t = [-    testProperty "t_fromList_toList" $ t_fromList_toList t-  , testProperty "t_fromList_size" $ t_fromList_size t-  , testProperty "t_lookup_present" $ t_lookup_present t-  , testProperty "t_lookup_missing" $ t_lookup_missing t-#if MIN_VERSION_containers(0,5,0)-  , testProperty "t_lookupGT" $ t_lookupGT t-#endif-  , testProperty "t_delete_present" $ t_delete_present t-  , testProperty "t_unionL" $ t_unionL t-  , testProperty "t_foldl" $ t_foldl t-  , testProperty "t_foldlWithKey" $ t_foldlWithKey t-  , testProperty "t_foldl'" $ t_foldl' t-  , testProperty "t_foldlWithKey'" $ t_foldlWithKey' t-  , testProperty "t_keys" $ t_keys t-  ]--properties :: [Test]-properties = [-    testGroup "text" $ propertiesFor T.empty-  , testGroup "bytestring" $ propertiesFor B.empty-  ]---- Handy functions for fiddling with from ghci.--blist :: [ByteString] -> CritBit ByteString Word8-blist = C.fromList . flip zip [0..]--tlist :: [Text] -> CritBit Text Word8-tlist = C.fromList . flip zip [0..]--mlist :: [ByteString] -> Map.Map ByteString Word8-mlist = Map.fromList . flip zip [0..]--qc :: Testable prop => Int -> prop -> IO ()-qc n = quickCheckWith stdArgs { maxSuccess = n }
+ tests/Properties/Common.hs view
@@ -0,0 +1,178 @@+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, IncoherentInstances #-}+{-# LANGUAGE OverloadedStrings, Rank2Types #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module Properties.Common+    (+      Small(..)+    , qc+    , Props+    , Eq'(..)+    , SameAs(..)+    , (=?=)+    , (=??=)+    , (=*=)+    , (=?*=)+    , (=??*=)+    , (=**=)+    , (=*==)+    , notEmpty+    , prepends+    , kf+  ) where++import Control.Applicative ((<$>))+import qualified Data.ByteString.Char8 as B+import Data.CritBit.Map.Lazy (CritBitKey, byteCount)+import Data.Monoid (Monoid, mappend)+import Data.String (IsString, fromString)+import qualified Data.Text as T+import qualified Data.Vector.Generic as G+import qualified Data.Vector.Unboxed as U+import Data.Word+import Test.Framework (Test)+import Test.QuickCheck (Arbitrary(..), Args(..), quickCheckWith, stdArgs)+import Test.QuickCheck.Gen (Gen, resize, sized)+import Test.QuickCheck.Property (Property, Testable, (===), (.&&.), (.||.))++instance IsString (U.Vector Word8) where+    fromString = fromStringV++instance IsString (U.Vector Word16) where+    fromString = fromStringV++instance IsString (U.Vector Word32) where+    fromString = fromStringV++instance IsString (U.Vector Word64) where+    fromString = fromStringV++instance IsString (U.Vector Word) where+    fromString = fromStringV++instance IsString (U.Vector Char) where+    fromString = G.fromList++fromStringV :: (G.Vector v a, Integral a) => String -> v a+fromStringV = G.fromList . map (fromIntegral . fromEnum)++instance Arbitrary B.ByteString where+    arbitrary = B.pack <$> arbitrary+    shrink    = map B.pack . shrink . B.unpack++instance Arbitrary T.Text where+    arbitrary = T.pack <$> arbitrary+    shrink    = map T.pack . shrink . T.unpack++instance Arbitrary (U.Vector Word8) where+    arbitrary = arbitraryV+    shrink    = shrinkV++instance Arbitrary (U.Vector Word16) where+    arbitrary = arbitraryV+    shrink    = shrinkV++instance Arbitrary (U.Vector Word32) where+    arbitrary = arbitraryV+    shrink    = shrinkV++instance Arbitrary (U.Vector Word64) where+    arbitrary = arbitraryV+    shrink    = shrinkV++instance Arbitrary (U.Vector Word) where+    arbitrary = arbitraryV+    shrink    = shrinkV++instance Arbitrary (U.Vector Char) where+    arbitrary = arbitraryV+    shrink    = shrinkV++arbitraryV :: (G.Vector v a, Arbitrary a) => Gen (v a)+arbitraryV = G.fromList <$> arbitrary++shrinkV :: (G.Vector v a, Arbitrary a) => v a -> [v a]+shrinkV = map G.fromList . shrink . G.toList++newtype Small a = Small { fromSmall :: a }+    deriving (Eq, Ord, Show)++instance (Show a, Arbitrary a) => Arbitrary (Small a) where+    arbitrary = Small <$> (sized $ \n -> resize (smallish n) arbitrary)+      where+        smallish = round . (sqrt :: Double -> Double) . fromIntegral . abs+    shrink = map Small . shrink . fromSmall++type Props k = (Arbitrary k, CritBitKey k, Ord k, IsString k, Monoid k, Show k) => k -> [Test]++infix 4 =^=, =?=, =??=++-- | Compares heterogeneous values+class (Show f, Show g) => Eq' f g where+  (=^=) :: f -> g -> Property++instance (Show t, Eq t) => Eq' t t where+  (=^=) = (===)++instance (Eq' a1 b1, Eq' a2 b2, Eq' a3 b3) => Eq' (a1, a2, a3) (b1, b2, b3)+  where (a1, a2, a3) =^= (b1, b2, b3) = a1 =^= b1 .&&. a2 =^= b2 .&&. a3 =^= b3++-- | Compares functions taking one scalar+(=?=) :: Eq' a b => (t -> a) -> (t -> b) -> k -> t -> Property+f =?= g = const $ \t -> f t =^= g t++-- | Compares functions taking two scalars+(=??=) :: Eq' a b => (t -> s -> a) -> (t -> s -> b) -> k -> t -> s -> Property+f =??= g = const $ \t s -> f t s =^= g t s++infix 4 =*=, =?*=, =*==++-- | Types 'f' and 'g' have same behavior and common represenation 'r'.+data SameAs f g r = SameAs {+    toF   :: r -> f+  , fromF :: f -> r+  , toG   :: r -> g+  , fromG :: g -> r+  }++-- | Compares two functions taking one container+(=*=) :: (Eq' a b) => (f -> a) -> (g -> b)+      -> SameAs f g r -> r -> Property+(f =*= g) sa i = f (toF sa i) =^= g (toG sa i)++-- | Compares two functions taking one scalar and one container+(=?*=) :: (Eq' a b) => (t -> f -> a) -> (t -> g -> b)+       -> SameAs f g r -> r -> t -> Property+(f =?*= g) sa i t = (f t =*= g t) sa i++-- | Compares functions taking two scalars and one container+(=??*=) :: (Eq' a b) => (t -> s -> f -> a) -> (t -> s -> g -> b)+        -> SameAs f g r -> r -> t -> s -> Property+(f =??*= g) sa i t s = (f t s =*= g t s) sa i++-- | Compares two functions taking two containers+(=**=) :: (Eq' a b) => (f -> f -> a) -> (g -> g -> b)+       -> SameAs f g r -> r -> r -> Property+(f =**= g) sa i = (f (toF sa i) =*= g (toG sa i)) sa++-- | Compares two functions taking one container with preprocessing+(=*==) :: (Eq' f g) => (z -> f) -> (z -> g) -> (p -> z)+       -> SameAs f g r -> p -> Property+(f =*== g) p _ i = f i' =^= g i'+  where i' = p i++-- | Input litst is non-empty+notEmpty :: (SameAs c1 c2 [i] -> [i] -> Property)+         -> SameAs c1 c2 [i] -> [i] -> Property+notEmpty f t items = null items .||. f t items++prepends :: (IsString k, Monoid k) => k -> k+prepends = mappend "test"++-- | Keys mapping function+kf :: (CritBitKey k, IsString k, Monoid k) => k -> k+kf k = fromString (show (byteCount k)) `mappend` k++-- Handy functions for fiddling with from ghci.++qc :: Testable prop => Int -> prop -> IO ()+qc n = quickCheckWith stdArgs { maxSuccess = n }
+ tests/Properties/Map.hs view
@@ -0,0 +1,353 @@+{-# LANGUAGE CPP, GeneralizedNewtypeDeriving, OverloadedStrings #-}+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, Rank2Types #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module Properties.Map+    where++import qualified Data.ByteString.Char8 as B+import Data.CritBit.Map.Lazy (CritBitKey, CritBit, byteCount)+import qualified Data.CritBit.Map.Lazy as C+import qualified Data.CritBit.Set as CSet+import Data.Foldable (foldMap)+import Data.Function (on)+import Data.List (unfoldr, sort, nubBy)+import Data.Map (Map)+import qualified Data.Map as Map+import Data.Monoid (Sum(..))+import qualified Data.Set as Set+import qualified Data.Text as T+import qualified Data.Vector.Generic as G+import qualified Data.Vector.Unboxed as U+import Data.Word+import Properties.Common+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)+import Test.QuickCheck.Property ((.&&.))++--only needed for a test requiring containers >= 0.5+#if MIN_VERSION_containers(0,5,0)+import Data.Functor.Identity (Identity(..))+#endif++type V = Word8++-- * Common modifier functions++kvvf :: (CritBitKey k) => k -> V -> V -> V+kvvf k v1 v2 = fromIntegral (byteCount k) * 3 + v1 * 2 - v2++kvvfm :: (CritBitKey k) => k -> V -> V -> Maybe V+kvvfm k v1 v2 = if even v1 then Just (kvvf k v1 v2) else Nothing++kvf :: (CritBitKey k) => k -> V -> V+kvf k v = kvvf k v 0++kvfm :: (CritBitKey k) => k -> V -> Maybe V+kvfm k v = kvvfm k v 0++vvfm :: V -> V -> Maybe V+vvfm = kvvfm ("" :: T.Text)++vfm :: V -> Maybe V+vfm = kvfm ("" :: T.Text)++propertiesFor :: Props k+propertiesFor w = concat [[]+  -- ** Lists+  , prop sa "t_fromList" $+        (C.fromList =*== Map.fromList) id+  , prop sa "t_fromListWith" $+        (C.fromListWith (-) =*== Map.fromListWith (-)) id+  , prop sa "t_fromListWithKey" $+        (C.fromListWithKey kvvf =*== Map.fromListWithKey kvvf) id++    -- * Query+  , prop sa "t_null" $+        C.null =*= Map.null+  , prop sa "t_size" $+        C.size =*= Map.size+  , prop sa "t_member" $+        C.member =?*= Map.member+  , prop sa "t_member" $+        C.notMember =?*= Map.notMember+  , prop sa "t_lookup" $+        C.lookup =?*= Map.lookup+  , prop sa "t_findWithDefault" $+        C.findWithDefault =??*= Map.findWithDefault++#if MIN_VERSION_containers(0,5,0)+  , prop sa "t_lookupGT" $+        C.lookupGT =?*= Map.lookupGT+  , prop sa "t_lookupGE" $+        C.lookupGE =?*= Map.lookupGE+  , prop sa "t_lookupLT" $+        C.lookupLT =?*= Map.lookupLT+  , prop sa "t_lookupLE" $+        C.lookupLE =?*= Map.lookupLE+#endif++  -- * Insertion+  , pmprop sa "t_insert" $+        C.insert =??*= Map.insert+  , pmprop sa "t_insertWith" $+        C.insertWith (-) =??*= Map.insertWith (-)+  , pmprop sa "t_insertWithKey" $+        C.insertWithKey kvvf =??*= Map.insertWithKey kvvf+  , pmprop sa "t_insertLookupWithKey" $+        C.insertLookupWithKey kvvf =??*= Map.insertLookupWithKey kvvf++  -- * Deletion+  , pmprop sa "t_delete" $+        C.delete =?*= Map.delete+  , pmprop sa "t_adjust" $+        C.adjust (+3) =?*= Map.adjust (+3)+  , pmprop sa "t_adjustWithKey" $+        C.adjustWithKey kvf =?*= Map.adjustWithKey kvf+  , pmprop sa "t_update" $+        C.update vfm =?*= Map.update vfm+  , pmprop sa "t_updateWithKey" $+        C.updateWithKey kvfm =?*= Map.updateWithKey kvfm+  , pmprop sa "t_updateLookupWithKey" $+        C.updateLookupWithKey kvfm =?*= Map.updateLookupWithKey kvfm+  , prop sa "t_alter" $+        let f = Just . maybe 1 (+1)+        in C.alter f =?*= Map.alter f+  , prop sa "t_alter_delete" $+        C.alter (const Nothing) =?*= Map.alter (const Nothing)++  -- * Combination+  -- ** Union+  , prop sa "t_union" $+        C.union =**= Map.union+  , prop sa "t_unionWith" $+        C.unionWith (-) =**= Map.unionWith (-)+  , prop sa "t_unionWithKey" $+        C.unionWithKey kvvf =**= Map.unionWithKey kvvf+  , prop sa "t_unions" $+        (  C.unions . map   C.fromList =*==+         Map.unions . map Map.fromList) fromSmall+  , prop sa "t_unionsWith" $+        (  C.unionsWith (-) . map   C.fromList =*==+         Map.unionsWith (-) . map Map.fromList) fromSmall+  , prop sa "t_unionL" $+        C.unionL =**= Map.union+  , prop sa "t_unionR" $+        C.unionR =**= flip Map.union++  -- ** Difference+  , prop sa "t_difference" $+        C.difference =**= Map.difference+  , prop sa "t_differenceWith" $+        C.differenceWith vvfm =**= Map.differenceWith vvfm+  , prop sa "t_differenceWithKey" $+        C.differenceWithKey kvvfm =**= Map.differenceWithKey kvvfm++  -- ** Intersection+  , prop sa "t_intersection" $+        C.intersection =**= Map.intersection+  , prop sa "t_intersectionWith" $+        C.intersectionWith (-) =**= Map.intersectionWith (-)+  , prop sa "t_intersectionWithKey" $+        C.intersectionWithKey kvvf =**= Map.intersectionWithKey kvvf++  -- * Traversal+  -- ** Map+  , prop sa "t_map" $+        C.map (+3) =*= Map.map (+3)+  , prop sa "t_mapWithKey" $+        C.mapWithKey kvf =*= Map.mapWithKey kvf+#if MIN_VERSION_containers(0,5,0)+  , prop sa "t_traverseWithKey" $+      let f _ = Identity . show . (+3)+      in runIdentity . C.traverseWithKey f =*= runIdentity . Map.traverseWithKey f+#endif+  , prop sa "t_mapAccum" $+        let f i v = (i + 1 :: Int, show $ v + 3)+        in C.mapAccum f 0 =*= Map.mapAccum f 0+  , prop sa "t_mapAccumWithKey" $+        let f i k v = (i + byteCount k, show $ v + 3)+        in C.mapAccumWithKey f 0 =*= Map.mapAccumWithKey f 0+  , prop sa "t_mapAccumRWithKey" $+        let f i k v = (i + byteCount k, show $ v + 3)+        in C.mapAccumRWithKey f 0 =*= Map.mapAccumRWithKey f 0+  , prop sa "t_mapKeys" $+        C.mapKeys kf =*= Map.mapKeys kf+  , prop sa "t_mapKeysWith" $+        C.mapKeysWith (+) kf =*= Map.mapKeysWith (+) kf+  , prop sa "t_mapKeysMonotonic" $+        C.mapKeysMonotonic prepends =*= Map.mapKeysMonotonic prepends++  -- * Folds+  , prop sa "t_foldl" $+        C.foldl (-) 0 =*= Map.foldl (-) 0+  , prop sa "t_foldlWithKey" $+        let f i k v = i * 37 + (byteCount k) * 17 + fromIntegral v+        in C.foldlWithKey f 0 =*= Map.foldlWithKey f 0+  , prop sa "t_foldr" $+        C.foldr (-) 0 =*= Map.foldr (-) 0+  , prop sa "t_foldrWithKey" $+        let f k v i = i * 37 + (byteCount k) * 17 + fromIntegral v+        in C.foldrWithKey f 0 =*= Map.foldrWithKey f 0++  -- ** Strict folds+  , prop sa "t_foldl'" $+        C.foldl' (-) 0 =*= Map.foldl' (-) 0+  , prop sa "t_foldlWithKey'" $+        let f i k v = i * 37 + (byteCount k) * 17 + fromIntegral v+        in C.foldlWithKey' f 0 =*= Map.foldlWithKey' f 0+  , prop sa "t_foldr'" $+        C.foldr' (-) 0 =*= Map.foldr' (-) 0+  , prop sa "t_foldrWithKey'" $+        let f k v i = i * 37 + (byteCount k) * 17 + fromIntegral v+        in C.foldrWithKey' f 0 =*= Map.foldrWithKey' f 0++  -- * Conversion+  , prop sa "t_elems" $+        C.elems =*= Map.elems+  , prop sa "t_keys" $+        C.keys =*= Map.keys+  , prop sa "assocs" $+        C.assocs =*= Map.assocs+  , prop sa "t_keysSet" $+        CSet.toList . C.keysSet =*= Set.toList . Map.keysSet+#if MIN_VERSION_containers(0,5,0)+  , prop sa "t_fromSet" $+        let f = length . show+        in C.fromSet f . C.keysSet =*= Map.fromSet f . Map.keysSet+#endif++  -- ** Ordered lists+  , prop sa "t_toAscList" $+        C.toAscList =*= Map.toAscList+  , prop sa "t_toDescList" $+        C.toDescList =*= Map.toDescList+  , prop sa "t_fromAscList" $+        (C.fromAscList =*== Map.fromAscList) sort+  , prop sa "t_fromAscListWith" $+        (C.fromAscListWith (+) =*== Map.fromAscListWith (+)) sort+  , prop sa "t_fromAscListWithKey" $+        (C.fromAscListWithKey kvvf =*== Map.fromAscListWithKey kvvf) sort+  , prop sa "t_fromDistinctAscList" $+        let p = nubBy ((==) `on` fst) . sort+        in (C.fromDistinctAscList =*== Map.fromDistinctAscList) p++  -- * Filter+  , prop sa "t_filter" $+        C.filter odd =*= Map.filter odd+  , prop sa "t_filterWithKey" $+        let p k v = odd $ kvf k v+        in C.filterWithKey p =*= Map.filterWithKey p+  , prop sa "t_partition" $ C.partition odd =*= Map.partition odd+  , prop sa "t_partitionWithKey" $+       let p k v = odd $ kvf k v+       in C.partitionWithKey p =*= Map.partitionWithKey p++  , prop sa "t_mapMaybe" $+        C.mapMaybe vfm =*= Map.mapMaybe vfm+  , prop sa "t_mapMaybeWithKey" $+        C.mapMaybeWithKey kvfm =*= Map.mapMaybeWithKey kvfm+  , prop sa "t_mapEither" $+        let f v = if even v then Left (2 * v) else Right (3 * v)+        in C.mapEither f =*= Map.mapEither f+  , prop sa "t_mapEitherWithKey" $+        let f k v = if even v then Left (kvf k v) else Right (3 * v)+        in C.mapEitherWithKey f =*= Map.mapEitherWithKey f++  , pmprop sa "t_split" $+        C.split =?*= Map.split+  , pmprop sa "t_splitLookup" $+        C.splitLookup =?*= Map.splitLookup++  -- * Submap+  , prop sa "t_isSubmapOf" $+        C.isSubmapOf =**= Map.isSubmapOf+  , prop sa "t_isSubmapOfBy" $+        C.isSubmapOfBy (<=) =**= Map.isSubmapOfBy (<=)+  , prop sa "t_isProperSubmapOf" $+        C.isProperSubmapOf =**= Map.isProperSubmapOf+  , prop sa "t_isProperSubmapOfBy" $+        C.isProperSubmapOfBy (<=) =**= Map.isProperSubmapOfBy (<=)++  -- * Min\/Max+  , prop sa "t_findMin" $ notEmpty $+        C.findMin =*= Map.findMin+  , prop sa "t_findMax" $ notEmpty $+        C.findMax =*= Map.findMax+  , prop sa "t_deleteMin" $ notEmpty $+        C.deleteMin =*= Map.deleteMin+  , prop sa "t_deleteMax" $ notEmpty $+        C.deleteMax =*= Map.deleteMax+  , prop sa "t_deleteFindMin" $ notEmpty $+        C.deleteFindMin =*= Map.deleteFindMin+  , prop sa "t_deleteFindMax" $ notEmpty $+        C.deleteFindMax =*= Map.deleteFindMax+  , prop sa "t_updateMin" $+        C.updateMinWithKey kvfm =*= Map.updateMinWithKey kvfm+  , prop sa "t_updateMax" $+        C.updateMaxWithKey kvfm =*= Map.updateMaxWithKey kvfm+  , prop sa "t_updateMinWithKey" $+        C.updateMinWithKey kvfm =*= Map.updateMinWithKey kvfm+  , prop sa "t_updateMaxWithKey" $+        C.updateMaxWithKey kvfm =*= Map.updateMaxWithKey kvfm+  , prop sa "t_minView" $+        unfoldr C.minView =*= unfoldr Map.minView+  , prop sa "t_maxView" $+        unfoldr C.maxView =*= unfoldr Map.maxView+  , prop sa "t_minViewWithKey" $+        unfoldr C.minViewWithKey =*= unfoldr Map.minViewWithKey+  , prop sa "t_maxViewWithKey" $+        unfoldr C.maxViewWithKey =*= unfoldr Map.maxViewWithKey++  , prop sa "t_foldMap" $+        foldMap Sum =*= foldMap Sum+  ]+  where+    prop sa' name q = [testProperty name $ q sa']+    pmprop sa' name t = [+       testProperty (name ++ "_general") $ general+     , testProperty (name ++ "_present") $ present+     , testProperty (name ++ "_missing") $ missing+     ]+     where+       general k   kvs = t sa' kvs k+       present k v kvs = t sa' ((k, v):kvs) k+       missing k   kvs = t sa' (filter ((/= k) . fst) kvs) k++    sa = sameAs w++    sameAs :: (CritBitKey k, Ord k)+           => k -> SameAs (CritBit k V) (Map k V) [(k, V)]+    sameAs _ = SameAs C.fromList C.toList Map.fromList Map.toList++properties :: [Test]+properties = [+    testGroup "text" $ propertiesFor T.empty+  , testGroup "bytestring" $ propertiesFor B.empty+  , testGroup "vector" [+      testGroup "unboxed" [+        testGroup "Word8" $ propertiesFor (G.empty :: U.Vector Word8)+      , testGroup "Word16" $ propertiesFor (G.empty :: U.Vector Word16)+      , testGroup "Word32" $ propertiesFor (G.empty :: U.Vector Word32)+      , testGroup "Word64" $ propertiesFor (G.empty :: U.Vector Word64)+      , testGroup "Word" $ propertiesFor (G.empty :: U.Vector Word)+      , testGroup "Char" $ propertiesFor (G.empty :: U.Vector Char)+      ]+  ]+  ]++instance (Eq k, Show k, Eq v, Show v) => Eq' (CritBit k v) (Map k v) where+   c =^= m = C.toList c =^= Map.toList m++instance (Eq' a1 b1, Eq k, Show k, Eq v, Show v) => Eq' (a1, CritBit k v) (b1, Map k v) where+  (a1, a2) =^= (b1, b2) = a1 =^= b1 .&&. a2 =^= b2++-- Handy functions for fiddling with from ghci.++blist :: [B.ByteString] -> CritBit B.ByteString Word8+blist = C.fromList . flip zip [0..]++tlist :: [T.Text] -> CritBit T.Text Word8+tlist = C.fromList . flip zip [0..]++mlist :: [B.ByteString] -> Map B.ByteString Word8+mlist = Map.fromList . flip zip [0..]
+ tests/Properties/Set.hs view
@@ -0,0 +1,121 @@+{-# LANGUAGE CPP, MultiParamTypeClasses, FlexibleInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module Properties.Set+    where++import qualified Data.ByteString.Char8 as B+import Data.CritBit.Map.Lazy (CritBitKey, byteCount)+import qualified Data.CritBit.Set as C+import Data.List (unfoldr, sort, nub)+import qualified Data.Set as S+import qualified Data.Text as T+import Properties.Common+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)+import Test.QuickCheck.Property ((.&&.))++kp :: (CritBitKey k) => k -> Bool+kp = even . byteCount++kii :: (CritBitKey k, Show k) => k -> Int -> Int+kii k v = byteCount k * 13 + v++propertiesFor :: Props k+propertiesFor t = concat [[]+  -- * Operators+  , prop "t_diff" $ (C.\\) =**= (S.\\)++  -- * Query+  , prop "t_null" $ C.null =*= S.null+  , prop "t_size" $ C.size =*= S.size+  , prop "t_member" $ C.member =?*= S.member+  , prop "t_notMember" $ C.notMember =?*= S.notMember+#if MIN_VERSION_containers(0,5,0)+  , prop "t_lookupLT" $ C.lookupLT =?*= S.lookupLT+  , prop "t_lookupGT" $ C.lookupGT =?*= S.lookupGT+  , prop "t_lookupLE" $ C.lookupLE =?*= S.lookupLE+  , prop "t_lookupGE" $ C.lookupGE =?*= S.lookupGE+#endif+  , prop "t_isSubsetOf" $ C.isSubsetOf =**= S.isSubsetOf+  , prop "t_isProperSubsetOf" $ C.isProperSubsetOf =**= S.isProperSubsetOf++  -- * Construction+--  , prop "t_empty" $ C.empty =^= S.empty+  , prop "t_singleton" $ notEmpty $ (C.singleton =*== S.singleton) head+  , prop "t_insert" $ C.insert =?*= S.insert+  , prop "t_delete" $ C.delete =?*= S.delete++  -- * Combine+  , prop "t_union" $ C.union =**= S.union+  , prop "t_unions" $ (C.unions . map C.fromList =*==+                         S.unions . map S.fromList) fromSmall+  , prop "t_difference" $ C.difference =**= S.difference+  , prop "t_intersection" $ C.intersection =**= S.intersection++  -- * Filter+  , prop "t_filter" $ C.filter kp =*= S.filter kp+  , prop "t_partition" $ C.partition kp =*= S.partition kp+  , prop "t_split" $ C.split =?*= S.split+  , prop "t_splitMember" $ C.splitMember =?*= S.splitMember++  -- * Map+  , prop "t_map" $ C.map kf =*= S.map kf+  , prop "t_mapMonotonic" $ C.mapMonotonic prepends =*= S.mapMonotonic prepends++  -- * Folds+  , prop "t_foldr" $ C.foldr kii 0 =*= S.foldr kii 0+  , prop "t_foldl" $ C.foldl (flip kii) 0 =*= S.foldl (flip kii) 0+  -- ** Strict folds+  , prop "t_foldr'" $ C.foldr' kii 0 =*= S.foldr' kii 0+  , prop "t_foldl'" $ C.foldl' (flip kii) 0 =*= S.foldl' (flip kii) 0++  -- * Min\/Max+  , prop "t_findMin" $ notEmpty $ C.findMin =*= S.findMin+  , prop "t_findMax" $ notEmpty $ C.findMax =*= S.findMax+  , prop "t_deleteMin" $ notEmpty $ C.deleteMin =*= S.deleteMin+  , prop "t_deleteMax" $ notEmpty $ C.deleteMax =*= S.deleteMax+  , prop "t_deleteFindMin" $ notEmpty $ C.deleteFindMin =*= S.deleteFindMin+  , prop "t_deleteFindMax" $ notEmpty $ C.deleteFindMax =*= S.deleteFindMax+  , prop "t_maxView" $ notEmpty $ unfoldr C.maxView =*= unfoldr S.maxView+  , prop "t_minView" $ notEmpty $ unfoldr C.minView =*= unfoldr S.minView++  -- * Conversion+  -- ** List+  , prop "t_elems" $ C.elems =*= S.elems+  , prop "t_toList" $ C.toList =*= S.toList+  , prop "t_fromList" $ (C.fromList =*== S.fromList) id++  -- ** Ordered list+  , prop "t_toAscList" $ C.toAscList =*= S.toAscList+#if MIN_VERSION_containers(0,5,0)+  , prop "t_toDescList" $ C.toDescList =*= S.toDescList+#endif+  , prop "t_fromAscList" $ (C.fromAscList =*== S.fromAscList) sort+  , prop "t_fromDistinctAscList" $+     (C.fromDistinctAscList =*== S.fromDistinctAscList) (nub . sort)+  ]+  where+    prop name q = [testProperty name $ q $ sameAs t]++    sameAs :: (CritBitKey k, Ord k) => k -> SameAs (C.Set k) (S.Set k) [k]+    sameAs _ = SameAs C.fromList C.toList S.fromList S.toList++properties :: [Test]+properties = [+    testGroup "text" $ propertiesFor T.empty+  , testGroup "bytestring" $ propertiesFor B.empty+  ]++instance (Show k, Eq k) => Eq' (C.Set k) (S.Set k) where+   c =^= m = C.toList c =^= S.toList m++instance (Eq' a1 b1, Eq k, Show k) => Eq' (a1, C.Set k) (b1, S.Set k) where+  (a1, a2) =^= (b1, b2) = a1 =^= b1 .&&. a2 =^= b2++-- Handy functions for fiddling with from ghci.++blist :: [B.ByteString] -> C.Set B.ByteString+blist = C.fromList++tlist :: [T.Text] -> S.Set T.Text+tlist = S.fromList