Use allocator backed array for json value decoder

This commit is contained in:
Marc Tiehuis 2018-05-03 19:26:24 +12:00
parent f17472635e
commit ef3111be23

View File

@ -1017,9 +1017,7 @@ const JsonParser = struct {
state: State, state: State,
copy_strings: bool, copy_strings: bool,
// Stores parent nodes and un-combined Values. // Stores parent nodes and un-combined Values.
// Worst case scenario we have nested key, values and so need two times the stack size. stack: ArrayList(Value),
stack: [2 * StreamingJsonParser.max_stack_size]Value,
stack_used: u16,
const State = enum { const State = enum {
ObjectKey, ObjectKey,
@ -1033,14 +1031,17 @@ const JsonParser = struct {
.allocator = allocator, .allocator = allocator,
.state = State.Simple, .state = State.Simple,
.copy_strings = copy_strings, .copy_strings = copy_strings,
.stack = undefined, .stack = ArrayList(Value).init(allocator),
.stack_used = 0,
}; };
} }
pub fn deinit(p: &JsonParser) void {
p.stack.deinit();
}
pub fn reset(p: &JsonParser) void { pub fn reset(p: &JsonParser) void {
p.state = State.Simple; p.state = State.Simple;
p.stack_used = 0; p.stack.shrink(0);
} }
pub fn parse(p: &JsonParser, input: []const u8) !ValueTree { pub fn parse(p: &JsonParser, input: []const u8) !ValueTree {
@ -1079,11 +1080,11 @@ const JsonParser = struct {
return error.IncompleteJsonInput; return error.IncompleteJsonInput;
} }
std.debug.assert(p.stack_used == 1); std.debug.assert(p.stack.len == 1);
return ValueTree { return ValueTree {
.arena = arena, .arena = arena,
.root = p.stack[0], .root = p.stack.at(0),
}; };
} }
@ -1093,16 +1094,15 @@ const JsonParser = struct {
switch (p.state) { switch (p.state) {
State.ObjectKey => switch (token.id) { State.ObjectKey => switch (token.id) {
Token.Id.ObjectEnd => { Token.Id.ObjectEnd => {
if (p.stack_used == 1) { if (p.stack.len == 1) {
return; return;
} }
var value = p.stack[p.stack_used - 1]; var value = p.stack.pop();
p.stack_used -= 1;
try p.pushToParent(value); try p.pushToParent(value);
}, },
Token.Id.String => { Token.Id.String => {
p.pushStack(try p.parseString(allocator, token, input, i)); try p.stack.append(try p.parseString(allocator, token, input, i));
p.state = State.ObjectValue; p.state = State.ObjectValue;
}, },
else => { else => {
@ -1110,41 +1110,41 @@ const JsonParser = struct {
}, },
}, },
State.ObjectValue => { State.ObjectValue => {
var object = &p.stack[p.stack_used - 2].Object; var object = &p.stack.items[p.stack.len - 2].Object;
var key = p.stack[p.stack_used - 1].String; var key = p.stack.items[p.stack.len - 1].String;
switch (token.id) { switch (token.id) {
Token.Id.ObjectBegin => { Token.Id.ObjectBegin => {
p.pushStack(Value { .Object = ObjectMap.init(allocator) }); try p.stack.append(Value { .Object = ObjectMap.init(allocator) });
p.state = State.ObjectKey; p.state = State.ObjectKey;
}, },
Token.Id.ArrayBegin => { Token.Id.ArrayBegin => {
p.pushStack(Value { .Array = ArrayList(Value).init(allocator) }); try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });
p.state = State.ArrayValue; p.state = State.ArrayValue;
}, },
Token.Id.String => { Token.Id.String => {
_ = try object.put(key, try p.parseString(allocator, token, input, i)); _ = try object.put(key, try p.parseString(allocator, token, input, i));
p.stack_used -= 1; _ = p.stack.pop();
p.state = State.ObjectKey; p.state = State.ObjectKey;
}, },
Token.Id.Number => { Token.Id.Number => {
_ = try object.put(key, try p.parseNumber(token, input, i)); _ = try object.put(key, try p.parseNumber(token, input, i));
p.stack_used -= 1; _ = p.stack.pop();
p.state = State.ObjectKey; p.state = State.ObjectKey;
}, },
Token.Id.True => { Token.Id.True => {
_ = try object.put(key, Value { .Bool = true }); _ = try object.put(key, Value { .Bool = true });
p.stack_used -= 1; _ = p.stack.pop();
p.state = State.ObjectKey; p.state = State.ObjectKey;
}, },
Token.Id.False => { Token.Id.False => {
_ = try object.put(key, Value { .Bool = false }); _ = try object.put(key, Value { .Bool = false });
p.stack_used -= 1; _ = p.stack.pop();
p.state = State.ObjectKey; p.state = State.ObjectKey;
}, },
Token.Id.Null => { Token.Id.Null => {
_ = try object.put(key, Value.Null); _ = try object.put(key, Value.Null);
p.stack_used -= 1; _ = p.stack.pop();
p.state = State.ObjectKey; p.state = State.ObjectKey;
}, },
else => { else => {
@ -1153,24 +1153,23 @@ const JsonParser = struct {
} }
}, },
State.ArrayValue => { State.ArrayValue => {
var array = &p.stack[p.stack_used - 1].Array; var array = &p.stack.items[p.stack.len - 1].Array;
switch (token.id) { switch (token.id) {
Token.Id.ArrayEnd => { Token.Id.ArrayEnd => {
if (p.stack_used == 1) { if (p.stack.len == 1) {
return; return;
} }
var value = p.stack[p.stack_used - 1]; var value = p.stack.pop();
p.stack_used -= 1;
try p.pushToParent(value); try p.pushToParent(value);
}, },
Token.Id.ObjectBegin => { Token.Id.ObjectBegin => {
p.pushStack(Value { .Object = ObjectMap.init(allocator) }); try p.stack.append(Value { .Object = ObjectMap.init(allocator) });
p.state = State.ObjectKey; p.state = State.ObjectKey;
}, },
Token.Id.ArrayBegin => { Token.Id.ArrayBegin => {
p.pushStack(Value { .Array = ArrayList(Value).init(allocator) }); try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });
p.state = State.ArrayValue; p.state = State.ArrayValue;
}, },
Token.Id.String => { Token.Id.String => {
@ -1195,27 +1194,27 @@ const JsonParser = struct {
}, },
State.Simple => switch (token.id) { State.Simple => switch (token.id) {
Token.Id.ObjectBegin => { Token.Id.ObjectBegin => {
p.pushStack(Value { .Object = ObjectMap.init(allocator) }); try p.stack.append(Value { .Object = ObjectMap.init(allocator) });
p.state = State.ObjectKey; p.state = State.ObjectKey;
}, },
Token.Id.ArrayBegin => { Token.Id.ArrayBegin => {
p.pushStack(Value { .Array = ArrayList(Value).init(allocator) }); try p.stack.append(Value { .Array = ArrayList(Value).init(allocator) });
p.state = State.ArrayValue; p.state = State.ArrayValue;
}, },
Token.Id.String => { Token.Id.String => {
p.pushStack(try p.parseString(allocator, token, input, i)); try p.stack.append(try p.parseString(allocator, token, input, i));
}, },
Token.Id.Number => { Token.Id.Number => {
p.pushStack(try p.parseNumber(token, input, i)); try p.stack.append(try p.parseNumber(token, input, i));
}, },
Token.Id.True => { Token.Id.True => {
p.pushStack(Value { .Bool = true }); try p.stack.append(Value { .Bool = true });
}, },
Token.Id.False => { Token.Id.False => {
p.pushStack(Value { .Bool = false }); try p.stack.append(Value { .Bool = false });
}, },
Token.Id.Null => { Token.Id.Null => {
p.pushStack(Value.Null); try p.stack.append(Value.Null);
}, },
Token.Id.ObjectEnd, Token.Id.ArrayEnd => { Token.Id.ObjectEnd, Token.Id.ArrayEnd => {
unreachable; unreachable;
@ -1225,12 +1224,12 @@ const JsonParser = struct {
} }
fn pushToParent(p: &JsonParser, value: &const Value) !void { fn pushToParent(p: &JsonParser, value: &const Value) !void {
switch (p.stack[p.stack_used - 1]) { switch (p.stack.at(p.stack.len - 1)) {
// Object Parent -> [ ..., object, <key>, value ] // Object Parent -> [ ..., object, <key>, value ]
Value.String => |key| { Value.String => |key| {
p.stack_used -= 1; _ = p.stack.pop();
var object = &p.stack[p.stack_used - 1].Object; var object = &p.stack.items[p.stack.len - 1].Object;
_ = try object.put(key, value); _ = try object.put(key, value);
p.state = State.ObjectKey; p.state = State.ObjectKey;
}, },
@ -1245,11 +1244,6 @@ const JsonParser = struct {
} }
} }
fn pushStack(p: &JsonParser, value: &const Value) void {
p.stack[p.stack_used] = *value;
p.stack_used += 1;
}
fn parseString(p: &JsonParser, allocator: &Allocator, token: &const Token, input: []const u8, i: usize) !Value { fn parseString(p: &JsonParser, allocator: &Allocator, token: &const Token, input: []const u8, i: usize) !Value {
// TODO: We don't strictly have to copy values which do not contain any escape // TODO: We don't strictly have to copy values which do not contain any escape
// characters if flagged with the option. // characters if flagged with the option.
@ -1270,6 +1264,7 @@ const debug = std.debug;
test "json parser dynamic" { test "json parser dynamic" {
var p = JsonParser.init(std.debug.global_allocator, false); var p = JsonParser.init(std.debug.global_allocator, false);
defer p.deinit();
const s = const s =
\\{ \\{
@ -1289,7 +1284,8 @@ test "json parser dynamic" {
; ;
var tree = try p.parse(s); var tree = try p.parse(s);
tree.deinit(); defer tree.deinit();
var root = tree.root; var root = tree.root;
var image = (??root.Object.get("Image")).value; var image = (??root.Object.get("Image")).value;