@@ -775,57 +775,80 @@ object JsonCodecMaker {
775775 }
776776 }
777777
778+ sealed trait TypeInfo
779+
780+ case class JavaEnumValueInfo (value : Tree , name : String )
781+
782+ case class JavaEnumInfo (valueInfos : List [JavaEnumValueInfo ], hasTransformed : Boolean , doEncoding : Boolean ) extends TypeInfo {
783+ val doLinearSearch : Boolean = valueInfos.size <= 8 && valueInfos.foldLeft(0 )(_ + _.name.length) <= 64
784+ }
785+
786+ case class FieldInfo (symbol : TermSymbol , mappedName : String , tmpName : TermName , getter : MethodSymbol ,
787+ defaultValue : Option [Tree ], resolvedTpe : Type , isStringified : Boolean )
788+
789+ case class ClassInfo (tpe : Type , paramLists : List [List [FieldInfo ]]) extends TypeInfo {
790+ val fields : List [FieldInfo ] = paramLists.flatten
791+ }
792+
793+ sealed trait TermNameKey
794+
795+ case class DecoderMethodKey (tpe : Type , isStringified : Boolean , discriminator : Tree ) extends TermNameKey
796+
797+ case class EncoderMethodKey (tpe : Type , isStringified : Boolean , discriminator : Tree ) extends TermNameKey
798+
799+ case class EqualsMethodKey (tpe : Type ) extends TermNameKey
800+
801+ case class FieldIndexMethodKey (tpe : Type ) extends TermNameKey
802+
803+ case class NullValueKey (tpe : Type ) extends TermNameKey
804+
805+ case class ScalaEnumValueKey (tpe : Type ) extends TermNameKey
806+
807+ case class MathContextValueKey (precision : Int ) extends TermNameKey
808+
778809 val rootTpe = weakTypeOf[A ].dealias
779810 val inferredKeyCodecs = mutable.Map [Type , Tree ]((rootTpe, EmptyTree ))
811+ val inferredValueCodecs = mutable.Map [Type , Tree ]((rootTpe, EmptyTree ))
812+ val typeInfos = new mutable.HashMap [Type , TypeInfo ]
813+ val termNames = new mutable.HashMap [TermNameKey , TermName ]
814+ val trees = new mutable.ArrayBuffer [Tree ]
780815
781816 def findImplicitKeyCodec (tpe : Type ): Tree = inferredKeyCodecs.getOrElseUpdate(tpe, {
782817 c.inferImplicitValue(c.typecheck(tq " com.github.plokhotnyuk.jsoniter_scala.core.JsonKeyCodec[ $tpe] " , c.TYPEmode ).tpe)
783818 })
784819
785- val inferredValueCodecs = mutable.Map [Type , Tree ]((rootTpe, EmptyTree ))
786-
787820 def findImplicitValueCodec (tpe : Type ): Tree = inferredValueCodecs.getOrElseUpdate(tpe, {
788821 c.inferImplicitValue(c.typecheck(tq " com.github.plokhotnyuk.jsoniter_scala.core.JsonValueCodec[ $tpe] " , c.TYPEmode ).tpe)
789822 })
790823
791- val mathContexts = new mutable.LinkedHashMap [Int , (TermName , Tree )]
792-
793824 def withMathContextFor (precision : Int ): Tree =
794825 if (precision == java.math.MathContext .DECIMAL128 .getPrecision) q " _root_.java.math.MathContext.DECIMAL128 "
795826 else if (precision == java.math.MathContext .DECIMAL64 .getPrecision) q " _root_.java.math.MathContext.DECIMAL64 "
796827 else if (precision == java.math.MathContext .DECIMAL32 .getPrecision) q " _root_.java.math.MathContext.DECIMAL32 "
797828 else if (precision == java.math.MathContext .UNLIMITED .getPrecision) q " _root_.java.math.MathContext.UNLIMITED "
798- else Ident (mathContexts.getOrElseUpdate(precision, {
799- val name = TermName (s " mc ${mathContexts.size}" )
800- (name, q " private[this] val $name = new _root_.java.math.MathContext( ${cfg.bigDecimalPrecision}, _root_.java.math.RoundingMode.HALF_EVEN) " )
801- })._1)
802-
803- val scalaEnumCaches = new mutable.LinkedHashMap [Type , (TermName , Tree )]
804-
805- def withScalaEnumCacheFor (tpe : Type ): Tree = Ident (scalaEnumCaches.getOrElseUpdate(tpe, {
806- val name = TermName (s " ec ${scalaEnumCaches.size}" )
807- val keyTpe =
808- if (cfg.useScalaEnumValueId) tq " Int "
809- else tq " String "
810- (name, q " private[this] val $name = new _root_.java.util.concurrent.ConcurrentHashMap[ $keyTpe, $tpe] " )
811- })._1)
812-
813- sealed trait TypeInfo
814-
815- case class JavaEnumValueInfo (value : Tree , name : String )
816-
817- case class JavaEnumInfo (valueInfos : List [JavaEnumValueInfo ], hasTransformed : Boolean , doEncoding : Boolean ) extends TypeInfo {
818- val doLinearSearch : Boolean = valueInfos.size <= 8 && valueInfos.foldLeft(0 )(_ + _.name.length) <= 64
819- }
820-
821- case class FieldInfo (symbol : TermSymbol , mappedName : String , tmpName : TermName , getter : MethodSymbol ,
822- defaultValue : Option [Tree ], resolvedTpe : Type , isStringified : Boolean )
829+ else Ident ({
830+ val termNameKey = new MathContextValueKey (precision)
831+ termNames.getOrElse(termNameKey, {
832+ val name = TermName (s " mc ${termNames.size}" )
833+ termNames.update(termNameKey, name)
834+ trees += q " private[this] val $name = new _root_.java.math.MathContext( ${cfg.bigDecimalPrecision}, _root_.java.math.RoundingMode.HALF_EVEN) "
835+ name
836+ })
837+ })
823838
824- case class ClassInfo (tpe : Type , paramLists : List [List [FieldInfo ]]) extends TypeInfo {
825- val fields : List [FieldInfo ] = paramLists.flatten
826- }
839+ def withScalaEnumCacheFor (tpe : Type ): Tree = Ident ({
840+ val termNameKey = new ScalaEnumValueKey (tpe)
841+ termNames.getOrElse(termNameKey, {
842+ val name = TermName (s " ec ${termNames.size}" )
843+ termNames.update(termNameKey, name)
844+ val keyTpe =
845+ if (cfg.useScalaEnumValueId) tq " Int "
846+ else tq " String "
847+ trees += q " private[this] val $name = new _root_.java.util.concurrent.ConcurrentHashMap[ $keyTpe, $tpe] "
848+ name
849+ })
850+ })
827851
828- val typeInfos = new mutable.HashMap [Type , TypeInfo ]
829852
830853 def getJavaEnumInfo (tpe : Type ): JavaEnumInfo = typeInfos.getOrElseUpdate(tpe, {
831854 val javaEnumValueNameMapper : String => String = n => cfg.javaEnumValueNameMapper.lift(n).getOrElse(n)
@@ -1337,44 +1360,49 @@ object JsonCodecMaker {
13371360 }
13381361 }
13391362
1340- val nullValues = new mutable.LinkedHashMap [Type , (TermName , Tree )]
1341-
1342- def withNullValueFor (tpe : Type )(f : => Tree ): Tree = Ident (nullValues.getOrElseUpdate(tpe, {
1343- val name = TermName (s " c ${nullValues.size}" )
1344- (name, q " private[this] val $name: $tpe = $f" )
1345- })._1)
1346-
1347- val fields = new mutable.LinkedHashMap [Type , (TermName , Tree )]
1348-
1349- def withFieldsFor (tpe : Type )(f : => Seq [String ]): Tree = Ident (fields.getOrElseUpdate(tpe, {
1350- val name = TermName (s " f ${fields.size}" )
1351- val cases = f.map {
1352- var i = - 1
1353- n =>
1354- i += 1
1355- cq " $i => $n"
1356- }
1357- (name,
1358- q """ private[this] def $name(i: Int): String =
1359- (i: @_root_.scala.annotation.switch @_root_.scala.unchecked) match {
1360- case .. $cases
1361- } """ )
1362- })._1)
1363-
1364- val equalsMethods = new mutable.LinkedHashMap [Type , (TermName , Tree )]
1363+ def withNullValueFor (tpe : Type )(f : => Tree ): Tree = Ident ({
1364+ val termNameKey = new NullValueKey (tpe)
1365+ termNames.getOrElse(termNameKey, {
1366+ val name = TermName (s " c ${termNames.size}" )
1367+ termNames.update(termNameKey, name)
1368+ trees += q " private[this] val $name: $tpe = $f"
1369+ name
1370+ })
1371+ })
13651372
1366- def withEqualsFor (tpe : Type , arg1 : Tree , arg2 : Tree )(f : => Tree ): Tree = {
1367- val equalsMethodName = equalsMethods.getOrElseUpdate(tpe, {
1368- val name = TermName (s " q ${equalsMethods.size}" )
1369- (name, q " private[this] def $name(x1: $tpe, x2: $tpe): _root_.scala.Boolean = $f" )
1370- })._1
1373+ def withFieldsByIndexFor (termNameKey : FieldIndexMethodKey )(f : => Seq [String ]): Tree =
1374+ Ident (termNames.getOrElse(termNameKey, {
1375+ val name = TermName (s " f ${termNames.size}" )
1376+ termNames.update(termNameKey, name)
1377+ val cases = f.map {
1378+ var i = - 1
1379+ n =>
1380+ i += 1
1381+ cq " $i => $n"
1382+ }
1383+ trees +=
1384+ q """ private[this] def $name(i: Int): String =
1385+ (i: @_root_.scala.annotation.switch @_root_.scala.unchecked) match {
1386+ case .. $cases
1387+ } """
1388+ name
1389+ }))
1390+
1391+ def withEqualsFor (termNameKey : EqualsMethodKey , arg1 : Tree , arg2 : Tree )(f : => Tree ): Tree = {
1392+ val equalsMethodName = termNames.getOrElse(termNameKey, {
1393+ val name = TermName (s " q ${termNames.size}" )
1394+ termNames.update(termNameKey, name)
1395+ val mTpe = termNameKey.tpe
1396+ trees += q " private[this] def $name(x1: $mTpe, x2: $mTpe): _root_.scala.Boolean = $f"
1397+ name
1398+ })
13711399 q " $equalsMethodName( $arg1, $arg2) "
13721400 }
13731401
13741402 def genArrayEquals (tpe : Type ): Tree = {
13751403 val tpe1 = typeArg1(tpe)
13761404 if (tpe1 <:< typeOf[Array [? ]]) {
1377- val equals = withEqualsFor(tpe1, q " x1(i) " , q " x2(i) " )(genArrayEquals(tpe1))
1405+ val equals = withEqualsFor(new EqualsMethodKey ( tpe1) , q " x1(i) " , q " x2(i) " )(genArrayEquals(tpe1))
13781406 q """ (x1 eq x2) || ((x1 ne null) && (x2 ne null) && {
13791407 val l = x1.length
13801408 (x2.length == l) && {
@@ -1386,31 +1414,24 @@ object JsonCodecMaker {
13861414 } else q " _root_.java.util.Arrays.equals(x1, x2) "
13871415 }
13881416
1389- case class MethodKey (tpe : Type , isStringified : Boolean , discriminator : Tree )
1390-
1391- val decodeMethodNames = new mutable.HashMap [MethodKey , TermName ]
1392- val methodTrees = new mutable.ArrayBuffer [Tree ]
1393-
1394- def withDecoderFor (methodKey : MethodKey , arg : Tree )(f : => Tree ): Tree = {
1395- val decodeMethodName = decodeMethodNames.getOrElse(methodKey, {
1396- val name = TermName (s " d ${decodeMethodNames.size}" )
1397- val mtpe = methodKey.tpe
1398- decodeMethodNames.update(methodKey, name)
1399- methodTrees +=
1400- q " private[this] def $name(in: _root_.com.github.plokhotnyuk.jsoniter_scala.core.JsonReader, default: $mtpe): $mtpe = $f"
1417+ def withDecoderFor (termNameKey : DecoderMethodKey , arg : Tree )(f : => Tree ): Tree = {
1418+ val decodeMethodName = termNames.getOrElse(termNameKey, {
1419+ val name = TermName (s " d ${termNames.size}" )
1420+ termNames.update(termNameKey, name)
1421+ val mTpe = termNameKey.tpe
1422+ trees +=
1423+ q " private[this] def $name(in: _root_.com.github.plokhotnyuk.jsoniter_scala.core.JsonReader, default: $mTpe): $mTpe = $f"
14011424 name
14021425 })
14031426 q " $decodeMethodName(in, $arg) "
14041427 }
14051428
1406- val encodeMethodNames = new mutable.HashMap [MethodKey , TermName ]
1407-
1408- def withEncoderFor (methodKey : MethodKey , arg : Tree )(f : => Tree ): Tree = {
1409- val encodeMethodName = encodeMethodNames.getOrElse(methodKey, {
1410- val name = TermName (s " e ${encodeMethodNames.size}" )
1411- encodeMethodNames.update(methodKey, name)
1412- methodTrees +=
1413- q " private[this] def $name(x: ${methodKey.tpe}, out: _root_.com.github.plokhotnyuk.jsoniter_scala.core.JsonWriter): _root_.scala.Unit = $f"
1429+ def withEncoderFor (termNameKey : EncoderMethodKey , arg : Tree )(f : => Tree ): Tree = {
1430+ val encodeMethodName = termNames.getOrElse(termNameKey, {
1431+ val name = TermName (s " e ${termNames.size}" )
1432+ termNames.update(termNameKey, name)
1433+ val mTpe = termNameKey.tpe
1434+ trees += q " private[this] def $name(x: $mTpe, out: _root_.com.github.plokhotnyuk.jsoniter_scala.core.JsonWriter): _root_.scala.Unit = $f"
14141435 name
14151436 })
14161437 q " $encodeMethodName( $arg, out) "
@@ -1510,7 +1531,7 @@ object JsonCodecMaker {
15101531 val checkReqVars =
15111532 if (required.isEmpty) Nil
15121533 else {
1513- val names = withFieldsFor( tpe)(mappedNames)
1534+ val names = withFieldsByIndexFor( new FieldIndexMethodKey ( tpe) )(mappedNames)
15141535 val reqMasks = fields.grouped(32 ).toArray.map(_.foldLeft(0 ) {
15151536 var i = - 1
15161537 (acc, fieldInfo) =>
@@ -1695,7 +1716,7 @@ object JsonCodecMaker {
16951716 q " new $tpe( ${genReadVal(types1, genNullValue(types1), isStringified, EmptyTree )}) "
16961717 } else {
16971718 val isColl = isCollection(tpe)
1698- val methodKey = new MethodKey (tpe, isColl & isStringified, discriminator)
1719+ val methodKey = new DecoderMethodKey (tpe, isColl & isStringified, discriminator)
16991720 if (isColl) {
17001721 if (tpe <:< typeOf[Array [? ]] || isImmutableArraySeq(tpe) || isMutableArraySeq(tpe)) withDecoderFor(methodKey, default) {
17011722 val tpe1 = typeArg1(tpe)
@@ -2074,10 +2095,11 @@ object JsonCodecMaker {
20742095 .. ${genWriteVal(q " v.get " , typeArg1(fTpe) :: allTypes, fieldInfo.isStringified, EmptyTree )}
20752096 } """
20762097 } else if (fTpe <:< typeOf[Array [? ]]) {
2098+ val methodKey = new EqualsMethodKey (fTpe)
20772099 val cond =
20782100 if (cfg.transientEmpty) {
2079- q " v.length != 0 && ! ${withEqualsFor(fTpe , q " v " , d)(genArrayEquals(fTpe))}"
2080- } else q " ! ${withEqualsFor(fTpe , q " v " , d)(genArrayEquals(fTpe))}"
2101+ q " v.length != 0 && ! ${withEqualsFor(methodKey , q " v " , d)(genArrayEquals(fTpe))}"
2102+ } else q " ! ${withEqualsFor(methodKey , q " v " , d)(genArrayEquals(fTpe))}"
20812103 q """ val v = x. ${fieldInfo.getter}
20822104 if ( $cond) {
20832105 .. ${genWriteConstantKey(fieldInfo.mappedName)}
@@ -2169,7 +2191,7 @@ object JsonCodecMaker {
21692191 genWriteVal(q " $m. ${valueClassValueSymbol(tpe)}" , valueClassValueType(tpe) :: types, isStringified, EmptyTree )
21702192 } else {
21712193 val isColl = isCollection(tpe)
2172- val methodKey = new MethodKey (tpe, isColl & isStringified, discriminator)
2194+ val methodKey = new EncoderMethodKey (tpe, isColl & isStringified, discriminator)
21732195 if (isColl) {
21742196 if (tpe <:< typeOf[Array [? ]] || isImmutableArraySeq(tpe) || isMutableArraySeq(tpe)) withEncoderFor(methodKey, m) {
21752197 val tpe1 = typeArg1(tpe)
@@ -2363,12 +2385,8 @@ object JsonCodecMaker {
23632385 if (cfg.decodingOnly) q " _root_.scala.Predef.??? "
23642386 else genWriteVal(q " x " , types, cfg.isStringified, EmptyTree )
23652387 }
2366- .. $methodTrees
2367- .. ${fields.values.map(_._2)}
2368- .. ${equalsMethods.values.map(_._2)}
2369- .. ${nullValues.values.map(_._2)}
2370- .. ${mathContexts.values.map(_._2)}
2371- .. ${scalaEnumCaches.values.map(_._2)}
2388+
2389+ .. $trees
23722390 }
23732391 x
23742392 } """
0 commit comments