[commit: packages/containers] master, revert-408-bugfix_394: Adding comments, and un-nesting restrictBM and withoutBM (60b9812)

git at git.haskell.org git at git.haskell.org
Mon Apr 17 21:48:01 UTC 2017


Repository : ssh://git@git.haskell.org/containers

On branches: master,revert-408-bugfix_394
Link       : http://git.haskell.org/packages/containers.git/commitdiff/60b98128c95804367eee5c7d29250ff15700adef

>---------------------------------------------------------------

commit 60b98128c95804367eee5c7d29250ff15700adef
Author: wren romano <wren at community.haskell.org>
Date:   Wed Feb 8 19:29:56 2017 -0800

    Adding comments, and un-nesting restrictBM and withoutBM
    
    The un-nesting is to guarantee that we don't accidentally close over
    things.


>---------------------------------------------------------------

60b98128c95804367eee5c7d29250ff15700adef
 Data/IntMap/Internal.hs | 96 ++++++++++++++++++++++++++++++-------------------
 1 file changed, 60 insertions(+), 36 deletions(-)

diff --git a/Data/IntMap/Internal.hs b/Data/IntMap/Internal.hs
index 262b1a9..15d83a4 100644
--- a/Data/IntMap/Internal.hs
+++ b/Data/IntMap/Internal.hs
@@ -1057,23 +1057,8 @@ withoutKeys t1@(Bin p1 m1 l1 r1) t2@(IntSet.Bin p2 m2 l2 r2)
         | nomatch p1 p2 m2  = t1
         | zero p1 m2        = withoutKeys t1 l2
         | otherwise         = withoutKeys t1 r2
-withoutKeys t1@(Bin _ _ _ _) (IntSet.Tip kx' bm') =
-    withoutBM t1 kx' bm' (IntSet.suffixBitMask + 1)
-    where
-    -- TODO(wrengr): this is still pretty naive. It could be improved by restricting @t@ on the recursive calls, so that the 'delete' in the basis case is faster. As is, this is linear in the size of the IntSet (as opposed to the previous version which was linear in the size of the IntMap; we want /O(n+m)/ at worst, just like for 'intersection').
-    withoutBM t !prefix !_ 0 = delete prefix t
-    withoutBM t prefix bmask bits =
-        case intFromNat (natFromInt bits `shiftRL` 1) of
-        bits2
-          | bmask .&. (shiftLL 1 bits2 - 1) == 0 ->
-              withoutBM t (prefix + bits2) (shiftRL bmask bits2) bits2
-          | shiftRL bmask bits2 .&. (shiftLL 1 bits2 - 1) == 0 ->
-              withoutBM t prefix bmask bits2
-          | otherwise ->
-              -- withoutKeys t (bin prefix bits2 _ _)
-              withoutBM
-                (withoutBM t (prefix + bits2) (shiftRL bmask bits2) bits2)
-                prefix bmask bits2
+withoutKeys t1@(Bin _ _ _ _) (IntSet.Tip p2 bm2) =
+    withoutBM t1 p2 bm2 (IntSet.suffixBitMask + 1)
 withoutKeys t1@(Bin _ _ _ _) IntSet.Nil = t1
 withoutKeys t1@(Tip k1 _) t2
     | k1 `IntSet.member` t2 = Nil
@@ -1081,6 +1066,31 @@ withoutKeys t1@(Tip k1 _) t2
 withoutKeys Nil _ = Nil
 
 
