Skip to content

Commit 6f6fa02

Browse files
committed
Strictify, simplify
Unboxed sums are lazy in their lifted fields, so we need to be explicitly strict. Using pattern synonyms cuts down tremendously on the noise.
1 parent c730baf commit 6f6fa02

File tree

4 files changed

+81
-26
lines changed

4 files changed

+81
-26
lines changed

Data/IntMap/Strict.hs

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
{-# LANGUAGE MagicHash #-}
88
{-# LANGUAGE UnboxedSums #-}
99
{-# LANGUAGE UnboxedTuples #-}
10+
{-# LANGUAGE PatternSynonyms #-}
11+
{-# LANGUAGE TypeInType #-}
12+
{-# LANGUAGE ScopedTypeVariables #-}
1013
#endif
1114

1215
#include "containers.h"
@@ -221,7 +224,7 @@ module Data.IntMap.Strict (
221224
, showTreeWith
222225
) where
223226

224-
import Prelude hiding (lookup,map,filter,foldr,foldl,null)
227+
import Prelude hiding (lookup,map,filter,foldr,foldl,null, ($!))
225228

226229
import Data.Bits
227230
import qualified Data.IntMap.Internal as L
@@ -310,6 +313,8 @@ import qualified Data.IntSet.Internal as IntSet
310313
import Utils.Containers.Internal.BitUtil
311314
#if __GLASGOW_HASKELL__ >= 802
312315
import Utils.Containers.Internal.PtrEquality (ptrEq)
316+
import Utils.Containers.Internal.UnboxedMaybe (Maybe#, pattern Nothing#, pattern Just#, toMaybe)
317+
import GHC.Exts (TYPE)
313318
#endif
314319
import Utils.Containers.Internal.StrictFold
315320
import Utils.Containers.Internal.StrictPair
@@ -336,6 +341,19 @@ import Control.Applicative (Applicative (..), liftA2)
336341
-- > map (\ v -> undefined) m == undefined -- m is not empty
337342
-- > mapKeys (\ k -> undefined) m == undefined -- m is not empty
338343

344+
#if __GLASGOW_HASKELL__ >= 802
345+
-- Annoyingly, Prelude.$! is not (yet) polykinded. So we just define
346+
-- our own.
347+
infixr 0 $!
348+
($!) :: forall r a (b :: TYPE r).
349+
(a -> b) -> a -> b
350+
f $! (!x) = f x
351+
#endif
352+
#else
353+
($!) :: (a -> b) -> a -> b
354+
f $! (!x) = f x
355+
#endif
356+
339357
{--------------------------------------------------------------------
340358
Query
341359
--------------------------------------------------------------------}
@@ -569,9 +587,11 @@ updateLookupWithKey f0 !k0 t0 = toPair $ go f0 k0 t0
569587
-- In short : @'lookup' k ('alter' f k m) = f ('lookup' k m)@.
570588
#if __GLASGOW_HASKELL__ >= 802
571589
alter :: (Maybe a -> Maybe a) -> Key -> IntMap a -> IntMap a
572-
alter f !k t = case alter# f k t of
573-
(# (# #) | #) -> t
574-
(# | t' #) -> t'
590+
alter f !k t = case alter# (\m -> case f (toMaybe m) of
591+
Nothing -> Nothing#
592+
Just x -> Just# x) k t of
593+
Nothing# -> t
594+
Just# t' -> t'
575595
{-# INLINE alter #-}
576596

577597

@@ -580,31 +600,31 @@ alter f !k t = case alter# f k t of
580600
--
581601
-- If no modifications are made to the map (# (# #) | #) is returned, otherwise
582602
-- (# | newMap #) is returned.
583-
alter# :: (Maybe a -> Maybe a) -> Key -> IntMap a -> (# (# #) | IntMap a #)
603+
alter# :: (Maybe# a -> Maybe# a) -> Key -> IntMap a -> Maybe# (IntMap a)
584604
alter# f !k t@(Bin p m l r)
585-
| nomatch k p m = case f Nothing of
586-
Nothing -> (# (# #) | #)
587-
Just !x -> (# | link k (Tip k x) p t #)
605+
| nomatch k p m = case f Nothing# of
606+
Nothing# -> Nothing#
607+
Just# !x -> Just# $! link k (Tip k x) p t
588608
| zero k m = case alter# f k l of
589-
(# (# #) | #) -> (# (# #) | #)
590-
(# | l' #) -> (# | binCheckLeft p m l' r #)
609+
Nothing# -> Nothing#
610+
Just# l' -> Just# $! binCheckLeft p m l' r
591611

592612
| otherwise = case alter# f k r of
593-
(# (# #) | #) -> (# (# #) | #)
594-
(# | r' #) -> (# | binCheckRight p m l r' #)
613+
Nothing# -> Nothing#
614+
Just# r' -> Just# $! binCheckRight p m l r'
595615

596616
alter# f k t@(Tip ky y)
597-
| k==ky = case f (Just y) of
598-
Just x -> if x `ptrEq` y
599-
then (# (# #) | #)
600-
else (# | Tip ky x #)
601-
Nothing -> (# | Nil #)
602-
| otherwise = case f Nothing of
603-
Just !x -> (# | link k (Tip k x) ky t #)
604-
Nothing -> (# (# #) | #)
605-
alter# f k Nil = case f Nothing of
606-
Just !x -> (# | Tip k x #)
607-
Nothing -> (# (# #) | #)
617+
| k==ky = case f (Just# y) of
618+
Just# !x -> if x `ptrEq` y
619+
then Nothing#
620+
else Just# (Tip ky x)
621+
Nothing# -> Just# Nil
622+
| otherwise = case f Nothing# of
623+
Just# !x -> Just# $! link k (Tip k x) ky t
624+
Nothing# -> Nothing#
625+
alter# f k Nil = case f Nothing# of
626+
Just# !x -> Just# (Tip k x)
627+
Nothing# -> Nothing#
608628

609629
#else
610630
alter :: (Maybe a -> Maybe a) -> Key -> IntMap a -> IntMap a
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{-# language MagicHash, UnboxedSums, UnboxedTuples, PatternSynonyms #-}
2+
3+
module Utils.Containers.Internal.UnboxedMaybe (Maybe#, pattern Nothing#, pattern Just#,
4+
toMaybe) where
5+
6+
type Maybe# a = (# (# #) | a #)
7+
8+
pattern Nothing# :: Maybe# a
9+
pattern Nothing# = (# (# #) | #)
10+
11+
pattern Just# :: a -> Maybe# a
12+
pattern Just# a = (# | a #)
13+
14+
{-# COMPLETE Nothing#, Just# #-}
15+
16+
toMaybe :: Maybe# a -> Maybe a
17+
toMaybe (Just# a) = Just a
18+
toMaybe _ = Nothing
19+
{-# INLINE toMaybe #-}

benchmarks/IntMap.hs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,13 @@ main = do
3434
, bench "delete" $ whnf (del keys) m
3535
, bench "update" $ whnf (upd keys) m
3636
, bench "updateLookupWithKey" $ whnf (upd' keys) m
37-
, bench "alter" $ whnf (alt keys) m
37+
, bench "alter" $ whnf (alt id keys) m
38+
39+
, bench "alter absent" $ whnf (alt id evens) m_odd
40+
, bench "alter insert" $ whnf (alt (const (Just 1)) evens) m_odd
41+
, bench "alter update" $ whnf (alt id evens) m_even
42+
, bench "alter delete" $ whnf (alt (const Nothing) evens) m
43+
3844
, bench "mapMaybe" $ whnf (M.mapMaybe maybeDel) m
3945
, bench "mapMaybeWithKey" $ whnf (M.mapMaybeWithKey (const maybeDel)) m
4046
, bench "fromList" $ whnf M.fromList elems
@@ -49,6 +55,13 @@ main = do
4955
values = [1..2^12]
5056
sum k v1 v2 = k + v1 + v2
5157
consPair k v xs = (k, v) : xs
58+
m_even = M.fromAscList elems_even :: M.IntMap Int
59+
m_odd = M.fromAscList elems_odd :: M.IntMap Int
60+
elems_even = zip evens evens
61+
elems_odd = zip odds odds
62+
evens = [2,4..bound]
63+
odds = [1,3..bound]
64+
bound = 2^12
5265

5366
add3 :: Int -> Int -> Int -> Int
5467
add3 x y z = x + y + z
@@ -89,8 +102,8 @@ upd xs m = foldl' (\m k -> M.update Just k m) m xs
89102
upd' :: [Int] -> M.IntMap Int -> M.IntMap Int
90103
upd' xs m = foldl' (\m k -> snd $ M.updateLookupWithKey (\_ a -> Just a) k m) m xs
91104

92-
alt :: [Int] -> M.IntMap Int -> M.IntMap Int
93-
alt xs m = foldl' (\m k -> M.alter id k m) m xs
105+
alt :: (Maybe Int -> Maybe Int) -> [Int] -> M.IntMap Int -> M.IntMap Int
106+
alt f xs m = foldl' (\m k -> M.alter f k m) m xs
94107

95108
maybeDel :: Int -> Maybe Int
96109
maybeDel n | n `mod` 3 == 0 = Nothing

containers.cabal

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ Library
8888
Utils.Containers.Internal.Coercions
8989
Data.Map.Internal.DeprecatedShowTree
9090
Data.IntMap.Internal.DeprecatedDebug
91+
if impl (ghc >= 7.2)
92+
other-modules:
93+
Utils.Containers.Internal.UnboxedMaybe
9194

9295
include-dirs: include
9396

0 commit comments

Comments
 (0)