Skip to content

Commit 91eaba3

Browse files
committed
Fix #818: add unsafe functions for converting between Set and Map
1 parent 9d90611 commit 91eaba3

File tree

5 files changed

+145
-0
lines changed

5 files changed

+145
-0
lines changed

containers-tests/tests/map-properties.hs

+48
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ main = defaultMain $ testGroup "map-properties"
104104
, testCase "argSet" test_argSet
105105
, testCase "fromSet" test_fromSet
106106
, testCase "fromArgSet" test_fromArgSet
107+
, testCase "unsafeSet" test_unsafeSet
108+
, testCase "unsafeSetA" test_unsafeSetA
109+
, testCase "unsafeFromSet" test_unsafeFromSet
110+
, testCase "unsafeFromSetA" test_unsafeFromSetA
107111
, testCase "toList" test_toList
108112
, testCase "fromList" test_fromList
109113
, testCase "fromListWith" test_fromListWith
@@ -252,6 +256,10 @@ main = defaultMain $ testGroup "map-properties"
252256
, testProperty "argSet" prop_argSet
253257
, testProperty "fromSet" prop_fromSet
254258
, testProperty "fromArgSet" prop_fromArgSet
259+
, testProperty "unsafeSet" prop_unsafeSet
260+
, testProperty "unsafeSetA" prop_unsafeSetA
261+
, testProperty "unsafeFromSet" prop_unsafeFromSet
262+
, testProperty "unsafeFromSetA" prop_unsafeFromSetA
255263
, testProperty "takeWhileAntitone" prop_takeWhileAntitone
256264
, testProperty "dropWhileAntitone" prop_dropWhileAntitone
257265
, testProperty "spanAntitone" prop_spanAntitone
@@ -707,6 +715,26 @@ test_fromArgSet = do
707715
fromArgSet (Set.fromList [Arg 3 "aaa", Arg 5 "aaaaa"]) @?= fromList [(5,"aaaaa"), (3,"aaa")]
708716
fromArgSet Set.empty @?= (empty :: IMap)
709717

718+
test_unsafeSet :: Assertion
719+
test_unsafeSet = do
720+
unsafeSet (,) (fromList [(5,"a"), (3,"b")]) @?= Set.fromList [(5,"a"), (3,"b")]
721+
unsafeSet undefined (empty :: UMap) @?= (Set.empty :: Set.Set Int)
722+
723+
test_unsafeSetA :: Assertion
724+
test_unsafeSetA = do
725+
unsafeSetA (\x y -> Just (x,y)) (fromList [(5,"a"), (3,"b")]) @?= Just (Set.fromList [(5,"a"), (3,"b")])
726+
unsafeSetA undefined (empty :: UMap) @?= Identity (Set.empty :: Set.Set Int)
727+
728+
test_unsafeFromSet :: Assertion
729+
test_unsafeFromSet = do
730+
unsafeFromSet (\k -> (k+1, replicate k 'a')) (Set.fromList [2, 4]) @?= fromList [(5,"aaaa"), (3,"aa")]
731+
unsafeFromSet undefined Set.empty @?= (empty :: IMap)
732+
733+
test_unsafeFromSetA :: Assertion
734+
test_unsafeFromSetA = do
735+
unsafeFromSetA (\k -> Just (k+1, replicate k 'a')) (Set.fromList [2, 4]) @?= Just (fromList [(5,"aaaa"), (3,"aa")])
736+
unsafeFromSetA undefined Set.empty @?= Identity (empty :: IMap)
737+
710738
----------------------------------------------------------------
711739
-- Lists
712740

@@ -1672,6 +1700,26 @@ prop_fromArgSet ys =
16721700
let xs = List.nubBy ((==) `on` fst) ys
16731701
in fromArgSet (Set.fromList $ List.map (uncurry Arg) xs) == fromList xs
16741702

