Skip to content

Commit 9a936b2

Browse files
committed
Clean up of code generation
1 parent 6f32f87 commit 9a936b2

File tree

1 file changed

+90
-65
lines changed

1 file changed

+90
-65
lines changed

macros/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/macros/JsonCodecMaker.scala

Lines changed: 90 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ object JsonCodecMaker {
129129

130130
def typeArg2(tpe: Type): Type = tpe.typeArgs.tail.head.dealias
131131

132-
def isValueClass(tpe: Type): Boolean = tpe <:< typeOf[AnyVal] && tpe.typeSymbol.asClass.isDerivedValueClass
132+
def isValueClass(tpe: Type): Boolean = tpe.typeSymbol.asClass.isDerivedValueClass
133133

134134
def valueClassValueMethod(tpe: Type): MethodSymbol = tpe.decls.head.asMethod
135135

@@ -156,9 +156,9 @@ object JsonCodecMaker {
156156
def isContainer(tpe: Type): Boolean =
157157
tpe <:< typeOf[Option[_]] || tpe <:< typeOf[Traversable[_]] || tpe <:< typeOf[Array[_]]
158158

159-
def containerCompanion(tpe: Type): Tree = {
159+
def collectionCompanion(tpe: Type): Tree = {
160160
val comp = tpe.typeSymbol.companion
161-
if (comp.isModule && (tpe <:< typeOf[Option[_]] || comp.fullName.startsWith("scala.collection."))) Ident(comp)
161+
if (comp.isModule && comp.fullName.startsWith("scala.collection.")) Ident(comp)
162162
else fail(s"Unsupported type '$tpe'. Please consider using a custom implicitly accessible codec for it.")
163163
}
164164

@@ -215,25 +215,32 @@ object JsonCodecMaker {
215215
}
216216

217217
def genReadArray(newBuilder: Tree, readVal: Tree, result: Tree = q"x"): Tree =
218-
genReadCollection(newBuilder, readVal, result, q"'['", q"']'", q"in.arrayEndOrCommaError()")
218+
q"""if (in.isNextToken('[')) {
219+
if (in.isNextToken(']')) default
220+
else {
221+
in.rollbackToken()
222+
..$newBuilder
223+
do {
224+
..$readVal
225+
} while (in.isNextToken(','))
226+
if (in.isCurrentToken(']')) $result
227+
else in.arrayEndOrCommaError()
228+
}
229+
} else in.readNullOrTokenError(default, '[')"""
219230

220231
def genReadMap(newBuilder: Tree, readKV: Tree, result: Tree = q"x"): Tree =
221-
genReadCollection(newBuilder, readKV, result, q"'{'", q"'}'", q"in.objectEndOrCommaError()")
222-
223-
def genReadCollection(newBuilder: Tree, loopBody: Tree, result: Tree,
224-
open: Tree, close: Tree, endError: Tree): Tree =
225-
q"""if (in.isNextToken($open)) {
226-
if (in.isNextToken($close)) default
232+
q"""if (in.isNextToken('{')) {
233+
if (in.isNextToken('}')) default
227234
else {
228235
in.rollbackToken()
229236
..$newBuilder
230237
do {
231-
..$loopBody
238+
..$readKV
232239
} while (in.isNextToken(','))
233-
if (in.isCurrentToken($close)) $result
234-
else $endError
240+
if (in.isCurrentToken('}')) $result
241+
else in.objectEndOrCommaError()
235242
}
236-
} else in.readNullOrTokenError(default, $open)"""
243+
} else in.readNullOrTokenError(default, '{')"""
237244

238245
def genWriteKey(x: Tree, tpe: Type): Tree = {
239246
val implKeyCodec = findImplicitKeyCodec(tpe)
@@ -253,20 +260,18 @@ object JsonCodecMaker {
253260
tpe =:= typeOf[MonthDay] || tpe =:= typeOf[OffsetDateTime] || tpe =:= typeOf[OffsetTime] ||
254261
tpe =:= typeOf[Period] || tpe =:= typeOf[Year] || tpe =:= typeOf[YearMonth] ||
255262
tpe =:= typeOf[ZonedDateTime] || tpe =:= typeOf[ZoneId] || tpe =:= typeOf[ZoneOffset]) q"out.writeKey($x)"
256-
else if (tpe <:< typeOf[Enumeration#Value]) {
257-
q"out.writeKey($x.toString)"
258-
} else if (tpe <:< typeOf[java.lang.Enum[_]]) {
259-
q"out.writeKey($x.name)"
260-
} else fail(s"Unsupported type to be used as map key '$tpe'.")
263+
else if (tpe <:< typeOf[Enumeration#Value]) q"out.writeKey($x.toString)"
264+
else if (tpe <:< typeOf[java.lang.Enum[_]]) q"out.writeKey($x.name)"
265+
else fail(s"Unsupported type to be used as map key '$tpe'.")
261266
}
262267

263268
def genWriteConstantKey(name: String): Tree =
264-
if (name.forall(JsonWriter.isNonEscapedAscii)) q"out.writeNonEscapedAsciiKey($name)"
265-
else q"out.writeKey($name)"
269+
if (isEncodingRequired(name)) q"out.writeKey($name)"
270+
else q"out.writeNonEscapedAsciiKey($name)"
266271

267272
def genWriteConstantVal(value: String): Tree =
268-
if (value.forall(JsonWriter.isNonEscapedAscii)) q"out.writeNonEscapedAsciiVal($value)"
269-
else q"out.writeVal($value)"
273+
if (isEncodingRequired(value)) q"out.writeVal($value)"
274+
else q"out.writeNonEscapedAsciiVal($value)"
270275

271276
def genWriteArray(x: Tree, writeVal: Tree): Tree =
272277
q"""out.writeArrayStart()
@@ -447,11 +452,11 @@ object JsonCodecMaker {
447452
else if (isValueClass(tpe)) q"null.asInstanceOf[$tpe]"
448453
else if (tpe <:< typeOf[Option[_]]) q"None"
449454
else if (tpe <:< typeOf[IntMap[_]] || tpe <:< typeOf[LongMap[_]] || tpe <:< typeOf[mutable.LongMap[_]]) {
450-
q"${containerCompanion(tpe)}.empty[${typeArg1(tpe)}]"
455+
q"${collectionCompanion(tpe)}.empty[${typeArg1(tpe)}]"
451456
} else if (tpe <:< typeOf[scala.collection.Map[_, _]]) {
452-
q"${containerCompanion(tpe)}.empty[${typeArg1(tpe)}, ${typeArg2(tpe)}]"
453-
} else if (tpe <:< typeOf[mutable.BitSet] || tpe <:< typeOf[BitSet]) q"${containerCompanion(tpe)}.empty"
454-
else if (tpe <:< typeOf[Traversable[_]]) q"${containerCompanion(tpe)}.empty[${typeArg1(tpe)}]"
457+
q"${collectionCompanion(tpe)}.empty[${typeArg1(tpe)}, ${typeArg2(tpe)}]"
458+
} else if (tpe =:= typeOf[mutable.BitSet] || tpe =:= typeOf[BitSet]) q"${collectionCompanion(tpe)}.empty"
459+
else if (tpe <:< typeOf[Traversable[_]]) q"${collectionCompanion(tpe)}.empty[${typeArg1(tpe)}]"
455460
else if (tpe <:< typeOf[Array[_]]) withNullValueFor(tpe)(q"new Array[${typeArg1(tpe)}](0)")
456461
else if (tpe.typeSymbol.isModuleClass) q"${tpe.typeSymbol.asClass.module}"
457462
else q"null"
@@ -511,48 +516,48 @@ object JsonCodecMaker {
511516
}"""
512517
} else if (tpe <:< typeOf[IntMap[_]]) withDecoderFor(methodKey, default) {
513518
val tpe1 = typeArg1(tpe)
514-
val comp = containerCompanion(tpe)
519+
val comp = collectionCompanion(tpe)
515520
genReadMap(q"var x = $comp.empty[$tpe1]",
516521
q"x = x.updated(in.readKeyAsInt(), ${genReadVal(tpe1, nullValue(tpe1), isStringified)})")
517522
} else if (tpe <:< typeOf[mutable.LongMap[_]]) withDecoderFor(methodKey, default) {
518523
val tpe1 = typeArg1(tpe)
519-
val comp = containerCompanion(tpe)
524+
val comp = collectionCompanion(tpe)
520525
genReadMap(q"val x = if (default.isEmpty) default else $comp.empty[$tpe1]",
521526
q"x.update(in.readKeyAsLong(), ${genReadVal(tpe1, nullValue(tpe1), isStringified)})")
522527
} else if (tpe <:< typeOf[LongMap[_]]) withDecoderFor(methodKey, default) {
523528
val tpe1 = typeArg1(tpe)
524-
val comp = containerCompanion(tpe)
529+
val comp = collectionCompanion(tpe)
525530
genReadMap(q"var x = $comp.empty[$tpe1]",
526531
q"x = x.updated(in.readKeyAsLong(), ${genReadVal(tpe1, nullValue(tpe1), isStringified)})")
527532
} else if (tpe <:< typeOf[mutable.Map[_, _]]) withDecoderFor(methodKey, default) {
528533
val tpe1 = typeArg1(tpe)
529534
val tpe2 = typeArg2(tpe)
530-
val comp = containerCompanion(tpe)
535+
val comp = collectionCompanion(tpe)
531536
genReadMap(q"val x = if (default.isEmpty) default else $comp.empty[$tpe1, $tpe2]",
532537
q"x.update(${genReadKey(tpe1)}, ${genReadVal(tpe2, nullValue(tpe2), isStringified)})")
533538
} else if (tpe <:< typeOf[Map[_, _]]) withDecoderFor(methodKey, default) {
534539
val tpe1 = typeArg1(tpe)
535540
val tpe2 = typeArg2(tpe)
536-
val comp = containerCompanion(tpe)
541+
val comp = collectionCompanion(tpe)
537542
genReadMap(q"var x = $comp.empty[$tpe1, $tpe2]",
538543
q"x = x.updated(${genReadKey(tpe1)}, ${genReadVal(tpe2, nullValue(tpe2), isStringified)})")
539-
} else if (tpe <:< typeOf[mutable.BitSet]) withDecoderFor(methodKey, default) {
540-
val comp = containerCompanion(tpe)
544+
} else if (tpe =:= typeOf[mutable.BitSet]) withDecoderFor(methodKey, default) {
545+
val comp = collectionCompanion(tpe)
541546
val readVal = if (isStringified) q"x.add(in.readStringAsInt())" else q"x.add(in.readInt())"
542547
genReadArray(q"val x = if (default.isEmpty) default else $comp.empty", readVal)
543-
} else if (tpe <:< typeOf[BitSet]) withDecoderFor(methodKey, default) {
544-
val comp = containerCompanion(tpe)
548+
} else if (tpe =:= typeOf[BitSet]) withDecoderFor(methodKey, default) {
549+
val comp = collectionCompanion(tpe)
545550
val readVal = if (isStringified) q"x += in.readStringAsInt()" else q"x += in.readInt()"
546551
genReadArray(q"val x = $comp.newBuilder", readVal, q"x.result()")
547552
} else if (tpe <:< typeOf[mutable.Traversable[_] with Growable[_]] &&
548553
!(tpe <:< typeOf[mutable.ArrayStack[_]])) withDecoderFor(methodKey, default) { // ArrayStack uses 'push' for '+='
549554
val tpe1 = typeArg1(tpe)
550-
val comp = containerCompanion(tpe)
555+
val comp = collectionCompanion(tpe)
551556
genReadArray(q"val x = if (default.isEmpty) default else $comp.empty[$tpe1]",
552557
q"x += ${genReadVal(tpe1, nullValue(tpe1), isStringified)}")
553558
} else if (tpe <:< typeOf[Traversable[_]]) withDecoderFor(methodKey, default) {
554559
val tpe1 = typeArg1(tpe)
555-
val comp = containerCompanion(tpe)
560+
val comp = collectionCompanion(tpe)
556561
genReadArray(q"val x = $comp.newBuilder[$tpe1]",
557562
q"x += ${genReadVal(tpe1, nullValue(tpe1), isStringified)}", q"x.result()")
558563
} else if (tpe <:< typeOf[Array[_]]) withDecoderFor(methodKey, default) {
@@ -598,11 +603,11 @@ object JsonCodecMaker {
598603
q"val _1: $t = ${genReadVal(t, nullValue(t), isStringified)}": Tree
599604
}{ case (acc, (t, i)) =>
600605
q"""..$acc
601-
val ${TermName(s"_${i + 1}")}: $t =
606+
val ${TermName("_" + (i + 1))}: $t =
602607
if (in.isNextToken(',')) ${genReadVal(t, nullValue(t), isStringified)}
603608
else in.commaError()"""
604609
}
605-
val vals = indexedTypes.map { case (t, i) => TermName(s"_${i + 1}") }
610+
val vals = indexedTypes.map { case (t, i) => TermName("_" + (i + 1)) }
606611
q"""if (in.isNextToken('[')) {
607612
..$readFields
608613
if (in.isNextToken(']')) new $tpe(..$vals)
@@ -628,15 +633,15 @@ object JsonCodecMaker {
628633
val reqVarNum = required.size
629634
val lastReqVarIndex = reqVarNum >> 5
630635
val lastReqVarBits = (1 << reqVarNum) - 1
631-
val reqVarNames = (0 to lastReqVarIndex).map(i => TermName(s"req$i"))
636+
val reqVarNames = (0 to lastReqVarIndex).map(i => TermName("req" + i))
632637
val bitmasks: Map[String, Tree] = required.zipWithIndex.map {
633638
case (r, i) => (r, q"${reqVarNames(i >> 5)} &= ${~(1 << i)}")
634639
}(breakOut)
635640
val reqVars =
636641
if (lastReqVarBits == 0) Nil
637642
else reqVarNames.init.map(n => q"var $n = -1") :+ q"var ${reqVarNames.last} = $lastReqVarBits"
638643
val checkReqVars = reqVarNames.map(n => q"$n == 0").reduce((e1, e2) => q"$e1 && $e2")
639-
val construct = q"new $tpe(..${members.map(m => q"${m.name} = ${TermName(s"_${m.name}")}")})"
644+
val construct = q"new $tpe(..${members.map(m => q"${m.name} = ${TermName("_" + m.name)}")})"
640645
val checkReqVarsAndConstruct =
641646
if (lastReqVarBits == 0) construct
642647
else {
@@ -649,12 +654,12 @@ object JsonCodecMaker {
649654
val defaults = getDefaults(tpe)
650655
val readVars = members.map { m =>
651656
val tpe = methodType(m)
652-
q"var ${TermName(s"_${m.name}")}: $tpe = ${defaults.getOrElse(m.name.decodedName.toString, nullValue(tpe))}"
657+
q"var ${TermName("_" + m.name)}: $tpe = ${defaults.getOrElse(m.name.decodedName.toString, nullValue(tpe))}"
653658
}
654659
val readFields = groupByOrdered(members)(hashCode).map { case (hashCode, ms) =>
655660
val checkNameAndReadValue = ms.foldRight(unexpectedFieldHandler) { case (m, acc) =>
656661
val decodedName = m.name.decodedName.toString
657-
val varName = TermName(s"_${m.name}")
662+
val varName = TermName("_" + m.name)
658663
val isStringified = getStringified(annotations, decodedName)
659664
val readValue = q"$varName = ${genReadVal(methodType(m), q"$varName", isStringified)}"
660665
val resetReqFieldFlag = bitmasks.getOrElse(decodedName, EmptyTree)
@@ -750,7 +755,7 @@ object JsonCodecMaker {
750755
genWriteMap(q"x", q"out.writeKey(kv._1)", genWriteVal(q"kv._2", typeArg1(tpe), isStringified))
751756
} else if (tpe <:< typeOf[scala.collection.Map[_, _]]) withEncoderFor(methodKey, m) {
752757
genWriteMap(q"x", genWriteKey(q"kv._1", typeArg1(tpe)), genWriteVal(q"kv._2", typeArg2(tpe), isStringified))
753-
} else if (tpe <:< typeOf[mutable.BitSet] || tpe <:< typeOf[BitSet]) withEncoderFor(methodKey, m) {
758+
} else if (tpe =:= typeOf[mutable.BitSet] || tpe =:= typeOf[BitSet]) withEncoderFor(methodKey, m) {
754759
genWriteArray(q"x", if (isStringified) q"out.writeValAsString(x)" else q"out.writeVal(x)")
755760
} else if (tpe <:< typeOf[Traversable[_]]) withEncoderFor(methodKey, m) {
756761
genWriteArray(q"x", genWriteVal(q"x", typeArg1(tpe), isStringified))
@@ -775,7 +780,7 @@ object JsonCodecMaker {
775780
} else if (tpe.typeSymbol.fullName.startsWith("scala.Tuple")) withEncoderFor(methodKey, m) {
776781
val writeFields = tpe.typeArgs.zipWithIndex.map { case (t, i) =>
777782
q"""out.writeComma()
778-
${genWriteVal(q"x.${TermName(s"_${i + 1}")}", t, isStringified)}"""
783+
${genWriteVal(q"x.${TermName("_" + (i + 1))}", t, isStringified)}"""
779784
}
780785
q"""out.writeArrayStart()
781786
..$writeFields
@@ -791,21 +796,26 @@ object JsonCodecMaker {
791796
val isStringified = getStringified(annotations, decodedName)
792797
defaults.get(decodedName) match {
793798
case Some(d) =>
794-
if (isContainer(tpe)) {
795-
val nonEmptyAndDefaultMatchingCheck =
796-
if (tpe <:< typeOf[Array[_]]) {
797-
q"""v.length > 0 && {
799+
if (tpe <:< typeOf[Traversable[_]]) {
800+
q"""val v = x.$m
801+
if (!v.isEmpty && v != $d) {
802+
..${genWriteConstantKey(mappedName)}
803+
..${genWriteVal(q"v", tpe, isStringified)}
804+
}"""
805+
} else if (tpe <:< typeOf[Option[_]]) {
806+
q"""val v = x.$m
807+
if (!v.isEmpty && v != $d) {
808+
..${genWriteConstantKey(mappedName)}
809+
..${genWriteVal(q"v.get", typeArg1(tpe), isStringified)}
810+
}"""
811+
} else if (tpe <:< typeOf[Array[_]]) {
812+
q"""val v = x.$m
813+
if (v.length > 0 && {
798814
val d = $d
799815
v.length != d.length || v.deep != d.deep
800-
}"""
801-
} else q"!v.isEmpty && v != $d"
802-
val writeVal =
803-
if (tpe <:< typeOf[Option[_]]) genWriteVal(q"v.get", typeArg1(tpe), isStringified)
804-
else genWriteVal(q"v", tpe, isStringified)
805-
q"""val v = x.$m
806-
if ($nonEmptyAndDefaultMatchingCheck) {
816+
}) {
807817
..${genWriteConstantKey(mappedName)}
808-
..$writeVal
818+
..${genWriteVal(q"v", tpe, isStringified)}
809819
}"""
810820
} else {
811821
q"""val v = x.$m
@@ -815,15 +825,23 @@ object JsonCodecMaker {
815825
}"""
816826
}
817827
case None =>
818-
if (isContainer(tpe)) {
819-
val nonEmptyCheck = if (tpe <:< typeOf[Array[_]]) q"v.length > 0" else q"!v.isEmpty"
820-
val writeVal =
821-
if (tpe <:< typeOf[Option[_]]) genWriteVal(q"v.get", typeArg1(tpe), isStringified)
822-
else genWriteVal(q"v", tpe, isStringified)
828+
if (tpe <:< typeOf[Traversable[_]]) {
829+
q"""val v = x.$m
830+
if (!v.isEmpty) {
831+
..${genWriteConstantKey(mappedName)}
832+
..${genWriteVal(q"v", tpe, isStringified)}
833+
}"""
834+
} else if (tpe <:< typeOf[Option[_]]) {
823835
q"""val v = x.$m
824-
if ($nonEmptyCheck) {
836+
if (!v.isEmpty) {
825837
..${genWriteConstantKey(mappedName)}
826-
..$writeVal
838+
..${genWriteVal(q"v.get", typeArg1(tpe), isStringified)}
839+
}"""
840+
} else if (tpe <:< typeOf[Array[_]]) {
841+
q"""val v = x.$m
842+
if (v.length > 0) {
843+
..${genWriteConstantKey(mappedName)}
844+
..${genWriteVal(q"v", tpe, isStringified)}
827845
}"""
828846
} else {
829847
q"""..${genWriteConstantKey(mappedName)}
@@ -870,6 +888,13 @@ object JsonCodecMaker {
870888
}
871889
}
872890

891+
private[this] def isEncodingRequired(s: String): Boolean = {
892+
val len = s.length
893+
var i = 0
894+
while (i < len && JsonWriter.isNonEscapedAscii(s.charAt(i))) i += 1
895+
i != len
896+
}
897+
873898
private[this] def groupByOrdered[A, K](xs: Traversable[A])(f: A => K): mutable.Map[K, mutable.Buffer[A]] = {
874899
val m = mutable.LinkedHashMap.empty[K, mutable.Buffer[A]].withDefault(_ => mutable.Buffer.empty[A])
875900
xs.foreach { x =>

0 commit comments

Comments
 (0)