Scala Specialization ArrayBuilder

I am looking for good practices not to rewrite the same code over and over again in order to achieve unboxedness. Let's say I have something like this:

def speedyArrayMaker[@specialized(Long) A: ClassTag](...): Array[A] = {
  val builder = Array.newBuilder[A]
  // do stuff with builder
  builder.result
}

This will lead to the unpacked repository underlying mine builderwhen possible, but as I understand it, no unboxed method calls it because I'm looking at an unspecialized attribute ArrayBuilder.

In a monomorphic world specialized in Long, I will write val builder = new ArrayBuilder.ofLong()and generally avoid boxing, but without speaking about ArrayBuilder/ builder, to be specialized in all primitive types, I cannot think of a good way to avoid duplication of effort here. One of the approaches I was thinking about could be within speedyArrayMaker:

val (add, builder): (A => Unit, ArrayBuilder[A]) = implicitly[ClassTag[A]].runtimeClass match {
  case java.lang.Long.TYPE =>
    val builder = new ArrayBuilder.ofLong()
    ((x: Long) => builder += x, builder).asInstanceOf
  case _ =>
    val builder = Array.newBuilder[A]
    ((x: A) => builder += x, builder)
}

+=, , Function1 add, Long. javap, ,

90:  invokestatic    #118; //Method scala/runtime/BoxesRunTime.boxToLong:(J)Ljava/lang/Long;
93:  invokeinterface #127,  2; //InterfaceMethod scala/collection/mutable/Builder.$plus$eq:(Ljava/lang/Object;)Lscala/collection/mutable/Builder;

Array.newBuilder[A] ( ) :

252: invokeinterface #204,  3; //InterfaceMethod scala/Function1.apply$mcVJ$sp:(J)V

. " ", , - . , , , Function1 , .

, , ? , , / , ArrayBuilder.of*, , .

Edit - , , :

def builderOf(x: Array[Int]): ArrayBuilder.ofInt = new ArrayBuilder.ofInt()
def builderOf(x: Array[Long]): ArrayBuilder.ofLong = new ArrayBuilder.ofLong()
def builderOf[A: ClassTag](x: Array[A]): ArrayBuilder[A] = ArrayBuilder.make[A]

:

val witness: Array[A] = null
val builder = builderOf(witness)

, -, builderOf ( Array[Long] ). - , ? , , . , "" , , , , , : (

+5
1

- ( ),

import scala.collection.mutable.ArrayBuilder
import scala.reflect.ClassTag

trait SpecializedArrayBuilder[@specialized(Long) A] {
  def +=(a: A)
  def result: Array[A]
}

trait LowPrioritySpecializedArrayBuilder {
  implicit def defaultBuilder[A: ClassTag] = new SpecializedArrayBuilder[A] {
    val builder = ArrayBuilder.make[A]
    def +=(a: A) = builder += a
    def result = builder.result
  }
}

object SpecializedArrayBuilder extends LowPrioritySpecializedArrayBuilder {
  implicit val longBuilder = new SpecializedArrayBuilder[Long] {
    val builder = new ArrayBuilder.ofLong
    def +=(a: Long) = builder += a
    def result = builder.result
  }
}

object Specialized {
  def speedyArrayMaker[@specialized(Long) A](a: A)
    (implicit builder: SpecializedArrayBuilder[A]): Array[A] = {
    builder += a
    builder.result
  }

  def main(arg: Array[String]) {
    val arr = speedyArrayMaker(1L)
    println(arr)
  }
}
+4

All Articles