1703+
prop_unsafeSet :: [(Int, Int)] -> Bool
1704+
prop_unsafeSet ys =
1705+
let xs = List.nubBy ((==) `on` fst) ys
1706+
in unsafeSet (,) (fromList xs) == Set.fromList xs
1707+
1708+
prop_unsafeSetA :: [(Int, Int)] -> Bool
1709+
prop_unsafeSetA ys =
1710+
let xs = List.nubBy ((==) `on` fst) ys
1711+
in unsafeSetA (\x y -> Identity (x,y)) (fromList xs) == Identity (Set.fromList xs)
1712+
1713+
prop_unsafeFromSet :: [(Int, Int)] -> Bool
1714+
prop_unsafeFromSet ys =
1715+
let xs = List.nubBy ((==) `on` fst) ys
1716+
in unsafeFromSet id (Set.fromList xs) == fromList xs
1717+
1718+
prop_unsafeFromSetA :: [(Int, Int)] -> Bool
1719+
prop_unsafeFromSetA ys =
1720+
let xs = List.nubBy ((==) `on` fst) ys
1721+
in unsafeFromSetA Identity (Set.fromList xs) == Identity (fromList xs)
1722+
16751723
prop_eq :: Map Int A -> Map Int A -> Property
16761724
prop_eq m1 m2 = (m1 == m2) === (toList m1 == toList m2)
16771725

containers/src/Data/Map/Internal.hs

