package dotty.tools package dotc package core package tasty import collection.mutable import Names.{Name, chrs, SimpleTermName, DerivedTermName} import NameOps.NameDecorator import NameKinds._ import Decorators._ import TastyBuffer._ import scala.io.Codec import TastyFormat._ class NameBuffer extends TastyBuffer(10000) { import NameBuffer._ private val nameRefs = new mutable.LinkedHashMap[Name, NameRef] def nameIndex(name: Name): NameRef = { val name1 = name.toTermName nameRefs.get(name1) match { case Some(ref) => ref case None => name1 match { case SignedName(original, Signature(params, result)) => nameIndex(original); nameIndex(result); params.foreach(nameIndex) case AnyQualifiedName(prefix, name) => nameIndex(prefix); nameIndex(name) case AnyUniqueName(original, separator, num) => nameIndex(separator.toTermName) if (!original.isEmpty) nameIndex(original) case DerivedTermName(original, _) => nameIndex(original) case _ => } val ref = NameRef(nameRefs.size) nameRefs(name1) = ref ref } } private def withLength(op: => Unit, lengthWidth: Int = 1): Unit = { val lengthAddr = currentAddr for (i <- 0 until lengthWidth) writeByte(0) op val length = currentAddr.index - lengthAddr.index - lengthWidth putNat(lengthAddr, length, lengthWidth) } def writeNameRef(ref: NameRef): Unit = writeNat(ref.index) def writeNameRef(name: Name): Unit = writeNameRef(nameRefs(name.toTermName)) def pickleNameContents(name: Name): Unit = { val tag = name.toTermName.info.kind.tag writeByte(tag) name.toTermName match { case name: SimpleTermName => val bytes = if (name.length == 0) new Array[Byte](0) else Codec.toUTF8(chrs, name.start, name.length) writeNat(bytes.length) writeBytes(bytes, bytes.length) case AnyQualifiedName(prefix, name) => withLength { writeNameRef(prefix); writeNameRef(name) } case AnyUniqueName(original, separator, num) => withLength { writeNameRef(separator.toTermName) writeNat(num) if (!original.isEmpty) writeNameRef(original) } case VariantName(original, sign) => withLength { writeNameRef(original); writeNat(sign + 1) } case AnyNumberedName(original, num) => withLength { writeNameRef(original); writeNat(num) } case SignedName(original, Signature(params, result)) => withLength( { writeNameRef(original); writeNameRef(result); params.foreach(writeNameRef) }, if ((params.length + 2) * maxIndexWidth <= maxNumInByte) 1 else 2) case DerivedTermName(original, _) => withLength { writeNameRef(original) } } } override def assemble(): Unit = { var i = 0 for ((name, ref) <- nameRefs) { assert(ref.index == i) i += 1 pickleNameContents(name) } } } object NameBuffer { private val maxIndexWidth = 3 // allows name indices up to 2^21. private val payloadBitsPerByte = 7 // determined by nat encoding in TastyBuffer private val maxNumInByte = (1 << payloadBitsPerByte) - 1 }