@@ -1208,60 +1208,50 @@ combineEq (x : xs) = combineEq' x xs
12081208-- | \(O(n)\). Build a set from an ascending list of distinct elements in linear time.
12091209-- /The precondition (input list is strictly ascending) is not checked./
12101210
1211- -- For some reason, when 'singleton' is used in fromDistinctAscList or in
1212- -- create, it is not inlined, so we inline it manually.
1213-
12141211-- See Note [fromDistinctAscList implementation]
12151212fromDistinctAscList :: [a ] -> Set a
1216- fromDistinctAscList = fromDistinctAscList_linkAll . Foldable. foldl' next ( State0 Nada )
1213+ fromDistinctAscList = ascLinkAll . Foldable. foldl' next Nada
12171214 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
12211218{-# INLINE fromDistinctAscList #-} -- INLINE for fusion
12221219
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
12281226
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 #-}
12331230
12341231-- | \(O(n)\). Build a set from a descending list of distinct elements in linear time.
12351232-- /The precondition (input list is strictly descending) is not checked./
12361233--
12371234-- @since 0.5.8
12381235
1239- -- For some reason, when 'singleton' is used in fromDistinctDescList or in
1240- -- create, it is not inlined, so we inline it manually.
1241-
12421236-- See Note [fromDistinctAscList implementation]
12431237fromDistinctDescList :: [a ] -> Set a
1244- fromDistinctDescList = fromDistinctDescList_linkAll . Foldable. foldl' next ( State0 Nada )
1238+ fromDistinctDescList = descLinkAll . Foldable. foldl' next Nada
12451239 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
12491243{-# INLINE fromDistinctDescList #-} -- INLINE for fusion
12501244
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
12611251
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 #-}
12651255
12661256data Stack a = Push ! a ! (Set a ) ! (Stack a ) | Nada
12671257
@@ -2183,24 +2173,29 @@ validsize t
21832173-- fromDistinctAscList is implemented by building up perfectly balanced trees
21842174-- while we consume elements from the list one by one. A stack of
21852175-- (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.
21962191--
21972192-- When we are out of elements, we link the (root, left branch)s in the stack
21982193-- top to bottom to get the final tree.
21992194--
22002195-- How long does this take? We do O(1) work per element excluding the links.
22012196-- 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).
22042199--
22052200-- Additionally, the implemention is written using foldl' over the input list,
22062201-- which makes it participate as a good consumer in list fusion.
0 commit comments