Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lazy.fromListWith leaks references to keys?! #382

Closed
sjakobi opened this issue Mar 19, 2022 · 0 comments · Fixed by #386
Closed

Lazy.fromListWith leaks references to keys?! #382

sjakobi opened this issue Mar 19, 2022 · 0 comments · Fixed by #386
Assignees

Comments

@sjakobi
Copy link
Member

sjakobi commented Mar 19, 2022

I believe that the thunks created by the combining function contain unnecessary references to the map keys.

fromListWith :: (Eq k, Hashable k) => (v -> v -> v) -> [(k, v)] -> HashMap k v
fromListWith f = List.foldl' (\ m (k, v) -> unsafeInsertWith f k v m) empty
{-# INLINE fromListWith #-}

-- | In-place update version of insertWith
unsafeInsertWith :: forall k v. (Eq k, Hashable k)
=> (v -> v -> v) -> k -> v -> HashMap k v
-> HashMap k v
unsafeInsertWith f k0 v0 m0 = unsafeInsertWithKey (const f) k0 v0 m0
{-# INLINABLE unsafeInsertWith #-}
unsafeInsertWithKey :: forall k v. (Eq k, Hashable k)
=> (k -> v -> v -> v) -> k -> v -> HashMap k v
-> HashMap k v
unsafeInsertWithKey f k0 v0 m0 = runST (go h0 k0 v0 0 m0)
where
h0 = hash k0
go :: Hash -> k -> v -> Shift -> HashMap k v -> ST s (HashMap k v)
go !h !k x !_ Empty = return $! Leaf h (L k x)
go h k x s t@(Leaf hy l@(L ky y))
| hy == h = if ky == k
then return $! Leaf h (L k (f k x y))
else return $! collision h l (L k x)
| otherwise = two s h k x hy t
go h k x s t@(BitmapIndexed b ary)
| b .&. m == 0 = do
ary' <- A.insertM ary i $! Leaf h (L k x)
return $! bitmapIndexedOrFull (b .|. m) ary'
| otherwise = do
st <- A.indexM ary i
st' <- go h k x (s+bitsPerSubkey) st
A.unsafeUpdateM ary i st'
return t
where m = mask h s
i = sparseIndex b m
go h k x s t@(Full ary) = do
st <- A.indexM ary i
st' <- go h k x (s+bitsPerSubkey) st
A.unsafeUpdateM ary i st'
return t
where i = index h s
go h k x s t@(Collision hy v)
| h == hy = return $! Collision h (updateOrSnocWithKey (\key a b -> (# f key a b #) ) k x v)
| otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)
{-# INLINABLE unsafeInsertWithKey #-}

Core:

fromListWith
  = \ (@k)
      (@v)
      _ [Occ=Dead]
      ($dHashable :: Hashable k)
      (eta :: v -> v -> v)
      (eta1 :: [(k, v)]) ->
      joinrec {
        go1 [Occ=LoopBreaker, Dmd=SCS(C1(L))]
          :: [(k, v)] -> HashMap k v -> HashMap k v
        [LclId[JoinId(2)], Arity=2, Str=<1L><1L>, Unf=OtherCon []]
        go1 (ds :: [(k, v)]) (eta2 [OS=OneShot] :: HashMap k v)
          = case ds of {
              [] -> eta2;
              : y ys ->
                case y of { (k1, v1) ->
                jump go1
                  ys
                  ($wunsafeInsertWithKey
                     @k @v $dHashable (\ _ [Occ=Dead] -> eta) k1 v1 eta2)
                }
            }; } in
      jump go1 eta1 (Empty @k @v)
@sjakobi sjakobi self-assigned this Mar 20, 2022
sjakobi added a commit that referenced this issue Mar 20, 2022
sjakobi added a commit that referenced this issue Mar 22, 2022
sjakobi added a commit that referenced this issue Mar 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant