diff --git a/sjsonnet/src/sjsonnet/ByteRenderer.scala b/sjsonnet/src/sjsonnet/ByteRenderer.scala index 7eb8656f..2287f641 100644 --- a/sjsonnet/src/sjsonnet/ByteRenderer.scala +++ b/sjsonnet/src/sjsonnet/ByteRenderer.scala @@ -391,7 +391,7 @@ class ByteRenderer(out: OutputStream = new java.io.ByteArrayOutputStream(), inde matDepth: Int, ctx: Materializer.MaterializeContext)(implicit evaluator: EvalScope): Unit = { val keys = - if (ctx.sort) obj.visibleKeyNames.sorted(Util.CodepointStringOrdering) + if (ctx.sort) obj.sortedVisibleKeyNames else obj.visibleKeyNames openObjBrace() diff --git a/sjsonnet/src/sjsonnet/Materializer.scala b/sjsonnet/src/sjsonnet/Materializer.scala index 0742ca6e..d184a9e0 100644 --- a/sjsonnet/src/sjsonnet/Materializer.scala +++ b/sjsonnet/src/sjsonnet/Materializer.scala @@ -100,7 +100,7 @@ abstract class Materializer { else materializeInlineObj(obj, visitor, depth, ctx) } else { val keys = - if (ctx.sort) obj.visibleKeyNames.sorted(Util.CodepointStringOrdering) + if (ctx.sort) obj.sortedVisibleKeyNames else obj.visibleKeyNames val ov = visitor.visitObject(keys.length, jsonableKeys = true, -1) var i = 0 @@ -432,7 +432,7 @@ abstract class Materializer { storePos(obj.pos) obj.triggerAllAsserts(ctx.brokenAssertionLogic) val keyNames = - if (ctx.sort) obj.visibleKeyNames.sorted(Util.CodepointStringOrdering) + if (ctx.sort) obj.sortedVisibleKeyNames else obj.visibleKeyNames val objVisitor = visitor.visitObject(keyNames.length, jsonableKeys = true, -1) stack.push( diff --git a/sjsonnet/src/sjsonnet/Val.scala b/sjsonnet/src/sjsonnet/Val.scala index 4b5d7633..af4acbaa 100644 --- a/sjsonnet/src/sjsonnet/Val.scala +++ b/sjsonnet/src/sjsonnet/Val.scala @@ -884,7 +884,18 @@ object Val { * Cached sorted field order for inline objects. Shared across all objects from the same * MemberList to avoid per-object sort + allocation. */ - @volatile private[sjsonnet] var _sortedInlineOrder: Array[Int] = null + private[sjsonnet] var _sortedInlineOrder: Array[Int] = null + + private[sjsonnet] var _sortedVisibleKeyNames: Array[String] = null + + private[sjsonnet] def sortedVisibleKeyNames: Array[String] = { + var r = _sortedVisibleKeyNames + if (r == null) { + r = visibleKeyNames.sorted(Util.CodepointStringOrdering) + _sortedVisibleKeyNames = r + } + r + } /** * When true, field caching can be skipped during materialization because no field body @@ -1402,7 +1413,7 @@ object Val { def foreachElement(sort: Boolean, pos: Position)(f: (String, Val) => Unit)(implicit ev: EvalScope): Unit = { - val keys = if (sort) visibleKeyNames.sorted(Util.CodepointStringOrdering) else visibleKeyNames + val keys = if (sort) sortedVisibleKeyNames else visibleKeyNames for (k <- keys) { val v = value(k, pos) f(k, v)