Skip to content

Commit c58db7d

Browse files
committed
use a class and a val to avoid the allocation of a LazyRef when w know that we always need the value
Inherit from AbstractFunctionX, rather than FunctionX to reduce bytecode
1 parent c4011e6 commit c58db7d

File tree

4 files changed

+53
-19
lines changed

4 files changed

+53
-19
lines changed

library/src/scala/collection/TraversableOnce.scala

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
package scala
1414
package collection
1515

16-
import mutable.{ Buffer, Builder, ArrayBuffer }
16+
import mutable.{ArrayBuffer, Buffer, Builder}
1717
import generic.CanBuildFrom
18-
import scala.annotation.unchecked.{ uncheckedVariance => uV }
19-
import scala.language.{implicitConversions, higherKinds}
18+
import scala.annotation.unchecked.{uncheckedVariance => uV}
19+
import scala.language.{higherKinds, implicitConversions}
2020
import scala.reflect.ClassTag
21+
import scala.runtime.AbstractFunction1
2122

2223
/** A template trait for collections which can be traversed either once only
2324
* or one or more times.
@@ -115,32 +116,39 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] {
115116

116117
// for internal use
117118
protected[this] def reversed = {
118-
object reverser extends Function1[A, Unit] {
119+
//avoid the LazyRef as we don't have an @eager object
120+
class reverser extends AbstractFunction1[A, Unit] {
119121
var elems: List[A] = Nil
120122
override def apply(v1: A): Unit = elems ::= v1
121123
}
124+
val reverser = new reverser
122125
self foreach reverser
123126
reverser.elems
124127
}
125128

126129
def size: Int = {
127130
//we can't guard with isEmpty as some implementation have
128131
// def isEmpty = size == 0
129-
object counter extends Function1[A, Unit] {
132+
133+
//avoid the LazyRef as we don't have an @eager object
134+
class counter extends AbstractFunction1[A, Unit] {
130135
var result = 0
131136
override def apply(v1: A): Unit = result += 1
132137
}
138+
val counter = new counter
133139
self foreach counter
134140
counter.result
135141
}
136142

137143
def nonEmpty: Boolean = !isEmpty
138144

139145
def count(p: A => Boolean): Int = {
140-
object counter extends Function1[A, Unit] {
146+
//avoid the LazyRef as we don't have an @eager object
147+
class counter extends AbstractFunction1[A, Unit] {
141148
var result = 0
142149
override def apply(v1: A): Unit = if (p(v1)) result += 1
143150
}
151+
val counter = new counter
144152
this foreach counter
145153
counter.result
146154
}
@@ -182,10 +190,12 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] {
182190
def :\[B](z: B)(op: (A, B) => B): B = foldRight(z)(op)
183191

184192
def foldLeft[B](z: B)(op: (B, A) => B): B = {
185-
object folder extends Function1[A, Unit] {
193+
//avoid the LazyRef as we don't have an @eager object
194+
class folder extends AbstractFunction1[A, Unit] {
186195
var result = z
187196
override def apply(v1: A): Unit = result = op(result,v1)
188197
}
198+
val folder = new folder
189199
this foreach folder
190200
folder.result
191201
}
@@ -211,7 +221,8 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] {
211221
if (isEmpty)
212222
throw new UnsupportedOperationException("empty.reduceLeft")
213223

214-
object reducer extends Function1[A, Unit] {
224+
//avoid the LazyRef as we don't have an @eager object
225+
class reducer extends AbstractFunction1[A, Unit] {
215226
var first = true
216227
var acc: B = 0.asInstanceOf[B]
217228

@@ -222,6 +233,7 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] {
222233
}
223234
else acc = op(acc, x)
224235
}
236+
val reducer = new reducer
225237
self foreach reducer
226238
reducer.acc
227239
}
@@ -268,11 +280,12 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] {
268280
def maxBy[B](f: A => B)(implicit cmp: Ordering[B]): A = {
269281
if (isEmpty)
270282
throw new UnsupportedOperationException("empty.maxBy")
271-
object maxer extends Function1[A, Unit] {
283+
284+
//avoid the LazyRef as we don't have an @eager object
285+
class maxer extends AbstractFunction1[A, Unit] {
272286
var maxF: B = null.asInstanceOf[B]
273287
var maxElem: A = null.asInstanceOf[A]
274288
var first = true
275-
276289
override def apply(elem: A): Unit = {
277290
val fx = f(elem)
278291
if (first || cmp.gt(fx, maxF)) {
@@ -281,18 +294,21 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] {
281294
first = false
282295
}
283296
}
297+
284298
}
299+
val maxer = new maxer
285300
self foreach maxer
286301
maxer.maxElem
287302
}
288303
def minBy[B](f: A => B)(implicit cmp: Ordering[B]): A = {
289304
if (isEmpty)
290305
throw new UnsupportedOperationException("empty.minBy")
291-
object miner extends Function1[A, Unit] {
306+
307+
//avoid the LazyRef as we don't have an @eager object
308+
class miner extends AbstractFunction1[A, Unit] {
292309
var minF: B = null.asInstanceOf[B]
293310
var minElem: A = null.asInstanceOf[A]
294311
var first = true
295-
296312
override def apply(elem: A): Unit = {
297313
val fx = f(elem)
298314
if (first || cmp.lt(fx, minF)) {
@@ -301,7 +317,9 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] {
301317
first = false
302318
}
303319
}
320+
304321
}
322+
val miner = new miner
305323
self foreach miner
306324
miner.minElem
307325
}
@@ -388,7 +406,8 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] {
388406
*/
389407
def addString(b: StringBuilder, start: String, sep: String, end: String): StringBuilder = {
390408
b append start
391-
object appender extends Function1[A, Unit] {
409+
410+
class appender extends AbstractFunction1[A, Unit] {
392411
var first = true
393412
override def apply(x: A): Unit = {
394413
if (first) {
@@ -401,6 +420,7 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] {
401420
}
402421
}
403422
}
423+
val appender = new appender
404424
self foreach appender
405425
b append end
406426
b

library/src/scala/collection/immutable/HashMap.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import java.{util => ju}
1919
import generic._
2020
import scala.annotation.unchecked.{uncheckedVariance => uV}
2121
import parallel.immutable.ParHashMap
22+
import scala.runtime.{AbstractFunction1, AbstractFunction2}
2223
import scala.util.hashing.MurmurHash3
2324

2425
/** This class implements immutable maps using a hash trie.
@@ -215,22 +216,26 @@ sealed class HashMap[A, +B] extends AbstractMap[A, B]
215216
this.merge0(thatHash, 0, merger)
216217

217218
case that: HasForeachEntry[A, B] =>
218-
object adder extends Function2[A, B, Unit] {
219+
//avoid the LazyRef as we don't have an @eager object
220+
class adder extends AbstractFunction2[A, B, Unit] {
219221
var result: HashMap[A, B] = HashMap.this
220222
override def apply(key: A, value: B): Unit = {
221223
result = result.updated0(key, computeHash(key), 0, value, null, merger)
222224
}
223225
}
226+
val adder = new adder
224227
that foreachEntry adder
225228
adder.result
226229
case that =>
227-
object adder extends Function1[(A,B), Unit] {
230+
//avoid the LazyRef as we don't have an @eager object
231+
class adder extends AbstractFunction1[(A,B), Unit] {
228232
var result: HashMap[A, B] = HashMap.this
229233
override def apply(kv: (A, B)): Unit = {
230234
val key = kv._1
231235
result = result.updated0(key, computeHash(key), 0, kv._2, kv, merger)
232236
}
233237
}
238+
val adder = new adder
234239
that.asInstanceOf[GenTraversableOnce[(A,B)]] foreach adder
235240
adder.result
236241
}

library/src/scala/collection/immutable/HashSet.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import java.util
1919
import generic._
2020
import scala.collection.parallel.immutable.ParHashSet
2121
import scala.annotation.tailrec
22+
import scala.runtime.AbstractFunction1
2223

2324
/** This class implements immutable sets using a hash trie.
2425
*
@@ -93,10 +94,12 @@ sealed class HashSet[A] extends AbstractSet[A]
9394
else nullToEmpty(union0(that, 0))
9495
case _ =>
9596
if (that.isEmpty) this else {
96-
object acc extends Function1[A, Unit] {
97+
//avoid the LazyRef as we don't have an @eager object
98+
class acc extends AbstractFunction1[A, Unit] {
9799
var res = HashSet.this
98100
override def apply(v1: A): Unit = res += v1
99101
}
102+
val acc = new acc
100103
if (that.isInstanceOf[Set[A]])
101104
that foreach acc
102105
else

library/src/scala/util/hashing/MurmurHash3.scala

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
package scala
1414
package util.hashing
1515

16-
import java.lang.Integer.{ rotateLeft => rotl }
16+
import java.lang.Integer.{rotateLeft => rotl}
17+
18+
import scala.runtime.AbstractFunction1
1719

1820
private[hashing] class MurmurHash3 {
1921
/** Mix in a block of data into an intermediate hash value. */
@@ -104,7 +106,8 @@ private[hashing] class MurmurHash3 {
104106
finalizeHash(h, 0)
105107
}
106108
else {
107-
object hasher extends Function1[Any, Unit] {
109+
//avoid the LazyRef as we don't have an @eager object
110+
class hasher extends AbstractFunction1[Any, Unit] {
108111
var a, b, n = 0
109112
var c = 1
110113
override def apply(x: Any): Unit = {
@@ -115,6 +118,7 @@ private[hashing] class MurmurHash3 {
115118
n += 1
116119
}
117120
}
121+
val hasher = new hasher
118122
xs foreach hasher
119123
var h = seed
120124
h = mix(h, hasher.a)
@@ -128,14 +132,16 @@ private[hashing] class MurmurHash3 {
128132
final def orderedHash(xs: TraversableOnce[Any], seed: Int): Int = {
129133
if (xs.isEmpty) finalizeHash(seed, 0)
130134
else {
131-
object hasher extends Function1[Any, Unit] {
135+
//avoid the LazyRef as we don't have an @eager object
136+
class hasher extends AbstractFunction1[Any, Unit] {
132137
var n = 0
133138
var h = seed
134139
override def apply(x: Any): Unit = {
135140
h = mix(h, x.##)
136141
n += 1
137142
}
138143
}
144+
val hasher = new hasher
139145
xs foreach hasher
140146
finalizeHash(hasher.h, hasher.n)
141147
}

0 commit comments

Comments
 (0)