add json module json

This commit is contained in:
tursom 2020-11-04 14:40:13 +08:00
parent 37b2cbfedd
commit 9e9cd7695c
3 changed files with 218 additions and 1 deletions

View File

@ -16,4 +16,5 @@ include 'utils:mail'
include 'utils:csv'
include 'utils:TrafficForward'
include 'utils:performance-test'
include 'utils:math'
include 'utils:math'
include 'utils:json'

3
utils/json/build.gradle Normal file
View File

@ -0,0 +1,3 @@
dependencies {
compile project(":")
}

View File

@ -0,0 +1,213 @@
package cn.tursom.utils.json
import com.sun.org.apache.xalan.internal.lib.ExsltMath.power
import java.lang.RuntimeException
object Json {
class JsonFormatException(message: String? = null) : RuntimeException(message) {
internal constructor(content: JsonParseContent) : this("${content.json}[${content.index}]")
}
fun parse(json: String): Any? {
val content = JsonParseContent(json)
val parse = parse(content)
jumpWhitespace(content)
if (content.index != json.length) throw JsonFormatException(json)
return parse
}
internal data class JsonParseContent(inline val json: String, inline var index: Int = 0)
private fun parse(content: JsonParseContent): Any? {
jumpWhitespace(content)
return when (content.json[content.index]) {
'{' -> parseObj(content)
'[' -> parseArray(content)
'"' -> parseString(content)
'+', '-', in '0'..'9' -> parseNumber(content)
't', 'f' -> parseBoolean(content)
'n' -> parseNull(content)
else -> throw JsonFormatException(content)
}
}
@Suppress("NOTHING_TO_INLINE")
private inline fun parseNull(content: JsonParseContent) = if (content.json.startsWith("null", content.index)) {
content.index += 4
null
} else throw JsonFormatException(content)
@Suppress("ControlFlowWithEmptyBody", "NOTHING_TO_INLINE")
private inline fun parseBoolean(content: JsonParseContent) = when {
content.json.startsWith("true", content.index) -> {
content.index += 4
true
}
content.json.startsWith("false", content.index) -> {
content.index += 5
false
}
else -> throw JsonFormatException(content)
}
@Suppress("NOTHING_TO_INLINE")
private inline fun jumpWhitespaceLoopCondition(json: String, index: Int) = index < json.length && json[index] in " \t\r\n"
@Suppress("NOTHING_TO_INLINE")
private inline fun jumpWhitespace(content: JsonParseContent) {
@Suppress("ControlFlowWithEmptyBody")
if (jumpWhitespaceLoopCondition(content.json, content.index)) while (jumpWhitespaceLoopCondition(content.json, ++content.index));
}
@Suppress("NOTHING_TO_INLINE")
private inline fun charToInt(char: Char): Int {
val indexOf = char - '0'
if (indexOf < 0 || indexOf > 9) throw JsonFormatException("$char is not an number")
return indexOf
}
@Suppress("NOTHING_TO_INLINE")
private inline fun parseInt(content: JsonParseContent): Number {
var number = charToInt(content.json[content.index]).toLong()
while (++content.index < content.json.length && content.json[content.index] in '0'..'9') {
number = number * 10 + charToInt(content.json[content.index])
}
return if (number <= Int.MAX_VALUE) number.toInt() else number
}
@Suppress("NOTHING_TO_INLINE")
private inline fun parseNumber(content: JsonParseContent): Number {
val negative = content.json[content.index] == '-'
if (negative || content.json[content.index] == '+') content.index++
var number: Number = when (content.json[content.index]) {
in '0'..'9' -> parseInt(content)
else -> throw JsonFormatException(content)
}
if (content.index < content.json.length && content.json[content.index] == '.') {
if (++content.index >= content.json.length) throw JsonFormatException(content)
var base = 0.1
var double = charToInt(content.json[content.index]) * base
while (++content.index < content.json.length && content.json[content.index] in '0'..'9') {
base *= 0.1
double += charToInt(content.json[content.index]) * base
}
number = number.toDouble() + double
}
if (content.index < content.json.length && content.json[content.index] in "eE") {
val powerNegative = when (content.json[++content.index]) {
'-' -> true
'+' -> false
else -> {
content.index--
false
}
}
content.index++
number = number.toDouble() * power(10.0, parseInt(content).toLong() * if (powerNegative) -1.0 else 1.0)
}
return if (negative) when (number) {
is Int -> -number
is Long -> -number
else -> -number.toDouble()
} else number
}
@Suppress("NOTHING_TO_INLINE")
private inline fun parseString(content: JsonParseContent): String {
if (content.json[content.index++] != '"') throw JsonFormatException("string not begin with '\"'")
val builder = StringBuilder()
while (content.index < content.json.length) when (content.json[content.index]) {
'\\' -> {
when (content.json[++content.index]) {
'b' -> builder.append('\b')
'f' -> builder.append('\u000C')
'n' -> builder.append('\n')
'r' -> builder.append('\r')
't' -> builder.append('\t')
'u' -> {
var char = 0
repeat(4) {
val indexOf = "0123456789abcdef".indexOf(content.json[++content.index].toLowerCase())
if (indexOf < 0) throw JsonFormatException(content)
char = char * 16 + indexOf
}
builder.append(char.toChar())
}
else -> builder.append(content.json[content.index])
}
content.index++
}
'"' -> {
content.index++
return builder.toString()
}
else -> builder.append(content.json[content.index++])
}
throw JsonFormatException(content)
}
@Suppress("NOTHING_TO_INLINE")
private inline fun parseObj(content: JsonParseContent): Map<String, Any?> {
if (content.json[content.index++] != '{') throw JsonFormatException(content)
jumpWhitespace(content)
if (content.json[content.index] == '}') {
content.index++
return emptyMap()
}
val map = HashMap<String, Any?>()
while (true) {
jumpWhitespace(content)
val key = parseString(content)
jumpWhitespace(content)
if (content.json[content.index++] != ':') throw JsonFormatException(content)
map[key] = parse(content)
jumpWhitespace(content)
when (content.json[content.index++]) {
',' -> continue
'}' -> break
else -> throw JsonFormatException("json object not ends with '}'")
}
}
return map
}
@Suppress("NOTHING_TO_INLINE")
private inline fun parseArray(content: JsonParseContent): List<Any?> {
if (content.json[content.index++] != '[') throw JsonFormatException(content)
jumpWhitespace(content)
if (content.json[content.index] == ']') {
content.index++
return emptyList()
}
val array = ArrayList<Any?>()
while (true) {
array.add(parse(content))
jumpWhitespace(content)
if (content.index >= content.json.length) throw JsonFormatException(content)
when (content.json[content.index++]) {
',' -> continue
']' -> break
else -> throw JsonFormatException(content)
}
}
return array
}
}
//fun main() {
// println(Json.parse(" null "))
// println(Json.parse(" true "))
// println(Json.parse(" false "))
// println(Json.parse(" 123 "))
// println(Json.parse(" -123 "))
// println(Json.parse(" 123.0 "))
// println(Json.parse(" 123.0 "))
// println(Json.parse(" 123e2 "))
// println(Json.parse(" 123e10 "))
// println(Json.parse(" -123.5e10 "))
// println(Json.parse(" \"bb-12\\t3\\\".5e10aa\" "))
// println(Json.parse(" {} "))
// println(Json.parse(" {\"a\":3, \"c\": {}} "))
// println(Json.parse("[1,3, 4 ,\"cc\\u0041\" , true , false , null , {}, {\"a\":\"b\"} , [ ] , [] , {\"a\":3, \"c\": {}, \"b\":[]}]"))
// println(Json.parse(" [1,3,4] "))
//}