Skip to content

Commit e82e287

Browse files
committed
Simplify fromDistinct{Asc,Desc}List for Set, Map
Uses only the Stack, making FromDistinctMonoState unnecessary. This implementation also allows for quick access to the last element, which may be used in fromAscListWith, mapKeysWith, etc.
1 parent 549d22b commit e82e287

File tree

3 files changed

+86
-108
lines changed

3 files changed

+86
-108
lines changed

containers/src/Data/Map/Internal.hs

Lines changed: 31 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -358,13 +358,12 @@ module Data.Map.Internal (
358358
, link
359359
, link2
360360
, glue
361-
, fromDistinctAscList_linkTop
362-
, fromDistinctAscList_linkAll
363-
, fromDistinctDescList_linkTop
364-
, fromDistinctDescList_linkAll
361+
, ascLinkTop
362+
, ascLinkAll
363+
, descLinkTop
364+
, descLinkAll
365365
, MaybeS(..)
366366
, Identity(..)
367-
, FromDistinctMonoState(..)
368367
, Stack(..)
369368
, foldl'Stack
370369

@@ -3832,28 +3831,25 @@ fromDescListWithKey f xs
38323831
-- > valid (fromDistinctAscList [(3,"b"), (5,"a")]) == True
38333832
-- > valid (fromDistinctAscList [(3,"b"), (5,"a"), (5,"b")]) == False
38343833

3835-
-- For some reason, when 'singleton' is used in fromDistinctAscList or in
3836-
-- create, it is not inlined, so we inline it manually.
3837-
38383834
-- See Note [fromDistinctAscList implementation] in Data.Set.Internal.
38393835
fromDistinctAscList :: [(k,a)] -> Map k a
3840-
fromDistinctAscList = fromDistinctAscList_linkAll . Foldable.foldl' next (State0 Nada)
3836+
fromDistinctAscList = ascLinkAll . Foldable.foldl' next Nada
38413837
where
3842-
next :: FromDistinctMonoState k a -> (k,a) -> FromDistinctMonoState k a
3843-
next (State0 stk) (!kx, x) = fromDistinctAscList_linkTop (Bin 1 kx x Tip Tip) stk
3844-
next (State1 l stk) (kx, x) = State0 (Push kx x l stk)
3838+
next :: Stack k a -> (k, a) -> Stack k a
3839+
next (Push kx x Tip stk) (!ky, y) = ascLinkTop stk 1 (singleton kx x) ky y
3840+
next stk (!kx, x) = Push kx x Tip stk
38453841
{-# INLINE fromDistinctAscList #-} -- INLINE for fusion
38463842

3847-
fromDistinctAscList_linkTop :: Map k a -> Stack k a -> FromDistinctMonoState k a
3848-
fromDistinctAscList_linkTop r@(Bin rsz _ _ _ _) (Push kx x l@(Bin lsz _ _ _ _) stk)
3849-
| rsz == lsz = fromDistinctAscList_linkTop (bin kx x l r) stk
3850-
fromDistinctAscList_linkTop l stk = State1 l stk
3851-
{-# INLINABLE fromDistinctAscList_linkTop #-}
3843+
ascLinkTop :: Stack k a -> Int -> Map k a -> k -> a -> Stack k a
3844+
ascLinkTop (Push kx x l@(Bin lsz _ _ _ _) stk) !rsz r ky y
3845+
| lsz == rsz = ascLinkTop stk sz (Bin sz kx x l r) ky y
3846+
where
3847+
sz = lsz + rsz + 1
3848+
ascLinkTop stk !_ l kx x = Push kx x l stk
38523849

3853-
fromDistinctAscList_linkAll :: FromDistinctMonoState k a -> Map k a
3854-
fromDistinctAscList_linkAll (State0 stk) = foldl'Stack (\r kx x l -> link kx x l r) Tip stk
3855-
fromDistinctAscList_linkAll (State1 r0 stk) = foldl'Stack (\r kx x l -> link kx x l r) r0 stk
3856-
{-# INLINABLE fromDistinctAscList_linkAll #-}
3850+
ascLinkAll :: Stack k a -> Map k a
3851+
ascLinkAll stk = foldl'Stack (\r kx x l -> link kx x l r) Tip stk
3852+
{-# INLINABLE ascLinkAll #-}
38573853

38583854
-- | \(O(n)\). Build a map from a descending list of distinct elements in linear time.
38593855
-- /The precondition is not checked./
@@ -3864,32 +3860,26 @@ fromDistinctAscList_linkAll (State1 r0 stk) = foldl'Stack (\r kx x l -> link kx
38643860
--
38653861
-- @since 0.5.8
38663862

3867-
-- For some reason, when 'singleton' is used in fromDistinctDescList or in
3868-
-- create, it is not inlined, so we inline it manually.
3869-
38703863
-- See Note [fromDistinctAscList implementation] in Data.Set.Internal.
38713864
fromDistinctDescList :: [(k,a)] -> Map k a
3872-
fromDistinctDescList = fromDistinctDescList_linkAll . Foldable.foldl' next (State0 Nada)
3865+
fromDistinctDescList = descLinkAll . Foldable.foldl' next Nada
38733866
where
3874-
next :: FromDistinctMonoState k a -> (k,a) -> FromDistinctMonoState k a
3875-
next (State0 stk) (!kx, x) = fromDistinctDescList_linkTop (Bin 1 kx x Tip Tip) stk
3876-
next (State1 r stk) (kx, x) = State0 (Push kx x r stk)
3867+
next :: Stack k a -> (k, a) -> Stack k a
3868+
next (Push ky y Tip stk) (!kx, x) = descLinkTop kx x 1 (singleton ky y) stk
3869+
next stk (ky, y) = Push ky y Tip stk
38773870
{-# INLINE fromDistinctDescList #-} -- INLINE for fusion
38783871

3879-
fromDistinctDescList_linkTop :: Map k a -> Stack k a -> FromDistinctMonoState k a
3880-
fromDistinctDescList_linkTop l@(Bin lsz _ _ _ _) (Push kx x r@(Bin rsz _ _ _ _) stk)
3881-
| lsz == rsz = fromDistinctDescList_linkTop (bin kx x l r) stk
3882-
fromDistinctDescList_linkTop r stk = State1 r stk
3883-
{-# INLINABLE fromDistinctDescList_linkTop #-}
3884-
3885-
fromDistinctDescList_linkAll :: FromDistinctMonoState k a -> Map k a
3886-
fromDistinctDescList_linkAll (State0 stk) = foldl'Stack (\l kx x r -> link kx x l r) Tip stk
3887-
fromDistinctDescList_linkAll (State1 l0 stk) = foldl'Stack (\l kx x r -> link kx x l r) l0 stk
3888-
{-# INLINABLE fromDistinctDescList_linkAll #-}
3872+
descLinkTop :: k -> a -> Int -> Map k a -> Stack k a -> Stack k a
3873+
descLinkTop kx x !lsz l (Push ky y r@(Bin rsz _ _ _ _) stk)
3874+
| lsz == rsz = descLinkTop kx x sz (Bin sz ky y l r) stk
3875+
where
3876+
sz = lsz + rsz + 1
3877+
descLinkTop ky y !_ r stk = Push ky y r stk
3878+
{-# INLINABLE descLinkTop #-}
38893879

3890-
data FromDistinctMonoState k a
3891-
= State0 !(Stack k a)
3892-
| State1 !(Map k a) !(Stack k a)
3880+
descLinkAll :: Stack k a -> Map k a
3881+
descLinkAll stk = foldl'Stack (\l kx x r -> link kx x l r) Tip stk
3882+
{-# INLINABLE descLinkAll #-}
38933883

38943884
data Stack k a = Push !k a !(Map k a) !(Stack k a) | Nada
38953885

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

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -331,11 +331,10 @@ import Data.Map.Internal
331331
, filterAMissing
332332
, merge
333333
, mergeA
334-
, fromDistinctAscList_linkTop
335-
, fromDistinctAscList_linkAll
336-
, fromDistinctDescList_linkTop
337-
, fromDistinctDescList_linkAll
338-
, FromDistinctMonoState (..)
334+
, ascLinkTop
335+
, ascLinkAll
336+
, descLinkTop
337+
, descLinkAll
339338
, Stack (..)
340339
, (!)
341340
, (!?)
@@ -1733,16 +1732,13 @@ fromDescListWithKey f xs0 = fromDistinctDescList xs1
17331732
-- > valid (fromDistinctAscList [(3,"b"), (5,"a")]) == True
17341733
-- > valid (fromDistinctAscList [(3,"b"), (5,"a"), (5,"b")]) == False
17351734

1736-
-- For some reason, when 'singleton' is used in fromDistinctAscList or in
1737-
-- create, it is not inlined, so we inline it manually.
1738-
17391735
-- See Note [fromDistinctAscList implementation] in Data.Set.Internal.
17401736
fromDistinctAscList :: [(k,a)] -> Map k a
1741-
fromDistinctAscList = fromDistinctAscList_linkAll . Foldable.foldl' next (State0 Nada)
1737+
fromDistinctAscList = ascLinkAll . Foldable.foldl' next Nada
17421738
where
1743-
next :: FromDistinctMonoState k a -> (k,a) -> FromDistinctMonoState k a
1744-
next (State0 stk) (!kx, !x) = fromDistinctAscList_linkTop (Bin 1 kx x Tip Tip) stk
1745-
next (State1 l stk) (!kx, !x) = State0 (Push kx x l stk)
1739+
next :: Stack k a -> (k, a) -> Stack k a
1740+
next (Push kx x Tip stk) (!ky, !y) = ascLinkTop stk 1 (singleton kx x) ky y
1741+
next stk (!kx, !x) = Push kx x Tip stk
17461742
{-# INLINE fromDistinctAscList #-} -- INLINE for fusion
17471743

17481744
-- | \(O(n)\). Build a map from a descending list of distinct elements in linear time.
@@ -1752,14 +1748,11 @@ fromDistinctAscList = fromDistinctAscList_linkAll . Foldable.foldl' next (State0
17521748
-- > valid (fromDistinctDescList [(5,"a"), (3,"b")]) == True
17531749
-- > valid (fromDistinctDescList [(5,"a"), (3,"b"), (3,"a")]) == False
17541750

1755-
-- For some reason, when 'singleton' is used in fromDistinctDescList or in
1756-
-- create, it is not inlined, so we inline it manually.
1757-
17581751
-- See Note [fromDistinctAscList implementation] in Data.Set.Internal.
17591752
fromDistinctDescList :: [(k,a)] -> Map k a
1760-
fromDistinctDescList = fromDistinctDescList_linkAll . Foldable.foldl' next (State0 Nada)
1753+
fromDistinctDescList = descLinkAll . Foldable.foldl' next Nada
17611754
where
1762-
next :: FromDistinctMonoState k a -> (k,a) -> FromDistinctMonoState k a
1763-
next (State0 stk) (!kx, !x) = fromDistinctDescList_linkTop (Bin 1 kx x Tip Tip) stk
1764-
next (State1 r stk) (!kx, !x) = State0 (Push kx x r stk)
1755+
next :: Stack k a -> (k, a) -> Stack k a
1756+
next (Push ky y Tip stk) (!kx, !x) = descLinkTop kx x 1 (singleton ky y) stk
1757+
next stk (!ky, !y) = Push ky y Tip stk
17651758
{-# INLINE fromDistinctDescList #-} -- INLINE for fusion

containers/src/Data/Set/Internal.hs

Lines changed: 43 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,60 +1207,50 @@ combineEq (x : xs) = combineEq' x xs
12071207
-- | \(O(n)\). Build a set from an ascending list of distinct elements in linear time.
12081208
-- /The precondition (input list is strictly ascending) is not checked./
12091209

1210-
-- For some reason, when 'singleton' is used in fromDistinctAscList or in
1211-
-- create, it is not inlined, so we inline it manually.
1212-
12131210
-- See Note [fromDistinctAscList implementation]
12141211
fromDistinctAscList :: [a] -> Set a
1215-
fromDistinctAscList = fromDistinctAscList_linkAll . Foldable.foldl' next (State0 Nada)
1212+
fromDistinctAscList = ascLinkAll . Foldable.foldl' next Nada
12161213
where
1217-
next :: FromDistinctMonoState a -> a -> FromDistinctMonoState a
1218-
next (State0 stk) !x = fromDistinctAscList_linkTop (Bin 1 x Tip Tip) stk
1219-
next (State1 l stk) x = State0 (Push x l stk)
1214+
next :: Stack a -> a -> Stack a
1215+
next (Push x Tip stk) !y = ascLinkTop stk 1 (singleton x) y
1216+
next stk !x = Push x Tip stk
12201217
{-# INLINE fromDistinctAscList #-} -- INLINE for fusion
12211218

1222-
fromDistinctAscList_linkTop :: Set a -> Stack a -> FromDistinctMonoState a
1223-
fromDistinctAscList_linkTop r@(Bin rsz _ _ _) (Push x l@(Bin lsz _ _ _) stk)
1224-
| rsz == lsz = fromDistinctAscList_linkTop (bin x l r) stk
1225-
fromDistinctAscList_linkTop l stk = State1 l stk
1226-
{-# INLINABLE fromDistinctAscList_linkTop #-}
1219+
ascLinkTop :: Stack a -> Int -> Set a -> a -> Stack a
1220+
ascLinkTop (Push x l@(Bin lsz _ _ _) stk) !rsz r y
1221+
| lsz == rsz = ascLinkTop stk sz (Bin sz x l r) y
1222+
where
1223+
sz = lsz + rsz + 1
1224+
ascLinkTop stk !_ r y = Push y r stk
12271225

1228-
fromDistinctAscList_linkAll :: FromDistinctMonoState a -> Set a
1229-
fromDistinctAscList_linkAll (State0 stk) = foldl'Stack (\r x l -> link x l r) Tip stk
1230-
fromDistinctAscList_linkAll (State1 r0 stk) = foldl'Stack (\r x l -> link x l r) r0 stk
1231-
{-# INLINABLE fromDistinctAscList_linkAll #-}
1226+
ascLinkAll :: Stack a -> Set a
1227+
ascLinkAll stk = foldl'Stack (\r x l -> link x l r) Tip stk
1228+
{-# INLINABLE ascLinkAll #-}
12321229

12331230
-- | \(O(n)\). Build a set from a descending list of distinct elements in linear time.
12341231
-- /The precondition (input list is strictly descending) is not checked./
12351232
--
12361233
-- @since 0.5.8
12371234

1238-
-- For some reason, when 'singleton' is used in fromDistinctDescList or in
1239-
-- create, it is not inlined, so we inline it manually.
1240-
12411235
-- See Note [fromDistinctAscList implementation]
12421236
fromDistinctDescList :: [a] -> Set a
1243-
fromDistinctDescList = fromDistinctDescList_linkAll . Foldable.foldl' next (State0 Nada)
1237+
fromDistinctDescList = descLinkAll . Foldable.foldl' next Nada
12441238
where
1245-
next :: FromDistinctMonoState a -> a -> FromDistinctMonoState a
1246-
next (State0 stk) !x = fromDistinctDescList_linkTop (Bin 1 x Tip Tip) stk
1247-
next (State1 r stk) x = State0 (Push x r stk)
1239+
next :: Stack a -> a -> Stack a
1240+
next (Push y Tip stk) !x = descLinkTop x 1 (singleton y) stk
1241+
next stk !y = Push y Tip stk
12481242
{-# INLINE fromDistinctDescList #-} -- INLINE for fusion
12491243

1250-
fromDistinctDescList_linkTop :: Set a -> Stack a -> FromDistinctMonoState a
1251-
fromDistinctDescList_linkTop l@(Bin lsz _ _ _) (Push x r@(Bin rsz _ _ _) stk)
1252-
| lsz == rsz = fromDistinctDescList_linkTop (bin x l r) stk
1253-
fromDistinctDescList_linkTop r stk = State1 r stk
1254-
{-# INLINABLE fromDistinctDescList_linkTop #-}
1255-
1256-
fromDistinctDescList_linkAll :: FromDistinctMonoState a -> Set a
1257-
fromDistinctDescList_linkAll (State0 stk) = foldl'Stack (\l x r -> link x l r) Tip stk
1258-
fromDistinctDescList_linkAll (State1 l0 stk) = foldl'Stack (\l x r -> link x l r) l0 stk
1259-
{-# INLINABLE fromDistinctDescList_linkAll #-}
1244+
descLinkTop :: a -> Int -> Set a -> Stack a -> Stack a
1245+
descLinkTop x !lsz l (Push y r@(Bin rsz _ _ _) stk)
1246+
| lsz == rsz = descLinkTop x sz (Bin sz y l r) stk
1247+
where
1248+
sz = lsz + rsz + 1
1249+
descLinkTop y !_ r stk = Push y r stk
12601250

1261-
data FromDistinctMonoState a
1262-
= State0 !(Stack a)
1263-
| State1 !(Set a) !(Stack a)
1251+
descLinkAll :: Stack a -> Set a
1252+
descLinkAll stk = foldl'Stack (\l x r -> link x l r) Tip stk
1253+
{-# INLINABLE descLinkAll #-}
12641254

12651255
data Stack a = Push !a !(Set a) !(Stack a) | Nada
12661256

@@ -2121,24 +2111,29 @@ validsize t
21212111
-- fromDistinctAscList is implemented by building up perfectly balanced trees
21222112
-- while we consume elements from the list one by one. A stack of
21232113
-- (root, perfectly balanced left branch) pairs is maintained, in increasing
2124-
-- order of size from top to bottom.
2125-
--
2126-
-- When we get an element from the list, we attempt to link it as the right
2127-
-- branch with the top (root, perfect left branch) of the stack to create a new
2128-
-- perfect tree. We can only do this if the left branch has size 1. If we link
2129-
-- it, we get a perfect tree of size 3. We repeat this process, merging with the
2130-
-- top of the stack as long as the sizes match. When we can't link any more, the
2131-
-- perfect tree we built so far is a potential left branch. The next element
2132-
-- we find becomes the root, and we push this new (root, left branch) on the
2133-
-- stack.
2114+
-- order of size from top to bottom. The stack reflects the binary
2115+
-- representation of the total number of elements in it, with every level having
2116+
-- a power of 2 number of elements.
2117+
--
2118+
-- When we get an element from the list, we check the (root, left branch) at the
2119+
-- top of the stack.
2120+
-- If the tree there is not empty, we push the element with an empty left child
2121+
-- on the stack.
2122+
-- If the tree is empty, the root is packed into a singleton tree to act as a
2123+
-- right branch for trees higher up the stack. It is linked with left branches
2124+
-- in the stack, but only when they have equal size. This preserves the
2125+
-- perfectly balanced property. When there is a size mismatch, the tree is
2126+
-- too small to link. It is pushed on the stack as a left branch with the new
2127+
-- element as root, awaiting a right branch which will make it large enough to
2128+
-- be linked further.
21342129
--
21352130
-- When we are out of elements, we link the (root, left branch)s in the stack
21362131
-- top to bottom to get the final tree.
21372132
--
21382133
-- How long does this take? We do O(1) work per element excluding the links.
21392134
-- Over n elements, we build trees with at most n nodes total, and each link is
2140-
-- done in O(1) using `bin`. The final linking of the stack is done in O(log n)
2141-
-- using `link` (proof below). The total time is thus O(n).
2135+
-- done in O(1) using `Bin`. The final linking of the stack is done in O(log n)
2136+
-- using `link` (proof below). The total time is thus O(n).
21422137
--
21432138
-- Additionally, the implemention is written using foldl' over the input list,
21442139
-- which makes it participate as a good consumer in list fusion.

0 commit comments

Comments
 (0)