+-- TODO(wrengr): Right now this is still pretty naive. It essentially
+-- unpacks the 'IntSetBitMap' into a tree-representation, and then
+-- calls 'delete' on each element of the set; thus, it is
+-- /O(min(m,W) * min(n,W)/. While technically that degenerates to
+-- /O(1)/ for a fixed /W/, it's morally equivalent to /O(m * log n)/.
+-- Really, we should be able to get this down to /O(n+m)/ just like
+-- 'difference' is. One way to do this would be to restrict @t@
+-- on the recursive calls, so that the 'lookup's are cheaper. But
+-- we should be able to do even better by avoiding the call to
+-- 'lookup' entirely.
+withoutBM :: IntMap a -> IntSetPrefix -> IntSetBitMap -> Key -> IntMap a
+withoutBM t !prefix !_ 0 = delete prefix t
+withoutBM t prefix bmask bits =
+    case intFromNat (natFromInt bits `shiftRL` 1) of
+    bits2
+      | bmask .&. (shiftLL 1 bits2 - 1) == 0 ->
+          withoutBM t (prefix + bits2) (shiftRL bmask bits2) bits2
+      | shiftRL bmask bits2 .&. (shiftLL 1 bits2 - 1) == 0 ->
+          withoutBM t prefix bmask bits2
+      | otherwise ->
+          -- withoutKeys t (bin prefix bits2 _ _)
+          withoutBM
+            (withoutBM t (prefix + bits2) (shiftRL bmask bits2) bits2)
+            prefix bmask bits2
+
 {--------------------------------------------------------------------
   Intersection
 --------------------------------------------------------------------}
@@ -1114,25 +1124,8 @@ restrictKeys t1@(Bin p1 m1 l1 r1) t2@(IntSet.Bin p2 m2 l2 r2)
         | nomatch p1 p2 m2  = Nil
         | zero p1 m2        = restrictKeys t1 l2
         | otherwise         = restrictKeys t1 r2
-restrictKeys t1@(Bin _ _ _ _) (IntSet.Tip kx' bm') =
-    restrictBM t1 kx' bm' (IntSet.suffixBitMask + 1)
-    where
-    -- TODO(wrengr): this is still pretty naive. It could be improved by restricting @t@ on the recursive calls, so that the 'lookup' in the basis case is faster. As is, this is linear in the size of the IntSet (as opposed to the previous version which was linear in the size of the IntMap; we want /O(n+m)/ at worst, just like for 'intersection').
-    restrictBM t !prefix !_ 0 =
-        case lookup prefix t of
-        Nothing -> Nil
-        Just x -> Tip prefix x
-    restrictBM t prefix bmask bits =
-        case intFromNat (natFromInt bits `shiftRL` 1) of
-        bits2
-          | bmask .&. (shiftLL 1 bits2 - 1) == 0 ->
-              restrictBM t (prefix + bits2) (shiftRL bmask bits2) bits2
-          | shiftRL bmask bits2 .&. (shiftLL 1 bits2 - 1) == 0 ->
-              restrictBM t prefix bmask bits2
-          | otherwise ->
-              bin prefix bits2
-                (restrictBM t prefix bmask bits2)
-                (restrictBM t (prefix + bits2) (shiftRL bmask bits2) bits2)
+restrictKeys t1@(Bin _ _ _ _) (IntSet.Tip p2 bm2) =
+    restrictBM t1 p2 bm2 (IntSet.suffixBitMask + 1)
 restrictKeys (Bin _ _ _ _) IntSet.Nil = Nil
 restrictKeys t1@(Tip k1 _) t2
     | k1 `IntSet.member` t2 = t1
@@ -1140,6 +1133,37 @@ restrictKeys t1@(Tip k1 _) t2
 restrictKeys Nil _ = Nil
 
 
+type IntSetPrefix = Int
+type IntSetBitMap = Word
+
+-- TODO(wrengr): Right now this is still pretty naive. It essentially
+-- unpacks the 'IntSetBitMap' into a tree-representation, and then
+-- calls 'lookup' on each element of the set; thus, it is
+-- /O(min(m,W) * min(n,W)/. While technically that degenerates to
+-- /O(1)/ for a fixed /W/, it's morally equivalent to /O(m * log n)/.
+-- Really, we should be able to get this down to /O(n+m)/ just like
+-- 'intersection' is. One way to do this would be to restrict @t@
+-- on the recursive calls, so that the 'lookup's are cheaper. But
+-- we should be able to do even better by avoiding the call to
+-- 'lookup' entirely.
+restrictBM :: IntMap a -> IntSetPrefix -> IntSetBitMap -> Key -> IntMap a
+restrictBM t !prefix !_ 0 =
+    case lookup prefix t of
+    Nothing -> Nil
+    Just x -> Tip prefix x
+restrictBM t prefix bmask bits =
+    case intFromNat (natFromInt bits `shiftRL` 1) of
+    bits2
+      | bmask .&. (shiftLL 1 bits2 - 1) == 0 ->
+          restrictBM t (prefix + bits2) (shiftRL bmask bits2) bits2
+      | shiftRL bmask bits2 .&. (shiftLL 1 bits2 - 1) == 0 ->
+          restrictBM t prefix bmask bits2
+      | otherwise ->
+          bin prefix bits2
+            (restrictBM t prefix bmask bits2)
+            (restrictBM t (prefix + bits2) (shiftRL bmask bits2) bits2)
+
+
 -- | /O(n+m)/. The intersection with a combining function.
 --
 -- > intersectionWith (++) (fromList [(5, "a"), (3, "b")]) (fromList [(5, "A"), (7, "C")]) == singleton 5 "aA"



More information about the ghc-commits mailing list