@@ -72,19 +72,12 @@ sealed abstract class AndThen[-T, +R] extends (T => R) with Product with Seriali
7272 // technique implemented for `cats.effect.IO#map`
7373 g match {
7474 case atg : AndThen [R , A ] =>
75- (this , atg) match {
76- case (Single (f, indexf), Single (gs, indexg)) if indexf + indexg < fusionMaxStackDepth =>
77- Single (f.andThen(gs), indexf + indexg + 1 )
78- case (Concat (left, Single (f, indexf)), Single (gs, indexg)) if indexf + indexg < fusionMaxStackDepth =>
79- Concat (left, Single (f.andThen(gs), indexf + indexg + 1 ))
80- case _ =>
81- Concat (this , atg)
82- }
75+ AndThen .andThen(this , atg)
8376 case _ =>
8477 this match {
85- case Single (f, index) if index != fusionMaxStackDepth =>
78+ case Single (f, index) if index < fusionMaxStackDepth =>
8679 Single (f.andThen(g), index + 1 )
87- case Concat (left, Single (f, index)) if index != fusionMaxStackDepth =>
80+ case Concat (left, Single (f, index)) if index < fusionMaxStackDepth =>
8881 Concat (left, Single (f.andThen(g), index + 1 ))
8982 case _ =>
9083 Concat (this , Single (g, 0 ))
@@ -95,20 +88,12 @@ sealed abstract class AndThen[-T, +R] extends (T => R) with Product with Seriali
9588 // Fusing calls up to a certain threshold, using the fusion
9689 // technique implemented for `cats.effect.IO#map`
9790 g match {
98- case atg : AndThen [A , T ] =>
99- (this , atg) match {
100- case (Single (f, indexf), Single (gs, indexg)) if indexf + indexg < fusionMaxStackDepth =>
101- Single (f.compose(gs), indexf + indexg + 1 )
102- case (Concat (Single (f, indexf), right), Single (gs, indexg)) if indexf + indexg < fusionMaxStackDepth =>
103- Concat (Single (f.compose(gs), indexf + indexg + 1 ), right)
104- case _ =>
105- Concat (atg, this )
106- }
91+ case atg : AndThen [A , T ] => AndThen .andThen(atg, this )
10792 case _ =>
10893 this match {
109- case Single (f, index) if index != fusionMaxStackDepth =>
94+ case Single (f, index) if index < fusionMaxStackDepth =>
11095 Single (f.compose(g), index + 1 )
111- case Concat (Single (f, index), right) if index != fusionMaxStackDepth =>
96+ case Concat (Single (f, index), right) if index < fusionMaxStackDepth =>
11297 Concat (Single (f.compose(g), index + 1 ), right)
11398 case _ =>
11499 Concat (Single (g, 0 ), this )
@@ -166,15 +151,14 @@ object AndThen extends AndThenInstances0 {
166151 * Establishes the maximum stack depth when fusing `andThen` or
167152 * `compose` calls.
168153 *
169- * The default is `128`, from which we subtract one as an optimization,
170- * a "!=" comparison being slightly more efficient than a "<".
154+ * The default is `128`.
171155 *
172156 * This value was reached by taking into account the default stack
173157 * size as set on 32 bits or 64 bits, Linux or Windows systems,
174158 * being enough to notice performance gains, but not big enough
175159 * to be in danger of triggering a stack-overflow error.
176160 */
177- final private val fusionMaxStackDepth = 127
161+ final private val fusionMaxStackDepth = 128
178162
179163 /**
180164 * If you are going to call this function many times, right associating it
@@ -187,13 +171,20 @@ object AndThen extends AndThenInstances0 {
187171 // end is right associated
188172 middle match {
189173 case sm @ Single (_, _) =>
190- val newEnd = Concat (sm, end)
174+ // here we use andThen to fuse singles below
175+ // the threshold that may have been hidden
176+ // by Concat structure previously
177+ val newEnd = AndThen .andThen(sm, end)
191178 beg match {
192- case sb @ Single (_, _) => Concat (sb, newEnd)
193- case Concat (begA, begB) => loop(begA, begB, newEnd, true )
179+ case sb @ Single (_, _) =>
180+ AndThen .andThen(sb, newEnd)
181+ case Concat (begA, begB) =>
182+ loop(begA, begB, newEnd, true )
194183 }
195184 case Concat (mA, mB) =>
196185 // rotate mA onto beg:
186+ // we don't need to use andThen here since we
187+ // are still preparing to put onto the end
197188 loop(Concat (beg, mA), mB, end, true )
198189 }
199190 } else {
@@ -210,6 +201,46 @@ object AndThen extends AndThenInstances0 {
210201 case Concat (Single (_, _), Single (_, _)) | Single (_, _) => fn
211202 }
212203 }
204+
205+ /**
206+ * true if this fn is already right associated, which is the faster
207+ * for calling
208+ */
209+ @ tailrec
210+ final def isRightAssociated [A , B ](fn : AndThen [A , B ]): Boolean =
211+ fn match {
212+ case Single (_, _) => true
213+ case Concat (Single (_, _), right) => isRightAssociated(right)
214+ case _ => false
215+ }
216+
217+ final def andThen [A , B , C ](ab : AndThen [A , B ], bc : AndThen [B , C ]): AndThen [A , C ] =
218+ ab match {
219+ case Single (f, indexf) =>
220+ bc match {
221+ case Single (g, indexg) =>
222+ if (indexf + indexg < fusionMaxStackDepth) Single (f.andThen(g), indexf + indexg + 1 )
223+ else Concat (ab, bc)
224+
225+ case Concat (Single (g, indexg), right) if indexf + indexg < fusionMaxStackDepth =>
226+ Concat (Single (f.andThen(g), indexf + indexg + 1 ), right)
227+
228+ case _ => Concat (ab, bc)
229+ }
230+ case Concat (leftf, Single (f, indexf)) =>
231+ bc match {
232+ case Single (g, indexg) =>
233+ if (indexf + indexg < fusionMaxStackDepth) Concat (leftf, Single (f.andThen(g), indexf + indexg + 1 ))
234+ else Concat (ab, bc)
235+
236+ case Concat (Single (g, indexg), right) if indexf + indexg < fusionMaxStackDepth =>
237+ Concat (leftf, Concat (Single (f.andThen(g), indexf + indexg + 1 ), right))
238+
239+ case _ =>
240+ Concat (ab, bc)
241+ }
242+ case _ => Concat (ab, bc)
243+ }
213244}
214245
215246abstract private [data] class AndThenInstances0 extends AndThenInstances1 {
@@ -276,7 +307,7 @@ abstract private[data] class AndThenInstances0 extends AndThenInstances1 {
276307 AndThen (fn1.split(f, g))
277308
278309 def compose [A , B , C ](f : AndThen [B , C ], g : AndThen [A , B ]): AndThen [A , C ] =
279- f.compose(g )
310+ AndThen .andThen(g, f )
280311 }
281312}
282313
0 commit comments