+56
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,10 @@ module Data.Map.Internal (
270270
, argSet
271271
, fromSet
272272
, fromArgSet
273+
, unsafeSet
274+
, unsafeSetA
275+
, unsafeFromSet
276+
, unsafeFromSetA
273277

274278
-- ** Lists
275279
, toList
@@ -3504,6 +3508,58 @@ fromArgSet :: Set.Set (Arg k a) -> Map k a
35043508
fromArgSet Set.Tip = Tip
35053509
fromArgSet (Set.Bin sz (Arg x v) l r) = Bin sz x v (fromArgSet l) (fromArgSet r)
35063510

3511+
-- | \(O(n)\). Build a set from the elements in a map and a function which for each
3512+
-- element computes its value. The function must preserve the relative ordering
3513+
-- of the keys. /The precondition is not checked./
3514+
--
3515+
-- > unsafeSet id (fromList [(5,"a"), (3,"b")]) == Data.Set.fromList [(3,"b"),(5,"a")]
3516+
-- > unsafeSet undefined empty == Data.Set.empty
3517+
3518+
unsafeSet :: (k -> a -> b) -> Map k a -> Set.Set b
3519+
unsafeSet f = go
3520+
where
3521+
go Tip = Set.Tip
3522+
go (Bin sz kx x l r) = Set.Bin sz (f kx x) (go l) (go r)
3523+
3524+
-- | \(O(n)\). Build a set from the elements in a map and a function which for each
3525+
-- element computes its value inside an 'Applicative'. The function must preserve
3526+
-- the relative ordering of the keys. /The precondition is not checked./
3527+
--
3528+
-- > unsafeSetA Identity (fromList [(5,"a"), (3,"b")]) == Data.Set.fromList [(3,"b"),(5,"a")]
3529+
-- > unsafeSetA undefined empty == Identity (Data.Set.empty)
3530+
3531+
unsafeSetA :: Applicative t => (k -> a -> t b) -> Map k a -> t (Set.Set b)
3532+
unsafeSetA f = go
3533+
where
3534+
go Tip = pure Set.Tip
3535+
go (Bin sz kx x l r) = liftA3 (Set.Bin sz) (f kx x) (go l) (go r)
3536+
3537+
-- | \(O(n)\). Build a map from a set of elements and a function which for each
3538+
-- element computes its key and value. The function must preserve the relative
3539+
-- ordering of the elements. /The precondition is not checked./
3540+
--
3541+
-- > unsafeFromSet id (Data.Set.fromList [(3,"aaa"), (5,"aaaaa")]) == fromList [(5,"aaaaa"), (3,"aaa")]
3542+
-- > unsafeFromSet undefined Data.Set.empty == empty
3543+
3544+
unsafeFromSet :: (b -> (k, a)) -> Set.Set b -> Map k a
3545+
unsafeFromSet f = go
3546+
where
3547+
go Set.Tip = Tip
3548+
go (Set.Bin sz x l r) = uncurry (Bin sz) (f x) (go l) (go r)
3549+
3550+
-- | \(O(n)\). Build a map from a set of elements and a function which for each
3551+
-- element computes its key and value inside an 'Applicative'. The function must
3552+
-- preserve the relative ordering of the elements. /The precondition is not checked./
3553+
--
3554+
-- > unsafeFromSetA Identity (Data.Set.fromList [(3,"aaa"), (5,"aaaaa")]) == Identity (fromList [(5,"aaaaa"), (3,"aaa")])
3555+
-- > unsafeFromSetA undefined Data.Set.empty == Identity empty
3556+
3557+
unsafeFromSetA :: Applicative t => (b -> t (k, a)) -> Set.Set b -> t (Map k a)
3558+
unsafeFromSetA f = go
3559+
where
3560+
go Set.Tip = pure Tip
3561+
go (Set.Bin sz x l r) = liftA3 (uncurry (Bin sz)) (f x) (go l) (go r)
3562+
35073563
{--------------------------------------------------------------------
35083564
Lists
35093565
--------------------------------------------------------------------}

containers/src/Data/Map/Lazy.hs

+4
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ module Data.Map.Lazy (
9999
, singleton
100100
, fromSet
101101
, fromArgSet
102+
, unsafeFromSet
103+
, unsafeFromSetA
102104

103105
-- ** From Unordered Lists
104106
, fromList
@@ -218,6 +220,8 @@ module Data.Map.Lazy (
218220
, assocs
219221
, keysSet
220222
, argSet
223+
, unsafeSet
224+
, unsafeSetA
221225

222226
-- ** Lists
223227
, toList

containers/src/Data/Map/Strict.hs

+4
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ module Data.Map.Strict
114114
, singleton
115115
, fromSet
116116
, fromArgSet
117+
, unsafeFromSet
118+
, unsafeFromSetA
117119

118120
-- ** From Unordered Lists
119121
, fromList
@@ -233,6 +235,8 @@ module Data.Map.Strict
233235
, assocs
234236
, keysSet
235237
, argSet
238+
, unsafeSet
239+
, unsafeSetA
236240

237241
-- ** Lists
238242
, toList

containers/src/Data/Map/Strict/Internal.hs

+33
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,10 @@ module Data.Map.Strict.Internal
232232
, argSet
233233
, fromSet
234234
, fromArgSet
235+
, unsafeSet
236+
, unsafeSetA
237+
, unsafeFromSet
238+
, unsafeFromSetA
235239

236240
-- ** Lists
237241
, toList
@@ -420,6 +424,8 @@ import Data.Map.Internal
420424
, toDescList
421425
, union
422426
, unions
427+
, unsafeSet
428+
, unsafeSetA
423429
, withoutKeys )
424430

425431
import Data.Map.Internal.Debug (valid)
@@ -1476,6 +1482,33 @@ fromArgSet :: Set.Set (Arg k a) -> Map k a
14761482
fromArgSet Set.Tip = Tip
14771483
fromArgSet (Set.Bin sz (Arg x v) l r) = v `seq` Bin sz x v (fromArgSet l) (fromArgSet r)
14781484

1485+
-- | \(O(n)\). Build a map from a set of elements and a function which for each
1486+
-- element computes its key and value. The function must preserve the relative
1487+
-- ordering of the elements. /The precondition is not checked./
1488+
--
1489+
-- > unsafeFromSet id (Data.Set.fromList [(3,"aaa"), (5,"aaaaa")]) == fromList [(5,"aaaaa"), (3,"aaa")]
1490+
-- > unsafeFromSet undefined Data.Set.empty == empty
1491+
1492+
unsafeFromSet :: (b -> (k, a)) -> Set.Set b -> Map k a
1493+
unsafeFromSet f = go
1494+
where
1495+
go Set.Tip = Tip
1496+
go (Set.Bin sz x l r) = case f x of
1497+
(k,!v) -> Bin sz k v (go l) (go r)
1498+
1499+
-- | \(O(n)\). Build a map from a set of elements and a function which for each
1500+
-- element computes its key and value inside an 'Applicative'. The function must
1501+
-- preserve the relative ordering of the elements. /The precondition is not checked./
1502+
--
1503+
-- > unsafeFromSetA Identity (Data.Set.fromList [(3,"aaa"), (5,"aaaaa")]) == Identity (fromList [(5,"aaaaa"), (3,"aaa")])
1504+
-- > unsafeFromSetA undefined Data.Set.empty == Identity empty
1505+
1506+
unsafeFromSetA :: Applicative t => (b -> t (k, a)) -> Set.Set b -> t (Map k a)
1507+
unsafeFromSetA f = go
1508+
where
1509+
go Set.Tip = pure Tip
1510+
go (Set.Bin sz x l r) = liftA3 (\(k,!v) -> Bin sz k v) (f x) (go l) (go r)
1511+
14791512
{--------------------------------------------------------------------
14801513
Lists
14811514
--------------------------------------------------------------------}

0 commit comments

Comments
 (0)