Skip to content

Instantly share code, notes, and snippets.

@sirthias
Created July 27, 2015 22:38
Show Gist options
  • Save sirthias/88be2871d363f023c237 to your computer and use it in GitHub Desktop.
Save sirthias/88be2871d363f023c237 to your computer and use it in GitHub Desktop.
Comparison of Vector-based and Array-based basic JValue ASTs
package org.json4s.basic.ast
import scala.annotation.tailrec
import scala.collection.immutable.VectorBuilder
/**
* Minimal AST for " The JavaScript Object Notation (JSON) Data Interchange Format"
* RFC 7159 (https://tools.ietf.org/html/rfc7159)
*/
sealed abstract class JValue extends Serializable with Product
case object JNull extends JValue
sealed abstract class JBoolean extends JValue {
def isEmpty = false
def get: Boolean
}
object JBoolean {
def apply(x: Boolean): JBoolean = if (x) JTrue else JFalse
}
case object JTrue extends JBoolean {
def get = true
}
case object JFalse extends JBoolean {
def get = false
}
final case class JString(value: String) extends JValue
/**
* Contract: `value` *must* be formatted according to https://tools.ietf.org/html/rfc7159#section-6
*/
final case class JNumber(value: String) extends JValue
object JNumber {
def apply(value: Byte): JNumber = JNumber(value.toString)
def apply(value: Short): JNumber = JNumber(value.toString)
def apply(value: Int): JNumber = JNumber(value.toString)
def apply(value: Long): JNumber = JNumber(value.toString)
def apply(value: Float): JNumber = JNumber(value.toString)
def apply(value: Double): JNumber = JNumber(value.toString)
def apply(value: BigInt): JNumber = JNumber(value.toString)
def apply(value: BigDecimal): JNumber = JNumber(value.toString)
}
sealed abstract class JContainer[T <: AnyRef] extends JValue {
def value: Vector[T] = {
val array = underlyingArray_unsafe
val vb = new VectorBuilder[T]
@tailrec def copyFrom(ix: Int): Vector[T] =
if (ix < array.length) {
vb += array(ix)
copyFrom(ix + 1)
} else vb.result()
copyFrom(0)
}
def isEmpty = false
def get: Vector[T] = value
def underlyingArray_unsafe: Array[T]
def productArity = 1
def productElement(n: Int): Any =
if (n == 0) value else throw new IndexOutOfBoundsException(s"Expected 0, was $n")
override def equals(obj: Any): Boolean =
obj match {
case x: JContainer[_] ⇒
canEqual(obj) && java.util.Arrays.equals(underlyingArray_unsafe.asInstanceOf[Array[Object]],
x.underlyingArray_unsafe.asInstanceOf[Array[Object]])
case _ ⇒ false
}
override def hashCode(): Int = java.util.Arrays.hashCode(underlyingArray_unsafe.asInstanceOf[Array[Object]])
}
sealed abstract class JObject extends JContainer[JField] {
override def productPrefix = "JObject"
def canEqual(that: Any): Boolean = that.isInstanceOf[JObject]
}
object JObject {
def apply(fields: JField*): JObject = create_unsafe(fields.toArray)
def apply(fields: Vector[JField]): JObject = create_unsafe(fields.toArray)
def apply(fields: Array[JField]): JObject = JObject(fields, 0, fields.length)
def apply(fields: Array[JField], start: Int, end: Int): JObject = {
val len = end - start
if (len < 0) throw new IllegalArgumentException(s"$start > $end")
val slice = new Array[JField](len)
System.arraycopy(fields, start, slice, 0, math.min(fields.length - start, len))
create_unsafe(slice)
}
def create_unsafe(_fields: Array[JField]): JObject =
new JObject {
def underlyingArray_unsafe = _fields
}
def unapply(obj: JObject): JObject = obj
}
final case class JField(key: String, value: JValue)
sealed abstract class JArray extends JContainer[JValue] {
override def productPrefix = "JArray"
def canEqual(that: Any): Boolean = that.isInstanceOf[JArray]
}
object JArray {
def apply(elements: JValue*): JArray = create_unsafe(elements.toArray)
def apply(elements: Vector[JValue]): JArray = create_unsafe(elements.toArray)
def apply(elements: Array[JValue]): JArray = JArray(elements, 0, elements.length)
def apply(elements: Array[JValue], start: Int, end: Int): JArray = {
val len = end - start
if (len < 0) throw new IllegalArgumentException(s"$start > $end")
val slice = new Array[JValue](len)
System.arraycopy(elements, start, slice, 0, math.min(elements.length - start, len))
create_unsafe(slice)
}
def create_unsafe(_elements: Array[JValue]): JArray =
new JArray {
def underlyingArray_unsafe = _elements
}
def unapply(obj: JArray): JArray = obj
}
package org.json4s.basic.ast
/**
* Minimal AST for " The JavaScript Object Notation (JSON) Data Interchange Format"
* RFC 7159 (https://tools.ietf.org/html/rfc7159)
*/
sealed abstract class JValue extends Serializable with Product
case object JNull extends JValue
sealed abstract class JBoolean extends JValue {
def isEmpty = false
def get: Boolean = value
def value: Boolean
}
object JBoolean {
def apply(x: Boolean): JBoolean = if (x) JTrue else JFalse
}
case object JTrue extends JBoolean {
def value = true
}
case object JFalse extends JBoolean {
def value = false
}
final case class JString(value: String) extends JValue
/**
* Contract: `value` *must* be formatted according to https://tools.ietf.org/html/rfc7159#section-6
*/
final case class JNumber(value: String) extends JValue
object JNumber {
def apply(value: Byte): JNumber = JNumber(value.toString)
def apply(value: Short): JNumber = JNumber(value.toString)
def apply(value: Int): JNumber = JNumber(value.toString)
def apply(value: Long): JNumber = JNumber(value.toString)
def apply(value: Float): JNumber = JNumber(value.toString)
def apply(value: Double): JNumber = JNumber(value.toString)
def apply(value: BigInt): JNumber = JNumber(value.toString)
def apply(value: BigDecimal): JNumber = JNumber(value.toString)
}
final case class JObject(fields: Vector[JField]) extends JValue
final case class JField(key: String, value: JValue)
final case class JArray(elements: Vector[JValue]) extends JValue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment