mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-26 12:55:06 +00:00
Use tables instead of seqs for json objects
Significant speedup for some operations, fixes #3809 Not tested very well yet
This commit is contained in:
@@ -51,7 +51,7 @@
|
||||
## ]
|
||||
|
||||
import
|
||||
hashes, strutils, lexbase, streams, unicode, macros
|
||||
hashes, tables, strutils, lexbase, streams, unicode, macros
|
||||
|
||||
type
|
||||
JsonEventKind* = enum ## enumeration of all events that may occur when parsing
|
||||
@@ -567,7 +567,7 @@ type
|
||||
of JNull:
|
||||
nil
|
||||
of JObject:
|
||||
fields*: seq[tuple[key: string, val: JsonNode]]
|
||||
fields*: Table[string, JsonNode]
|
||||
of JArray:
|
||||
elems*: seq[JsonNode]
|
||||
|
||||
@@ -617,7 +617,7 @@ proc newJObject*(): JsonNode =
|
||||
## Creates a new `JObject JsonNode`
|
||||
new(result)
|
||||
result.kind = JObject
|
||||
result.fields = @[]
|
||||
result.fields = initTable[string, JsonNode]()
|
||||
|
||||
proc newJArray*(): JsonNode =
|
||||
## Creates a new `JArray JsonNode`
|
||||
@@ -657,8 +657,8 @@ proc getBVal*(n: JsonNode, default: bool = false): bool =
|
||||
else: return n.bval
|
||||
|
||||
proc getFields*(n: JsonNode,
|
||||
default: seq[tuple[key: string, val: JsonNode]] = @[]):
|
||||
seq[tuple[key: string, val: JsonNode]] =
|
||||
default = initTable[string, JsonNode]()):
|
||||
Table[string, JsonNode] =
|
||||
## Retrieves the key, value pairs of a `JObject JsonNode`.
|
||||
##
|
||||
## Returns ``default`` if ``n`` is not a ``JObject``, or if ``n`` is nil.
|
||||
@@ -700,8 +700,8 @@ proc `%`*(keyVals: openArray[tuple[key: string, val: JsonNode]]): JsonNode =
|
||||
## Generic constructor for JSON data. Creates a new `JObject JsonNode`
|
||||
new(result)
|
||||
result.kind = JObject
|
||||
newSeq(result.fields, keyVals.len)
|
||||
for i, p in pairs(keyVals): result.fields[i] = p
|
||||
result.fields = initTable[string, JsonNode]()
|
||||
for key, val in items(keyVals): result.fields[key] = val
|
||||
|
||||
proc `%`*(elements: openArray[JsonNode]): JsonNode =
|
||||
## Generic constructor for JSON data. Creates a new `JArray JsonNode`
|
||||
@@ -761,7 +761,9 @@ proc `==`* (a,b: JsonNode): bool =
|
||||
of JObject:
|
||||
a.fields == b.fields
|
||||
|
||||
proc hash* (n:JsonNode): Hash =
|
||||
proc hash*(n: Table[string, JsonNode]): Hash
|
||||
|
||||
proc hash*(n: JsonNode): Hash =
|
||||
## Compute the hash for a JSON node
|
||||
case n.kind
|
||||
of JArray:
|
||||
@@ -779,6 +781,11 @@ proc hash* (n:JsonNode): Hash =
|
||||
of JNull:
|
||||
result = hash(0)
|
||||
|
||||
proc hash*(n: Table[string, JsonNode]): Hash =
|
||||
for key, val in n:
|
||||
result = result !& hash(key) !& hash(val)
|
||||
result = !$result
|
||||
|
||||
proc len*(n: JsonNode): int =
|
||||
## If `n` is a `JArray`, it returns the number of elements.
|
||||
## If `n` is a `JObject`, it returns the number of pairs.
|
||||
@@ -793,10 +800,7 @@ proc `[]`*(node: JsonNode, name: string): JsonNode {.inline.} =
|
||||
## If the value at `name` does not exist, returns nil
|
||||
assert(not isNil(node))
|
||||
assert(node.kind == JObject)
|
||||
for key, item in items(node.fields):
|
||||
if key == name:
|
||||
return item
|
||||
return nil
|
||||
result = node.fields.getOrDefault(name)
|
||||
|
||||
proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} =
|
||||
## Gets the node at `index` in an Array. Result is undefined if `index`
|
||||
@@ -808,8 +812,7 @@ proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} =
|
||||
proc hasKey*(node: JsonNode, key: string): bool =
|
||||
## Checks if `key` exists in `node`.
|
||||
assert(node.kind == JObject)
|
||||
for k, item in items(node.fields):
|
||||
if k == key: return true
|
||||
result = node.fields.hasKey(key)
|
||||
|
||||
proc existsKey*(node: JsonNode, key: string): bool {.deprecated.} = node.hasKey(key)
|
||||
## Deprecated for `hasKey`
|
||||
@@ -820,20 +823,14 @@ proc add*(father, child: JsonNode) =
|
||||
father.elems.add(child)
|
||||
|
||||
proc add*(obj: JsonNode, key: string, val: JsonNode) =
|
||||
## Adds ``(key, val)`` pair to the JObject node `obj`. For speed
|
||||
## reasons no check for duplicate keys is performed!
|
||||
## But ``[]=`` performs the check.
|
||||
## Sets a field from a `JObject`.
|
||||
assert obj.kind == JObject
|
||||
obj.fields.add((key, val))
|
||||
obj.fields[key] = val
|
||||
|
||||
proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} =
|
||||
## Sets a field from a `JObject`. Performs a check for duplicate keys.
|
||||
## Sets a field from a `JObject`.
|
||||
assert(obj.kind == JObject)
|
||||
for i in 0..obj.fields.len-1:
|
||||
if obj.fields[i].key == key:
|
||||
obj.fields[i].val = val
|
||||
return
|
||||
obj.fields.add((key, val))
|
||||
obj.fields[key] = val
|
||||
|
||||
proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
|
||||
## Traverses the node and gets the given value. If any of the
|
||||
@@ -856,13 +853,11 @@ proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
|
||||
node[keys[keys.len-1]] = value
|
||||
|
||||
proc delete*(obj: JsonNode, key: string) =
|
||||
## Deletes ``obj[key]`` preserving the order of the other (key, value)-pairs.
|
||||
## Deletes ``obj[key]``.
|
||||
assert(obj.kind == JObject)
|
||||
for i in 0..obj.fields.len-1:
|
||||
if obj.fields[i].key == key:
|
||||
obj.fields.delete(i)
|
||||
return
|
||||
raise newException(IndexError, "key not in object")
|
||||
if not obj.fields.hasKey(key):
|
||||
raise newException(IndexError, "key not in object")
|
||||
obj.fields.del(key)
|
||||
|
||||
proc copy*(p: JsonNode): JsonNode =
|
||||
## Performs a deep copy of `a`.
|
||||
@@ -879,8 +874,8 @@ proc copy*(p: JsonNode): JsonNode =
|
||||
result = newJNull()
|
||||
of JObject:
|
||||
result = newJObject()
|
||||
for key, field in items(p.fields):
|
||||
result.fields.add((key, copy(field)))
|
||||
for key, val in pairs(p.fields):
|
||||
result.fields[key] = copy(val)
|
||||
of JArray:
|
||||
result = newJArray()
|
||||
for i in items(p.elems):
|
||||
@@ -924,15 +919,17 @@ proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true,
|
||||
if node.fields.len > 0:
|
||||
result.add("{")
|
||||
result.nl(ml) # New line
|
||||
for i in 0..len(node.fields)-1:
|
||||
var i = 0
|
||||
for key, val in pairs(node.fields):
|
||||
if i > 0:
|
||||
result.add(", ")
|
||||
result.nl(ml) # New Line
|
||||
inc i
|
||||
# Need to indent more than {
|
||||
result.indent(newIndent(currIndent, indent, ml))
|
||||
result.add(escapeJson(node.fields[i].key))
|
||||
result.add(escapeJson(key))
|
||||
result.add(": ")
|
||||
toPretty(result, node.fields[i].val, indent, ml, false,
|
||||
toPretty(result, val, indent, ml, false,
|
||||
newIndent(currIndent, indent, ml))
|
||||
result.nl(ml)
|
||||
result.indent(currIndent) # indent the same as {
|
||||
@@ -994,7 +991,7 @@ proc toUgly*(result: var string, node: JsonNode) =
|
||||
result.add "]"
|
||||
of JObject:
|
||||
result.add "{"
|
||||
for key, value in items(node.fields):
|
||||
for key, value in pairs(node.fields):
|
||||
if comma: result.add ","
|
||||
else: comma = true
|
||||
result.add key.escapeJson()
|
||||
@@ -1033,15 +1030,15 @@ iterator mitems*(node: var JsonNode): var JsonNode =
|
||||
iterator pairs*(node: JsonNode): tuple[key: string, val: JsonNode] =
|
||||
## Iterator for the child elements of `node`. `node` has to be a JObject.
|
||||
assert node.kind == JObject
|
||||
for key, val in items(node.fields):
|
||||
for key, val in pairs(node.fields):
|
||||
yield (key, val)
|
||||
|
||||
iterator mpairs*(node: var JsonNode): var tuple[key: string, val: JsonNode] =
|
||||
iterator mpairs*(node: var JsonNode): tuple[key: string, val: var JsonNode] =
|
||||
## Iterator for the child elements of `node`. `node` has to be a JObject.
|
||||
## Items can be modified
|
||||
## Values can be modified
|
||||
assert node.kind == JObject
|
||||
for keyVal in mitems(node.fields):
|
||||
yield keyVal
|
||||
for key, val in mpairs(node.fields):
|
||||
yield (key, val)
|
||||
|
||||
proc eat(p: var JsonParser, tok: TokKind) =
|
||||
if p.tok == tok: discard getTok(p)
|
||||
|
||||
Reference in New Issue
Block a user