@@ -1207,60 +1207,50 @@ combineEq (x : xs) = combineEq' x xs
1207
1207
-- | \(O(n)\). Build a set from an ascending list of distinct elements in linear time.
1208
1208
-- /The precondition (input list is strictly ascending) is not checked./
1209
1209
1210
- -- For some reason, when 'singleton' is used in fromDistinctAscList or in
1211
- -- create, it is not inlined, so we inline it manually.
1212
-
1213
1210
-- See Note [fromDistinctAscList implementation]
1214
1211
fromDistinctAscList :: [a ] -> Set a
1215
- fromDistinctAscList = fromDistinctAscList_linkAll . Foldable. foldl' next ( State0 Nada )
1212
+ fromDistinctAscList = ascLinkAll . Foldable. foldl' next Nada
1216
1213
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
1220
1217
{-# INLINE fromDistinctAscList #-} -- INLINE for fusion
1221
1218
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
1227
1225
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 #-}
1232
1229
1233
1230
-- | \(O(n)\). Build a set from a descending list of distinct elements in linear time.
1234
1231
-- /The precondition (input list is strictly descending) is not checked./
1235
1232
--
1236
1233
-- @since 0.5.8
1237
1234
1238
- -- For some reason, when 'singleton' is used in fromDistinctDescList or in
1239
- -- create, it is not inlined, so we inline it manually.
1240
-
1241
1235
-- See Note [fromDistinctAscList implementation]
1242
1236
fromDistinctDescList :: [a ] -> Set a
1243
- fromDistinctDescList = fromDistinctDescList_linkAll . Foldable. foldl' next ( State0 Nada )
1237
+ fromDistinctDescList = descLinkAll . Foldable. foldl' next Nada
1244
1238
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
1248
1242
{-# INLINE fromDistinctDescList #-} -- INLINE for fusion
1249
1243
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
1260
1250
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 #-}
1264
1254
1265
1255
data Stack a = Push ! a ! (Set a ) ! (Stack a ) | Nada
1266
1256
@@ -2121,24 +2111,29 @@ validsize t
2121
2111
-- fromDistinctAscList is implemented by building up perfectly balanced trees
2122
2112
-- while we consume elements from the list one by one. A stack of
2123
2113
-- (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.
2134
2129
--
2135
2130
-- When we are out of elements, we link the (root, left branch)s in the stack
2136
2131
-- top to bottom to get the final tree.
2137
2132
--
2138
2133
-- How long does this take? We do O(1) work per element excluding the links.
2139
2134
-- 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).
2142
2137
--
2143
2138
-- Additionally, the implemention is written using foldl' over the input list,
2144
2139
-- which makes it participate as a good consumer in list fusion.
0 commit comments