@@ -1208,60 +1208,50 @@ combineEq (x : xs) = combineEq' x xs
1208
1208
-- | \(O(n)\). Build a set from an ascending list of distinct elements in linear time.
1209
1209
-- /The precondition (input list is strictly ascending) is not checked./
1210
1210
1211
- -- For some reason, when 'singleton' is used in fromDistinctAscList or in
1212
- -- create, it is not inlined, so we inline it manually.
1213
-
1214
1211
-- See Note [fromDistinctAscList implementation]
1215
1212
fromDistinctAscList :: [a ] -> Set a
1216
- fromDistinctAscList = fromDistinctAscList_linkAll . Foldable. foldl' next ( State0 Nada )
1213
+ fromDistinctAscList = ascLinkAll . Foldable. foldl' next Nada
1217
1214
where
1218
- next :: FromDistinctMonoState a -> a -> FromDistinctMonoState a
1219
- next (State0 stk) ! x = fromDistinctAscList_linkTop ( Bin 1 x Tip Tip ) stk
1220
- next ( State1 l stk) x = State0 ( Push x l stk)
1215
+ next :: Stack a -> a -> Stack a
1216
+ next (Push x Tip stk) ! y = ascLinkTop stk 1 (singleton x) y
1217
+ next stk ! x = Push x Tip stk
1221
1218
{-# INLINE fromDistinctAscList #-} -- INLINE for fusion
1222
1219
1223
- fromDistinctAscList_linkTop :: Set a -> Stack a -> FromDistinctMonoState a
1224
- fromDistinctAscList_linkTop r@ (Bin rsz _ _ _) (Push x l@ (Bin lsz _ _ _) stk)
1225
- | rsz == lsz = fromDistinctAscList_linkTop (bin x l r) stk
1226
- fromDistinctAscList_linkTop l stk = State1 l stk
1227
- {-# INLINABLE fromDistinctAscList_linkTop #-}
1220
+ ascLinkTop :: Stack a -> Int -> Set a -> a -> Stack a
1221
+ ascLinkTop (Push x l@ (Bin lsz _ _ _) stk) ! rsz r y
1222
+ | lsz == rsz = ascLinkTop stk sz (Bin sz x l r) y
1223
+ where
1224
+ sz = lsz + rsz + 1
1225
+ ascLinkTop stk ! _ r y = Push y r stk
1228
1226
1229
- fromDistinctAscList_linkAll :: FromDistinctMonoState a -> Set a
1230
- fromDistinctAscList_linkAll (State0 stk) = foldl'Stack (\ r x l -> link x l r) Tip stk
1231
- fromDistinctAscList_linkAll (State1 r0 stk) = foldl'Stack (\ r x l -> link x l r) r0 stk
1232
- {-# INLINABLE fromDistinctAscList_linkAll #-}
1227
+ ascLinkAll :: Stack a -> Set a
1228
+ ascLinkAll stk = foldl'Stack (\ r x l -> link x l r) Tip stk
1229
+ {-# INLINABLE ascLinkAll #-}
1233
1230
1234
1231
-- | \(O(n)\). Build a set from a descending list of distinct elements in linear time.
1235
1232
-- /The precondition (input list is strictly descending) is not checked./
1236
1233
--
1237
1234
-- @since 0.5.8
1238
1235
1239
- -- For some reason, when 'singleton' is used in fromDistinctDescList or in
1240
- -- create, it is not inlined, so we inline it manually.
1241
-
1242
1236
-- See Note [fromDistinctAscList implementation]
1243
1237
fromDistinctDescList :: [a ] -> Set a
1244
- fromDistinctDescList = fromDistinctDescList_linkAll . Foldable. foldl' next ( State0 Nada )
1238
+ fromDistinctDescList = descLinkAll . Foldable. foldl' next Nada
1245
1239
where
1246
- next :: FromDistinctMonoState a -> a -> FromDistinctMonoState a
1247
- next (State0 stk) ! x = fromDistinctDescList_linkTop ( Bin 1 x Tip Tip ) stk
1248
- next ( State1 r stk) x = State0 ( Push x r stk)
1240
+ next :: Stack a -> a -> Stack a
1241
+ next (Push y Tip stk) ! x = descLinkTop x 1 (singleton y ) stk
1242
+ next stk ! y = Push y Tip stk
1249
1243
{-# INLINE fromDistinctDescList #-} -- INLINE for fusion
1250
1244
1251
- fromDistinctDescList_linkTop :: Set a -> Stack a -> FromDistinctMonoState a
1252
- fromDistinctDescList_linkTop l@ (Bin lsz _ _ _) (Push x r@ (Bin rsz _ _ _) stk)
1253
- | lsz == rsz = fromDistinctDescList_linkTop (bin x l r) stk
1254
- fromDistinctDescList_linkTop r stk = State1 r stk
1255
- {-# INLINABLE fromDistinctDescList_linkTop #-}
1256
-
1257
- fromDistinctDescList_linkAll :: FromDistinctMonoState a -> Set a
1258
- fromDistinctDescList_linkAll (State0 stk) = foldl'Stack (\ l x r -> link x l r) Tip stk
1259
- fromDistinctDescList_linkAll (State1 l0 stk) = foldl'Stack (\ l x r -> link x l r) l0 stk
1260
- {-# INLINABLE fromDistinctDescList_linkAll #-}
1245
+ descLinkTop :: a -> Int -> Set a -> Stack a -> Stack a
1246
+ descLinkTop x ! lsz l (Push y r@ (Bin rsz _ _ _) stk)
1247
+ | lsz == rsz = descLinkTop x sz (Bin sz y l r) stk
1248
+ where
1249
+ sz = lsz + rsz + 1
1250
+ descLinkTop y ! _ r stk = Push y r stk
1261
1251
1262
- data FromDistinctMonoState a
1263
- = State0 ! ( Stack a )
1264
- | State1 ! ( Set a ) ! ( Stack a )
1252
+ descLinkAll :: Stack a -> Set a
1253
+ descLinkAll stk = foldl'Stack ( \ l x r -> link x l r) Tip stk
1254
+ {-# INLINABLE descLinkAll #-}
1265
1255
1266
1256
data Stack a = Push ! a ! (Set a ) ! (Stack a ) | Nada
1267
1257
@@ -2183,24 +2173,29 @@ validsize t
2183
2173
-- fromDistinctAscList is implemented by building up perfectly balanced trees
2184
2174
-- while we consume elements from the list one by one. A stack of
2185
2175
-- (root, perfectly balanced left branch) pairs is maintained, in increasing
2186
- -- order of size from top to bottom.
2187
- --
2188
- -- When we get an element from the list, we attempt to link it as the right
2189
- -- branch with the top (root, perfect left branch) of the stack to create a new
2190
- -- perfect tree. We can only do this if the left branch has size 1. If we link
2191
- -- it, we get a perfect tree of size 3. We repeat this process, merging with the
2192
- -- top of the stack as long as the sizes match. When we can't link any more, the
2193
- -- perfect tree we built so far is a potential left branch. The next element
2194
- -- we find becomes the root, and we push this new (root, left branch) on the
2195
- -- stack.
2176
+ -- order of size from top to bottom. The stack reflects the binary
2177
+ -- representation of the total number of elements in it, with every level having
2178
+ -- a power of 2 number of elements.
2179
+ --
2180
+ -- When we get an element from the list, we check the (root, left branch) at the
2181
+ -- top of the stack.
2182
+ -- If the tree there is not empty, we push the element with an empty left child
2183
+ -- on the stack.
2184
+ -- If the tree is empty, the root is packed into a singleton tree to act as a
2185
+ -- right branch for trees higher up the stack. It is linked with left branches
2186
+ -- in the stack, but only when they have equal size. This preserves the
2187
+ -- perfectly balanced property. When there is a size mismatch, the tree is
2188
+ -- too small to link. It is pushed on the stack as a left branch with the new
2189
+ -- element as root, awaiting a right branch which will make it large enough to
2190
+ -- be linked further.
2196
2191
--
2197
2192
-- When we are out of elements, we link the (root, left branch)s in the stack
2198
2193
-- top to bottom to get the final tree.
2199
2194
--
2200
2195
-- How long does this take? We do O(1) work per element excluding the links.
2201
2196
-- Over n elements, we build trees with at most n nodes total, and each link is
2202
- -- done in O(1) using `bin `. The final linking of the stack is done in O(log n)
2203
- -- using `link` (proof below). The total time is thus O(n).
2197
+ -- done in O(1) using `Bin `. The final linking of the stack is done in O(log n)
2198
+ -- using `link` (proof below). The total time is thus O(n).
2204
2199
--
2205
2200
-- Additionally, the implemention is written using foldl' over the input list,
2206
2201
-- which makes it participate as a good consumer in list fusion.
0 commit comments