Skip to content

Commit bcebc7a

Browse files
committed
Merge pull request #71 from treeowl/fmapcoerceintmap
Implement map/coerce for IntMap
2 parents b2c1c79 + ee3eb5f commit bcebc7a

File tree

7 files changed

+83
-10
lines changed

7 files changed

+83
-10
lines changed

Data/IntMap/Base.hs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@
99
#if __GLASGOW_HASKELL__ >= 708
1010
{-# LANGUAGE TypeFamilies #-}
1111
#endif
12+
-- We use cabal-generated MIN_VERSION_base to adapt to changes of base.
13+
-- Nevertheless, as a convenience, we also allow compiling without cabal by
14+
-- defining trivial MIN_VERSION_base if needed.
15+
#ifndef MIN_VERSION_base
16+
#define MIN_VERSION_base(major1,major2,minor) 0
17+
#endif
18+
1219
-----------------------------------------------------------------------------
1320
-- |
1421
-- Module : Data.IntMap.Base
@@ -240,20 +247,16 @@ import qualified GHC.Exts as GHCExts
240247
#endif
241248
import Text.Read
242249
#endif
250+
#if __GLASGOW_HASKELL__ >= 709
251+
import Data.Coerce
252+
#endif
243253

244254
-- Use macros to define strictness of functions.
245255
-- STRICT_x_OF_y denotes an y-ary function strict in the x-th parameter.
246256
-- We do not use BangPatterns, because they are not in any standard and we
247257
-- want the compilers to be compiled by as many compilers as possible.
248258
#define STRICT_1_OF_2(fn) fn arg _ | arg `seq` False = undefined
249259

250-
-- We use cabal-generated MIN_VERSION_base to adapt to changes of base.
251-
-- Nevertheless, as a convenience, we also allow compiling without cabal by
252-
-- defining trivial MIN_VERSION_base if needed.
253-
#ifndef MIN_VERSION_base
254-
#define MIN_VERSION_base(major1,major2,minor) 0
255-
#endif
256-
257260

258261
-- A "Nat" is a natural machine word (an unsigned Int)
259262
type Nat = Word
@@ -1307,6 +1310,12 @@ map f t
13071310
"map/map" forall f g xs . map f (map g xs) = map (f . g) xs
13081311
#-}
13091312
#endif
1313+
#if __GLASGOW_HASKELL__ >= 709
1314+
-- Safe coercions were introduced in 7.8, but did not play well with RULES yet.
1315+
{-# RULES
1316+
"map/coerce" map coerce = coerce
1317+
#-}
1318+
#endif
13101319

13111320
-- | /O(n)/. Map a function over all values in the map.
13121321
--

Data/IntMap/Strict.hs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
{-# LANGUAGE CPP #-}
2-
#if !defined(TESTING) && __GLASGOW_HASKELL__ >= 709
3-
{-# LANGUAGE Safe #-}
4-
#elif !defined(TESTING) && __GLASGOW_HASKELL__ >= 703
2+
#if !defined(TESTING) && __GLASGOW_HASKELL__ >= 703
53
{-# LANGUAGE Trustworthy #-}
64
#endif
75
-----------------------------------------------------------------------------
@@ -262,6 +260,9 @@ import qualified Data.IntSet.Base as IntSet
262260
import Data.Utils.BitUtil
263261
import Data.Utils.StrictFold
264262
import Data.Utils.StrictPair
263+
#if __GLASGOW_HASKELL__ >= 709
264+
import Data.Coerce
265+
#endif
265266

266267
-- $strictness
267268
--
@@ -724,6 +725,11 @@ map f t
724725
"map/map" forall f g xs . map f (map g xs) = map (f . g) xs
725726
#-}
726727
#endif
728+
#if __GLASGOW_HASKELL__ >= 709
729+
{-# RULES
730+
"map/coerce" map coerce = coerce
731+
#-}
732+
#endif
727733

728734
-- | /O(n)/. Map a function over all values in the map.
729735
--

tests-ghc/all.T

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ test('sequence001', normal, compile_and_run, ['-package containers'])
88
test('mapcoerceseq', when(compiler_ge('ghc','7.9')), compile_and_run, ['-package containers'])
99
test('mapcoercemap', when(compiler_ge('ghc','7.9')), compile_and_run, ['-package containers'])
1010
test('mapcoercesmap', when(compiler_ge('ghc','7.9')), compile_and_run, ['-package containers'])
11+
test('mapcoerceintmap', when(compiler_ge('ghc','7.9')), compile_and_run, ['-package containers'])
12+
test('mapcoerceintmapstrict', when(compiler_ge('ghc','7.9')), compile_and_run, ['-package containers'])

tests-ghc/mapcoerceintmap.hs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{-# LANGUAGE MagicHash #-}
2+
3+
import GHC.Exts hiding (fromList)
4+
import Unsafe.Coerce
5+
import Data.IntMap.Lazy
6+
7+
newtype Age = Age Int
8+
9+
fooAge :: IntMap Int -> IntMap Age
10+
fooAge = fmap Age
11+
fooCoerce :: IntMap Int -> IntMap Age
12+
fooCoerce = fmap coerce
13+
fooUnsafeCoerce :: IntMap Int -> IntMap Age
14+
fooUnsafeCoerce = fmap unsafeCoerce
15+
16+
same :: a -> b -> IO ()
17+
same x y = case reallyUnsafePtrEquality# (unsafeCoerce x) y of
18+
1# -> putStrLn "yes"
19+
_ -> putStrLn "no"
20+
21+
main = do
22+
let l = fromList [(1,1),(2,2),(3,3)]
23+
same (fooAge l) l
24+
same (fooCoerce l) l
25+
same (fooUnsafeCoerce l) l

tests-ghc/mapcoerceintmap.stdout

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
yes
2+
yes
3+
yes

tests-ghc/mapcoerceintmapstrict.hs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{-# LANGUAGE MagicHash #-}
2+
3+
import GHC.Exts hiding (fromList)
4+
import Unsafe.Coerce
5+
import Data.IntMap.Strict as IM
6+
7+
newtype Age = Age Int
8+
9+
fooAge :: IntMap Int -> IntMap Age
10+
fooAge = IM.map Age
11+
fooCoerce :: IntMap Int -> IntMap Age
12+
fooCoerce = IM.map coerce
13+
fooUnsafeCoerce :: IntMap Int -> IntMap Age
14+
fooUnsafeCoerce = IM.map unsafeCoerce
15+
16+
same :: a -> b -> IO ()
17+
same x y = case reallyUnsafePtrEquality# (unsafeCoerce x) y of
18+
1# -> putStrLn "yes"
19+
_ -> putStrLn "no"
20+
21+
main = do
22+
let l = fromList [(1,1),(2,2),(3,3)]
23+
same (fooAge l) l
24+
same (fooCoerce l) l
25+
same (fooUnsafeCoerce l) l
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
yes
2+
yes
3+
yes

0 commit comments

Comments
 (0)